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…