File size: 4,556 Bytes
794b22f
c3fdf10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* repro-v073.mjs - reproduce every claim from the 2026-10-23 Claude review
 * of v0.7.2 before touching any code. Green = the bug exists as reported. */
import { parse, STATE_WORDS } from '../public/dssl/parser.js';
import { resolve } from '../public/dssl/resolver.js';

const compileDoc = (src, file = 'repro.dssl') => {
  const { ast, errors } = parse(src, file);
  const doc = resolve(ast, file);
  return { parseErrors: errors, doc };
};

let found = 0;
const repro = (name, cond) => {
  if (cond) { found++; console.log(`REPRODUCED  ${name}`); }
  else console.log(`not repro'd  ${name}`);
};

// --- bug 1: row: gap 8 between center loses "between" --------------------
{
  const { doc } = compileDoc('toolbar { row: gap 8 between center }');
  const decls = doc.rules[0]?.decls || [];
  const jc = decls.filter(d => d.prop === 'justify-content');
  const ai = decls.filter(d => d.prop === 'align-items');
  console.log('  decls:', decls.map(d => `${d.prop}:${d.value}`).join(' | '));
  repro('bug1: justify-content written twice (last wins = center)', jc.length === 2 && jc[1].value === 'center');
  repro('bug1: bare center also writes align-items (both axes)', ai.length === 1);
}

// --- bug 2: @font-face crashes the compiler -------------------------------
{
  let threw = null, out = '';
  try {
    const r = compileDoc('@font-face { font-family: X; src: url(x.woff2) }');
    out = JSON.stringify(r.doc.rules || []);
  } catch (e) { threw = e; }
  repro('bug2: @font-face THROWS instead of compile error', !!threw);
  if (threw) console.log('  throw:', threw.message);
}

// --- bug 3: @supports leaks inner rule unconditionally --------------------
{
  const { parseErrors, doc } = compileDoc('@supports (display:grid) { .a { display: grid } }');
  const leaked = (doc.rules || []).some(r => (r.sel || '').includes('a'));
  const atErr = parseErrors.some(e => /@supports/.test(e.message));
  console.log('  parse errors:', parseErrors.map(e => e.message).join(' ; ').slice(0, 120));
  repro('bug3: unknown at-rule errors reported', atErr);
  repro('bug3: inner rule STILL APPLIES unconditionally', leaked);
}

// --- bug 4: unquoted url() gives false errors ------------------------------
{
  const { parseErrors, doc } = compileDoc('.a { background: url(a.png) no-repeat }');
  const msgs = parseErrors.map(e => e.message).join(' ; ');
  const badValue = /unknown value "(a\.png|no-repeat)"/.test(msgs);
  const emitted = (doc.rules[0]?.decls || []).some(d => /url\(a\.png\)/.test(d.value));
  console.log('  errors:', msgs.slice(0, 140) || '(none)');
  repro('bug4: false unknown-value errors for unquoted url parts', badValue);
  repro('bug4: declaration still emitted (error + emit confusion)', emitted);
  // control: quoted form is fine
  const q = compileDoc('.a { background: url("a.png") no-repeat }');
  console.log('  quoted errors:', q.parseErrors.map(e => e.message).join(';').slice(0, 100) || '(none)');
}

// --- bug 5a: animation: spin 1s infinite -> did you mean "span" -----------
{
  const { parseErrors } = compileDoc('.a { animation: spin 1s infinite }');
  const silly = parseErrors.some(e => /span/.test(e.message));
  console.log('  errors:', parseErrors.map(e => `${e.message}${e.hint ? ' [' + e.hint + ']' : ''}`).join(' ; ').slice(0, 160));
  repro('bug5a: silly "span" suggestion instead of motion guidance', silly);
}

// --- bug 5b: !important errors AND still emits ----------------------------
{
  const { parseErrors, doc } = compileDoc('.a { color: red !important }');
  const wrongErr = parseErrors.some(e => /unknown value "important"/.test(e.message));
  const emitted = (doc.rules[0]?.decls || []).some(d => /important/.test(d.value));
  console.log('  errors:', parseErrors.map(e => e.message).join(';').slice(0, 120));
  console.log('  emitted value:', doc.rules[0]?.decls.map(d => d.value).join('|'));
  repro('bug5b: !important reported as unknown value "important"', wrongErr);
  repro('bug5b: !important still emitted in the value', emitted);
}

// --- bug 5c: transition CSS form gives no conversion hint ------------------
{
  const { parseErrors } = compileDoc('.a { transition: color .2s ease }');
  const hint = parseErrors.some(e => /200/.test(e.hint || '') && /transition/.test(e.hint || ''));
  console.log('  errors:', parseErrors.map(e => `${e.message}${e.hint ? ' [' + e.hint + ']' : ''}`).join(' ; ').slice(0, 200) || '(none)');
  repro('bug5c: CSS transition form rejected with no DSSL-form hint', parseErrors.length > 0 && !hint);
}

console.log(`\n${found} claim(s) reproduced`);