@salesforce/metadata-visualizer-core
v1.1.0
Published
Platform agnostic framework for visualizing Salesforce metadata with extensible plugin system
Readme
@salesforce/metadata-visualizer-core
Platform-agnostic framework for visualizing Salesforce metadata with an extensible plugin system.
Overview
The Salesforce Metadata Visualizer Framework is a platform-agnostic TypeScript library for building metadata visualization tools. It provides a plugin-based architecture that works across VS Code, CLI tools, web applications, and other environments.
Features
- Platform-Agnostic - Works in VS Code, Node.js, browsers, and more
- Plugin-Based Architecture - Extensible system for custom visualizers
- Modular Design - Clean separation of concerns (parse → render → display)
- Type-Safe - Full TypeScript support with comprehensive type definitions
- Lightweight - Minimal dependencies, focused API
- Contract Enforcement - Framework validates plugin metadata and structure
Installation
npm install @salesforce/metadata-visualizer-coreQuick Start
import {
PluginManager,
VisualizationEngine,
} from '@salesforce/metadata-visualizer-core';
import { IPlatformContext } from '@salesforce/metadata-core-sdk';
// Initialize framework with platform context
const context: IPlatformContext = /* your platform context */;
const pluginManager = new PluginManager(context);
const engine = new VisualizationEngine(context, pluginManager);
// Load plugins (automatically loads from @salesforce/metadata-plugins via getAllVisualizers())
await pluginManager.loadPlugins();
// Visualize a metadata file
const result = await engine.visualize('/path/to/Account.object-meta.xml');
if (result) {
console.log(result.rendered.html);
}Architecture
The framework follows a layered architecture:
┌─────────────────────────────────────────┐
│ Platform Layer │
│ - VS Code, Node.js, Browser │
│ - IPlatformContext │
│ (IFileSystem, ILogger, ITelemetry) │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Core Framework │
│ - VisualizationEngine │
│ - PluginManager │
│ - HtmlVizGenerator │
│ - ErrorManager │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Plugin System (SDK) │
│ - IVisualizationPlugin │
│ - IMetadataParser │
│ - MetadataPluginInfo │
└─────────────────────────────────────────┘Data Flow
1. Input: Metadata File
↓
2. Plugin Discovery: Find plugin via canHandle()
↓
3. Version Info: Collect project version info
↓
4. Parser: Extract structured data via parser.parse(filePath, versionInfo)
↓
5. Validation: Optional validate(data) check
↓
6. Rendering: Auto-detect React build in ui/ directory, generate HTML via HtmlVizGenerator
↓
7. Display: Platform renders HTML (webview, browser, etc.)Core API
VisualizationEngine
Main entry point for visualizing metadata.
class VisualizationEngine {
constructor(context: IPlatformContext, pluginManager: PluginManager);
/**
* Visualize and render a metadata file.
* Returns null on errors (errors reported to ErrorManager).
*/
async visualize<T = any>(filePath: string): Promise<VisualizationResult<T> | null>;
/** Check if a file can be visualized by any registered plugin */
canVisualize(filePath: string): boolean;
/** Get all supported file patterns across registered plugins */
getSupportedFilePatterns(): string[];
/** Get the ErrorManager instance for subscribing to errors */
getErrorManager(): ErrorManager;
/** Dispose resources */
dispose(): void;
}PluginManager
Manages plugin registration and lifecycle.
class PluginManager {
constructor(context: IPlatformContext);
/**
* Load plugins from plugin package.
* Automatically loads via getAllVisualizers() from @salesforce/metadata-plugins.
*
* Framework responsibilities:
* - Calls getMetadataPluginInfo() hook on each plugin
* - Validates plugin metadata (id, name, author, filePatterns)
* - Validates plugin structure (parser, canHandle)
* - Initializes plugins with platform context
* - Registers plugins in internal registry
*
* @returns Number of successfully loaded plugins
*/
async loadPlugins(): Promise<number>;
/** Find the best plugin that can handle the given file (highest priority) */
findVisualizerPluginForFile(filePath: string): IVisualizationPlugin | undefined;
/** Get all registered visualizer plugins */
getAllVisualizerPlugins(): IVisualizationPlugin[];
/** Register a visualizer plugin manually */
async registerVisualizer(plugin: IVisualizationPlugin): Promise<void>;
/** Unregister a visualizer plugin by ID */
unregisterVisualizer(pluginId: string): void;
/** Check if any plugin can handle the file */
isSupportedFileForVisualization(filePath: string): boolean;
/** Get all supported file patterns */
getSupportedFilePatterns(): string[];
/** Reload all plugins */
async reloadAll(): Promise<void>;
}HtmlVizGenerator
Generates HTML from React build output for plugin rendering.
class HtmlVizGenerator {
constructor(fileSystem: IFileSystem);
/** Generate complete HTML document from React build + plugin data */
async generate(config: HtmlVizConfig): Promise<string>;
}
interface HtmlVizConfig {
buildDir: string; // Path to React build output directory
pluginId: string; // Plugin identifier
data: any; // Plugin data to inject into React app
filePath: string; // File path being visualized
}ErrorManager
Central error management service.
class ErrorManager {
/** Report a new error (overwrites previous, notifies callback) */
reportError(error: PluginError): void;
/** Clear the current error */
clearError(): void;
/** Retrieve the current error */
getError(): PluginError | null;
/** Set callback invoked when an error is reported */
setOnErrorReported(callback: ((error: PluginError) => void) | undefined): void;
/** Dispose and clean up */
dispose(): void;
}Platform Context
Provided by core-sdk (@salesforce/metadata-core-sdk). See the @salesforce/metadata-core-sdk package for details.
interface IPlatformContext {
readonly fileSystem: IFileSystem;
readonly logger: ILogger;
readonly telemetry: ITelemetry;
readonly reactBuildsBasePath: string;
readonly pluginSettings?: Record<string, unknown>;
}Building Plugins
Plugin Contract
Every plugin implements IVisualizationPlugin from @salesforce/metadata-core-sdk:
interface IVisualizationPlugin<TData = any> {
/** Get plugin metadata (mandatory hook, called during registration) */
getMetadataPluginInfo(): MetadataPluginInfo;
/** Parser for extracting structured data (required) */
parser: IMetadataParser<TData>;
/** Check if this plugin can handle the given file (required) */
canHandle(filePath: string): boolean;
/** Initialize plugin with platform context (required) */
initialize(context: IPlatformContext): Promise<void>;
/** Dispose plugin resources (optional) */
dispose?(): void;
}Note: Rendering is handled automatically by the framework. The framework auto-detects React builds by checking for ui/ directory in plugin build outputs.
Metadata Contract
Plugins must provide metadata via getMetadataPluginInfo():
interface MetadataPluginInfo {
id: string; // Must match plugin folder name
name: string; // Human-readable name
description?: string; // Plugin description (optional)
author: string; // Plugin author/team
filePatterns: string[]; // File patterns (e.g., ['.object-meta.xml'])
priority?: number; // Selection priority when multiple plugins match (default: 0)
trustedSources?: {
// CSP directives for external resources (optional)
scripts?: string[];
styles?: string[];
connect?: string[];
};
}Example: Custom Object Visualizer
import {
IVisualizationPlugin,
MetadataPluginInfo,
IMetadataParser,
IPlatformContext,
} from '@salesforce/metadata-core-sdk';
import type { VersionInfo } from '@salesforce/metadata-core-sdk';
interface ObjectMetadata {
name: string;
fields: Field[];
}
class ObjectParser implements IMetadataParser<ObjectMetadata> {
async parse(filePath: string, versionInfo: VersionInfo): Promise<ObjectMetadata> {
// Parse XML and return structured data
return { name: 'Account', fields: [] };
}
}
export class ObjectVisualizer implements IVisualizationPlugin<ObjectMetadata> {
private readonly pluginMetadata: MetadataPluginInfo = {
id: 'object', // Must match folder name
name: 'Object Visualizer',
description: 'Visualize Salesforce Custom Objects',
author: 'Object Team',
filePatterns: ['.object-meta.xml'],
};
readonly parser: IMetadataParser<ObjectMetadata>;
constructor() {
this.parser = new ObjectParser();
}
getMetadataPluginInfo(): MetadataPluginInfo {
return this.pluginMetadata;
}
canHandle(filePath: string): boolean {
return filePath.endsWith('.object-meta.xml');
}
async initialize(context: IPlatformContext): Promise<void> {
// Initialize plugin with platform context
}
// Framework auto-detects React builds and handles rendering automatically
}Plugin Lifecycle
- Registration - Framework calls
getMetadataPluginInfo()and validates metadata - Initialization - Framework calls
initialize(context)once - File Handling - Framework calls
canHandle(filePath)to find matching plugin - Parsing - Framework calls
parser.parse(filePath, versionInfo)to extract data - Validation - Framework calls
parser.validate(data)if provided - Rendering - Framework auto-detects React builds in
ui/directory and generates HTML - Disposal - Framework calls
dispose()when plugin is unloaded
Plugin Metadata Validation
The framework enforces plugin metadata contract:
- Validates
idis non-empty string (must match folder name) - Validates
nameis non-empty string - Validates
authoris non-empty string - Validates
filePatternsis non-empty array with non-empty strings - TypeScript enforces plugin structure (
parser,canHandle, etc.)
Package Exports
// Core classes
import {
PluginManager,
VisualizationEngine,
HtmlVizGenerator,
ErrorManager,
} from '@salesforce/metadata-visualizer-core';
// Types
import type {
VisualizationResult,
RenderedContent,
HtmlVizConfig,
ErrorListener,
} from '@salesforce/metadata-visualizer-core';License
BSD-3-Clause
Support
For issues or questions, please file an issue at: https://github.com/forcedotcom/salesforce-metadata-visualizer-support/issues
