npm.io
1.2.0 • Published 3d ago

@salesforce/metadata-visualizer-core

Licence
BSD-3-Clause
Version
1.2.0
Deps
2
Size
114 kB
Vulns
0
Weekly
0
Stars
3

@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-core

Quick 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
  1. Registration - Framework calls getMetadataPluginInfo() and validates metadata
  2. Initialization - Framework calls initialize(context) once
  3. File Handling - Framework calls canHandle(filePath) to find matching plugin
  4. Parsing - Framework calls parser.parse(filePath, versionInfo) to extract data
  5. Validation - Framework calls parser.validate(data) if provided
  6. Rendering - Framework auto-detects React builds in ui/ directory and generates HTML
  7. Disposal - Framework calls dispose() when plugin is unloaded

Plugin Metadata Validation

The framework enforces plugin metadata contract:

  • Validates id is non-empty string (must match folder name)
  • Validates name is non-empty string
  • Validates author is non-empty string
  • Validates filePatterns is 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

Keywords