Repository navigation
Navigation blocks: use shared render_submenu_icon and auto-prefix cross-file PHP functions #75774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
abfc46c
46a5c40
0582cc3
6b06c12
a6ba99e
77cb33e
2387228
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -302,7 +302,7 @@ function normalizePath( p ) { | |
| return p.replace( /\\/g, '/' ); | ||
| } | ||
|
|
||
| function transformPhpContent( content, transforms ) { | ||
| function transformPhpContent( content, transforms, allFunctionNames = [] ) { | ||
| const { | ||
| functionPrefix = '', | ||
| classSuffix = '', | ||
|
|
@@ -328,14 +328,42 @@ function transformPhpContent( content, transforms ) { | |
| } | ||
|
|
||
| if ( functionPrefix ) { | ||
| content = Array.from( | ||
| content.matchAll( /^\s*function ([^\(]+)/gm ) | ||
| ).reduce( ( result, [ , functionName ] ) => { | ||
| return result.replace( | ||
| // Find functions defined in this file. | ||
| const localFunctions = new Set( | ||
| Array.from( content.matchAll( /^\s*function ([^\(]+)/gm ) ).map( | ||
| ( [ , name ] ) => name | ||
| ) | ||
| ); | ||
|
|
||
| // Rename locally-defined functions and all their references in this file. | ||
| for ( const functionName of localFunctions ) { | ||
| // Skip functions already prefixed (e.g., by the prefixFunctions step above). | ||
| if ( functionName.startsWith( functionPrefix ) ) { | ||
| continue; | ||
| } | ||
| content = content.replace( | ||
| new RegExp( functionName + '(?![a-zA-Z0-9_])', 'g' ), | ||
| ( match ) => functionPrefix + match.replace( /^wp_/, '' ) | ||
| ); | ||
| }, content ); | ||
| } | ||
|
|
||
| // Prefix cross-file function references (functions defined in other | ||
| // files within the same package). Skip functions that are local to | ||
| // this file since they were already handled above. | ||
| const crossFileFunctions = allFunctionNames.filter( | ||
| ( name ) => ! localFunctions.has( name ) | ||
| ); | ||
| if ( crossFileFunctions.length ) { | ||
| const funcPattern = crossFileFunctions.join( '|' ); | ||
| content = content.replace( | ||
| new RegExp( | ||
| '(?<![a-zA-Z0-9_])(?:' + funcPattern + ')(?![a-zA-Z0-9_])', | ||
| 'g' | ||
| ), | ||
| ( match ) => | ||
| `${ functionPrefix }${ match.replace( /^wp_/, '' ) }` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this use the same replace regex/method as one of the ones above? |
||
| ); | ||
|
Comment on lines
+357
to
+365
|
||
| } | ||
| } | ||
|
|
||
| if ( addActionPriority ) { | ||
|
|
@@ -671,6 +699,29 @@ async function bundlePackage( packageName, options = {} ) { | |
| const packageSourceDir = path.join( packageDir, 'src' ); | ||
| const outputDir = path.join( BUILD_DIR, 'scripts', packageName ); | ||
|
|
||
| // Collect all function definitions across PHP files so that | ||
| // cross-file references can be auto-prefixed without needing | ||
| // a manual prefixFunctions entry. | ||
| const allFunctionNames = []; | ||
| if ( transforms.php?.functionPrefix ) { | ||
| for ( const filePattern of files ) { | ||
| const matchedFiles = await glob( | ||
| normalizePath( path.join( packageDir, filePattern ) ) | ||
| ); | ||
| for ( const sourceFile of matchedFiles ) { | ||
| if ( ! sourceFile.endsWith( '.php' ) ) { | ||
| continue; | ||
| } | ||
| const content = await readFile( sourceFile, 'utf8' ); | ||
| for ( const [ , name ] of content.matchAll( | ||
| /^\s*function ([^\(]+)/gm | ||
| ) ) { | ||
| allFunctionNames.push( name ); | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+702
to
+722
|
||
| } | ||
|
|
||
| for ( const filePattern of files ) { | ||
| const matchedFiles = await glob( | ||
| normalizePath( path.join( packageDir, filePattern ) ) | ||
|
|
@@ -696,7 +747,8 @@ async function bundlePackage( packageName, options = {} ) { | |
| ); | ||
| const transformed = transformPhpContent( | ||
| content, | ||
| transforms.php | ||
| transforms.php, | ||
| allFunctionNames | ||
| ); | ||
|
|
||
| if ( transforms.php.filenameSuffix ) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The local function renaming regex only enforces an identifier boundary at the end of the match. Without a start boundary it can rename substrings inside longer identifiers (e.g.
my_block_core_foocontainingblock_core_foo). Align this with the cross-file regex by enforcing a start boundary (and escaping the function name when building the RegExp).