or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

common-utilities.mdindex.mdopenapi-v2-types.mdopenapi-v3-types.mdworkspace-management.md
tile.json

common-utilities.mddocs/

Common Utilities

Core utilities for working with OpenAPI documents including reference resolution, extension property handling, and type guards. These utilities work with both OpenAPI 2.0 and 3.0 documents.

Capabilities

Reference Resolution

Utilities for resolving $ref references in OpenAPI documents with circular dependency detection.

/**
 * Gets an object instance for the item, regardless if it's a reference or not.
 * @param document - Entire OpenAPI document
 * @param item - Reference item or direct object
 * @param stack - Stack for circular dependency detection
 * @returns Dereferenced object with metadata
 */
function dereference<T extends {} | undefined>(
  document: any,
  item: Refable<T>,
  stack?: string[]
): Dereferenced<T>;

/**
 * Identifies if a given refable is a reference or an instance
 * @param item - Check if item is a reference
 * @returns Type guard indicating if item is PathReference
 */
function isReference<T extends {} | undefined>(item: Refable<T>): item is PathReference;

Usage Examples:

import { dereference, isReference, OpenAPI3Document } from "@azure-tools/openapi";

const document: OpenAPI3Document = {
  openapi: "3.0.0",
  info: { title: "Test", version: "1.0" },
  paths: {},
  components: {
    schemas: {
      User: {
        type: "object",
        properties: {
          id: { type: "integer" },
          profile: { $ref: "#/components/schemas/Profile" }
        }
      },
      Profile: {
        type: "object",
        properties: {
          name: { type: "string" }
        }
      }
    }
  }
};

// Check if something is a reference
const profileRef = document.components?.schemas?.User?.properties?.profile;
if (profileRef && isReference(profileRef)) {
  console.log("It's a reference:", profileRef.$ref);
  
  // Resolve the reference
  const resolved = dereference(document, profileRef);
  console.log("Resolved to:", resolved.instance);
  console.log("Reference name:", resolved.name); // "Profile"
  console.log("From reference:", resolved.fromRef); // true
}

Extension Property Handling

Utilities for working with OpenAPI extension properties (keys starting with "x-").

/**
 * Returns true if the key starts with `x-`
 * @param key - Key to check
 * @returns Type guard for extension keys
 */
function isExtensionKey(key: string | ExtensionKey): key is ExtensionKey;

/**
 * Only return properties starting with x-
 * @param dictionary - Object to filter
 * @returns Array of extension keys
 */
function includeXDashKeys<T extends Record<string | ExtensionKey, any>>(
  dictionary: T,
): Extract<keyof T, ExtensionKey>[];

/**
 * Only return properties NOT starting with x-
 * @param dictionary - Object to filter
 * @returns Array of non-extension keys
 */
function omitXDashKeys<T extends {}>(dictionary: T): Exclude<keyof T, ExtensionKey>[];

/**
 * Extract only extension properties from an object
 * @param obj - Object to filter
 * @returns Object with only x-* properties
 */
function includeXDashProperties<T extends Record<string | ExtensionKey, any> | undefined>(
  obj: T,
): T extends undefined ? undefined : Pick<T, Extract<keyof T, ExtensionKey>>;

/**
 * Remove extension properties from an object
 * @param obj - Object to filter
 * @returns Object without x-* properties
 */
function omitXDashProperties<T extends {} | undefined>(
  obj: T,
): T extends undefined ? undefined : Pick<T, Exclude<keyof T, ExtensionKey>>;

Usage Examples:

import { 
  isExtensionKey, 
  includeXDashProperties, 
  omitXDashProperties 
} from "@azure-tools/openapi";

const schema = {
  type: "object",
  properties: { name: { type: "string" } },
  "x-custom-property": "custom-value",
  "x-vendor-extension": { some: "data" }
};

// Check if a key is an extension
console.log(isExtensionKey("x-custom")); // true
console.log(isExtensionKey("type")); // false

// Extract only extension properties
const extensions = includeXDashProperties(schema);
console.log(extensions);
// { "x-custom-property": "custom-value", "x-vendor-extension": { some: "data" } }

// Remove extension properties
const cleanSchema = omitXDashProperties(schema);
console.log(cleanSchema);
// { type: "object", properties: { name: { type: "string" } } }

Types

interface PathReference {
  $ref: string;
}

type Refable<T extends {} | undefined> = T | PathReference;

interface Dereferenced<T> {
  /** The resolved instance */
  instance: T;
  /** Name of the referenced item */
  name: string;
  /** Whether this came from a reference */
  fromRef?: boolean;
}

type ExtensionKey = `x-${string}`;

type Extensions = {
  [key in ExtensionKey]: any;
};

Error Handling

The dereference function throws errors for invalid references:

  • Circular Reference Error: When a reference chain creates a circular dependency
  • Invalid Reference Error: When a $ref path doesn't exist in the document
try {
  const resolved = dereference(document, reference);
  // Use resolved.instance
} catch (error) {
  if (error.message.includes("Circular $ref")) {
    // Handle circular reference
  } else if (error.message.includes("Invalid Reference")) {
    // Handle invalid reference
  }
}