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:
Madhu Dollu 2022-06-16 11:55:35 +05:30 committed by GitHub
parent 3052082b30
commit 51a1181e59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 1 deletions

View file

@ -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",

View file

@ -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(' ') ? '&nbsp;' : ''
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);
}
}