File size: 2,457 Bytes
f6dcaa7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env node
// Validate the scroll registry and manifests with the same checks the page runs.
//   node tools/validate_scroll.mjs                      all scrolls in scrolls/index.json
//   node tools/validate_scroll.mjs path/to/manifest.json [--local]
// --local applies the limits used for "Open your own" (as a visitor's browser would).
// Exit code 1 if anything is wrong. Git LFS pointer files count as present.
import { readFileSync, statSync, existsSync } from 'node:fs';
import { dirname, resolve, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { validateManifest, validateRegistry, LOCAL_LIMITS, REGISTRY_LIMITS, peelOrder } from '../lib/manifest.js';

const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const args = process.argv.slice(2);
const local = args.includes('--local');
const paths = args.filter((a) => !a.startsWith('--'));
let bad = 0;

function lfsSize(p) {
  // an LFS pointer stands for the real file: report the size it records
  const st = statSync(p);
  if (st.size < 400) { const t = readFileSync(p, 'utf8'); const m = /^version https:\/\/git-lfs.*\nsize (\d+)/m.exec(t); if (m) return +m[1]; }
  return st.size;
}

function check(manifestPath, trusted) {
  let m;
  try { m = JSON.parse(readFileSync(manifestPath, 'utf8')); }
  catch (e) { console.log(`FAIL ${manifestPath}: ${e.message}`); bad++; return; }
  const base = resolve(dirname(manifestPath), m.base || '');
  const v = validateManifest(m, {
    trusted, limits: trusted ? REGISTRY_LIMITS : LOCAL_LIMITS,
    fileSize: (p) => { const f = join(base, p); return existsSync(f) ? lfsSize(f) : null; },
  });
  const n = v.ok ? peelOrder(m).length : 0;
  console.log(`${v.ok ? 'ok  ' : 'FAIL'} ${manifestPath}${v.ok ? `: ${m.id}, ${n} windings, ${m.layers.length} layers, ${v.files.length} files` : ''}`);
  for (const e of v.errors) console.log(`  error: ${e}`);
  for (const w of v.warnings) console.log(`  note: ${w}`);
  if (!v.ok) bad++;
}

if (paths.length) for (const p of paths) check(resolve(p), !local);
else {
  const reg = JSON.parse(readFileSync(join(root, 'scrolls/index.json'), 'utf8'));
  const r = validateRegistry(reg);
  console.log(`${r.ok ? 'ok  ' : 'FAIL'} scrolls/index.json: ${reg.scrolls?.length ?? 0} scrolls`);
  for (const e of r.errors) console.log(`  error: ${e}`);
  if (!r.ok) bad++;
  for (const s of reg.scrolls || []) check(join(root, s.manifest), true);
}
process.exit(bad ? 1 : 0);