# TransformEngine

Normalize formulas with a profile, tune the pipeline, and read the transform report.

https://texform.dev/api/js/transform-engine

## `TransformEngine`

Kind: class

```ts
TransformEngine(options: TransformEngineOptions)
```

A profile-based normalization engine: a parser paired with a transform
pipeline.

`TransformEngine` normalizes a formula into the canonical form selected by a
[Profile](/api/js/transform-engine#Profile). It exposes a string-to-string [TransformEngine.normalize](/api/js/transform-engine#TransformEngine.normalize)
path and an in-place [TransformEngine.transform](/api/js/transform-engine#TransformEngine.transform) path over a live
[Document](/api/js/document#Document). It also exposes its own [TransformEngine.parse](/api/js/transform-engine#TransformEngine.parse) and the
shared knowledge base through [TransformEngine.knowledgeBase](/api/js/transform-engine#TransformEngine.knowledgeBase). For the conceptual model —
profiles, the multi-phase pipeline, and the eliminated-form contract — see the
Transforms guide.

Since 0.4.0 the bundled parser defaults to lenient [ParseConfig](/api/js/parser#ParseConfig), and
transform options are a nested camelCase overlay ([TransformConfig](/api/js/transform-engine#TransformConfig) /
[NormalizeConfig](/api/js/transform-engine#NormalizeConfig)), not flat `rewriteEnabled` / `maxIterations` keys.
`null` / `undefined` / omitted means not set. Unknown keys, snake_case keys,
arrays in object positions, and wrong scalar types throw
[TexformConfigError](/api/js/utilities#TexformConfigError) with a camelCase path. There is no complete
config class on the JavaScript surface; read the effective defaults with
[TransformEngine.defaultTransformConfig](/api/js/transform-engine#TransformEngine.defaultTransformConfig).

```ts
import { TransformEngine } from 'texform';

const engine = new TransformEngine({ profile: 'corpus' });
engine.normalize(String.raw`a \over b`); // '\\frac { a } { b }'
engine.normalize(String.raw`a \over b`, { rewrite: { enabled: false } });
engine.normalizeWithReport(String.raw`a \over b`).report.rewrite.iterations;
```

- [Profile](https://texform.dev/api/js/transform-engine.md#Profile)
- [TransformEngine.normalize](https://texform.dev/api/js/transform-engine.md#TransformEngine.normalize)
- [TransformEngine.transform](https://texform.dev/api/js/transform-engine.md#TransformEngine.transform)
- [Document](https://texform.dev/api/js/document.md#Document)
- [TransformEngine.parse](https://texform.dev/api/js/transform-engine.md#TransformEngine.parse)
- [TransformEngine.knowledgeBase](https://texform.dev/api/js/transform-engine.md#TransformEngine.knowledgeBase)
- [ParseConfig](https://texform.dev/api/js/parser.md#ParseConfig)
- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)
- [NormalizeConfig](https://texform.dev/api/js/transform-engine.md#NormalizeConfig)
- [TexformConfigError](https://texform.dev/api/js/utilities.md#TexformConfigError)
- [TransformEngine.defaultTransformConfig](https://texform.dev/api/js/transform-engine.md#TransformEngine.defaultTransformConfig)
- [Parser](https://texform.dev/api/js/parser.md#Parser)
- [Transforms](https://texform.dev/docs/transforms.md)

#### `TransformEngine`

```ts
TransformEngine(options: TransformEngineOptions)
```

Construct an engine for a profile, optionally sharing a knowledge base,
or disabling rules.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `options` | TransformEngineOptions | — | - A [TransformEngineOptions](/api/js/transform-engine#TransformEngineOptions) object. `profile` is
required; an unknown profile throws [TexformConfigError](/api/js/utilities#TexformConfigError). |

#### `parse`

```ts
parse(src: string, config: ParseConfig | null | undefined): ParseResult
```

Parse a LaTeX string into a [ParseResult](/api/js/parser#ParseResult), using this engine's parser.

Non-null documents from this result share the engine's KnowledgeBase, so
they can be edited and then passed to [TransformEngine.transform](/api/js/transform-engine#TransformEngine.transform). The
The engine parser defaults to lenient parsing; pass `config` to override it
per call.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | string | — | - The LaTeX source string. |
| `config` | ParseConfig | null | undefined | — | - A [ParseConfig](/api/js/parser#ParseConfig) overlay, or omit/`null` for the
defaults. |

**Returns** `ParseResult` The parse result (`document` and `diagnostics`).

- [ParseResult](https://texform.dev/api/js/parser.md#ParseResult)
- [TransformEngine.transform](https://texform.dev/api/js/transform-engine.md#TransformEngine.transform)
- [ParseConfig](https://texform.dev/api/js/parser.md#ParseConfig)

#### `normalize`

```ts
normalize(src: string, config: NormalizeConfig | null | undefined): string
```

Parse, normalize, and serialize a formula in one call.

Normalization is gated on a complete tree: if the input cannot produce one,
this throws [TexformParseError](/api/js/utilities#TexformParseError) carrying its `diagnostics` and the
partial `document`. Empty input is complete and normalizes normally.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | string | — | - The LaTeX source string. |
| `config` | NormalizeConfig | null | undefined | — | - A [NormalizeConfig](/api/js/transform-engine#NormalizeConfig) overlay, or omit/`null` to use
the engine defaults. The same `{ rewrite: { enabled: false } }` shape is
accepted by [TransformEngine.transform](/api/js/transform-engine#TransformEngine.transform). |

**Returns** `string` The serialized LaTeX string. This path does not build a report.

```ts
const engine = new TransformEngine({ profile: 'corpus' });
engine.normalize(String.raw`\dv{f}{x}`);
// '\\frac { \\mathrm { d } f } { \\mathrm { d } x }'
```

- [TexformParseError](https://texform.dev/api/js/utilities.md#TexformParseError)
- [NormalizeConfig](https://texform.dev/api/js/transform-engine.md#NormalizeConfig)
- [TransformEngine.transform](https://texform.dev/api/js/transform-engine.md#TransformEngine.transform)

#### `normalizeWithReport`

```ts
normalizeWithReport(src: string, config: NormalizeConfig | null | undefined): NormalizeReportResult
```

Parse, normalize, and serialize a formula, returning text and a diagnostic report.

Accepts the same source and [NormalizeConfig](/api/js/transform-engine#NormalizeConfig) overlay as
[TransformEngine.normalize](/api/js/transform-engine#TransformEngine.normalize). Output text and errors follow that
contract. Report fields, phase divisions, and counters are diagnostic and
are not part of the stable compatibility promise. A failure does not
return a partial report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | string | — | - The LaTeX source string. |
| `config` | NormalizeConfig | null | undefined | — | - A [NormalizeConfig](/api/js/transform-engine#NormalizeConfig) overlay, or omit/`null` to use
the engine defaults. |

**Returns** `NormalizeReportResult` The normalized string and its [TransformReport](/api/js/transform-engine#TransformReport).

- [NormalizeConfig](https://texform.dev/api/js/transform-engine.md#NormalizeConfig)
- [TransformEngine.normalize](https://texform.dev/api/js/transform-engine.md#TransformEngine.normalize)
- [TransformReport](https://texform.dev/api/js/transform-engine.md#TransformReport)

#### `transform`

```ts
transform(document: Document, config: TransformConfig | null | undefined): void
```

Transform a live [Document](/api/js/document#Document) in place.

The document must share this engine's KnowledgeBase instance.
A document that [Document.hasErrors](/api/js/document#Document.hasErrors) is read-only and cannot be
transformed; this precondition error is surfaced as [TexformTransformError](/api/js/utilities#TexformTransformError).
This path returns no value and does not build a report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `document` | Document | — | - The live document to update in place. |
| `config` | TransformConfig | null | undefined | — | - A [TransformConfig](/api/js/transform-engine#TransformConfig) overlay, or omit/`null` to use
the profile defaults. Nested per-phase shape; does not accept parse
options. |

**Returns** `void`

```ts
const engine = new TransformEngine({ profile: 'corpus' });
const result = engine.parse(String.raw`a \over b`);
if (result.document) {
  engine.transform(result.document);
  result.document.toLatex(); // '\\frac { a } { b }'
}
```

- [Document](https://texform.dev/api/js/document.md#Document)
- [Document.hasErrors](https://texform.dev/api/js/document.md#Document.hasErrors)
- [TexformTransformError](https://texform.dev/api/js/utilities.md#TexformTransformError)
- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

#### `transformWithReport`

```ts
transformWithReport(document: Document, config: TransformConfig | null | undefined): TransformReport
```

Transform a live [Document](/api/js/document#Document) in place and return its diagnostic report.

Accepts the same document and [TransformConfig](/api/js/transform-engine#TransformConfig) overlay as
[TransformEngine.transform](/api/js/transform-engine#TransformEngine.transform). Ownership, completeness, and errors
follow that contract. The report is diagnostic and is not part of the
stable compatibility promise. A failure does not return a partial report.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `document` | Document | — | - The live document to update in place. |
| `config` | TransformConfig | null | undefined | — | - A [TransformConfig](/api/js/transform-engine#TransformConfig) overlay, or omit/`null` to use
the profile defaults. |

**Returns** `TransformReport` The diagnostic transform report.

```ts
const engine = new TransformEngine({ profile: 'corpus' });
const result = engine.parse(String.raw`a \over b`);
if (result.document) {
  const report = engine.transformWithReport(result.document);
  report.rewrite.rules.some((rule) => rule.key === 'base/over-to-frac');
}
```

- [Document](https://texform.dev/api/js/document.md#Document)
- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)
- [TransformEngine.transform](https://texform.dev/api/js/transform-engine.md#TransformEngine.transform)

#### `defaultParseConfig`

```ts
defaultParseConfig(): Complete<ParseConfig>
```

Return this engine's complete default [ParseConfig](/api/js/parser#ParseConfig).

**Returns** `Complete<ParseConfig>`

- [ParseConfig](https://texform.dev/api/js/parser.md#ParseConfig)

#### `defaultTransformConfig`

```ts
defaultTransformConfig(): Complete<TransformConfig>
```

Return this engine's complete default [TransformConfig](/api/js/transform-engine#TransformConfig) for its
profile.

**Returns** `Complete<TransformConfig>`

- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

### Knowledge-base lookups

Query the knowledge the parser loaded. Predicate methods take a single `name`; lookup methods take `name` and a `mode` of `"math"` or `"text"` and return a knowledge-entry object or `null`.

#### `knowledgeBase`

```ts
knowledgeBase(): KnowledgeBase
```

**Returns** `KnowledgeBase`

### Lifecycle

#### `free`

```ts
free(): void
```

Release the WASM handle for this engine immediately.

Prefer a `using` declaration so `[Symbol.dispose]()` runs at scope exit.
After `free()`, further use is invalid. Skipping `free()` is safe:
garbage collection still reclaims the handle, just not at a determined
time. Call `free()` (or use `using`) when many short-lived engines
would otherwise accumulate WASM memory.

**Returns** `void`

#### `[Symbol.dispose]`

```ts
[Symbol.dispose](): void
```

Release the WASM handle. Same as [TransformEngine.free](/api/js/transform-engine#TransformEngine.free); used by `using`.

**Returns** `void`

- [TransformEngine.free](https://texform.dev/api/js/transform-engine.md#TransformEngine.free)

## `TransformEngineOptions`

Kind: interface

Construction options for [TransformEngine](/api/js/transform-engine#TransformEngine): a shared knowledge base,
the required normalization [Profile](/api/js/transform-engine#Profile), and optional rule disabling.

| Name | Type | Description |
| --- | --- | --- |
| `profile` | Profile | The normalization profile (required). Unknown values throw [TexformConfigError](/api/js/utilities#TexformConfigError). |
| `disableRules` | string[] | undefined | Rewrite rule keys to disable, such as `"physics/dv-to-frac-d"`. |

- [TransformEngine](https://texform.dev/api/js/transform-engine.md#TransformEngine)
- [Profile](https://texform.dev/api/js/transform-engine.md#Profile)

## `NormalizeConfig`

Kind: interface

Per-run overlay for [TransformEngine.normalize](/api/js/transform-engine#TransformEngine.normalize): parse keys from
[ParseConfig](/api/js/parser#ParseConfig) plus transform keys from [TransformConfig](/api/js/transform-engine#TransformConfig),
flattened together. `null` / `undefined` / omitted means not set.

```ts
const engine = new TransformEngine({ profile: 'corpus' });
engine.normalize(String.raw`a \over b`, {
  rewrite: { maxIterations: 50 },
  flattenGroups: { enabled: false },
});
```

- [TransformEngine.normalize](https://texform.dev/api/js/transform-engine.md#TransformEngine.normalize)
- [ParseConfig](https://texform.dev/api/js/parser.md#ParseConfig)
- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

## `TransformConfig`

Kind: interface

The nested, per-phase transform configuration, overriding a profile's
transform defaults.

Each field controls one pipeline phase. This is the transform-only shape; it
does not accept parser-strictness keys (those belong to
[NormalizeConfig](/api/js/transform-engine#NormalizeConfig)).

Every field is an optional overlay key: `null` / `undefined` / omitted keeps
the profile's value. Unknown keys, snake_case keys, arrays in object
positions, and wrong scalar types throw [TexformConfigError](/api/js/utilities#TexformConfigError) with a
camelCase field path. Read the effective defaults with
[TransformEngine.defaultTransformConfig](/api/js/transform-engine#TransformEngine.defaultTransformConfig).

| Name | Type | Description |
| --- | --- | --- |
| `lowerAttributes` | LowerAttributesConfig | undefined | LowerAttributes phase switches. |
| `rewrite` | RewriteConfig | undefined | Rewrite phase switches. |
| `finalizeAst` | FinalizeAstConfig | undefined | FinalizeAst phase switches. |
| `flattenGroups` | FlattenGroupsConfig | null | undefined | FlattenGroups phase switches. `null` keeps the profile's FlattenGroups values. |

- [NormalizeConfig](https://texform.dev/api/js/transform-engine.md#NormalizeConfig)
- [TexformConfigError](https://texform.dev/api/js/utilities.md#TexformConfigError)
- [TransformEngine.defaultTransformConfig](https://texform.dev/api/js/transform-engine.md#TransformEngine.defaultTransformConfig)

## `RewriteConfig`

Kind: interface

Per-run switches for the fixed-point Rewrite phase.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | boolean | undefined | Whether the phase runs. When `false`, legacy syntax is left untouched. |
| `maxIterations` | number | undefined | Cap on Rewrite fixed-point passes. |

- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

## `LowerAttributesConfig`

Kind: interface

Per-run switches for the LowerAttributes phase.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | boolean | undefined | Whether the phase runs. Defaults to the profile's setting. |

- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

## `FinalizeAstConfig`

Kind: interface

Per-run switches for the FinalizeAst phase.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | boolean | undefined | Whether the phase runs. Defaults to enabled in every public profile. |

- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

## `FlattenGroupsConfig`

Kind: interface

Per-run switches for the FlattenGroups phase (redundant-brace removal).

`enabled` governs whether the phase runs. `preserveRenderedSpacing` keeps
groups whose only public-facing effect is rendered math spacing; it does
not control serializer source whitespace ([SerializeOptions](/api/js/serialize#SerializeOptions)
`*Spacing` fields). Structural guards stay on even when
`preserveRenderedSpacing` is `false`. Omitted keys fall back to the
profile's defaults — for example, `corpus` leaves
`preserveRenderedSpacing` off.

| Name | Type | Description |
| --- | --- | --- |
| `enabled` | boolean | null | undefined | Whether the phase runs. `null` / omitted keeps the profile value. |
| `preserveRenderedSpacing` | boolean | null | undefined | Keep groups whose only public-facing effect is rendered math spacing.

This is not serializer source spacing. Structural guards stay on even
when this is `false`. `null` / omitted keeps the profile value. |

- [SerializeOptions](https://texform.dev/api/js/serialize.md#SerializeOptions)
- [TransformConfig](https://texform.dev/api/js/transform-engine.md#TransformConfig)

## `NormalizeReportResult`

Kind: interface

Text plus the diagnostic report from [TransformEngine.normalizeWithReport](/api/js/transform-engine#TransformEngine.normalizeWithReport).

Plain [TransformEngine.normalize](/api/js/transform-engine#TransformEngine.normalize) returns the string directly and does
not build this object.

| Name | Type | Description |
| --- | --- | --- |
| `normalized` | string | The serialized LaTeX after parsing and normalization. |
| `report` | TransformReport | The diagnostic report for this call. |

- [TransformEngine.normalizeWithReport](https://texform.dev/api/js/transform-engine.md#TransformEngine.normalizeWithReport)
- [TransformEngine.normalize](https://texform.dev/api/js/transform-engine.md#TransformEngine.normalize)

## `TransformReport`

Kind: interface

Diagnostic report for one explicit report call.

Output text and errors follow the ordinary transform contract. Report
fields, phase divisions, and these counters are diagnostic: they are not
part of the stable compatibility promise. A disabled phase stays present as
zeros or an empty array. Field names are camelCase, the JavaScript view of
the snake_case data exposed by the Python binding.

| Name | Type | Description |
| --- | --- | --- |
| `warnings` | TransformWarning[] | Unknown input names, deduplicated and sorted by kind and name. |
| `lowerAttributes` | LowerAttributesReport | LowerAttributes activity, summed across its two passes. |
| `rewrite` | RewriteReport | Rewrite iterations and per-rule outcomes. |
| `finalizeAst` | FinalizeAstReport | Prime merges and text normalizations. |
| `flattenGroups` | FlattenGroupsReport | Flatten actions and guard hits. |

## `TransformWarning`

Kind: interface

An unknown input name whose arguments or scope cannot be guaranteed.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | "unknown-command" | "unknown-environment" | The unknown input name's category. |
| `name` | string | Name without command or environment delimiters. |
| `message` | string | Explanation of the semantic uncertainty. |

## `LowerAttributesReport`

Kind: interface

The LowerAttributes phase report.

| Name | Type | Description |
| --- | --- | --- |
| `attributes` | AttributeStat[] | Per-attribute activity, sorted by `attr` then `value`. |
| `eliminatedEmptySegments` | number | Empty attribute segments removed by the phase. |

## `AttributeStat`

Kind: interface

Activity for one `(attr, value)` pair in LowerAttributes.

| Name | Type | Description |
| --- | --- | --- |
| `attr` | string | Stable attribute name, such as `"math_font"` or `"text_size"`. |
| `value` | string | Stable value token for that attribute. |
| `consumed` | AttributeFormCounts | Input forms consumed by LowerAttributes. |
| `redundant` | AttributeFormCounts | Consumed forms that did not change the emitted attribute state. |
| `emitted` | AttributeFormCounts | Canonical forms emitted by LowerAttributes. |

## `AttributeFormCounts`

Kind: interface

Counts of an attribute form split by carrier: `declaratives` (scope-affecting
declarations such as `{\bf ...}`) and `prefixes` (prefix commands such as
`\mathbf{...}`).

| Name | Type | Description |
| --- | --- | --- |
| `declaratives` | number | Count carried by declarative-form markup. |
| `prefixes` | number | Count carried by prefix-command markup. |

## `RewriteRuleStat`

Kind: interface

One rewrite rule's outcome for a single call.

| Name | Type | Description |
| --- | --- | --- |
| `key` | string | Stable rule key. |
| `appliedCount` | number | Times the rule applied. |
| `skippedCount` | number | Times the scheduler matched the rule and apply returned skipped. |

## `RewriteReport`

Kind: interface

The Rewrite phase report.

| Name | Type | Description |
| --- | --- | --- |
| `iterations` | number | Fixed-point passes, including the final unchanged convergence check.
Zero when the phase is disabled or no rules are scheduled. |
| `rules` | RewriteRuleStat[] | Rules that recorded activity, sorted by `key`. |

## `FinalizeAstReport`

Kind: interface

The FinalizeAst phase report.

| Name | Type | Description |
| --- | --- | --- |
| `primeRunMerges` | number | Contiguous `Prime` runs merged. Each run counts once. |
| `textNormalizations` | number | Text segments or text argument slots whose content changed. |

## `FlattenGroupsActionCounts`

Kind: interface

Flatten actions that changed the tree.

| Name | Type | Description |
| --- | --- | --- |
| `removedEmpty` | number | Empty groups removed. |
| `replacedSingleChild` | number | Groups replaced by their only child. |
| `inlinedMultiChild` | number | Multi-child groups inlined into the parent. |
| `unwrappedSlot` | number | Slot wrappers removed. |

## `FlattenGroupsGuardCounts`

Kind: interface

Preserve-guard hits for one FlattenGroups run.

A hit is the first guard branch reached for a group, plus the scripted-base
sub-count. `commandContactViaScriptedBase` is also included in
`commandContact`. These counters are not a partition of preserved groups.

| Name | Type | Description |
| --- | --- | --- |
| `unknownCommandArguments` | number | Possible arguments following an unknown command. |
| `argumentCapture` | number | Groups whose removal would let a command before or inside them read the
next token as an omitted optional or delimited argument. |
| `declarativeScope` | number | Declarative-scope protection. |
| `scriptBase` | number | Script-base protection. |
| `envBody` | number | Environment-body protection. |
| `infixScope` | number | Infix-scope protection. |
| `commandContact` | number | Command-contact protection. |
| `commandContactViaScriptedBase` | number | Command contact established through a scripted base. |
| `emptyGroup` | number | Empty-group protection. |
| `loneAtomSpacingChar` | number | Single spacing-character protection. |
| `leadingAtomSpacingChar` | number | Leading spacing-character protection. |
| `delimitedPair` | number | Delimited-pair protection. |

## `FlattenGroupsReport`

Kind: interface

The FlattenGroups phase report.

| Name | Type | Description |
| --- | --- | --- |
| `actions` | FlattenGroupsActionCounts | Flatten actions that changed the tree. |
| `guardHits` | FlattenGroupsGuardCounts | Preserve-guard hits for this call. |

## `TransformProfile`

Kind: typeAlias

```ts
"authoring" | "faithful" | "corpus" | "equiv"
```

Normalization profile selecting the canonical form for one downstream
scenario: `authoring` (polished author-facing output), `faithful` (same
rendered formula, convenience macros expanded), `corpus` (training-data
normalization, layout hints dropped), or `equiv` (aggressive
canonicalization for equivalence comparison).

- [TransformEngineOptions](https://texform.dev/api/js/transform-engine.md#TransformEngineOptions)

## `Profile`

Kind: typeAlias

```ts
"authoring" | "faithful" | "corpus" | "equiv"
```

Normalization profile passed to [TransformEngineOptions](/api/js/transform-engine#TransformEngineOptions): `"authoring"`,
`"faithful"`, `"corpus"`, or `"equiv"`.

- [TransformEngineOptions](https://texform.dev/api/js/transform-engine.md#TransformEngineOptions)
- [TransformProfile](https://texform.dev/api/js/transform-engine.md#TransformProfile)

## `RuleLevel`

Kind: typeAlias

```ts
"authoring" | "faithful" | "corpus" | "equiv"
```

How aggressively a transform rule may rewrite, layered from least to most
destructive of stylistic detail.

A rule level is the first profile that accepts a rule's output as a
suitable product; it is orthogonal to a rule's equivalence guarantee.

