MCPcopy
hub / github.com/claude-code-best/claude-code / validateComponentFile

Function validateComponentFile

src/utils/plugins/validatePlugin.ts:517–639  ·  view source on GitHub ↗

* Validate the YAML frontmatter in a plugin component markdown file. * * The runtime loader (parseFrontmatter) silently drops unparseable YAML to a * debug log and returns an empty object. That's the right resilience choice * for the load path, but authors running `claude plugin validate` want a

(
  filePath: string,
  content: string,
  fileType: 'skill' | 'agent' | 'command',
)

Source from the content-addressed store, hash-verified

515 * would silently swallow.
516 */
517function validateComponentFile(
518 filePath: string,
519 content: string,
520 fileType: 'skill' | 'agent' | 'command',
521): ValidationResult {
522 const errors: ValidationError[] = []
523 const warnings: ValidationWarning[] = []
524
525 const match = content.match(FRONTMATTER_REGEX)
526 if (!match) {
527 warnings.push({
528 path: 'frontmatter',
529 message:
530 'No frontmatter block found. Add YAML frontmatter between --- delimiters ' +
531 'at the top of the file to set description and other metadata.',
532 })
533 return { success: true, errors, warnings, filePath, fileType }
534 }
535
536 const frontmatterText = match[1] || ''
537 let parsed: unknown
538 try {
539 parsed = parseYaml(frontmatterText)
540 } catch (e) {
541 errors.push({
542 path: 'frontmatter',
543 message:
544 `YAML frontmatter failed to parse: ${errorMessage(e)}. ` +
545 `At runtime this ${fileType} loads with empty metadata (all frontmatter ` +
546 `fields silently dropped).`,
547 })
548 return { success: false, errors, warnings, filePath, fileType }
549 }
550
551 if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
552 errors.push({
553 path: 'frontmatter',
554 message:
555 'Frontmatter must be a YAML mapping (key: value pairs), got ' +
556 `${Array.isArray(parsed) ? 'an array' : parsed === null ? 'null' : typeof parsed}.`,
557 })
558 return { success: false, errors, warnings, filePath, fileType }
559 }
560
561 const fm = parsed as Record<string, unknown>
562
563 // description: must be scalar. coerceDescriptionToString logs+drops arrays/objects at runtime.
564 if (fm.description !== undefined) {
565 const d = fm.description
566 if (
567 typeof d !== 'string' &&
568 typeof d !== 'number' &&
569 typeof d !== 'boolean' &&
570 d !== null
571 ) {
572 errors.push({
573 path: 'description',
574 message:

Callers 1

validatePluginContentsFunction · 0.85

Calls 3

parseYamlFunction · 0.85
errorMessageFunction · 0.50
pushMethod · 0.45

Tested by

no test coverage detected