Metadata-Version: 2.4
Name: myform
Version: 1.0.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: POSIX :: Linux
Classifier: Framework :: Pytest
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Typing :: Typed
Requires-Dist: mdformat>=1.0,<2
Requires-Dist: mdformat-deflist>=0.1.4
Requires-Dist: mdformat-footnote>=0.1.2
Requires-Dist: mdformat-front-matters>=2.0.0
Requires-Dist: mdformat-gfm>=1.0.0
Requires-Dist: mdit-py-plugins>=0.5.0
Requires-Dist: more-itertools>=10.7.0
Requires-Dist: my-basis>=1.0.0
Requires-Dist: pydantic>=2.11.7
Requires-Dist: regex>=2024.4.28
Requires-Dist: srsly>=2.5.3
License-File: LICENSE
Summary: A typed translator that reads MyST and GFM and writes MyST, GFM, rST, and Typst.
Author-email: Robb Doering <robb@doering.ai>
License-Expression: MPL-2.0
Requires-Python: >=3.13
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Documentation, https://myform.readthedocs.io
Project-URL: Homepage, https://gitlab.com/doering-ai/libs/myform
Project-URL: Issues, https://gitlab.com/doering-ai/libs/myform/-/issues
Project-URL: Repository, https://gitlab.com/doering-ai/libs/myform

# myform

> **Status:** `myform 0.7.0` is public on PyPI.
> The current development branch prepares the next release; expect breaking changes there.

![Pipeline Status](https://img.shields.io/gitlab/pipeline-status/doering-ai/libs/myform?branch=main) ![Test Coverage](https://img.shields.io/gitlab/pipeline-coverage/doering-ai/libs/myform?branch=main) [![License](https://img.shields.io/gitlab/license/doering-ai/libs/myform)](LICENSE) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) [![pyrefly](https://img.shields.io/endpoint?url=https://pyrefly.org/badge.json)](https://github.com/facebook/pyrefly) [![ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

`myform` is a universal docs-format translator built around one absolute, typed document tree.
It reads MyST Markdown and GitHub Flavored Markdown (GFM), then writes idiomatic MyST, GFM, Sphinx reStructuredText, or Typst.
Formatting is the identity case: `myform.convert(text, format, format)` runs through the same reader, typed tree, and writer as a cross-format conversion.

| Format                  | Read | Write |
| :---------------------- | :--: | :---: |
| MyST Markdown           | Yes  |  Yes  |
| GFM                     | Yes  |  Yes  |
| Sphinx reStructuredText |  No  |  Yes  |
| Typst                   |  No  |  Yes  |

The two Markdown identity conversions remain the compatibility rail.
They produce byte-for-byte the same text as the existing mdformat pipelines, including the MyST opinions developed in this repository.

## Install

Install the public release from PyPI:

```sh
pip install myform
```

To develop from the checked-out source with `uv`:

```sh
uv sync --all-extras
uv run myform --help
```

`myform 0.7.0` does not include a native Typst reader; Typst remains write-only as the format table shows.
The current development branch is preparing that next-release reader behind a native extension.
Its source builds require Rust 1.92.
The development release pipeline intentionally produces one audited `cp313-abi3-manylinux_2_28_x86_64` wheel; macOS, Windows, non-x86_64 Linux, and older-glibc Linux systems must build from source until a verified wheel matrix is added.
`import myform` itself remains pure Python and does not load the extension.

## Translate documents

```sh
uv run myform convert guide.md --from myst --to rst -o guide.rst
printf '# Hello\n' | uv run myform convert - --from gfm --to typst
uv run myform convert guide.md --from myst --to gfm --report json >guide.gfm
```

Use `-` as the input path to read stdin.
Output goes to stdout unless `-o/--output` names a file.
Conversion reports always go to stderr, keeping document output safe for pipelines.
Choose `--report summary` (the default), `--report json`, or `--report none`.

## Format documents

The `format` verb performs an identity conversion:

```sh
uv run myform format README.md
uv run myform format README.md --format myst -o README.formatted.md
```

The Python API exposes the same contract:

```python
import myform

rst = myform.convert(source, 'myst', 'rst')
formatted = myform.convert(source, 'myst', 'myst')
```

## Configure translation

`myform` discovers the nearest `myform.yaml`, `.myform.yaml`, or `[tool.myform]` table by walking upward from the target path.
Within one directory, that order is also the precedence order.
The nearest directory wins rather than merging several files.

```yaml
degrade:
  mode: annotate
  comments: true
assist:
  enabled: false
typst:
  postformat: off
extensions: []
```

Every non-native conversion is represented in the conversion report.
The default `annotate` degradation mode also leaves a provenance comment when the target supports comments; `silent` suppresses comments but not reports, while `strict` refuses carrying or dropping unsupported constructs.

The optional LM assist is degradation-only and disabled by default, which makes zero network calls.
When enabled, it uses the configured local OpenAI-compatible gateway and retains a deterministic fallback.

The committed [`myform.schema.json`](myform.schema.json) and [`myst-options.schema.json`](myst-options.schema.json) schemas describe the translator and mdformat-facade configuration surfaces.
Refresh or verify both with:

```sh
uv run myform-write-schema
uv run myform-write-schema --check
```

## Use the MyST mdformat facade

The original plugin remains available through mdformat's `myst` extension entry point:

```sh
uv run mdformat README.md
```

This repository began as a ground-up rewrite of [`mdformat-myst`](https://github.com/executablebooks/mdformat-myst), written to make uncompiled MyST documents look closer to the hand-formatted sources maintained by the MyST team.
That facade remains useful on its own:

1. [Targets](https://myst-parser.readthedocs.io/en/latest/syntax/cross-referencing.html#creating-explicit-targets) hug the headings or blocks they identify instead of being separated by an extra blank line.

2. [Directive options](https://myst-parser.readthedocs.io/en/latest/syntax/roles-and-directives.html) prefer the readable `:key: value` prefix form and escalate to a YAML block only when necessary.

3. Directive contents are formatted as first-class Markdown rather than treated as opaque text.

4. Parser and renderer rules are explicit, decorator-registered examples of a modern mdformat extension.

5. YAML values use `srsly`'s maintained `ruamel.yaml` integration.

6. The optional `sembr` mode reflows paragraphs to [one sentence per line](https://sembr.org/) without changing their rendered output:

   ```toml
   [plugin.myst]
   sembr = true
   ```

   Enable it per invocation with `mdformat --sembr <filename>`; `--no-sembr` overrides the TOML setting.

The facade also preserves established skip-formatting comments:

```md
<!-- myform-ignore -->

This next block is left exactly as written.
```

```md
<!-- myform-ignore-start -->

Every block in this range is preserved.

<!-- myform-ignore-end -->
```

```md
<!-- myform-ignore-file -->
```

The markers act at the document top level.
Their strings remain configurable through `[plugin.myst]`.

## Documentation

- [Documentation front door](docs/index.md)
- [API reference](docs/api.md)
- [Universal translator specification](docs/spec/myform-spec.md)
- [Typst ecosystem memo](docs/spec/typst-ecosystem-memo.md)
- [Release procedure](RELEASING.md)

