Update npm dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-12-09 07:31:22 +00:00
parent fa97880c6d
commit 46b45e6762
952 changed files with 5472 additions and 2904 deletions

View File

@@ -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`;