CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-backstage--plugin-catalog-node

Node.js utilities and types for building Backstage catalog modules, providing core APIs for catalog processors, entity providers, and processing workflows

Pending
Overview
Eval results
Files

catalog-processing.mddocs/

Catalog Processing

Core catalog processor interface and utilities for building custom catalog processors that handle entity ingestion, transformation, and validation during catalog processing workflows.

Capabilities

CatalogProcessor Interface

The main interface for implementing custom catalog processors that can read locations, process entities, and emit results.

/**
 * Core interface for processing catalog locations and entities
 */
type CatalogProcessor = {
  /**
   * A unique identifier for the Catalog Processor.
   */
  getProcessorName(): string;

  /**
   * Reads the contents of a location.
   * @param location - The location to read
   * @param optional - Whether a missing target should trigger an error
   * @param emit - A sink for items resulting from the read
   * @param parser - A parser that takes raw catalog descriptor data and turns it into result pieces
   * @param cache - A cache for storing values local to this processor and the current entity
   * @returns True if handled by this processor, false otherwise
   */
  readLocation?(
    location: LocationSpec,
    optional: boolean,
    emit: CatalogProcessorEmit,
    parser: CatalogProcessorParser,
    cache: CatalogProcessorCache,
  ): Promise<boolean>;

  /**
   * Pre-processes an emitted entity, after it has been emitted but before it has been validated.
   * This type of processing usually involves enriching the entity with additional data.
   * @param entity - The (possibly partial) entity to process
   * @param location - The location that the entity came from
   * @param emit - A sink for auxiliary items resulting from the processing
   * @param originLocation - The location that the entity originally came from
   * @param cache - A cache for storing values local to this processor and the current entity
   * @returns The same entity or a modified version of it
   */
  preProcessEntity?(
    entity: Entity,
    location: LocationSpec,
    emit: CatalogProcessorEmit,
    originLocation: LocationSpec,
    cache: CatalogProcessorCache,
  ): Promise<Entity>;

  /**
   * Validates the entity as a known entity kind, after it has been pre-processed.
   * @param entity - The entity to validate
   * @returns Resolves to true if the entity was known and valid, false if unknown, or rejects with error if invalid
   */
  validateEntityKind?(entity: Entity): Promise<boolean>;

  /**
   * Post-processes an emitted entity, after it has been validated.
   * @param entity - The entity to process
   * @param location - The location that the entity came from
   * @param emit - A sink for auxiliary items resulting from the processing
   * @param cache - A cache for storing values local to this processor and the current entity
   * @returns The same entity or a modified version of it
   */
  postProcessEntity?(
    entity: Entity,
    location: LocationSpec,
    emit: CatalogProcessorEmit,
    cache: CatalogProcessorCache,
  ): Promise<Entity>;
};

Usage Examples:

import { CatalogProcessor, processingResult } from "@backstage/plugin-catalog-node";
import { Entity } from "@backstage/catalog-model";
import { LocationSpec } from "@backstage/plugin-catalog-common";

class AnnotationProcessor implements CatalogProcessor {
  getProcessorName(): string {
    return "annotation-processor";
  }

  async preProcessEntity(
    entity: Entity,
    location: LocationSpec,
    emit: CatalogProcessorEmit,
    originLocation: LocationSpec,
    cache: CatalogProcessorCache
  ): Promise<Entity> {
    // Add processing timestamp
    const processedEntity = {
      ...entity,
      metadata: {
        ...entity.metadata,
        annotations: {
          ...entity.metadata.annotations,
          "backstage.io/processed-at": new Date().toISOString(),
          "backstage.io/processed-by": this.getProcessorName()
        }
      }
    };

    // Store processing info in cache
    await cache.set("lastProcessed", Date.now());
    
    return processedEntity;
  }

  async validateEntityKind(entity: Entity): Promise<boolean> {
    // Only handle Component entities
    if (entity.kind === "Component") {
      if (!entity.metadata.name) {
        throw new Error("Component entities must have a name");
      }
      return true;
    }
    return false;
  }
}

CatalogProcessorEmit Function

Callback function for emitting processing results during catalog processing.

/**
 * Callback for emitting processing results
 * @param generated - The processing result to emit
 */
type CatalogProcessorEmit = (generated: CatalogProcessorResult) => void;

CatalogProcessorCache Interface

Cache interface for storing processor-specific data during entity processing.

/**
 * A cache for storing data during processing.
 * Values are local to each processor and scoped to the entity being processed.
 */
interface CatalogProcessorCache {
  /**
   * Retrieve a value from the cache.
   * @param key - Cache key to retrieve
   * @returns The cached value or undefined if not found
   */
  get<ItemType extends JsonValue>(key: string): Promise<ItemType | undefined>;

  /**
   * Store a value in the cache.
   * @param key - Cache key to store under
   * @param value - Value to store in cache
   */
  set<ItemType extends JsonValue>(key: string, value: ItemType): Promise<void>;
}

CatalogProcessorParser Type

Parser function type for processing raw catalog descriptor data.

/**
 * A parser that takes raw catalog descriptor data and turns it into result pieces.
 * The default implementation performs YAML document parsing.
 * @param options - Parsing options containing data buffer and location
 * @returns AsyncIterable of processing results
 */
type CatalogProcessorParser = (options: {
  data: Buffer;
  location: LocationSpec;
}) => AsyncIterable<CatalogProcessorResult>;

Usage Examples:

import { CatalogProcessorParser } from "@backstage/plugin-catalog-node";
import * as yaml from "js-yaml";

// Custom parser for JSON files
const jsonParser: CatalogProcessorParser = async function* ({ data, location }) {
  try {
    const content = data.toString('utf-8');
    const parsed = JSON.parse(content);
    
    if (Array.isArray(parsed)) {
      for (const item of parsed) {
        yield {
          type: 'entity',
          entity: item,
          location
        };
      }
    } else {
      yield {
        type: 'entity',
        entity: parsed,
        location
      };
    }
  } catch (error) {
    yield {
      type: 'error',
      location,
      error: new Error(`Failed to parse JSON: ${error.message}`)
    };
  }
};

// Usage in a processor
class JsonProcessor implements CatalogProcessor {
  getProcessorName(): string {
    return "json-processor";
  }

  async readLocation(
    location: LocationSpec,
    optional: boolean,
    emit: CatalogProcessorEmit,
    parser: CatalogProcessorParser,
    cache: CatalogProcessorCache
  ): Promise<boolean> {
    if (!location.target.endsWith('.json')) {
      return false;
    }

    // Fetch the JSON file data (implementation depends on location type)
    const data = await fetchLocationData(location);
    
    // Use custom JSON parser instead of default YAML parser
    for await (const result of jsonParser({ data, location })) {
      emit(result);
    }
    
    return true;
  }
}

Processing Result Types

All processor methods that emit results use these standardized result types:

type CatalogProcessorResult =
  | CatalogProcessorLocationResult
  | CatalogProcessorEntityResult
  | CatalogProcessorRelationResult
  | CatalogProcessorErrorResult
  | CatalogProcessorRefreshKeysResult;

type CatalogProcessorLocationResult = {
  type: 'location';
  location: LocationSpec;
};

type CatalogProcessorEntityResult = {
  type: 'entity';
  entity: Entity;
  location: LocationSpec;
};

type CatalogProcessorRelationResult = {
  type: 'relation';
  relation: EntityRelationSpec;
};

type CatalogProcessorErrorResult = {
  type: 'error';
  error: Error;
  location: LocationSpec;
};

type CatalogProcessorRefreshKeysResult = {
  type: 'refresh';
  key: string;
};

Install with Tessl CLI

npx tessl i tessl/npm-backstage--plugin-catalog-node

docs

alpha-apis.md

catalog-processing.md

entity-providers.md

index.md

location-conversion.md

processing-results.md

tile.json