Skip to content

Latest commit

 

History

History
352 lines (257 loc) · 7.84 KB

File metadata and controls

352 lines (257 loc) · 7.84 KB

Developer Experience Features

AshTypescript provides features to improve developer experience: namespace organization, JSDoc generation, and API manifest documentation.

Namespaces

Namespaces organize RPC actions into logical groups, improving discoverability in large codebases.

Configuration Levels

Namespaces can be configured at three levels with cascading precedence:

Domain Level - Default namespace for all resources in a domain:

defmodule MyApp.Domain do
  use Ash.Domain, extensions: [AshTypescript.Rpc]

  typescript_rpc do
    namespace :api  # All resources default to "api" namespace

    resource MyApp.Todo do
      rpc_action :list_todos, :read
    end
  end
end

Resource Level - Override for all actions on a specific resource:

typescript_rpc do
  namespace :api

  resource MyApp.Todo do
    namespace :todos  # Overrides domain namespace

    rpc_action :list_todos, :read
    rpc_action :create_todo, :create
  end

  resource MyApp.User do
    # Uses domain namespace "api"
    rpc_action :list_users, :read
  end
end

Action Level - Override for a specific action:

typescript_rpc do
  namespace :api

  resource MyApp.Todo do
    namespace :todos

    rpc_action :list_todos, :read  # Uses "todos"
    rpc_action :admin_list, :read, namespace: :admin  # Uses "admin"
  end
end

Precedence Order

Action namespace > Resource namespace > Domain namespace > nil

Generated Output

With namespaces enabled, the generated JSDoc includes the namespace:

/**
 * List all todos
 *
 * @ashActionType :read
 * @namespace todos
 */
export async function listTodos(...) { ... }

JSDoc Generation

Generated TypeScript functions include JSDoc comments that provide IDE discoverability through hover documentation and autocomplete hints.

Default Output

Every generated RPC function includes basic JSDoc:

/**
 * List all todos
 *
 * @ashActionType :read
 */
export async function listTodos(...) { ... }

Exposing Ash Metadata

Enable detailed Ash metadata in JSDoc for development:

config :ash_typescript,
  add_ash_internals_to_jsdoc: true

This adds internal references:

/**
 * List all todos
 *
 * @ashActionType :read
 * @ashResource MyApp.Todo
 * @ashAction :list_todos
 * @ashActionDef lib/my_app/resources/todo.ex
 * @rpcActionDef lib/my_app/domain.ex
 * @namespace todos
 */
export async function listTodos(...) { ... }

JSDoc Tags Reference

Tag Description When Shown
@ashActionType Ash action type (:read, :create, etc.) Always
@ashResource Full Elixir module name When add_ash_internals_to_jsdoc: true
@ashAction Internal Ash action name When add_ash_internals_to_jsdoc: true
@ashActionDef Source file of Ash action definition When add_ash_internals_to_jsdoc: true
@rpcActionDef Source file of RPC action configuration When add_ash_internals_to_jsdoc: true
@namespace Action namespace When namespace is configured
@see Related actions When see: option is configured
@deprecated Deprecation notice When deprecated: option is configured

Source Path Prefix (Monorepos)

For monorepo setups where Elixir code is in a subdirectory:

config :ash_typescript,
  source_path_prefix: "backend"

Output:

/**
 * @ashActionDef backend/lib/my_app/resources/todo.ex
 * @rpcActionDef backend/lib/my_app/domain.ex
 */

Custom Descriptions

Override default descriptions per action:

typescript_rpc do
  resource MyApp.Todo do
    rpc_action :list_todos, :read,
      description: "Fetch all todos for the current user"
  end
end

When add_ash_internals_to_jsdoc: true, the Ash action's description is used as fallback if no RPC description is set.

Related Actions

Link related actions in JSDoc using the see option:

rpc_action :list_todos, :read,
  see: [:create_todo, :update_todo]

Output:

/**
 * @see createTodo
 * @see updateTodo
 */

Deprecation Notices

Mark actions as deprecated:

rpc_action :old_list, :read,
  deprecated: true

rpc_action :legacy_list, :read,
  deprecated: "Use listTodos instead"

Output:

/**
 * @deprecated
 */

/**
 * @deprecated Use listTodos instead
 */

Manifest Generation

Generate a Markdown manifest documenting all RPC actions for API documentation and developer onboarding.

Configuration

config :ash_typescript,
  manifest_file: "./docs/RPC_MANIFEST.md",
  add_ash_internals_to_manifest: true

Sample Output

# RPC Action Manifest

Generated: 2025-01-15

## Namespace: todos

### Todo

| Function | Action Type | Ash Action | Resource | Validation | Zod Schema | Channel |
|----------|-------------|------------|----------|------------|------------|---------|
| `listTodos` | read | `list` | `MyApp.Todo` | `validateListTodos` | `ListTodosInputSchema` | `listTodosChannel` |
| `createTodo` | create | `create` | `MyApp.Todo` | `validateCreateTodo` | `CreateTodoInputSchema` | `createTodoChannel` |

- **`listTodos`**: Fetch all todos for the current user
- **`createTodo`**: Create a new Todo | **See also:** `listTodos`

**Typed Queries:**
- `todoFields` -> `TodoFieldsResult`: Pre-defined field selection

Grouping Behavior

  • With namespaces: Actions grouped by namespace
  • Without namespaces: Actions grouped by domain

Controlling Manifest Content

The add_ash_internals_to_manifest config controls whether internal Ash details are shown:

Setting Columns Shown
false Function, Action Type
true Function, Action Type, Ash Action, Resource

Configuration Reference

All Developer Experience Options

config :ash_typescript,
  # JSDoc configuration
  add_ash_internals_to_jsdoc: false,  # Show Ash module/action details
  source_path_prefix: nil,            # Prefix for source paths (monorepos)

  # Manifest configuration
  manifest_file: nil,                 # Path to generate manifest (nil = disabled)
  add_ash_internals_to_manifest: false  # Show Ash details in manifest

Development vs Production

Development Configuration:

# config/dev.exs
config :ash_typescript,
  add_ash_internals_to_jsdoc: true,
  add_ash_internals_to_manifest: true,
  manifest_file: "./docs/RPC_MANIFEST.md"

Production Configuration:

# config/prod.exs
config :ash_typescript,
  add_ash_internals_to_jsdoc: false,
  add_ash_internals_to_manifest: false

Common Patterns

Namespace Organization by Feature

typescript_rpc do
  resource MyApp.Todo do
    namespace :todos
    rpc_action :list_todos, :read
    rpc_action :create_todo, :create
  end

  resource MyApp.User do
    namespace :users
    rpc_action :list_users, :read
    rpc_action :get_current_user, :get_current, namespace: :auth
  end

  resource MyApp.Session do
    namespace :auth
    rpc_action :login, :create
    rpc_action :logout, :destroy
  end
end

Development-Only Metadata

# config/config.exs
config :ash_typescript,
  add_ash_internals_to_jsdoc: Mix.env() == :dev,
  add_ash_internals_to_manifest: Mix.env() == :dev

Monorepo Setup

# backend/config/config.exs
config :ash_typescript,
  source_path_prefix: "backend",
  output_file: "../frontend/src/generated/ash_rpc.ts"

Next Steps