Repository: naturalcrit/homebrewery (js)

Issue:
images with alt-text with bad spaces get eaten
### Renderer

v3

### Browser

Chrome

### Operating System

MacOS

### What happened?

If there are 2 or more consecutive spaces in the alt-text for an image, everything breaks. It also breaks if the alt-text either starts with or ends with a space. (This occurs with or without a `{curly-inject}`, and in standalone images, not just list items.)

The problem is not present with [Marked v14.0.0](https://marked.js.org/demo/?outputType=html&text=!%5Bhomebrew%20mug%20%20%20where%20is%20my%20image%3F%3F%5D(http%3A%2F%2Fi.imgur.com%2FhMna6G0.png)&options=%7B%0A%20%22async%22%3A%20false%2C%0A%20%22breaks%22%3A%20false%2C%0A%20%22extensions%22%3A%20null%2C%0A%20%22gfm%22%3A%20true%2C%0A%20%22hooks%22%3A%20null%2C%0A%20%22pedantic%22%3A%20false%2C%0A%20%22silent%22%3A%20false%2C%0A%20%22tokenizer%22%3A%20null%2C%0A%20%22walkTokens%22%3A%20null%0A%7D&version=14.0.0) (or earlier). I suspect some side effect from HB's variables code.

<img width="1208" alt="image" src="https://github.com/user-attachments/assets/a0a05d36-b2d4-41bd-9a58-25e5b085b5f1">


### Code

```gfm
# Bug with alt-text image

{{note
If there are 2 or more consecutive spaces in the alt-text for an image, everything breaks. It also breaks if the alt-text either starts with or ends with a space.
}}

1. ![ where is my image??](http://i.imgur.com/hMna6G0.png)
2. ![where  is my image??](http://i.imgur.com/hMna6G0.png)
3. ![where is my image?? ](http://i.imgur.com/hMna6G0.png)
4. ![where is my image??](http://i.imgur.com/hMna6G0.png){height=20%,width=20%}
```


Pull request description:
Fix space issue in image tags 
## Description

Alter varCallInline content to align with preceding varDefBlock in inline definitions.

This was failing due to both labels having the extraneous spaces cleaned up but the variable label portion of the varCallInline did not, preventing them from being matched during variable resolution.

## Related Issues or Discussions

- Closes #3659 

## QA Instructions, Screenshots, Recordings

# Bug with alt-text image

```
{{note
If there are 2 or more consecutive spaces in the alt-text for an image, everything breaks. It also breaks if the alt-text either starts with or ends with a space.
}}

1. ![ where is my image??](http://i.imgur.com/hMna6G0.png)
2. ![where  is my image??](http://i.imgur.com/hMna6G0.png)
3. ![where is my image?? ](http://i.imgur.com/hMna6G0.png)
4. ![where is my image??](http://i.imgur.com/hMna6G0.png){height=20%,width=20%}
```

All 4 should show. Previously, only the 4th.

### Reviewer Checklist

*Reviewers, refer to this list when testing features, or suggest new items *
- [x] Verify new features are functional
  - [x] Image links with any number and placement of arbitrary space work.
- [x] Verify old features have not broken
- [ ] Identify opportunities for simplification and refactoring
- [x] Check for code legibility and appropriate comments


Patch:
diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js
index a8b877f4..0b90c051 100644
--- a/shared/naturalcrit/markdown.js
+++ b/shared/naturalcrit/markdown.js
@@ -60,6 +60,11 @@ mathParser.functions.signed = function (a) {
 	return `${a}`;
 };
 
+// Normalize variable names; trim edge spaces and shorten blocks of whitespace to 1 space
+const normalizeVarNames = (label)=>{
+	return label.trim().replace(/\s+/g, ' ');
+};
+
 //Processes the markdown within an HTML block if it's just a class-wrapper
 renderer.html = function (token) {
 	let html = token.text;
@@ -509,7 +514,7 @@ const replaceVar = function(input, hoist=false, allowUnresolved=false) {
 	const match = regex.exec(input);
 
 	const prefix = match[1];
-	const label  = match[2];
+	const label  = normalizeVarNames(match[2]); // Ensure the label name is normalized as it should be in the var stack.
 
 	//v=====--------------------< HANDLE MATH >-------------------=====v//
 	const mathRegex = /[a-z]+\(|[+\-*/^(),]/g;
@@ -664,8 +669,8 @@ function MarkedVariables() {
 							});
 					}
 					if(match[3]) { // Block Definition
-						const label   = match[4] ? match[4].trim().replace(/\s+/g, ' ')    : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
-						const content = match[5] ? match[5].trim().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
+						const label   = match[4] ? normalizeVarNames(match[4]) : null;
+						const content = match[5] ? match[5].trim().replace(/[ \t]+/g, ' ') : null; // Normalize text content (except newlines for block-level content)
 
 						varsQueue.push(
 							{ type    : 'varDefBlock',
@@ -674,7 +679,7 @@ function MarkedVariables() {
 							});
 					}
 					if(match[6]) { // Block Call
-						const label = match[7] ? match[7].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
+						const label = match[7] ? normalizeVarNames(match[7]) : null;
 
 						varsQueue.push(
 							{ type    : 'varCallBlock',
@@ -683,7 +688,7 @@ function MarkedVariables() {
 							});
 					}
 					if(match[8]) { // Inline Definition
-						const label = match[10] ? match[10].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
+						const label = match[10] ? normalizeVarNames(match[10]) : null;
 						let content = match[11] || null;
 
 						// In case of nested (), find the correct matching end )
@@ -715,7 +720,7 @@ function MarkedVariables() {
 							});
 					}
 					if(match[12]) { // Inline Call
-						const label = match[13] ? match[13].trim().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
+						const label = match[13] ? normalizeVarNames(match[13]) : null;
 
 						varsQueue.push(
 							{ type    : 'varCallInline',


Test patch:
diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js
index 41259da7..4c91d7d0 100644
--- a/tests/markdown/variables.test.js
+++ b/tests/markdown/variables.test.js
@@ -410,4 +410,29 @@ describe('Regression Tests', ()=>{
 		const rendered = Markdown.render(source).trimReturns();
 		expect(rendered).toBe('<table><thead><tr><th>title 1</th><th>title 2</th><th>title 3</th><th>title 4</th></tr></thead><tbody><tr><td><a href=\"bar\">foo</a></td><td>Ipsum</td><td>)</td><td>)</td></tr></tbody></table>');
 	});
+
+	it('Handle Extra spaces in image alt-text 1', function(){
+		const source='![ where is my image??](http://i.imgur.com/hMna6G0.png)';
+		const rendered = Markdown.render(source).trimReturns();
+		expect(rendered).toBe('<p><img src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\"></p>');
+	});
+
+	it('Handle Extra spaces in image alt-text 2', function(){
+		const source='![where  is my image??](http://i.imgur.com/hMna6G0.png)';
+		const rendered = Markdown.render(source).trimReturns();
+		expect(rendered).toBe('<p><img src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\"></p>');
+	});
+
+	it('Handle Extra spaces in image alt-text 3', function(){
+		const source='![where is my image?? ](http://i.imgur.com/hMna6G0.png)';
+		const rendered = Markdown.render(source).trimReturns();
+		expect(rendered).toBe('<p><img src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\"></p>');
+	});
+
+	it('Handle Extra spaces in image alt-text 4', function(){
+		const source='![where is my image??](http://i.imgur.com/hMna6G0.png){height=20%,width=20%}';
+		const rendered = Markdown.render(source).trimReturns();
+		expect(rendered).toBe('<p><img style=\"--HB_src:url(http://i.imgur.com/hMna6G0.png);\" src=\"http://i.imgur.com/hMna6G0.png\" alt=\"where is my image??\" height=\"20%\" width=\"20%\"></p>');
+	});
+
 });
\ No newline at end of file