File size: 3,751 Bytes
2d39154
794b22f
2d39154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794b22f
2d39154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794b22f
2d39154
 
 
 
 
 
 
 
 
 
 
794b22f
2d39154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env node
/* test-v071.mjs - v0.7.1 regression: comment line numbers.
 * The extension's test suite caught it: every `//` comment doubled a newline
 * in the stripped source, so every line number after the first comment
 * drifted +1 and diagnostics pointed one line late. Block comments were
 * fine; line comments were lying. These tests pin the fix. */
import { parse } from '../public/dssl/parser.js';
import { resolve } from '../public/dssl/resolver.js';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const here = path.dirname(fileURLToPath(import.meta.url));
let passed = 0, failed = 0;
const ok = (cond, name) => {
  if (cond) { passed++; console.log(`  ok  ${name}`); }
  else { failed++; console.log(`FAIL  ${name}`); }
};

console.log('1 - comment placements keep true line numbers');
{
  const cases = [
    ['leading', '// c\n.a {\n  x: 1\n}', 3],
    ['inner', '.a {\n  // c\n  x: 1\n}', 3],
    ['trailing', '.a {\n  x: 1 // c\n}', 2],
    ['block leading', '/* c */\n.a {\n  x: 1\n}', 3],
    ['block inner', '.a {\n  /* c */\n  x: 1\n}', 3],
    ['many comments', '// one\n// two\n.a {\n  // three\n  x: 1 // four\n}', 5],
    ['comment at eof no newline', '.a {\n  x: 1\n}\n// tail', null],
    ['crlf', '// c\r\n.a {\r\n  x: 1\r\n}', 3],
  ];
  for (const [name, src, want] of cases) {
    const { ast, errors } = parse(src, 't.dssl');
    const rule = ast.children.find((n) => n.kind === 'selector');
    const got = rule ? rule.children[0].line : null;
    const bad = errors.filter((e) => !/missing|not a valid|expected/.test(e.message));
    ok((want === null || got === want) && bad.length === 0, `${name}: decl line ${got}${want === null ? '' : ' (want ' + want + ')'}`);
  }
}

console.log('2 - errors and warnings carry honest lines after comments');
{
  const src = '// header comment\n.nav-links {\n  display: none\n  column: gap 2\n}\n.bad {\n  background: colr.accent\n}\n';
  // lines 1-based: display=3, column=4, colr=7
  const { ast } = parse(src, 't.dssl');
  const doc = resolve(ast, 't.dssl', {});
  const warn = doc.warnings.find((w) => w.message.includes('column'));
  ok(warn && warn.line === 4, `ordering warning fires on the column: line (got ${warn && warn.line}, want 4)`);
  const err = doc.errors.find((e) => e.message.includes('colr'));
  ok(err && err.line === 7, `misspelled token error on its own line (got ${err && err.line}, want 7)`);
}

console.log('3 - the real site stylesheets: spot-check line honesty');
{
  // parse a real stylesheet that opens with a comment block and verify a
  // known rule lands where it lives on disk
  import('node:fs').then(({ readFileSync }) => {
    try {
      const p = path.join(here, '..', 'public', 'styles', 'tokens.dssl');
      const src = readFileSync(p, 'utf8');
      const lines = src.split('\n');
      // find a real declaration line with a known shape
      const idx = lines.findIndex((l) => /--dssl-color-ink/.test(l));
      if (idx >= 0) {
        const { ast } = parse(src, 'tokens.dssl');
        let found = null;
        const walk = (n) => {
          if (found) return;
          for (const c of n.children || []) {
            if (c.kind === 'decl' && /ink/.test(c.prop || '')) { found = c; return; }
            walk(c);
          }
        };
        walk(ast);
        ok(found && found.line === idx + 1, `tokens.dssl decl on disk line ${idx + 1}, parser says ${found && found.line}`);
      } else {
        ok(true, 'tokens.dssl shape changed; spot-check skipped');
      }
    } catch (e) {
      ok(false, 'site stylesheet spot-check threw: ' + e.message);
    }
    finish();
  });
}

function finish() {
  console.log(`\n${passed} passed, ${failed} failed`);
  process.exit(failed ? 1 : 0);
}