Utility to update patterns with escaped strings and image paths (#5985)
* add theme unility to escape strings and image paths in patterns * update esc function for attributes * fix regex for pattern filename * replace prefixed space character with
This commit is contained in:
parent
3052082b30
commit
51a1181e59
2 changed files with 119 additions and 1 deletions
|
@ -28,6 +28,7 @@
|
|||
"core:push": "node ./theme-utils.mjs push-core-themes",
|
||||
"core:sync": "node ./theme-utils.mjs sync-core-theme",
|
||||
"build:variations": "node ./variations/build-variations.mjs",
|
||||
"patterns:escape": "node ./theme-utils.mjs escape-patterns",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -41,7 +42,9 @@
|
|||
"inquirer": "^8.2.0",
|
||||
"lint-staged": "^12.3.4",
|
||||
"lodash": "^4.17.21",
|
||||
"open": "^8.4.0"
|
||||
"open": "^8.4.0",
|
||||
"parse5-html-rewriting-stream": "^7.0.0",
|
||||
"table": "^6.8.0"
|
||||
},
|
||||
"stylelint": {
|
||||
"extends": "@wordpress/stylelint-config",
|
||||
|
|
115
theme-utils.mjs
115
theme-utils.mjs
|
@ -2,6 +2,8 @@ import { spawn } from 'child_process';
|
|||
import fs, { existsSync } from 'fs';
|
||||
import open from 'open';
|
||||
import inquirer from 'inquirer';
|
||||
import { RewritingStream } from 'parse5-html-rewriting-stream';
|
||||
import { table } from 'table';
|
||||
|
||||
const remoteSSH = 'wpcom-sandbox';
|
||||
const sandboxPublicThemesFolder = '/home/wpdev/public_html/wp-content/themes/pub';
|
||||
|
@ -107,6 +109,10 @@ const commands = {
|
|||
additionalArgs: '<theme-slug> <since>',
|
||||
run: (args) => rebuildThemeChangelog(args?.[1], args?.[2])
|
||||
},
|
||||
"escape-patterns": {
|
||||
helpText: 'Escapes block patterns for pattern files that have changes (staged or unstaged).',
|
||||
run: () => escapePatterns()
|
||||
},
|
||||
"help": {
|
||||
helpText: 'Displays the main help message.',
|
||||
run: (args) => showHelp(args?.[1])
|
||||
|
@ -1130,3 +1136,112 @@ export async function executeCommand(command, logResponse) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function escapePatterns() {
|
||||
// get staged files
|
||||
const staged = (await executeCommand(`git diff --cached --name-only`)).split('\n');
|
||||
// get unstaged, untracked files
|
||||
const unstaged = (await executeCommand(`git ls-files -m -o --exclude-standard`)).split('\n');
|
||||
|
||||
// avoid duplicates and filter pattern files
|
||||
const patterns = [...new Set([...staged, ...unstaged])].filter(file => file.match(/.*\/patterns\/.*.php/g));
|
||||
|
||||
// arrange patterns by theme
|
||||
const themePatterns = patterns.reduce((acc, file) => {
|
||||
const themeSlug = file.split('/').shift();
|
||||
return {
|
||||
...acc,
|
||||
[themeSlug]: (acc[themeSlug] || []).concat(file)
|
||||
};
|
||||
}, {});
|
||||
|
||||
Object.entries(themePatterns).forEach(async ([themeSlug, patterns]) => {
|
||||
console.log(getPatternTable(themeSlug, patterns));
|
||||
|
||||
const prompt = await inquirer.prompt([{
|
||||
type: 'input',
|
||||
message: 'Verify the theme slug',
|
||||
name: "themeSlug",
|
||||
default: themeSlug
|
||||
}]);
|
||||
|
||||
if (!prompt.themeSlug) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rewriter = getReWriter(prompt.themeSlug);
|
||||
patterns.forEach(file => {
|
||||
const tmpFile = `${file}-tmp`;
|
||||
const rstream = fs.createReadStream( file, { encoding: 'UTF-8' } );
|
||||
const wstream = fs.createWriteStream( tmpFile, { encoding: 'UTF-8' } );
|
||||
wstream.on('finish', () => {
|
||||
fs.renameSync(tmpFile, file);
|
||||
});
|
||||
|
||||
rstream.pipe(rewriter).pipe(wstream);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Helper functions
|
||||
function getReWriter(themeSlug) {
|
||||
const rewriter = new RewritingStream();
|
||||
|
||||
rewriter.on('text', (_, raw) => {
|
||||
rewriter.emitRaw(escapeText(raw, themeSlug));
|
||||
});
|
||||
|
||||
rewriter.on('startTag', (startTag, rawHtml) => {
|
||||
if (startTag.tagName === 'img') {
|
||||
const attrs = startTag.attrs.filter(attr => ['src', 'alt'].includes(attr.name));
|
||||
attrs.forEach(attr => {
|
||||
if (attr.name === 'src') {
|
||||
attr.value = escapeImagePath(attr.value);
|
||||
} else if (attr.name === 'alt') {
|
||||
attr.value = escapeText(attr.value, themeSlug, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (startTag.tagName === 'p') {
|
||||
console.log({tag: startTag, rawHtml})
|
||||
}
|
||||
|
||||
rewriter.emitStartTag(startTag);
|
||||
});
|
||||
|
||||
return rewriter;
|
||||
}
|
||||
|
||||
function escapeText(text, themeSlug, isAttr = false) {
|
||||
const trimmedText = text && text.trim();
|
||||
if (!themeSlug || !trimmedText || trimmedText.startsWith(`<?php`)) return text;
|
||||
const escFunction = isAttr ? 'esc_attr__' : 'esc_html__';
|
||||
const spaceChar = text.startsWith(' ') ? ' ' : ''
|
||||
const resultText = text.replace('\'', '\\\'').trim();
|
||||
return `${spaceChar}<?php echo ${escFunction}( '${resultText}', '${themeSlug}' ); ?>`;
|
||||
}
|
||||
|
||||
function escapeImagePath(src) {
|
||||
if (!src || src.trim().startsWith('<?php')) return src;
|
||||
|
||||
const assetsDir = 'assets';
|
||||
const parts = src.split('/');
|
||||
const resultSrc = parts.slice(parts.indexOf(assetsDir)).join('/');
|
||||
return `<?php echo esc_url( get_template_directory_uri() ); ?>/${resultSrc}`;
|
||||
}
|
||||
|
||||
function getPatternTable(themeSlug, patterns) {
|
||||
const tableConfig = {
|
||||
columnDefault: {
|
||||
width: 80,
|
||||
},
|
||||
header: {
|
||||
alignment: 'center',
|
||||
content: `THEME: ${themeSlug}\n\n Following patterns may get updated with escaped strings and/or image paths`,
|
||||
}
|
||||
};
|
||||
|
||||
return table([patterns], tableConfig);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue