|
9 | 9 | * @package WordPress |
10 | 10 | */ |
11 | 11 |
|
| 12 | +const child_process = require( 'child_process' ); |
12 | 13 | const fs = require( 'fs' ); |
13 | 14 | const path = require( 'path' ); |
14 | 15 | const json2php = require( 'json2php' ); |
@@ -353,18 +354,9 @@ function generateScriptModulesPackages() { |
353 | 354 | const jsPathRegular = jsPathMin.replace( /\.min\.js$/, '.js' ); |
354 | 355 |
|
355 | 356 | try { |
356 | | - // Read and parse the PHP asset file. |
357 | | - const phpContent = fs.readFileSync( fullPath, 'utf8' ); |
358 | | - // Extract the array from PHP: <?php return array(...); |
359 | | - const match = phpContent.match( |
360 | | - /return\s+array\(([\s\S]*?)\);/ |
361 | | - ); |
362 | | - if ( match ) { |
363 | | - // Parse PHP array to JavaScript object. |
364 | | - const assetData = parsePHPArray( match[ 1 ] ); |
365 | | - assetsMin[ jsPathMin ] = assetData; |
366 | | - assetsRegular[ jsPathRegular ] = assetData; |
367 | | - } |
| 357 | + const assetData = readReturnedValueFromPHPFile( fullPath ); |
| 358 | + assetsMin[ jsPathMin ] = assetData; |
| 359 | + assetsRegular[ jsPathRegular ] = assetData; |
368 | 360 | } catch ( error ) { |
369 | 361 | console.error( |
370 | 362 | ` ⚠️ Error reading ${ relativePath }:`, |
@@ -446,26 +438,19 @@ function generateScriptLoaderPackages() { |
446 | 438 | } |
447 | 439 |
|
448 | 440 | try { |
449 | | - // Read and parse the PHP asset file. |
450 | | - const phpContent = fs.readFileSync( assetFile, 'utf8' ); |
451 | | - // Extract the array from PHP: <?php return array(...); |
452 | | - const match = phpContent.match( /return\s+array\(([\s\S]*?)\);/ ); |
453 | | - if ( match ) { |
454 | | - // Parse PHP array to JavaScript object. |
455 | | - const assetData = parsePHPArray( match[ 1 ] ); |
456 | | - |
457 | | - // For regular scripts, use dependencies as-is. |
458 | | - if ( ! assetData.dependencies ) { |
459 | | - assetData.dependencies = []; |
460 | | - } |
| 441 | + const assetData = readReturnedValueFromPHPFile( assetFile ); |
461 | 442 |
|
462 | | - // Create entries for both minified and non-minified versions. |
463 | | - const jsPathMin = `${ entry.name }.min.js`; |
464 | | - const jsPathRegular = `${ entry.name }.js`; |
465 | | - |
466 | | - assetsMin[ jsPathMin ] = assetData; |
467 | | - assetsRegular[ jsPathRegular ] = assetData; |
| 443 | + // For regular scripts, use dependencies as-is. |
| 444 | + if ( ! assetData.dependencies ) { |
| 445 | + assetData.dependencies = []; |
468 | 446 | } |
| 447 | + |
| 448 | + // Create entries for both minified and non-minified versions. |
| 449 | + const jsPathMin = `${ entry.name }.min.js`; |
| 450 | + const jsPathRegular = `${ entry.name }.js`; |
| 451 | + |
| 452 | + assetsMin[ jsPathMin ] = assetData; |
| 453 | + assetsRegular[ jsPathRegular ] = assetData; |
469 | 454 | } catch ( error ) { |
470 | 455 | console.error( |
471 | 456 | ` ⚠️ Error reading ${ entry.name }/index.min.asset.php:`, |
@@ -663,179 +648,39 @@ function generateBlocksJson() { |
663 | 648 | } |
664 | 649 |
|
665 | 650 | /** |
666 | | - * Parse PHP array syntax to JavaScript object. |
667 | | - * Uses a simple but effective approach for the specific format in asset files. |
| 651 | + * Given a path to a PHP file which returns a single value, converts that |
| 652 | + * value into a native JavaScript value (limited by JSON serialization). |
668 | 653 | * |
669 | | - * @param {string} phpArrayContent - PHP array content (without outer 'array(' and ')'). |
670 | | - * @return {Object|Array} Parsed JavaScript object or array. |
| 654 | + * @throws Error when PHP source file unable to be read, or PHP is unavailable. |
| 655 | + * |
| 656 | + * @param {string} phpFilepath Absolute path of PHP file returning a single value. |
| 657 | + * @return {Object|Array} JavaScript representation of value from input file. |
671 | 658 | */ |
672 | | -function parsePHPArray( phpArrayContent ) { |
673 | | - phpArrayContent = phpArrayContent.trim(); |
674 | | - |
675 | | - // First, extract all nested array() blocks and replace with placeholders. |
676 | | - const nestedArrays = []; |
677 | | - let content = phpArrayContent; |
678 | | - let depth = 0; |
679 | | - let inString = false; |
680 | | - let stringChar = ''; |
681 | | - let currentArray = ''; |
682 | | - let arrayStart = -1; |
683 | | - |
684 | | - for ( let i = 0; i < content.length; i++ ) { |
685 | | - const char = content[ i ]; |
686 | | - |
687 | | - // Track strings. |
688 | | - if ( |
689 | | - ( char === "'" || char === '"' ) && |
690 | | - ( i === 0 || content[ i - 1 ] !== '\\' ) |
691 | | - ) { |
692 | | - if ( ! inString ) { |
693 | | - inString = true; |
694 | | - stringChar = char; |
695 | | - } else if ( char === stringChar ) { |
696 | | - inString = false; |
697 | | - } |
698 | | - } |
699 | | - |
700 | | - if ( ! inString ) { |
701 | | - // Look for array( keyword. |
702 | | - if ( content.substring( i, i + 6 ) === 'array(' ) { |
703 | | - if ( depth === 0 ) { |
704 | | - arrayStart = i; |
705 | | - currentArray = ''; |
706 | | - } |
707 | | - depth++; |
708 | | - if ( depth > 1 ) { |
709 | | - currentArray += 'array('; |
710 | | - } |
711 | | - i += 5; // Skip 'array('. |
712 | | - continue; |
713 | | - } |
714 | | - |
715 | | - if ( depth > 0 ) { |
716 | | - if ( char === '(' ) { |
717 | | - depth++; |
718 | | - currentArray += char; |
719 | | - } else if ( char === ')' ) { |
720 | | - depth--; |
721 | | - if ( depth === 0 ) { |
722 | | - // Found complete nested array. |
723 | | - const placeholder = `__ARRAY_${ nestedArrays.length }__`; |
724 | | - nestedArrays.push( currentArray ); |
725 | | - content = |
726 | | - content.substring( 0, arrayStart ) + |
727 | | - placeholder + |
728 | | - content.substring( i + 1 ); |
729 | | - i = arrayStart + placeholder.length - 1; |
730 | | - currentArray = ''; |
731 | | - } else { |
732 | | - currentArray += char; |
733 | | - } |
734 | | - } else { |
735 | | - currentArray += char; |
736 | | - } |
737 | | - } |
738 | | - } else if ( depth > 0 ) { |
739 | | - currentArray += char; |
740 | | - } |
741 | | - } |
742 | | - |
743 | | - // Now parse the simplified content. |
744 | | - const result = {}; |
745 | | - const values = []; |
746 | | - let isAssociative = false; |
747 | | - |
748 | | - // Split by top-level commas. |
749 | | - const parts = []; |
750 | | - depth = 0; |
751 | | - inString = false; |
752 | | - let currentPart = ''; |
753 | | - |
754 | | - for ( let i = 0; i < content.length; i++ ) { |
755 | | - const char = content[ i ]; |
756 | | - |
757 | | - if ( |
758 | | - ( char === "'" || char === '"' ) && |
759 | | - ( i === 0 || content[ i - 1 ] !== '\\' ) |
760 | | - ) { |
761 | | - inString = ! inString; |
762 | | - } |
763 | | - |
764 | | - if ( ! inString && char === ',' && depth === 0 ) { |
765 | | - parts.push( currentPart.trim() ); |
766 | | - currentPart = ''; |
767 | | - } else { |
768 | | - currentPart += char; |
769 | | - if ( ! inString ) { |
770 | | - if ( char === '(' ) { |
771 | | - depth++; |
772 | | - } |
773 | | - if ( char === ')' ) { |
774 | | - depth--; |
775 | | - } |
776 | | - } |
| 659 | +function readReturnedValueFromPHPFile( phpFilepath ) { |
| 660 | + const results = child_process.spawnSync( |
| 661 | + 'php', |
| 662 | + [ '-r', '$path = file_get_contents( "php://stdin" ); if ( ! is_file( $path ) ) { die( 1 ); } try { $data = require $path; } catch ( \\Throwable $e ) { die( 2 ); } $json = json_encode( $data ); if ( ! is_string( $json ) ) { die( 3 ); } echo $json;' ], |
| 663 | + { |
| 664 | + encoding: 'utf8', |
| 665 | + input: phpFilepath, |
777 | 666 | } |
778 | | - } |
779 | | - if ( currentPart.trim() ) { |
780 | | - parts.push( currentPart.trim() ); |
781 | | - } |
782 | | - |
783 | | - // Parse each part. |
784 | | - for ( const part of parts ) { |
785 | | - const arrowMatch = part.match( /^(.+?)\s*=>\s*(.+)$/ ); |
786 | | - |
787 | | - if ( arrowMatch ) { |
788 | | - isAssociative = true; |
789 | | - let key = arrowMatch[ 1 ].trim().replace( /^['"]|['"]$/g, '' ); |
790 | | - let value = arrowMatch[ 2 ].trim(); |
| 667 | + ); |
791 | 668 |
|
792 | | - // Replace placeholders. |
793 | | - while ( value.match( /__ARRAY_(\d+)__/ ) ) { |
794 | | - value = value.replace( /__ARRAY_(\d+)__/, ( match, index ) => { |
795 | | - return 'array(' + nestedArrays[ parseInt( index ) ] + ')'; |
796 | | - } ); |
797 | | - } |
| 669 | + switch ( results.status ) { |
| 670 | + case 0: |
| 671 | + return JSON.parse( results.stdout ); |
798 | 672 |
|
799 | | - result[ key ] = parseValue( value ); |
800 | | - } else { |
801 | | - // No arrow, indexed array. |
802 | | - let value = part; |
| 673 | + case 1: |
| 674 | + throw new Error( `Could not read PHP source file: '${ phpFilepath }'` ); |
803 | 675 |
|
804 | | - // Replace placeholders. |
805 | | - while ( value.match( /__ARRAY_(\d+)__/ ) ) { |
806 | | - value = value.replace( /__ARRAY_(\d+)__/, ( match, index ) => { |
807 | | - return 'array(' + nestedArrays[ parseInt( index ) ] + ')'; |
808 | | - } ); |
809 | | - } |
| 676 | + case 2: |
| 677 | + throw new Error( `PHP source file did not return value when imported: '${ phpFilepath }'` ); |
810 | 678 |
|
811 | | - values.push( parseValue( value ) ); |
812 | | - } |
| 679 | + case 3: |
| 680 | + throw new Error( `Could not serialize PHP source value into JSON: '${ phpFilepath }'` ); |
813 | 681 | } |
814 | 682 |
|
815 | | - return isAssociative ? result : values; |
816 | | - |
817 | | - /** |
818 | | - * Parse a single value. |
819 | | - * |
820 | | - * @param {string} value - The value string to parse. |
821 | | - * @return {*} Parsed value. |
822 | | - */ |
823 | | - function parseValue( value ) { |
824 | | - value = value.trim(); |
825 | | - |
826 | | - if ( value.startsWith( 'array(' ) && value.endsWith( ')' ) ) { |
827 | | - return parsePHPArray( value.substring( 6, value.length - 1 ) ); |
828 | | - } else if ( value.match( /^['"].*['"]$/ ) ) { |
829 | | - return value.substring( 1, value.length - 1 ); |
830 | | - } else if ( value === 'true' ) { |
831 | | - return true; |
832 | | - } else if ( value === 'false' ) { |
833 | | - return false; |
834 | | - } else if ( ! isNaN( value ) && value !== '' ) { |
835 | | - return parseInt( value, 10 ); |
836 | | - } |
837 | | - return value; |
838 | | - } |
| 683 | + throw new Error( `Unknown error while reading PHP source file: '${ phpFilepath }'` ); |
839 | 684 | } |
840 | 685 |
|
841 | 686 | /** |
|
0 commit comments