@imwz/wp-pattern-sentinel 0.2.3 → 0.2.5
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/package.json +1 -1
- package/src/editor.js +30 -1
- package/src/main.js +21 -12
package/package.json
CHANGED
package/src/editor.js
CHANGED
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
import { log } from './format.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Replace inline PHP expressions with static equivalents so the block editor
|
|
5
|
+
* receives valid markup and the round-trip comparison stays accurate.
|
|
6
|
+
*
|
|
7
|
+
* Handles the PHP patterns that appear in Elayne theme patterns:
|
|
8
|
+
* <?php esc_html_e( 'Text', 'elayne' ); ?> → Text
|
|
9
|
+
* <?php echo esc_html__( 'Text', 'elayne' ); ?> → Text
|
|
10
|
+
* <?php esc_attr_e( 'Alt text', 'elayne' ); ?> → Alt text
|
|
11
|
+
* <?php echo esc_attr__( 'Alt text', 'elayne' ); ?> → Alt text
|
|
12
|
+
* <?php echo esc_url( get_template_directory_uri() ); ?> → http://example.com
|
|
13
|
+
* All other <?php ... ?> blocks → removed
|
|
14
|
+
*/
|
|
15
|
+
function stripPhpForValidation(content) {
|
|
16
|
+
if (!content.includes('<?php')) return content;
|
|
17
|
+
|
|
18
|
+
return content
|
|
19
|
+
.replace(/<\?php\s+(?:esc_html_e|esc_html__)\s*\(\s*'([^']+)'\s*,\s*'[^']+'\s*\)\s*;?\s*\?>/g, '$1')
|
|
20
|
+
.replace(/<\?php\s+(?:esc_html_e|esc_html__)\s*\(\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)\s*;?\s*\?>/g, '$1')
|
|
21
|
+
.replace(/<\?php\s+echo\s+esc_html__\s*\(\s*'([^']+)'\s*,\s*'[^']+'\s*\)\s*;?\s*\?>/g, '$1')
|
|
22
|
+
.replace(/<\?php\s+(?:esc_attr_e|esc_attr__)\s*\(\s*'([^']+)'\s*,\s*'[^']+'\s*\)\s*;?\s*\?>/g, '$1')
|
|
23
|
+
.replace(/<\?php\s+(?:esc_attr_e|esc_attr__)\s*\(\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)\s*;?\s*\?>/g, '$1')
|
|
24
|
+
.replace(/<\?php\s+echo\s+esc_attr__\s*\(\s*'([^']+)'\s*,\s*'[^']+'\s*\)\s*;?\s*\?>/g, '$1')
|
|
25
|
+
.replace(/<\?php\s+echo\s+esc_url\s*\([\s\S]*?\)\s*;?\s*\?>/g, 'http://example.com')
|
|
26
|
+
.replace(/<\?php[\s\S]*?\?>/g, '')
|
|
27
|
+
.trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
3
30
|
/**
|
|
4
31
|
* Strip the PHP file header (opening tag + docblock) and return the raw block markup.
|
|
32
|
+
* Inline PHP expressions within the block markup are replaced with static values
|
|
33
|
+
* so the editor receives valid content for round-trip validation.
|
|
5
34
|
* Returns null if no block comment is found.
|
|
6
35
|
*
|
|
7
36
|
* WordPress pattern files look like:
|
|
@@ -21,7 +50,7 @@ export function extractBlockContent(fileContent) {
|
|
|
21
50
|
.trim();
|
|
22
51
|
|
|
23
52
|
if (!stripped.startsWith('<!--')) return null;
|
|
24
|
-
return stripped;
|
|
53
|
+
return stripPhpForValidation(stripped);
|
|
25
54
|
}
|
|
26
55
|
|
|
27
56
|
/**
|
package/src/main.js
CHANGED
|
@@ -30,20 +30,27 @@ export async function main() {
|
|
|
30
30
|
args: ['--disable-web-security'],
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// Login once, then share the session cookies across all worker contexts.
|
|
34
|
+
// Concurrent logins to WordPress (even with valid credentials) trigger a
|
|
35
|
+
// reauth=1 redirect loop — serialising login avoids this entirely.
|
|
34
36
|
let contexts;
|
|
35
37
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
log('Logging in to WordPress...', 'cyan');
|
|
39
|
+
const firstContext = await browser.newContext({ viewport: options.viewport });
|
|
40
|
+
const loginPage = await firstContext.newPage();
|
|
41
|
+
loginPage.setDefaultTimeout(60000);
|
|
42
|
+
const ok = await loginToWordPress(loginPage, options.adminUrl, options.user, options.pass);
|
|
43
|
+
await loginPage.close();
|
|
44
|
+
if (!ok) throw new Error('Failed to authenticate with WordPress');
|
|
45
|
+
log(`Authenticated — sharing session across ${options.concurrency} worker(s)`, 'green');
|
|
46
|
+
|
|
47
|
+
const cookies = await firstContext.cookies();
|
|
48
|
+
contexts = [firstContext];
|
|
49
|
+
for (let i = 1; i < options.concurrency; i++) {
|
|
50
|
+
const ctx = await browser.newContext({ viewport: options.viewport });
|
|
51
|
+
await ctx.addCookies(cookies);
|
|
52
|
+
contexts.push(ctx);
|
|
53
|
+
}
|
|
47
54
|
} catch (error) {
|
|
48
55
|
log(error.message, 'red');
|
|
49
56
|
await browser.close();
|
|
@@ -78,6 +85,8 @@ async function validatePatternFile(patternPath, options, context) {
|
|
|
78
85
|
const patternName = path.basename(patternPath);
|
|
79
86
|
const startTime = Date.now();
|
|
80
87
|
|
|
88
|
+
log(` Validating: ${patternName}`, 'cyan');
|
|
89
|
+
|
|
81
90
|
let fileContent;
|
|
82
91
|
try {
|
|
83
92
|
fileContent = await fs.promises.readFile(patternPath, 'utf8');
|