All files / packages/icons/.claude/skills/icons-release/scripts verify-preview.js

0% Statements 0/36
0% Branches 0/24
0% Functions 0/1
0% Lines 0/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                                                                                                                                                                       
#!/usr/bin/env node
'use strict'
 
/**
 * verify-preview
 *
 * Deterministically verifies that every eligible icon made it into the
 * previewer data, and emits the per-set `?search=` preview URLs for the
 * human visual check. Does NOT start a server (a long-running dev server
 * can't return JSON) — the SKILL starts the previewer and the human
 * opens the URLs.
 *
 * Usage:
 *   node .claude/skills/icons-release/scripts/verify-preview.js --release R264 [--port 3000] [--skip-build]
 *
 * Output: { success, step, data: { expected, rendered, missing, previewUrls } }
 */
 
const fs = require('fs')
const path = require('path')
const { spawnSync } = require('child_process')
 
const { succeed, failWith, run, log } = require('./lib/output')
const { parseArgs } = require('./lib/args')
const { loadWorkset } = require('./lib/workset')
 
const STEP = 'verify-preview'
const MODEL_PATH = path.join('public', 'icons-all.json')
 
function main() {
  const args = parseArgs(process.argv.slice(2))
  if (!args.release) {
    throw Object.assign(new Error('--release is required (e.g. --release R264)'), {
      code: 'MISSING_ARG'
    })
  }
  const port = args.port || '3000'
  const baseUrl = args['base-url'] || `http://localhost:${port}`
 
  const { release, icons } = loadWorkset(args.release)
 
  // Regenerate previewer data unless told to skip (so the check is fresh).
  if (!args['skip-build']) {
    log('> yarn build:public')
    // Child output → our stderr; stdout stays reserved for the JSON envelope.
    const result = spawnSync('yarn build:public', {
      shell: true,
      stdio: ['ignore', 2, 2]
    })
    if (result.status !== 0) {
      failWith(STEP, 'previewerDataFailed', `yarn build:public exited with code ${result.status}`)
    }
  }
 
  if (!fs.existsSync(MODEL_PATH)) {
    failWith(STEP, 'noModelData', `${MODEL_PATH} not found. Run the previewer build first.`)
  }
  const model = JSON.parse(fs.readFileSync(MODEL_PATH, 'utf8'))
 
  const missing = []
  const bySet = {}
 
  for (const icon of icons) {
    const set = icon.icon_type
    const entry = model[set] || { common: [], directional: [] }
    const present =
      (entry.common || []).includes(icon.icon_name) ||
      (entry.directional || []).includes(icon.icon_name)
 
    if (!present) {
      missing.push({ icon: icon.icon_name, icon_type: set })
    } else {
      ;(bySet[set] = bySet[set] || []).push(icon.icon_name)
    }
  }
 
  const previewUrls = {}
  for (const [set, names] of Object.entries(bySet)) {
    previewUrls[set] = `${baseUrl}/${set}?search=${names.join(',')}`
  }
 
  succeed(STEP, {
    release,
    expected: icons.length,
    rendered: icons.length - missing.length,
    missing,
    previewUrls
  })
}
 
run(STEP, main)