Skip to content

Commit 790686e

Browse files
authored
Merge pull request #229 from mi-examples/develop
fix: Variables Editor client script fails to parse, blanking the whole UI
2 parents 2a76fde + e207d1a commit 790686e

5 files changed

Lines changed: 32 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# [1.2.0-beta.3](https://github.com/mi-examples/pp-dev/compare/v1.2.0-beta.2...v1.2.0-beta.3) (2026-08-07)
2+
3+
4+
### Bug Fixes
5+
6+
* Variables Editor client script fails to parse, blanking the whole UI ([2e48b2e](https://github.com/mi-examples/pp-dev/commit/2e48b2e69c12124a6d300503a80b40f649de1316))
7+
18
# [1.2.0-beta.2](https://github.com/mi-examples/pp-dev/compare/v1.2.0-beta.1...v1.2.0-beta.2) (2026-08-07)
29

310

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@metricinsights/pp-dev",
33
"type": "module",
4-
"version": "1.2.0-beta.2",
4+
"version": "1.2.0-beta.3",
55
"description": "Portal Page dev build tool",
66
"bin": {
77
"pp-dev": "bin/pp-dev.js"

src/lib/variables-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ function escapeHtml(s) {
526526
// (see DistService.saveTemplateVariablesFile). Backslash/quote-escape for the JS-string
527527
// context first, then HTML-escape the result so it can't break out of the attribute either.
528528
function escapeJsAttr(s) {
529-
return escapeHtml(String(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'"));
529+
return escapeHtml(String(s).replace(/\\\\/g, '\\\\\\\\').replace(/'/g, "\\\\'"));
530530
}
531531
532532
function showBanner(type, html) {

tests/unit/lib/variables-editor.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,5 +341,26 @@ describe('registerVariablesEditorRoutes', () => {
341341
expect(res.body).not.toContain('id="tab-schema"');
342342
expect(res.body).not.toContain('id="save-btn"');
343343
});
344+
345+
// Every `<script>` block is built via string concatenation inside one giant template
346+
// literal — a backslash-escaping mistake there (e.g. a regex like /\\/) is invisible to
347+
// `tsc`/eslint (it's just characters inside a string) and only breaks at runtime when the
348+
// browser parses it, which none of the tests above would ever catch. `new Function` parses
349+
// without executing, so this fails fast on any embedded-script SyntaxError.
350+
it('embeds syntactically valid client-side JavaScript in every <script> block', async () => {
351+
const app = register({ miAPI: { isTemplateLess: false } as unknown as MiAPI });
352+
const res = makeRes();
353+
354+
app.handlers.get(`GET ${VARIABLES_EDITOR_PATH}`)!({}, res);
355+
356+
const html = res.body as string;
357+
const scripts = [...html.matchAll(/<script>([\s\S]*?)<\/script>/g)].map((m) => m[1]);
358+
359+
expect(scripts.length).toBeGreaterThan(0);
360+
361+
for (const script of scripts) {
362+
expect(() => new Function(script)).not.toThrow();
363+
}
364+
});
344365
});
345366
});

0 commit comments

Comments
 (0)