Skip to content

Commit 2cf3917

Browse files
committed
Revert "Better handle variants in traces (particularly syntax errors)"
This reverts commit a25b4e4.
1 parent a25b4e4 commit 2cf3917

File tree

4 files changed

+20
-74
lines changed

4 files changed

+20
-74
lines changed

copydecks/en/copydeck.json

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,6 @@
5353

5454
"SyntaxError": {
5555
"variants": [
56-
{
57-
"if": {
58-
"match_message": ["expected ':'"]
59-
},
60-
"title": "Missing colon (:) at the end",
61-
"summary": "This line starts a block and needs a colon at {{loc}}: {{codeLine}}",
62-
"why": "In Python, lines that start a block must end with a colon.",
63-
"steps": [
64-
"Add a colon (:) at the end of that line."
65-
]
66-
},
6756
{
6857
"if": {
6958
"match_code": ["^(\\s*)(if|for|while|def|class|elif|else|try|except|with)\\b"],

src/adapters/pyodide.ts

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,6 @@ export const pyodideAdapter: AdapterFn = (raw, code) => {
2121
if (cc) col = parseInt(cc[1], 10);
2222
}
2323

24-
if (!line) {
25-
const m1 = raw.match(/on\s+line\s+(\d+)\s+of\s+([^\s:]+)(?::\s*([\s\S]*))?/i);
26-
if (m1) {
27-
line = parseInt(m1[1], 10);
28-
file = m1[2];
29-
const afterColon = (m1[3] || "").split(/\r?\n/);
30-
const snippet = afterColon.find(s => s.trim() && !/^\s*\^+\s*$/.test(s));
31-
}
32-
}
33-
3424
let name: string | undefined;
3525
const q = (message || "").match(/["']([^"']+)["']/);
3626
if (q) name = q[1];
@@ -48,20 +38,10 @@ export const pyodideAdapter: AdapterFn = (raw, code) => {
4838
};
4939

5040
if (code && line) {
51-
const codeLines = code.split(/\r?\n/);
52-
t.codeLine = codeLines[line - 1]?.trim();
53-
t.codeBefore = codeLines.slice(Math.max(0, line - 3), line - 1);
54-
t.codeAfter = codeLines.slice(line, line + 2);
55-
} else {
56-
const m1 = raw.match(/on\s+line\s+\d+\s+of\s+[^\s:]+:(?:\s*([\s\S]*))?/i);
57-
if (m1 && m1[1]) {
58-
const snippet = m1[1].split(/\r?\n/).find(s => s.trim() && !/^\s*\^+\s*$/.test(s));
59-
if (snippet) t.codeLine = snippet.trim();
60-
}
41+
const lines = code.split(/\r?\n/);
42+
t.codeLine = lines[line - 1]?.trim();
43+
t.codeBefore = lines.slice(Math.max(0, line - 3), line - 1);
44+
t.codeAfter = lines.slice(line, line + 2);
6145
}
62-
63-
const looksLikeError = /Error\b/i.test(raw) || /Traceback/i.test(raw) || /pyodide/i.test(raw);
64-
if (!looksLikeError) return null;
65-
6646
return t;
6747
};

src/adapters/skulpt.ts

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,24 @@ const lastLineTypeMessage = (raw: string) => {
88
};
99

1010
export const skulptAdapter: AdapterFn = (raw, code) => {
11-
// Skulpt traces vary - we accept both "Traceback..." and editor summaries
11+
if (!/skulpt/i.test(raw) && !/Traceback/i.test(raw)) {
12+
// still try; skulpt often includes "on line X of", etc.
13+
}
1214
const { type, message, tail, lines } = lastLineTypeMessage(raw);
1315
let file: string | undefined, line: number | undefined, col: number | undefined;
1416

15-
// standard Python-style frames (Skulpt often emits these)
1617
for (const L of lines) {
1718
const mm = L.match(/File\s+"([^"]+)",\s+line\s+(\d+)/i);
1819
if (mm) {
1920
file = mm[1];
2021
line = parseInt(mm[2], 10);
2122
}
2223
}
23-
2424
if (!line) {
25-
const m1 = raw.match(/on\s+line\s+(\d+)\s+of\s+([^\s:]+)(?::\s*([\s\S]*))?/i);
26-
if (m1) {
27-
line = parseInt(m1[1], 10);
28-
file = m1[2];
29-
const afterColon = (m1[3] || "").split(/\r?\n/);
30-
const snippet = afterColon.find(s => s.trim() && !/^\s*\^+\s*$/.test(s));
25+
const loc = tail.match(/\b(?:on|at)\s+line\s+(\d+)\s+(?:of|in)\s+([^\s:]+)\b/i);
26+
if (loc) {
27+
line = parseInt(loc[1], 10);
28+
file = loc[2];
3129
}
3230
}
3331

@@ -48,20 +46,10 @@ export const skulptAdapter: AdapterFn = (raw, code) => {
4846
};
4947

5048
if (code && line) {
51-
const codeLines = code.split(/\r?\n/);
52-
t.codeLine = codeLines[line - 1]?.trim();
53-
t.codeBefore = codeLines.slice(Math.max(0, line - 3), line - 1);
54-
t.codeAfter = codeLines.slice(line, line + 2);
55-
} else {
56-
const m1 = raw.match(/on\s+line\s+\d+\s+of\s+[^\s:]+:(?:\s*([\s\S]*))?/i);
57-
if (m1 && m1[1]) {
58-
const snippet = m1[1].split(/\r?\n/).find(s => s.trim() && !/^\s*\^+\s*$/.test(s));
59-
if (snippet) t.codeLine = snippet.trim();
60-
}
49+
const lines = code.split(/\r?\n/);
50+
t.codeLine = lines[line - 1]?.trim();
51+
t.codeBefore = lines.slice(Math.max(0, line - 3), line - 1);
52+
t.codeAfter = lines.slice(line, line + 2);
6153
}
62-
63-
const looksLikeError = /Error\b/i.test(raw) || /Traceback/i.test(raw) || /skulpt/i.test(raw);
64-
if (!looksLikeError) return null;
65-
6654
return t;
6755
};

src/engine.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,15 @@ export const loadCopydeck = (deck: CopyDeck) => (S.copy = deck);
1313
export const registerAdapter = (name: string, fn: (raw: string, code?: string) => Trace | null) =>
1414
(S.adapters[name] = fn);
1515

16-
const isTrace = (x: unknown): x is Trace =>
17-
!!x && typeof x === "object" && "raw" in (x as any) && "message" in (x as any);
18-
1916
const coerceTrace = (input: string | Error | Trace, code?: string): Trace => {
20-
if (isTrace(input)) return input as Trace;
21-
22-
const raw =
23-
typeof input === "string"
24-
? input
25-
: String((input as Error).stack || (input as Error).message || input);
26-
17+
if ((input as Trace).raw !== undefined) return input as Trace;
18+
const raw = typeof input === "string" ? input : String((input as Error).stack || (input as Error).message || input);
2719
// try adapters in registration order
2820
for (const key of Object.keys(S.adapters)) {
2921
const t = S.adapters[key](raw, code);
3022
if (t) return t;
3123
}
32-
33-
// fallback generic trace
24+
// generic fallback
3425
const lines = raw.trim().split(/\r?\n/).filter(Boolean);
3526
const tail = lines[lines.length - 1] || "";
3627
const m = tail.match(/^(\w+Error)\s*:\s*(.*)$/);
@@ -40,9 +31,8 @@ const coerceTrace = (input: string | Error | Trace, code?: string): Trace => {
4031
raw,
4132
runtime: "unknown"
4233
};
43-
44-
if (code && t.line) {
45-
t.codeLine = code.split(/\r?\n/)[t.line - 1]?.trim();
34+
if (code) {
35+
t.codeLine = code.split(/\r?\n/)[(t.line || 1) - 1]?.trim();
4636
}
4737
return t;
4838
};
@@ -138,7 +128,6 @@ export const explain = (opts: ExplainOptions): ExplainResult => {
138128

139129
const chosen = pickVariant(trace, code, audience);
140130
if (!chosen) {
141-
// this generic fallback copy should live in the copydeck instead...
142131
return {
143132
trace,
144133
variantId: "Other/variants/0",

0 commit comments

Comments
 (0)