<!--
This file was generated by Spark. Do not edit it by hand.
-->
# AshTypst.Resource

Spark DSL extension for rendering Typst templates as Ash generic actions.

This extension adds a `typst` DSL section to your Ash resource where you can
declare reusable templates and render actions. Each render action is transformed
into an Ash generic action that compiles and exports a Typst document, returning
an `AshTypst.Document` struct.

## Usage

Add the extension to your resource:

    defmodule MyApp.Invoice do
      use Ash.Resource,
        domain: MyApp.Domain,
        extensions: [AshTypst.Resource]

      # Opt this resource into the encoding protocol so `read` results can be
      # serialized to Typst and injected into your templates.
      @derive AshTypst.Code

      typst do
        root "priv/typst"

        template :invoice do
          source "invoice.typ"
          inputs %{"company" => "Acme Corp"}
        end

        template :receipt do
          # ~TYPST sigil is auto-imported in template blocks
          markup ~TYPST"""
          #import "data.typ": record, args
          = Receipt #args.receipt_number
          *Customer:* #record.name
          """
        end

        render :generate_pdf do
          template :invoice
          format :pdf

          argument :invoice_id, :string, allow_nil?: false

          read :one do
            filter expr(id == ^arg(:invoice_id))
            load [:line_items, :customer]
          end

          pdf_options do
            pdf_standards [:pdf_a_2b]
          end
        end
      end
    end

Then call the action like any other Ash generic action:

    input = Ash.ActionInput.for_action(MyApp.Invoice, :generate_pdf, %{invoice_id: "123"})
    {:ok, %AshTypst.Document{format: :pdf, data: pdf_binary}} = Ash.run_action(input)

## How It Works

1. **Templates** are declared in the `typst` section. Each template has either an
   inline `markup` string (the `~TYPST` sigil is auto-imported inside `template`
   blocks) or a `source` file path relative to the `root` directory.

2. **Render actions** reference a template and specify an output `format` (`:pdf`,
   `:svg`, or `:html`). They can optionally declare arguments, a `read` to fetch
   resource data, and format-specific options like `pdf_options`.

3. At compile time, the `BuildActions` transformer converts each render entity into
   a standard `Ash.Resource.Actions.Action`.

4. At runtime, the action implementation creates a context, sets the template,
   injects data (arguments and/or read results) into a virtual file, compiles, and
   exports in the requested format.

## Data Injection

The render action injects data into a virtual file (default `"data.typ"`) that your
template can `#import`:

- **No read**: only `args` (a dictionary of action arguments) is available.
- **Read `:one`**: both `record` (the single resource) and `args` are available.
- **Read `:many`**: `records` (an array, streamed in batches) and `args` are available.

Any render action that declares a `read` encodes the fetched resource records
via the `AshTypst.Code` protocol, so the resource must opt in by adding
`@derive AshTypst.Code` (see the usage example above). Deriving serializes the
resource's public fields; for custom serialization, implement the protocol
directly with `defimpl AshTypst.Code, for: MyApp.Invoice`.

## DSL Reference

For the complete DSL reference with all options, see `d:AshTypst.Resource`.


## typst
Configuration for Typst template rendering.

### Nested DSLs
 * [template](#typst-template)
 * [render](#typst-render)
   * argument
   * read
   * pdf_options
   * prepare
   * validate





### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`root`](#typst-root){: #typst-root } | `String.t \| {atom, String.t}` | `"priv/typst"` | Root directory for template file resolution. Accepts either:   * a `String.t()` — used verbatim. Relative paths resolve     against the current working directory and only work when     cwd matches the project root (dev/test).   * a `{otp_app, sub_path}` tuple — resolved at runtime via     `Application.app_dir/2`, which works in dev, test, and     Mix releases (where `priv/` lives at     `<release>/lib/<app>-<version>/priv/...`). For releases-friendly setups, prefer the tuple form:     root({:my_app, "priv/typst"}) |
| [`font_paths`](#typst-font_paths){: #typst-font_paths } | `list(String.t \| {atom, String.t})` | `[]` | Additional font search directories. Each entry may be a string (used verbatim) or a `{otp_app, sub_path}` tuple (resolved via `Application.app_dir/2` at runtime). Mix releases relocate `priv/` files, so the tuple form is recommended for paths rooted in your app's `priv/`. |
| [`ignore_system_fonts`](#typst-ignore_system_fonts){: #typst-ignore_system_fonts } | `boolean` | `false` | Skip system font loading. |



### typst.template
```elixir
template name
```


Declares a reusable Typst template.





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`name`](#typst-template-name){: #typst-template-name .spark-required} | `atom` |  | Unique template identifier. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`source`](#typst-template-source){: #typst-template-source } | `String.t` |  | File path relative to the `root` directory. |
| [`markup`](#typst-template-markup){: #typst-template-markup } | `String.t` |  | Inline Typst markup string (`~TYPST` sigil is auto-imported). |
| [`inputs`](#typst-template-inputs){: #typst-template-inputs } | `map` |  | Static `sys.inputs` key/value pairs (string keys and values). |





### Introspection

Target: `AshTypst.Resource.Template`

### typst.render
```elixir
render name
```


Declares a Typst template rendering action.

### Nested DSLs
 * [argument](#typst-render-argument)
 * [read](#typst-render-read)
 * [pdf_options](#typst-render-pdf_options)
 * [prepare](#typst-render-prepare)
 * [validate](#typst-render-validate)




### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`name`](#typst-render-name){: #typst-render-name .spark-required} | `atom` |  | Action name (becomes the generic action name). |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`template`](#typst-render-template){: #typst-render-template .spark-required} | `atom` |  | Reference to a template declared in the `typst` section. |
| [`format`](#typst-render-format){: #typst-render-format .spark-required} | `:pdf \| :svg \| :html \| :bundle` |  | Output export format. |
| [`description`](#typst-render-description){: #typst-render-description } | `String.t` |  | Action description. |
| [`page`](#typst-render-page){: #typst-render-page } | `non_neg_integer` |  | Page index for SVG rendering. |
| [`pretty`](#typst-render-pretty){: #typst-render-pretty } | `boolean` | `false` | Format HTML/SVG output (also within bundles) in a human-readable way. |
| [`render_bleed`](#typst-render-render_bleed){: #typst-render-render_bleed } | `boolean` | `false` | Include bleed margins for SVG output (also within bundles). |
| [`data_file`](#typst-render-data_file){: #typst-render-data_file } | `String.t` | `"data.typ"` | Virtual file path for serialized data. |
| [`transaction?`](#typst-render-transaction?){: #typst-render-transaction? } | `boolean` | `false` | Wrap action execution in a transaction. |


### typst.render.argument
```elixir
argument name, type
```


Declares an argument on the action.





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`name`](#typst-render-argument-name){: #typst-render-argument-name .spark-required} | `atom` |  | The name of the argument |
| [`type`](#typst-render-argument-type){: #typst-render-argument-type .spark-required} | `module` |  | The type of the argument. See `Ash.Type` for more. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`description`](#typst-render-argument-description){: #typst-render-argument-description } | `String.t` |  | An optional description for the argument. |
| [`constraints`](#typst-render-argument-constraints){: #typst-render-argument-constraints } | `keyword` | `[]` | Constraints to provide to the type when casting the value. For more information, see `Ash.Type`. |
| [`allow_nil?`](#typst-render-argument-allow_nil?){: #typst-render-argument-allow_nil? } | `boolean` | `true` | Whether or not the argument value may be nil (or may be not provided). If nil value is given error is raised. |
| [`public?`](#typst-render-argument-public?){: #typst-render-argument-public? } | `boolean` | `true` | Whether or not the argument should appear in public interfaces |
| [`sensitive?`](#typst-render-argument-sensitive?){: #typst-render-argument-sensitive? } | `boolean` | `false` | Whether or not the argument value contains sensitive information, like PII(Personally Identifiable Information). See the [security guide](/documentation/topics/security/sensitive-data.md) for more. |
| [`default`](#typst-render-argument-default){: #typst-render-argument-default } | `any` |  | The default value for the argument to take. It can be a zero argument function e.g `&MyMod.my_fun/0` or a value |





### Introspection

Target: `Ash.Resource.Actions.Argument`

### typst.render.read
```elixir
read cardinality
```


Declares how to fetch resource data to pass to the template.





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`cardinality`](#typst-render-read-cardinality){: #typst-render-read-cardinality .spark-required} | `:one \| :many` |  | `:one` uses `Ash.read_one`, `:many` uses `Ash.read`. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`filter`](#typst-render-read-filter){: #typst-render-read-filter } | `any` |  | Ash filter expression; supports `^arg(:name)` to reference action arguments. |
| [`load`](#typst-render-read-load){: #typst-render-read-load } | `list(any)` | `[]` | Relationships, calculations, and aggregates to load. |
| [`select`](#typst-render-read-select){: #typst-render-read-select } | `list(atom)` |  | Attributes to select (nil = all). |
| [`sort`](#typst-render-read-sort){: #typst-render-read-sort } | `any` |  | Sort specification. |
| [`limit`](#typst-render-read-limit){: #typst-render-read-limit } | `pos_integer` |  | Max records to return (`:many` only). |
| [`batch_size`](#typst-render-read-batch_size){: #typst-render-read-batch_size } | `pos_integer` | `100` | Batch size for streaming large datasets into virtual file (`:many` only). |
| [`not_found`](#typst-render-read-not_found){: #typst-render-read-not_found } | `:error \| nil` | `:error` | Behavior when `:one` finds no record. |





### Introspection

Target: `AshTypst.Resource.Render.Read`

### typst.render.pdf_options


PDF-specific export options.






### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`pages`](#typst-render-pdf_options-pages){: #typst-render-pdf_options-pages } | `String.t` |  | Page range, 1-indexed (e.g., `"1-3,5,7-9"`). |
| [`pdf_standards`](#typst-render-pdf_options-pdf_standards){: #typst-render-pdf_options-pdf_standards } | `list(:pdf_1_7 \| :pdf_a_2b \| :pdf_a_3b)` | `[]` | PDF compliance standards. |
| [`document_id`](#typst-render-pdf_options-document_id){: #typst-render-pdf_options-document_id } | `String.t` |  | PDF document identifier. |





### Introspection

Target: `AshTypst.Resource.Render.PdfOptions`

### typst.render.prepare
```elixir
prepare preparation
```


Declares a preparation that runs before the template is rendered.





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`preparation`](#typst-render-prepare-preparation){: #typst-render-prepare-preparation .spark-required} | `(any, any -> any) \| module` |  | The module and options for a preparation. Also accepts functions take the query and the context. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`on`](#typst-render-prepare-on){: #typst-render-prepare-on } | `:read \| :action \| :create \| :update \| :destroy \| list(:read \| :action \| :create \| :update \| :destroy)` | `[:read]` | The action types the preparation should run on. By default, preparations only run on read actions. Use `:action` to run on generic actions. |
| [`where`](#typst-render-prepare-where){: #typst-render-prepare-where } | `(any, any -> any) \| module \| list((any, any -> any) \| module)` | `[]` | Validations that should pass in order for this preparation to apply. Any of these validations failing will result in this preparation being ignored. |
| [`only_when_valid?`](#typst-render-prepare-only_when_valid?){: #typst-render-prepare-only_when_valid? } | `boolean` | `false` | If the preparation should only run on valid queries. |





### Introspection

Target: `Ash.Resource.Preparation`

### typst.render.validate
```elixir
validate validation
```


Declares a validation for this action.





### Arguments

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`validation`](#typst-render-validate-validation){: #typst-render-validate-validation .spark-required} | `(any, any -> any) \| module` |  | The module (or module and opts) that implements the `Ash.Resource.Validation` behaviour. Also accepts a function that receives the changeset and its context. |
### Options

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`where`](#typst-render-validate-where){: #typst-render-validate-where } | `(any, any -> any) \| module \| list((any, any -> any) \| module)` | `[]` | Validations that should pass in order for this validation to apply. Any of these validations failing will result in this validation being ignored. |
| [`only_when_valid?`](#typst-render-validate-only_when_valid?){: #typst-render-validate-only_when_valid? } | `boolean` | `false` | If the validation should only run on valid changesets. Useful for expensive validations or validations that depend on valid data. |
| [`message`](#typst-render-validate-message){: #typst-render-validate-message } | `String.t` |  | If provided, overrides any message set by the validation error |
| [`description`](#typst-render-validate-description){: #typst-render-validate-description } | `String.t` |  | An optional description for the validation |
| [`before_action?`](#typst-render-validate-before_action?){: #typst-render-validate-before_action? } | `boolean` | `false` | If set to `true`, the validation will be run in a before_action hook |
| [`always_atomic?`](#typst-render-validate-always_atomic?){: #typst-render-validate-always_atomic? } | `boolean` | `false` | By default, validations are only run atomically if all changes will be run atomically or if there is no `validate/3` callback defined. Set this to `true` to run it atomically always. |





### Introspection

Target: `Ash.Resource.Validation`




### Introspection

Target: `AshTypst.Resource.Render`





<style type="text/css">.spark-required::after { content: "*"; color: red !important; }</style>
