UNPKG

apisurf

Version:

Analyze API surface changes between npm package versions to catch breaking changes

198 lines (197 loc) 7.41 kB
/** * Formats inspect results as Markdown. */ export function formatInspectMarkdownOutput(result, verbose = false) { const lines = []; // Header lines.push(`# API Surface Report: ${result.packageName}@${result.version}`); lines.push(''); if (result.repositoryUrl) { lines.push(`**Repository:** ${result.repositoryUrl}`); lines.push(''); } // Summary lines.push('## Summary'); lines.push(''); lines.push(result.summary); // Errors if (result.errors && result.errors.length > 0) { lines.push(''); lines.push('### ⚠️ Errors'); lines.push(''); result.errors.forEach(error => { lines.push(`- ${error}`); }); } if (!result.success) { return lines.join('\n'); } // Table of Contents if (result.apiSurfaces.size > 1) { lines.push(''); lines.push('## Entry Points'); lines.push(''); for (const [entryPoint] of result.apiSurfaces) { const displayName = entryPoint === 'main' ? 'Main Export' : entryPoint; const anchor = entryPoint.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase(); lines.push(`- [${displayName}](#${anchor})`); } } // API Surfaces for (const [entryPoint, surface] of result.apiSurfaces) { lines.push(''); const displayName = entryPoint === 'main' ? 'Main Export' : `Export: ${entryPoint}`; lines.push(`## ${displayName}`); lines.push(''); // Statistics const stats = []; if (surface.defaultExport) stats.push('Default export'); if (surface.namedExports.size > 0) stats.push(`${surface.namedExports.size} named exports`); if (surface.typeOnlyExports.size > 0) stats.push(`${surface.typeOnlyExports.size} type exports`); if (surface.starExports.length > 0) stats.push(`${surface.starExports.length} re-exports`); if (stats.length > 0) { lines.push(`**Stats:** ${stats.join(', ')}`); lines.push(''); } // Default export if (surface.defaultExport) { lines.push('### Default Export'); lines.push(''); lines.push('This module has a default export.'); lines.push(''); } // Named exports if (surface.namedExports.size > 0) { lines.push('### Named Exports'); lines.push(''); if (verbose && surface.typeDefinitions) { // Detailed view with type information const exports = Array.from(surface.namedExports).sort(); exports.forEach(name => { const typeDef = surface.typeDefinitions?.get(name); if (typeDef) { lines.push(`#### \`${name}\` (${typeDef.kind})`); lines.push(''); lines.push(formatTypeDefinitionMarkdown(typeDef)); lines.push(''); } else { lines.push(`- \`${name}\``); } }); } else { // Simple list view lines.push('| Export | Type |'); lines.push('|--------|------|'); const exports = Array.from(surface.namedExports).sort(); exports.forEach(name => { const typeDef = surface.typeDefinitions?.get(name); const type = typeDef ? typeDef.kind : 'unknown'; lines.push(`| \`${name}\` | ${type} |`); }); lines.push(''); } } // Type-only exports if (surface.typeOnlyExports.size > 0) { lines.push('### Type Exports'); lines.push(''); if (verbose && surface.typeDefinitions) { // Detailed view const typeExports = Array.from(surface.typeOnlyExports).sort(); typeExports.forEach(name => { const typeDef = surface.typeDefinitions?.get(name); if (typeDef) { lines.push(`#### \`${name}\` (${typeDef.kind})`); lines.push(''); lines.push(formatTypeDefinitionMarkdown(typeDef)); lines.push(''); } else { lines.push(`- \`${name}\``); } }); } else { // Simple list view lines.push('| Type | Kind |'); lines.push('|------|------|'); const typeExports = Array.from(surface.typeOnlyExports).sort(); typeExports.forEach(name => { const typeDef = surface.typeDefinitions?.get(name); const kind = typeDef ? typeDef.kind : 'unknown'; lines.push(`| \`${name}\` | ${kind} |`); }); lines.push(''); } } // Star exports if (surface.starExports.length > 0) { lines.push('### Re-exports'); lines.push(''); lines.push('This module re-exports from the following modules:'); lines.push(''); surface.starExports.forEach(module => { lines.push(`- \`${module}\``); }); lines.push(''); } } return lines.join('\n'); } /** * Formats a type definition for Markdown output. */ function formatTypeDefinitionMarkdown(def) { const lines = []; if (def.signature) { lines.push('```typescript'); lines.push(def.signature); lines.push('```'); } // Additional details based on kind switch (def.kind) { case 'interface': case 'class': if (def.properties && def.properties.size > 0) { lines.push(''); lines.push('**Properties:**'); lines.push(''); lines.push('| Property | Type |'); lines.push('|----------|------|'); const props = Array.from(def.properties.entries()).sort((a, b) => a[0].localeCompare(b[0])); props.forEach(([name, type]) => { // Escape pipe characters in type strings const escapedType = type.replace(/\|/g, '\\|'); lines.push(`| \`${name}\` | \`${escapedType}\` |`); }); } break; case 'enum': if (def.members && def.members.length > 0) { lines.push(''); lines.push('**Members:**'); lines.push(''); def.members.forEach(member => { lines.push(`- \`${member}\``); }); } break; case 'function': if (def.parameters && def.returnType) { lines.push(''); lines.push('**Signature:**'); lines.push(''); lines.push('```typescript'); lines.push(`(${def.parameters.join(', ')}) => ${def.returnType}`); lines.push('```'); } break; } return lines.join('\n'); }