Skip to content
Back to skills

Build

ASecurity

Imported skill build from vercel

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 11, 2026
documentationtypescriptreactnextjsnoderefactoringgitperformance

Security analysis

A100/100

Scanned September 11, 2026

npx -y skills add bitwikiorg/skills.md --skill build --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Build?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Build
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bitwikiorg-build/badge)](https://www.skillsdirectory.com/skills/bitwikiorg-build)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
description: Imported skill build from vercel
name: build
signature: 915ec8ce5c18c54f62342ad43817e60c9100fd9113941d6ac7ba29f7e8bb93a0
source: /a0/tmp/skills_research/vercel/packages/react-best-practices-build/src/build.ts
---

#!/usr/bin/env node
/**
 * Build script to compile individual rule files into AGENTS.md
 */

import { readdir, readFile, writeFile } from 'fs/promises'
import { join } from 'path'
import { Rule, Section, GuidelinesDocument, ImpactLevel } from './types.js'
import { parseRuleFile, RuleFile } from './parser.js'
import { RULES_DIR, METADATA_FILE, OUTPUT_FILE, SKILL_DIR } from './config.js'

// Parse command line arguments
const args = process.argv.slice(2)
const upgradeVersion = args.includes('--upgrade-version')

/**
 * Increment a semver-style version string (e.g., "0.1.0" -> "0.1.1", "1.0" -> "1.1")
 */
function incrementVersion(version: string): string {
  const parts = version.split('.').map(Number)
  // Increment the last part
  parts[parts.length - 1]++
  return parts.join('.')
}

/**
 * Generate markdown from rules
 */
function generateMarkdown(
  sections: Section[],
  metadata: {
    version: string
    organization: string
    date: string
    abstract: string
    references?: string[]
  }
): string {
  let md = `# React Best Practices\n\n`
  md += `**Version ${metadata.version}**  \n`
  md += `${metadata.organization}  \n`
  md += `${metadata.date}\n\n`
  md += `> **Note:**  \n`
  md += `> This document is mainly for agents and LLMs to follow when maintaining,  \n`
  md += `> generating, or refactoring React and Next.js codebases at Vercel. Humans  \n`
  md += `> may also find it useful, but guidance here is optimized for automation  \n`
  md += `> and consistency by AI-assisted workflows.\n\n`
  md += `---\n\n`
  md += `## Abstract\n\n`
  md += `${metadata.abstract}\n\n`
  md += `---\n\n`
  md += `## Table of Contents\n\n`

  // Generate TOC
  sections.forEach((section) => {
    md += `${section.number}. [${section.title}](#${
      section.number
    }-${section.title.toLowerCase().replace(/\s+/g, '-')}) — **${
      section.impact
    }**\n`
    section.rules.forEach((rule) => {
      // GitHub generates anchors from the full heading text: "1.1 Title" -> "#11-title"
      const anchor = `${rule.id} ${rule.title}`
        .toLowerCase()
        .replace(/\s+/g, '-')
        .replace(/[^\w-]/g, '') // Remove special characters except hyphens
      md += `   - ${rule.id} [${rule.title}](#${anchor})\n`
    })
  })

  md += `\n---\n\n`

  // Generate sections
  sections.forEach((section) => {
    md += `## ${section.number}. ${section.title}\n\n`
    md += `**Impact: ${section.impact}${
      section.impactDescription ? ` (${section.impactDescription})` : ''
    }**\n\n`
    if (section.introduction) {
      md += `${section.introduction}\n\n`
    }

    section.rules.forEach((rule) => {
      md += `### ${rule.id} ${rule.title}\n\n`
      md += `**Impact: ${rule.impact}${
        rule.impactDescription ? ` (${rule.impactDescription})` : ''
      }**\n\n`
      md += `${rule.explanation}\n\n`

      rule.examples.forEach((example) => {
        if (example.description) {
          md += `**${example.label}: ${example.description}**\n\n`
        } else {
          md += `**${example.label}:**\n\n`
        }
        // Only generate code block if there's actual code
        if (example.code && example.code.trim()) {
          md += `\`\`\`${example.language || 'typescript'}\n`
          md += `${example.code}\n`
          md += `\`\`\`\n\n`
        }
        if (example.additionalText) {
          md += `${example.additionalText}\n\n`
        }
      })

      if (rule.references && rule.references.length > 0) {
        md += `Reference: ${rule.references
          .map((ref) => `[${ref}](${ref})`)
          .join(', ')}\n\n`
      }
    })

    md += `---\n\n`
  })

  // Add references section
  if (metadata.references && metadata.references.length > 0) {
    md += `## References\n\n`
    metadata.references.forEach((ref, i) => {
      md += `${i + 1}. [${ref}](${ref})\n`
    })
  }

  return md
}

/**
 * Main build function
 */
async function build() {
  try {
    console.log('Building AGENTS.md from rules...')
    console.log(`Rules directory: ${RULES_DIR}`)
    console.log(`Output file: ${OUTPUT_FILE}`)

    // Read all rule files (exclude files starting with _ and README.md)
    const files = await readdir(RULES_DIR)
    const ruleFiles = files
      .filter(
        (f) => f.endsWith('.md') && !f.startsWith('_') && f !== 'README.md'
      )
      .sort() // Sort filenames for consistent ordering across systems

    const ruleData: RuleFile[] = []
    for (const file of ruleFiles) {
      const filePath = join(RULES_DIR, file)
      try {
        const parsed = await parseRuleFile(filePath)
        ruleData.push(parsed)
      } catch (error) {
        console.error(`Error parsing ${file}:`, error)
      }
    }

    // Group rules by section
    const sectionsMap = new Map<number, Section>()

    ruleData.forEach(({ section, rule }) => {
      if (!sectionsMap.has(section)) {
        sectionsMap.set(section, {
          number: section,
          title: `Section ${section}`, // Will be overridden by section metadata
          impact: rule.impact,
          rules: [],
        })
      }
      sectionsMap.get(section)!.rules.push(rule)
    })

    // Sort rules within each section by title (using en-US locale for consistency across environments)
    sectionsMap.forEach((section) => {
      section.rules.sort((a, b) =>
        a.title.localeCompare(b.title, 'en-US', { sensitivity: 'base' })
      )

      // Assign IDs based on sorted order
      section.rules.forEach((rule, index) => {
        rule.id = `${section.number}.${index + 1}`
        rule.subsection = index + 1
      })
    })

    // Convert to array and sort
    const sections = Array.from(sectionsMap.values()).sort(
      (a, b) => a.number - b.number
    )

    // Read section metadata from consolidated _sections.md file
    const sectionsFile = join(RULES_DIR, '_sections.md')
    try {
      const sectionsContent = await readFile(sectionsFile, 'utf-8')

      // Parse sections using regex to match each section block
      const sectionBlocks = sectionsContent
        .split(/(?=^## \d+\. )/m)
        .filter(Boolean)

      for (const block of sectionBlocks) {
        // Extract section number and title, removing section ID in parentheses
        const headerMatch = block.match(
          /^## (\d+)\.\s+(.+?)(?:\s+\([^)]+\))?$/m
        )
        if (!headerMatch) continue

        const sectionNumber = parseInt(headerMatch[1])
        const sectionTitle = headerMatch[2].trim() // Strip (id) for output

        // Extract impact (format: **Impact:** CRITICAL)
        const impactMatch = block.match(/\*\*Impact:\*\*\s+(\w+(?:-\w+)?)/i)
        const impactLevel = impactMatch
          ? (impactMatch[1].toUpperCase().replace(/-/g, '-') as ImpactLevel)
          : 'MEDIUM'

        // Extract description (format: **Description:** text)
        const descMatch = block.match(
          /\*\*Description:\*\*\s+(.+?)(?=\n\n##|$)/s
        )
        const description = descMatch ? descMatch[1].trim() : ''

        // Update section if it exists
        const section = sections.find((s) => s.number === sectionNumber)
        if (section) {
          section.title = sectionTitle
          section.impact = impactLevel
          section.introduction = description
        }
      }
    } catch (error) {
      console.warn(
        'Warning: Could not read _sections.md, using defaults',
        error
      )
    }

    // Read metadata
    let metadata
    try {
      const metadataContent = await readFile(METADATA_FILE, 'utf-8')
      metadata = JSON.parse(metadataContent)
    } catch {
      metadata = {
        version: '1.0',
        organization: 'Vercel Engineering',
        date: new Date().toLocaleDateString('en-US', {
          month: 'long',
          year: 'numeric',
        }),
        abstract:
          'Performance optimization guide for React and Next.js applications, ordered by impact.',
      }
    }

    // Upgrade version if flag is passed
    if (upgradeVersion) {
      const oldVersion = metadata.version
      metadata.version = incrementVersion(oldVersion)
      console.log(`Upgrading version: ${oldVersion} -> ${metadata.version}`)

      // Write updated metadata.json
      await writeFile(METADATA_FILE, JSON.stringify(metadata, null, 2) + '\n', 'utf-8')
      console.log(`✓ Updated metadata.json`)

      // Update SKILL.md frontmatter
      const skillFile = join(SKILL_DIR, 'SKILL.md')
      const skillContent = await readFile(skillFile, 'utf-8')
      const updatedSkillContent = skillContent.replace(
        /^(---[\s\S]*?version:\s*)"[^"]*"([\s\S]*?---)$/m,
        `$1"${metadata.version}"$2`
      )
      await writeFile(skillFile, updatedSkillContent, 'utf-8')
      console.log(`✓ Updated SKILL.md`)
    }

    // Generate markdown
    const markdown = generateMarkdown(sections, metadata)

    // Write output
    await writeFile(OUTPUT_FILE, markdown, 'utf-8')

    console.log(
      `✓ Built AGENTS.md with ${sections.length} sections and ${ruleData.length} rules`
    )
  } catch (error) {
    console.error('Build failed:', error)
    process.exit(1)
  }
}

build()

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.