ucode-agent 1.19.1 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ucode-agent",
3
- "version": "1.19.1",
3
+ "version": "1.20.0",
4
4
  "description": "ucode - a terminal coding agent that reads, edits and runs your code, on NVIDIA and Cohere models.",
5
5
  "type": "module",
6
6
  "main": "ucode.js",
@@ -0,0 +1,59 @@
1
+ /**
2
+ * htmlcheck.js — the JavaScript inside an HTML file is still JavaScript.
3
+ *
4
+ * A single-file app keeps everything in one <script>, and nothing was looking
5
+ * at it: the checks run `node --check` on .js files and tsc on TypeScript
6
+ * projects, so an index.html whose script does not parse passed every one of
7
+ * them. The page renders, the CSS is right, and not one button works.
8
+ *
9
+ * The failure that prompted this: a model writing an HTML-escaping map inside
10
+ * an HTML file produced `"'":'''` — three quotes, a syntax error, the whole
11
+ * script dead. Everything looked finished.
12
+ *
13
+ * Parsing is Babel's, which ucode already carries. Only syntax is checked:
14
+ * an undefined variable is a runtime problem and this is not the place for it.
15
+ */
16
+
17
+ import { parse } from '@babel/parser';
18
+
19
+ /** Inline scripts worth parsing: not src=, not JSON, not a template. */
20
+ const SCRIPTS = /<script\b([^>]*)>([\s\S]*?)<\/script\s*>/gi;
21
+
22
+ const runnable = (attrs) => {
23
+ if (/\bsrc\s*=/i.test(attrs)) return false; // a separate file, checked on its own
24
+ const type = /\btype\s*=\s*["']?([^"'\s>]+)/i.exec(attrs)?.[1]?.toLowerCase();
25
+ if (!type) return true;
26
+ return type === 'module' || type === 'text/javascript' || type === 'application/javascript';
27
+ };
28
+
29
+ /**
30
+ * Syntax errors in a file's inline scripts, with lines counted in the HTML
31
+ * rather than in the extracted fragment — a line number that does not match
32
+ * the file is worse than none.
33
+ */
34
+ export function checkHtml(text) {
35
+ const html = String(text ?? '');
36
+ const problems = [];
37
+
38
+ for (const match of html.matchAll(SCRIPTS)) {
39
+ const [whole, attrs, body] = match;
40
+ if (!runnable(attrs) || !body.trim()) continue;
41
+
42
+ const before = html.slice(0, match.index + whole.indexOf(body));
43
+ const offset = before.split('\n').length - 1;
44
+
45
+ try {
46
+ parse(body, {
47
+ sourceType: 'module', // accepts a plain script too
48
+ allowReturnOutsideFunction: true,
49
+ errorRecovery: false,
50
+ plugins: ['topLevelAwait'],
51
+ });
52
+ } catch (err) {
53
+ const line = (err.loc?.line ?? 1) + offset;
54
+ problems.push({ line, message: String(err.message ?? err).replace(/\s*\(\d+:\d+\)$/, '') });
55
+ }
56
+ }
57
+
58
+ return problems;
59
+ }