Update npm dependencies
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
51
node_modules/@jqhtml/parser/dist/codegen.js
generated
vendored
51
node_modules/@jqhtml/parser/dist/codegen.js
generated
vendored
@@ -393,6 +393,28 @@ export class CodeGenerator {
|
||||
const processNodeForLine = (node) => {
|
||||
if (!node.line)
|
||||
return;
|
||||
// VALIDATION: Check for content() in <%!= %> blocks - must run before line filtering
|
||||
if (node.type === NodeType.EXPRESSION) {
|
||||
const expr = node;
|
||||
let trimmedCode = expr.code.trim();
|
||||
if (trimmedCode.endsWith(';')) {
|
||||
trimmedCode = trimmedCode.slice(0, -1).trim();
|
||||
}
|
||||
const isContentCall = trimmedCode === 'content()' ||
|
||||
trimmedCode.match(/^content\s*\(/);
|
||||
if (isContentCall && !expr.escaped) {
|
||||
const error = new JQHTMLParseError(`Invalid syntax: content() cannot be used in <%!= %> blocks`, expr.line, expr.column || 0, this.sourceContent, this.sourceFile);
|
||||
error.suggestion =
|
||||
`\n\ncontent() is a passthrough function - it passes inner HTML directly to the component.\n` +
|
||||
`The concept of "escaping" or "raw" output doesn't apply here.\n\n` +
|
||||
`Use <%= content() %> instead:\n\n` +
|
||||
` ✗ Wrong: <%!= content() %> ← invalid, makes no sense\n` +
|
||||
` ✓ Correct: <%= content() %> ← always use this form\n\n` +
|
||||
`The same applies to named slots:\n` +
|
||||
` ✓ <%= content('header') %>`;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const lineIndex = node.line - 2; // Adjust for array index (line 2 = index 0)
|
||||
if (lineIndex < 0 || lineIndex >= lines.length)
|
||||
return;
|
||||
@@ -508,6 +530,7 @@ export class CodeGenerator {
|
||||
let code;
|
||||
// Special handling for content() calls
|
||||
// Strip trailing semicolon if present (optional in <%= %> blocks)
|
||||
// Note: content() validation happens at the top of processNodeForLine()
|
||||
let trimmedCode = expr.code.trim();
|
||||
if (trimmedCode.endsWith(';')) {
|
||||
trimmedCode = trimmedCode.slice(0, -1).trim();
|
||||
@@ -516,11 +539,6 @@ export class CodeGenerator {
|
||||
// Default slot/content - check _inner_html first
|
||||
code = `(() => { if (this.args._inner_html) { _output.push(this.args._inner_html); } else if (typeof content === 'function') { const [contentInstructions] = content.call(this); _output.push(['_content', contentInstructions]); } })();`;
|
||||
}
|
||||
else if (trimmedCode.startsWith('content.') && trimmedCode.endsWith('()')) {
|
||||
// Named slot: content.header() (property access style)
|
||||
const slotName = trimmedCode.slice(8, -2); // Extract "header" from "content.header()"
|
||||
code = `(() => { if (typeof content === 'object' && typeof content.${slotName} === 'function') { const [contentInstructions] = content.${slotName}.call(this); _output.push(['_content', contentInstructions]); } })();`;
|
||||
}
|
||||
else if (trimmedCode.match(/^content\s*\(\s*['"]([^'"]+)['"]\s*(?:,\s*(.+?))?\s*\)$/)) {
|
||||
// Named slot: content('header') or content('header', data) (function call with string parameter and optional data)
|
||||
// Use the standard result pattern for proper handling
|
||||
@@ -733,15 +751,26 @@ export class CodeGenerator {
|
||||
if (trimmedCode.endsWith(';')) {
|
||||
trimmedCode = trimmedCode.slice(0, -1).trim();
|
||||
}
|
||||
// VALIDATION: content() must be used with <%= %>, not <%!= %>
|
||||
// content() is a passthrough function - its output is already HTML, not a string that needs escaping
|
||||
const isContentCall = trimmedCode === 'content()' ||
|
||||
trimmedCode.match(/^content\s*\(/);
|
||||
if (isContentCall && !node.escaped) {
|
||||
const error = new JQHTMLParseError(`Invalid syntax: content() cannot be used in <%!= %> blocks`, node.line, node.column || 0, this.sourceContent, this.sourceFile);
|
||||
error.suggestion =
|
||||
`\n\ncontent() is a passthrough function - it passes inner HTML directly to the component.\n` +
|
||||
`The concept of "escaping" or "raw" output doesn't apply here.\n\n` +
|
||||
`Use <%= content() %> instead:\n\n` +
|
||||
` ✗ Wrong: <%!= content() %> ← invalid, makes no sense\n` +
|
||||
` ✓ Correct: <%= content() %> ← always use this form\n\n` +
|
||||
`The same applies to named slots:\n` +
|
||||
` ✓ <%= content('header') %>`;
|
||||
throw error;
|
||||
}
|
||||
if (trimmedCode === 'content()') {
|
||||
// Default slot/content - check _inner_html first
|
||||
output = `(() => { if (this.args._inner_html) { _output.push(this.args._inner_html); } else if (typeof content === 'function') { const [contentInstructions] = content.call(this); _output.push(['_content', contentInstructions]); } })();`;
|
||||
}
|
||||
else if (trimmedCode.startsWith('content.') && trimmedCode.endsWith('()')) {
|
||||
// Named slot: content.header() (property access style)
|
||||
const slotName = trimmedCode.slice(8, -2); // Extract "header" from "content.header()"
|
||||
output = `(() => { if (typeof content === 'object' && typeof content.${slotName} === 'function') { const [contentInstructions] = content.${slotName}.call(this); _output.push(['_content', contentInstructions]); } })();`;
|
||||
}
|
||||
else if (trimmedCode.match(/^content\s*\(\s*['"]([^'"]+)['"]\s*(?:,\s*(.+?))?\s*\)$/)) {
|
||||
// Named slot: content('header') or content('header', data) (function call with string parameter and optional data)
|
||||
// Use the standard result pattern for proper handling
|
||||
@@ -1348,7 +1377,7 @@ export class CodeGenerator {
|
||||
for (const [name, component] of this.components) {
|
||||
code += `// Component: ${name}\n`;
|
||||
code += `jqhtml_components.set('${name}', {\n`;
|
||||
code += ` _jqhtml_version: '2.3.12',\n`; // Version will be replaced during build
|
||||
code += ` _jqhtml_version: '2.3.13',\n`; // Version will be replaced during build
|
||||
code += ` name: '${name}',\n`;
|
||||
code += ` tag: '${component.tagName}',\n`;
|
||||
code += ` defaultAttributes: ${this.serializeAttributeObject(component.defaultAttributes)},\n`;
|
||||
|
||||
Reference in New Issue
Block a user