Enhance EJS formatting functionality with new placeholder handling and text tag collapsing
All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good
This commit introduces several improvements to the EJS formatting logic in the `templateformatter.js` file. It adds new regex patterns for inline placeholders and text-only tags, enhancing the ability to manage EJS content. The `maskEjsBlocks` function is updated to differentiate between control and inline EJS tags, while the `restoreEjsBlocks` function now handles both comment and inline placeholders. Additionally, a new function, `collapseTextOnlyTags`, is introduced to ensure that text content within tags is properly formatted without unnecessary whitespace. Corresponding tests have been added to verify these enhancements, improving the overall template content formatting capabilities.
This commit is contained in:
parent
ff60d6cf09
commit
bec4c8bf4c
@ -59,4 +59,25 @@ describe('formatTemplateContent', () => {
|
||||
expect(result.content).not.toMatch(/\(\s+<%/);
|
||||
expect(result.content).not.toMatch(/%>\s+\)/);
|
||||
});
|
||||
|
||||
it('should not add a space next to a colon before EJS output', () => {
|
||||
const input =
|
||||
'<Barcode format="code128" height="33px" barcodeWidth="3">INV: <%= _reference %>\n </Barcode>';
|
||||
const result = formatTemplateContent(input);
|
||||
|
||||
expect(result.content).toBe(
|
||||
'<Barcode format="code128" height="33px" barcodeWidth="3">INV:<%= _reference %></Barcode>'
|
||||
);
|
||||
});
|
||||
|
||||
it('should keep barcode content and the closing tag on one line', () => {
|
||||
const input =
|
||||
'<Barcode format="code128" height="33px" barcodeWidth="3">INV:<%= _reference %></Barcode>';
|
||||
const result = formatTemplateContent(input);
|
||||
|
||||
expect(result.content).toBe(
|
||||
'<Barcode format="code128" height="33px" barcodeWidth="3">INV:<%= _reference %></Barcode>'
|
||||
);
|
||||
expect(result.content).not.toMatch(/%>\s*\n\s*<\/Barcode>/);
|
||||
});
|
||||
});
|
||||
|
||||
@ -4,7 +4,9 @@ const { html: beautifyHtml, js: beautifyJs } = beautify;
|
||||
|
||||
const EJS_BLOCK_REGEX = /<%[\s\S]*?%>/g;
|
||||
const EJS_TAG_REGEX = /^<%([=#-]?)([\s\S]*?)%>/;
|
||||
const EJS_PLACEHOLDER_REGEX = /<!--EJS_PH_(\d+)-->/g;
|
||||
const EJS_COMMENT_PLACEHOLDER_REGEX = /<!--EJS_PH_(\d+)-->/g;
|
||||
const EJS_INLINE_PLACEHOLDER_REGEX = /___EJS_PH_(\d+)___/g;
|
||||
const TEXT_ONLY_TAG_REGEX = /<([A-Za-z][\w:-]*)(\s[^>]*)?>([^<]*)<\/\1>/g;
|
||||
|
||||
const HTML_BEAUTIFY_OPTIONS = {
|
||||
indent_size: 2,
|
||||
@ -47,28 +49,53 @@ function formatEjsTag(tag) {
|
||||
}
|
||||
}
|
||||
|
||||
function isControlEjs(tag) {
|
||||
const match = tag.match(EJS_TAG_REGEX);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const [, modifier] = match;
|
||||
return !modifier;
|
||||
}
|
||||
|
||||
function maskEjsBlocks(content) {
|
||||
const ejsBlocks = [];
|
||||
|
||||
const masked = content.replace(EJS_BLOCK_REGEX, (match) => {
|
||||
const index = ejsBlocks.length;
|
||||
ejsBlocks.push(match);
|
||||
return `\n<!--EJS_PH_${index}-->\n`;
|
||||
if (isControlEjs(match)) {
|
||||
return `\n<!--EJS_PH_${index}-->\n`;
|
||||
}
|
||||
return `___EJS_PH_${index}___`;
|
||||
});
|
||||
|
||||
return { masked, ejsBlocks };
|
||||
}
|
||||
|
||||
function restoreEjsBlocks(content, ejsBlocks) {
|
||||
return content.replace(EJS_PLACEHOLDER_REGEX, (_, index) =>
|
||||
formatEjsTag(ejsBlocks[Number(index)])
|
||||
);
|
||||
const restore = (_, index) => formatEjsTag(ejsBlocks[Number(index)]);
|
||||
return content
|
||||
.replace(EJS_COMMENT_PLACEHOLDER_REGEX, restore)
|
||||
.replace(EJS_INLINE_PLACEHOLDER_REGEX, restore);
|
||||
}
|
||||
|
||||
function collapseTextOnlyTags(content) {
|
||||
return content.replace(TEXT_ONLY_TAG_REGEX, (_, tagName, attrs, inner) => {
|
||||
const collapsedInner = inner.replace(/^\s+|\s+$/g, '');
|
||||
return `<${tagName}${attrs || ''}>${collapsedInner}</${tagName}>`;
|
||||
});
|
||||
}
|
||||
|
||||
function tightenParenthesesAroundEjs(content) {
|
||||
return content.replace(/\(\s+(<%)/g, '($1').replace(/(%>)\s+\)/g, '$1)');
|
||||
}
|
||||
|
||||
function tightenColonsAroundEjs(content) {
|
||||
return content.replace(/:\s+(<%)/g, ':$1');
|
||||
}
|
||||
|
||||
export function formatTemplateContent(content) {
|
||||
if (content == null || typeof content !== 'string') {
|
||||
return { error: 'Content is required and must be a string.', code: 400 };
|
||||
@ -81,8 +108,10 @@ export function formatTemplateContent(content) {
|
||||
try {
|
||||
const { masked, ejsBlocks } = maskEjsBlocks(content);
|
||||
let formatted = beautifyHtml(masked, HTML_BEAUTIFY_OPTIONS);
|
||||
formatted = collapseTextOnlyTags(formatted);
|
||||
formatted = restoreEjsBlocks(formatted, ejsBlocks);
|
||||
formatted = tightenParenthesesAroundEjs(formatted);
|
||||
formatted = tightenColonsAroundEjs(formatted);
|
||||
return { content: formatted.trimEnd() };
|
||||
} catch (error) {
|
||||
return { error: error.message || 'Failed to format template content.', code: 400 };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user