Skip to content

Annotations

This document defines the @xript JSDoc annotation convention for declaring manifest bindings directly in TypeScript source code. A scanner reads these annotations and generates the bindings and capabilities sections of an xript manifest.

Declares a function as an xript binding at the given dot-delimited path. Dots create namespace nesting in the manifest. The tag applies to an exported function declaration or an exported const bound to an arrow function or function expression; in every form the parameters, return type, and async flag come from the declaration and the description and tags from its JSDoc.

/**
* Get value from the data store.
*
* @xript data.get
*/
export function getData(path: string): DataResult { ... }

Produces the manifest binding data.get (namespace data, member get).

Gates this binding behind a named capability. A binding carries a single capability — if more than one @xript-cap tag is present, the scanner keeps the first and warns about the rest.

/**
* Transfer currency between players.
*
* @xript economy.transfer
* @xript-cap modify-state
*/
export function transferCurrency(fromId: string, toId: string, amount: number): void { ... }

All metadata comes from standard JSDoc and TypeScript — @xript and @xript-cap are the only custom tags.

SourceManifest field
@xript <path>binding path (dot-delimited namespace nesting)
@xript-cap <name>capability field on the binding
JSDoc description (text before tags)description
@param tags + TypeScript parameter typesparams array
TypeScript return type / @returnsreturns
async keyword or Promise<> returnasync: true
@deprecated tagdeprecated

Dot-delimited paths produce nested namespace bindings:

/** @xript player.inventory.add */
export function addItem(item: string): void { ... }
/** @xript player.inventory.remove */
export function removeItem(item: string): boolean { ... }
/** @xript log */
export function log(message: string): void { ... }

Produces:

{
"bindings": {
"player": {
"description": "player namespace",
"members": {
"inventory": {
"description": "inventory namespace",
"members": {
"add": { "description": "...", "params": [...] },
"remove": { "description": "...", "params": [...], "returns": "boolean" }
}
}
}
},
"log": { "description": "...", "params": [...] }
}
}

Auto-generated namespace descriptions use the format "{name} namespace" and can be overridden by editing the manifest after scanning.

When the scanner encounters @xript-cap storage but storage is not defined in the manifest’s capabilities section, it auto-generates:

{
"storage": {
"description": "storage capability",
"risk": "low"
}
}

The scanner preserves existing capability definitions and warns about gaps.

  • Only processes exported functions with @xript JSDoc tags
  • Ignores functions without @xript tags
  • Reports diagnostics for: duplicate binding paths, missing descriptions, @xript-cap values with no matching capability definition
  • In merge mode: adds new bindings, warns about removed bindings (does not auto-delete), preserves manual edits to existing bindings
  • Class methods are supported if exported — the scanner treats them as standalone functions at the annotated path
/**
* Write a message to the application log.
*
* @xript log
* @param message - The message to log
* @param level - Log level
*/
export function log(message: string, level?: string): void { ... }
/**
* Save data to persistent storage.
*
* @xript storage.save
* @xript-cap persist
* @param key - Storage key
* @param value - Value to store
*/
export async function saveData(key: string, value: unknown): Promise<void> { ... }
/**
* Get player health.
*
* @xript player.getHealth
* @deprecated Use player.stats.get("health") instead
*/
export function getPlayerHealth(): number { ... }