mdka 2.2.0__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mdka-2.2.2/.github/CONTRIBUTING.md +42 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/ci.yaml +1 -1
- mdka-2.2.2/.github/workflows/crates-package-gate.yaml +78 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/create-release.yaml +17 -2
- mdka-2.2.2/.github/workflows/docs-example-gate.yaml +94 -0
- mdka-2.2.2/.github/workflows/npm-install-gate.yaml +68 -0
- mdka-2.2.2/.github/workflows/pypi-wheel-gate.yaml +112 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/release-npm.yaml +26 -2
- mdka-2.2.2/.github/workflows/scripts/check-docs-examples.py +307 -0
- {mdka-2.2.0 → mdka-2.2.2}/.gitignore +2 -0
- {mdka-2.2.0 → mdka-2.2.2}/CHANGELOG.md +85 -0
- {mdka-2.2.0 → mdka-2.2.2}/Cargo.lock +7 -46
- {mdka-2.2.0 → mdka-2.2.2}/Cargo.toml +2 -5
- {mdka-2.2.0 → mdka-2.2.2}/PKG-INFO +2 -2
- {mdka-2.2.0/python → mdka-2.2.2}/README.md +1 -1
- mdka-2.2.2/ROADMAP.md +602 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/memory.rs +7 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/core.md +9 -9
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/elements.md +32 -1
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/errors.md +2 -2
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/modes.md +5 -5
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/options.md +3 -3
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/design/architecture.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/design/performance-characteristics.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/getting-started/installation.md +2 -2
- mdka-2.2.2/docs/src/getting-started/usage-cli.md +64 -0
- mdka-2.2.2/docs/src/getting-started/usage-nodejs.md +143 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/getting-started/usage-python.md +23 -3
- {mdka-2.2.0 → mdka-2.2.2}/examples/measure_mem.rs +9 -3
- {mdka-2.2.0 → mdka-2.2.2}/examples/quick_mem.rs +6 -0
- {mdka-2.2.0 → mdka-2.2.2}/mdka/__init__.py +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/pyproject.toml +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/python/Cargo.toml +1 -1
- {mdka-2.2.0 → mdka-2.2.2/python}/README.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/python/src/lib.rs +21 -20
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/README.md +23 -2
- mdka-2.2.2/rfcs/accepted/024-inline-composition-output-sink.md +146 -0
- mdka-2.2.2/rfcs/accepted/025-output-validity-harness.md +168 -0
- mdka-2.2.2/rfcs/accepted/028-emphasis-around-block-content.md +169 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/000-rfc-lifecycle-policy.md +65 -0
- mdka-2.2.2/rfcs/done/007-english-only-public-surface.md +134 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/015-release-tooling-completion.md +1 -1
- mdka-2.2.2/rfcs/done/020-npm-distribution-repair.md +262 -0
- mdka-2.2.2/rfcs/done/021-bulk-output-collision-safety.md +116 -0
- mdka-2.2.2/rfcs/done/022-cli-allocator-and-jemalloc.md +151 -0
- mdka-2.2.2/rfcs/done/023-getting-started-doc-reconciliation.md +105 -0
- mdka-2.2.2/rfcs/done/026-consumer-artifact-gates.md +167 -0
- mdka-2.2.2/rfcs/done/027-verification-discipline.md +260 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/005-conversion-options-semantics/implementation-handoff.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/005-conversion-options-semantics/slice-b1-placement-correction-handoff.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/005-conversion-options-semantics/slices-bc-handoff.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/006-option-docs-and-binding-parity/implementation-handoff.md +2 -2
- mdka-2.2.2/rfcs/handoffs/007-english-only-public-surface/implementation-handoff.md +164 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/018-readme-prebuilt-binaries/implementation-handoff.md +1 -1
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/019-release-creation-via-dispatch/implementation-handoff.md +1 -1
- mdka-2.2.2/rfcs/handoffs/020-npm-distribution-repair/implementation-handoff.md +188 -0
- mdka-2.2.2/rfcs/handoffs/021-bulk-output-collision-safety/implementation-handoff.md +134 -0
- mdka-2.2.2/rfcs/handoffs/022-cli-allocator-and-jemalloc/alloc-counter-deprecation-handoff.md +136 -0
- mdka-2.2.2/rfcs/handoffs/022-cli-allocator-and-jemalloc/implementation-handoff.md +126 -0
- mdka-2.2.2/rfcs/handoffs/023-getting-started-doc-reconciliation/implementation-handoff.md +136 -0
- mdka-2.2.2/rfcs/handoffs/024-inline-composition-output-sink/implementation-handoff.md +152 -0
- mdka-2.2.2/rfcs/handoffs/025-output-validity-harness/implementation-handoff.md +147 -0
- mdka-2.2.2/rfcs/handoffs/026-consumer-artifact-gates/implementation-handoff.md +152 -0
- mdka-2.2.2/rfcs/handoffs/027-verification-discipline/implementation-handoff.md +170 -0
- mdka-2.2.2/rfcs/handoffs/028-emphasis-around-block-content/implementation-handoff.md +217 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/alloc_counter.rs +8 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/lib.rs +96 -28
- {mdka-2.2.0 → mdka-2.2.2}/src/options.rs +47 -43
- {mdka-2.2.0 → mdka-2.2.2}/tests/file_conversion.rs +85 -0
- mdka-2.2.0/.github/CONTRIBUTING.md +0 -13
- mdka-2.2.0/ROADMAP.md +0 -309
- mdka-2.2.0/docs/src/getting-started/usage-cli.md +0 -55
- mdka-2.2.0/docs/src/getting-started/usage-nodejs.md +0 -117
- {mdka-2.2.0 → mdka-2.2.2}/.gitattributes +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/CODE_OF_CONDUCT.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/SECURITY.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/docs.yaml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/release-crates.yaml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/release-executable.yaml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/release-pypi.yaml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.github/workflows/scripts/install-rust.sh +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.vscode/extensions.json +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/.vscode/settings.json +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/LICENSE +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/NOTICE +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/bench_common.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/deep_nest.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/flat.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/large.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/malformed.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/medium.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/scale_500k.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/scale_50k.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/scale_5m.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/benchdata/small.html +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/convert.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/parallel.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/benches/scaling.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/cargo-publish.sh +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/book.toml +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/SUMMARY.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/index.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/api/text-processing.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/assets/logo.png +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/design/features.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/design/philosophy.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/getting-started/usage-rust.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/getting-started/usage.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/docs/src/introduction.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/examples/quick_bench.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/examples/quick_compare.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/python/example.py +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/python/test_mdka.py +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/001-ci-quality-gates.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/002-governance-artifacts.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/003-architecture-doc-reconciliation.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/004-preprocessor-disposition.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/005-conversion-options-semantics.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/006-option-docs-and-binding-parity.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/014-release-time-ci-verification.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/016-hr-newline-reset.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/017-pre-fence-newline-reset.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/018-readme-prebuilt-binaries.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/done/019-release-creation-via-dispatch.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/001-ci-quality-gates/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/002-governance-artifacts/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/003-architecture-doc-reconciliation/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/004-preprocessor-disposition/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/014-release-time-ci-verification/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/015-release-tooling-completion/amendment-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/015-release-tooling-completion/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/015-release-tooling-completion/restore-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/016-hr-newline-reset/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/rfcs/handoffs/017-pre-fence-newline-reset/implementation-handoff.md +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/renderer.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/traversal/tests.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/traversal.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/utils/tests.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/src/utils.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/anchor_drift_guard.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/block_elements.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/characterisation_attributes.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/characterisation_elements.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/characterisation_structural.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/common.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/compat.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/hr_newline_reset.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/inline_elements.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/pre_fence_newline_reset.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/preserve_ids_anchors.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/tests/robustness.rs +0 -0
- {mdka-2.2.0 → mdka-2.2.2}/version.sh +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
## ✨ Contributing
|
|
2
|
+
|
|
3
|
+
We’re happy to receive feedback, bug reports, and questions via GitHub Issues.
|
|
4
|
+
Pull requests are also welcome — though please note that we may not always be able to accept them.
|
|
5
|
+
|
|
6
|
+
This project is maintained as a labor of love. We welcome community participation, but:
|
|
7
|
+
|
|
8
|
+
- Issues that are respectful and constructive are appreciated.
|
|
9
|
+
- Pull requests are reviewed, but acceptance is not guaranteed.
|
|
10
|
+
- We do not engage in long debates or vision disagreements.
|
|
11
|
+
- If you have a different direction in mind, please fork freely, provided proper licensing is respected.
|
|
12
|
+
|
|
13
|
+
Thanks for understanding the scope and spirit of the project.
|
|
14
|
+
|
|
15
|
+
## Documentation examples
|
|
16
|
+
|
|
17
|
+
Every fenced code block in `docs/src/` whose info string names `rust`,
|
|
18
|
+
`python`, `js` or `ts` is **checked in CI** by the `docs example gate`
|
|
19
|
+
workflow. Rust blocks are compiled against the crate, TypeScript blocks are
|
|
20
|
+
type-checked against the generated `node/index.d.ts`, JavaScript blocks are
|
|
21
|
+
parsed, and Python blocks are syntax-checked with every `mdka` symbol they
|
|
22
|
+
name resolved against the installed package.
|
|
23
|
+
|
|
24
|
+
A block that is deliberately **not** runnable on its own — a signature
|
|
25
|
+
display, a type declaration, or a snippet that relies on a variable
|
|
26
|
+
introduced in the surrounding prose — must say so in its info string:
|
|
27
|
+
|
|
28
|
+
````markdown
|
|
29
|
+
```rust,fragment
|
|
30
|
+
pub fn html_to_markdown(html: &str) -> String
|
|
31
|
+
```
|
|
32
|
+
````
|
|
33
|
+
|
|
34
|
+
**The marker is what excludes a block.** There is no list of exceptions kept
|
|
35
|
+
somewhere else, because such a list drifts out of step with the documents it
|
|
36
|
+
describes. Rust's own `ignore` and `no_run` are honoured for the same
|
|
37
|
+
purpose. A block with no info string at all — which is how sample *output*
|
|
38
|
+
is written — is never checked.
|
|
39
|
+
|
|
40
|
+
If a block is genuinely runnable, do not mark it as a fragment to quiet the
|
|
41
|
+
gate; fix the example. That gate exists because two shipped examples failed
|
|
42
|
+
on their first line.
|
|
@@ -50,7 +50,7 @@ jobs:
|
|
|
50
50
|
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
51
51
|
|
|
52
52
|
- name: cargo test
|
|
53
|
-
run: cargo test --workspace --locked
|
|
53
|
+
run: cargo test --workspace --all-features --locked
|
|
54
54
|
|
|
55
55
|
- name: cargo build
|
|
56
56
|
run: cargo build --workspace --locked
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: crates package gate
|
|
2
|
+
|
|
3
|
+
# RFC 026 §4.2. The `rust` job in ci.yaml runs `cargo test` in-workspace,
|
|
4
|
+
# where every path dependency resolves and every file is present. It cannot
|
|
5
|
+
# see a crate that compiles here and fails standalone -- through a missing
|
|
6
|
+
# `include`, a path dependency with no version, or a file absent from the
|
|
7
|
+
# packaged .crate.
|
|
8
|
+
#
|
|
9
|
+
# `cargo package` (without --no-verify) packages each crate and then builds
|
|
10
|
+
# from the extracted package, resolving dependencies from the registry
|
|
11
|
+
# rather than from the workspace. That is the consumer's build.
|
|
12
|
+
#
|
|
13
|
+
# Its own workflow file, not ci.yaml -- see RFC 026 §3.5 and RFC 020's
|
|
14
|
+
# correction record.
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
push:
|
|
18
|
+
branches: [main]
|
|
19
|
+
pull_request:
|
|
20
|
+
branches: [main]
|
|
21
|
+
workflow_dispatch:
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
28
|
+
cancel-in-progress: true
|
|
29
|
+
|
|
30
|
+
defaults:
|
|
31
|
+
run:
|
|
32
|
+
shell: bash
|
|
33
|
+
|
|
34
|
+
jobs:
|
|
35
|
+
crates-package-gate:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
timeout-minutes: 30
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Checkout repository
|
|
41
|
+
uses: actions/checkout@v6
|
|
42
|
+
|
|
43
|
+
- name: Cache cargo dependencies and build
|
|
44
|
+
uses: actions/cache@v5
|
|
45
|
+
with:
|
|
46
|
+
path: |
|
|
47
|
+
~/.cargo/registry
|
|
48
|
+
~/.cargo/git
|
|
49
|
+
target
|
|
50
|
+
key: ${{ runner.os }}-cargo-package-gate-${{ hashFiles('**/Cargo.lock') }}
|
|
51
|
+
restore-keys: |
|
|
52
|
+
${{ runner.os }}-cargo-package-gate-
|
|
53
|
+
|
|
54
|
+
# mdka first: the other three depend on it, and their verification
|
|
55
|
+
# builds resolve it from the registry.
|
|
56
|
+
#
|
|
57
|
+
# No --no-verify anywhere. Packaging without building the result would
|
|
58
|
+
# check that the tarball can be produced, not that it works -- which is
|
|
59
|
+
# the distinction this whole milestone is about.
|
|
60
|
+
- name: cargo package -p mdka
|
|
61
|
+
run: cargo package -p mdka --locked
|
|
62
|
+
|
|
63
|
+
- name: cargo package -p mdka-cli
|
|
64
|
+
run: cargo package -p mdka-cli --locked
|
|
65
|
+
|
|
66
|
+
- name: cargo package -p mdka-node
|
|
67
|
+
run: cargo package -p mdka-node --locked
|
|
68
|
+
|
|
69
|
+
- name: cargo package -p mdka-python
|
|
70
|
+
run: cargo package -p mdka-python --locked
|
|
71
|
+
|
|
72
|
+
- name: Show what each package actually contains
|
|
73
|
+
run: |
|
|
74
|
+
set -euo pipefail
|
|
75
|
+
for crate in target/package/*.crate; do
|
|
76
|
+
echo "=== $crate"
|
|
77
|
+
tar -tzf "$crate" | sed 's/^/ /'
|
|
78
|
+
done
|
|
@@ -64,8 +64,23 @@ jobs:
|
|
|
64
64
|
env:
|
|
65
65
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
66
66
|
run: |
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
tag="${{ github.ref_name }}"
|
|
68
|
+
link="https://github.com/${{ github.repository }}/blob/${tag}/CHANGELOG.md"
|
|
69
|
+
|
|
70
|
+
# Point at this version's CHANGELOG section. GitHub's heading anchor
|
|
71
|
+
# includes the release date ("## [2.2.1] - 2026-09-01" -> #221---2026-09-01),
|
|
72
|
+
# so it has to be derived from the heading rather than the version alone.
|
|
73
|
+
# If the heading is not found, the link degrades to the file itself --
|
|
74
|
+
# never to a broken anchor.
|
|
75
|
+
heading=$(grep -m1 "^## \[${tag}\]" CHANGELOG.md || true)
|
|
76
|
+
if [ -n "$heading" ]; then
|
|
77
|
+
anchor=$(printf '%s' "$heading" | sed 's/^## //' | tr -d '[].' | tr ' ' '-' | tr 'A-Z' 'a-z')
|
|
78
|
+
link="${link}#${anchor}"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
gh release create "${tag}" \
|
|
82
|
+
--title "${tag}" \
|
|
83
|
+
--notes "📖 [Changelog for ${tag}](${link})" \
|
|
69
84
|
--generate-notes
|
|
70
85
|
|
|
71
86
|
- name: Start the publishing workflows
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
name: docs example gate
|
|
2
|
+
|
|
3
|
+
# RFC 026 §4.3. Nothing has ever executed the examples in docs/src/. D-12
|
|
4
|
+
# and D-13 shipped examples that fail on their first line -- a duplicate
|
|
5
|
+
# `const`, and a TypeScript import of a type the bindings never exported.
|
|
6
|
+
#
|
|
7
|
+
# Every fenced block whose info string names a language we can check is
|
|
8
|
+
# checked. A block that is deliberately a fragment carries a `fragment`
|
|
9
|
+
# marker, and the marker is what excludes it: there is no list of exceptions
|
|
10
|
+
# kept elsewhere that can drift out of step with the documents. The
|
|
11
|
+
# convention is documented in CONTRIBUTING.md.
|
|
12
|
+
#
|
|
13
|
+
# Its own workflow file, not ci.yaml -- see RFC 026 §3.5.
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
branches: [main]
|
|
18
|
+
pull_request:
|
|
19
|
+
branches: [main]
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
concurrency:
|
|
26
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
27
|
+
cancel-in-progress: true
|
|
28
|
+
|
|
29
|
+
defaults:
|
|
30
|
+
run:
|
|
31
|
+
shell: bash
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
docs-example-gate:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
timeout-minutes: 20
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout repository
|
|
40
|
+
uses: actions/checkout@v6
|
|
41
|
+
|
|
42
|
+
- name: Setup Python
|
|
43
|
+
uses: actions/setup-python@v6
|
|
44
|
+
with:
|
|
45
|
+
python-version: 3.x
|
|
46
|
+
|
|
47
|
+
- name: Setup Node.js
|
|
48
|
+
uses: actions/setup-node@v6
|
|
49
|
+
with:
|
|
50
|
+
node-version: 24
|
|
51
|
+
|
|
52
|
+
- name: Cache cargo dependencies and build
|
|
53
|
+
uses: actions/cache@v5
|
|
54
|
+
with:
|
|
55
|
+
path: |
|
|
56
|
+
~/.cargo/registry
|
|
57
|
+
~/.cargo/git
|
|
58
|
+
target
|
|
59
|
+
key: ${{ runner.os }}-cargo-docs-gate-${{ hashFiles('**/Cargo.lock') }}
|
|
60
|
+
restore-keys: |
|
|
61
|
+
${{ runner.os }}-cargo-docs-gate-
|
|
62
|
+
|
|
63
|
+
# The TypeScript examples are checked against the generated
|
|
64
|
+
# declarations, so those must exist and be current.
|
|
65
|
+
- name: Generate the TypeScript declarations
|
|
66
|
+
working-directory: node
|
|
67
|
+
run: |
|
|
68
|
+
npm ci
|
|
69
|
+
npm run build
|
|
70
|
+
|
|
71
|
+
# Python examples resolve their `mdka` symbols against the installed
|
|
72
|
+
# package, so a documented function that does not exist is caught.
|
|
73
|
+
- name: Stage README for maturin
|
|
74
|
+
run: cp -f README.md python/
|
|
75
|
+
|
|
76
|
+
- name: Install uv
|
|
77
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
78
|
+
|
|
79
|
+
- name: Build and install the wheel into a venv
|
|
80
|
+
run: |
|
|
81
|
+
set -euo pipefail
|
|
82
|
+
uv venv
|
|
83
|
+
uv pip install maturin
|
|
84
|
+
cd python
|
|
85
|
+
source ../.venv/bin/activate
|
|
86
|
+
maturin build --out "$RUNNER_TEMP/wheels"
|
|
87
|
+
cd ..
|
|
88
|
+
python -m venv "$RUNNER_TEMP/docs-venv"
|
|
89
|
+
"$RUNNER_TEMP/docs-venv/bin/pip" install --no-index "$RUNNER_TEMP"/wheels/mdka-*.whl
|
|
90
|
+
|
|
91
|
+
- name: Check every runnable example in docs/src/
|
|
92
|
+
run: |
|
|
93
|
+
python .github/workflows/scripts/check-docs-examples.py \
|
|
94
|
+
--python "$RUNNER_TEMP/docs-venv/bin/python"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: npm install gate
|
|
2
|
+
|
|
3
|
+
# RFC 020 / RFC 026. This gate must NOT live in ci.yaml: release-npm.yaml and
|
|
4
|
+
# create-release.yaml gate on ci.yaml's conclusion, so a red gate there blocks
|
|
5
|
+
# the very release that would make it pass. See RFC 020's correction record.
|
|
6
|
+
#
|
|
7
|
+
# It installs the PUBLISHED package from the registry, the way a consumer does.
|
|
8
|
+
#
|
|
9
|
+
# It deliberately does not pack and install the local tarball. That was the
|
|
10
|
+
# original design and it could never pass: `optionalDependencies` are injected
|
|
11
|
+
# by `napi pre-publish` at release time, so a locally packed tarball has none,
|
|
12
|
+
# resolves no per-platform package, and always fails to load. It was testing an
|
|
13
|
+
# artifact that is not the one published.
|
|
14
|
+
#
|
|
15
|
+
# Consequence, stated rather than hidden: this gate reports on the LAST
|
|
16
|
+
# PUBLISHED release, not on the current working tree. That lag is inherent --
|
|
17
|
+
# a published artifact cannot be verified before it is published. What it buys
|
|
18
|
+
# is an alarm that would have been red for all twelve broken 2.x releases.
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
push:
|
|
22
|
+
branches: [main]
|
|
23
|
+
pull_request:
|
|
24
|
+
branches: [main]
|
|
25
|
+
workflow_dispatch:
|
|
26
|
+
schedule:
|
|
27
|
+
# Catch a registry-side regression even when nobody pushes.
|
|
28
|
+
- cron: '0 6 * * 1'
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
defaults:
|
|
34
|
+
run:
|
|
35
|
+
shell: bash
|
|
36
|
+
|
|
37
|
+
jobs:
|
|
38
|
+
npm-install-gate:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
timeout-minutes: 10
|
|
41
|
+
|
|
42
|
+
steps:
|
|
43
|
+
- name: Setup Node.js
|
|
44
|
+
uses: actions/setup-node@v6
|
|
45
|
+
with:
|
|
46
|
+
node-version: 24
|
|
47
|
+
|
|
48
|
+
- name: Install the published package from the registry and require it
|
|
49
|
+
run: |
|
|
50
|
+
set -euo pipefail
|
|
51
|
+
install_dir="$RUNNER_TEMP/npm-install-gate"
|
|
52
|
+
mkdir -p "$install_dir"
|
|
53
|
+
cd "$install_dir"
|
|
54
|
+
npm init -y >/dev/null
|
|
55
|
+
|
|
56
|
+
published=$(npm view mdka version)
|
|
57
|
+
echo "Testing published mdka@${published}"
|
|
58
|
+
npm install "mdka@${published}"
|
|
59
|
+
|
|
60
|
+
node -e "
|
|
61
|
+
const m = require('mdka');
|
|
62
|
+
const out = m.htmlToMarkdown('<h1>x</h1>');
|
|
63
|
+
if (!out.includes('# x')) {
|
|
64
|
+
console.error('unexpected output: ' + JSON.stringify(out));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
console.log('OK: mdka@${published} installs and converts:', JSON.stringify(out));
|
|
68
|
+
"
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: pypi wheel gate
|
|
2
|
+
|
|
3
|
+
# RFC 026 §4.1. The `python` job in ci.yaml runs `maturin develop` + pytest,
|
|
4
|
+
# which imports the project from the workspace. That cannot see anything
|
|
5
|
+
# missing from the *wheel* -- the artifact `pip install mdka` actually
|
|
6
|
+
# fetches. This gate builds the wheel, installs it into a venv outside the
|
|
7
|
+
# workspace, and imports it from there.
|
|
8
|
+
#
|
|
9
|
+
# Its own workflow file, not ci.yaml: release-npm.yaml and
|
|
10
|
+
# create-release.yaml gate on ci.yaml's conclusion, so an artifact gate
|
|
11
|
+
# living there can block the very release that would make it pass. That
|
|
12
|
+
# deadlocked 2.2.1. See RFC 020's correction record and RFC 026 §3.5.
|
|
13
|
+
#
|
|
14
|
+
# It does NOT assert py.typed. RFC 023 decided to remove that claim rather
|
|
15
|
+
# than ship the marker: every public symbol comes from a compiled PyO3
|
|
16
|
+
# module with no .pyi stubs, so shipping py.typed would silence a type
|
|
17
|
+
# checker without giving it anything to check. See RFC 023.
|
|
18
|
+
|
|
19
|
+
on:
|
|
20
|
+
push:
|
|
21
|
+
branches: [main]
|
|
22
|
+
pull_request:
|
|
23
|
+
branches: [main]
|
|
24
|
+
workflow_dispatch:
|
|
25
|
+
|
|
26
|
+
permissions:
|
|
27
|
+
contents: read
|
|
28
|
+
|
|
29
|
+
concurrency:
|
|
30
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
31
|
+
cancel-in-progress: true
|
|
32
|
+
|
|
33
|
+
defaults:
|
|
34
|
+
run:
|
|
35
|
+
shell: bash
|
|
36
|
+
|
|
37
|
+
jobs:
|
|
38
|
+
pypi-wheel-gate:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
timeout-minutes: 20
|
|
41
|
+
|
|
42
|
+
steps:
|
|
43
|
+
- name: Checkout repository
|
|
44
|
+
uses: actions/checkout@v6
|
|
45
|
+
|
|
46
|
+
- name: Setup Python
|
|
47
|
+
uses: actions/setup-python@v6
|
|
48
|
+
with:
|
|
49
|
+
python-version: 3.x
|
|
50
|
+
|
|
51
|
+
- name: Cache cargo dependencies and build
|
|
52
|
+
uses: actions/cache@v5
|
|
53
|
+
with:
|
|
54
|
+
path: |
|
|
55
|
+
~/.cargo/registry
|
|
56
|
+
~/.cargo/git
|
|
57
|
+
target
|
|
58
|
+
key: ${{ runner.os }}-cargo-wheel-gate-${{ hashFiles('**/Cargo.lock') }}
|
|
59
|
+
restore-keys: |
|
|
60
|
+
${{ runner.os }}-cargo-wheel-gate-
|
|
61
|
+
|
|
62
|
+
# python/pyproject.toml declares readme = "README.md" but the README
|
|
63
|
+
# lives at the repository root. Same staging the `python` job does.
|
|
64
|
+
- name: Stage README for maturin
|
|
65
|
+
run: cp -f README.md python/
|
|
66
|
+
|
|
67
|
+
- name: Install uv
|
|
68
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
69
|
+
|
|
70
|
+
- name: Install maturin
|
|
71
|
+
run: |
|
|
72
|
+
uv venv
|
|
73
|
+
uv pip install maturin
|
|
74
|
+
|
|
75
|
+
# `maturin build`, never `maturin develop`. develop is the blind spot
|
|
76
|
+
# this gate exists to close.
|
|
77
|
+
- name: Build the wheel
|
|
78
|
+
working-directory: python
|
|
79
|
+
run: |
|
|
80
|
+
source ../.venv/bin/activate
|
|
81
|
+
maturin build --out "$RUNNER_TEMP/wheels"
|
|
82
|
+
|
|
83
|
+
- name: Install the wheel outside the workspace and use it
|
|
84
|
+
run: |
|
|
85
|
+
set -euo pipefail
|
|
86
|
+
venv="$RUNNER_TEMP/wheel-gate-venv"
|
|
87
|
+
python -m venv "$venv"
|
|
88
|
+
wheel=$(ls "$RUNNER_TEMP"/wheels/mdka-*.whl)
|
|
89
|
+
echo "Installing $wheel"
|
|
90
|
+
"$venv/bin/pip" install --no-index "$wheel"
|
|
91
|
+
|
|
92
|
+
# cd out of the workspace so `import mdka` cannot resolve to the
|
|
93
|
+
# source tree instead of the installed package.
|
|
94
|
+
cd "$RUNNER_TEMP"
|
|
95
|
+
"$venv/bin/python" - <<'PY'
|
|
96
|
+
import mdka, pathlib, sys
|
|
97
|
+
|
|
98
|
+
# Prove we imported the installed package, not a source checkout.
|
|
99
|
+
where = pathlib.Path(mdka.__file__).resolve()
|
|
100
|
+
print("imported from:", where)
|
|
101
|
+
assert "site-packages" in where.parts, f"not the installed package: {where}"
|
|
102
|
+
|
|
103
|
+
out = mdka.html_to_markdown("<h1>x</h1>")
|
|
104
|
+
assert "# x" in out, f"unexpected output: {out!r}"
|
|
105
|
+
|
|
106
|
+
# The compiled binding must be inside the wheel, not merely
|
|
107
|
+
# importable because something else built it.
|
|
108
|
+
so = list(where.parent.glob("mdka_python*.so"))
|
|
109
|
+
assert so, f"native binding missing from the installed package: {list(where.parent.iterdir())}"
|
|
110
|
+
|
|
111
|
+
print("OK:", repr(out), "| binding:", so[0].name, "| version:", mdka.__version__)
|
|
112
|
+
PY
|
|
@@ -167,7 +167,32 @@ jobs:
|
|
|
167
167
|
run: |
|
|
168
168
|
npx napi create-npm-dirs
|
|
169
169
|
npx napi artifacts
|
|
170
|
-
|
|
170
|
+
|
|
171
|
+
# RFC 020: this step was missing entirely, which is why `npm install
|
|
172
|
+
# mdka` produced an unusable package for the whole 2.x line -- the
|
|
173
|
+
# per-platform packages were never published past 1.6.9, and the main
|
|
174
|
+
# package's manifest never carried optionalDependencies at all.
|
|
175
|
+
#
|
|
176
|
+
# --no-gh-release is required, not optional: `napi pre-publish`
|
|
177
|
+
# defaults --gh-release to true and would otherwise attempt to create
|
|
178
|
+
# a second GitHub release for a tag create-release.yaml already
|
|
179
|
+
# released, which fails (non-fatally -- it's caught and logged -- but
|
|
180
|
+
# there is no reason to invite the noise).
|
|
181
|
+
- name: napi pre-publish (publish per-platform packages, inject optionalDependencies)
|
|
182
|
+
working-directory: node
|
|
183
|
+
env:
|
|
184
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
185
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
186
|
+
run: npx napi pre-publish --no-gh-release
|
|
187
|
+
|
|
188
|
+
# No `npm ci` here. The `napi pre-publish` step above rewrites
|
|
189
|
+
# package.json to add optionalDependencies for the per-platform
|
|
190
|
+
# packages, which puts it out of sync with package-lock.json --
|
|
191
|
+
# `npm ci` refuses to run in that state and fails the publish. It was
|
|
192
|
+
# also redundant: the "Install dependencies" step above already ran
|
|
193
|
+
# `npm install`, and `npm publish` does not need node_modules.
|
|
194
|
+
# Removed 2026-09-01 after it blocked the 2.2.1 npm publish, which is
|
|
195
|
+
# the first release in which pre-publish ever ran.
|
|
171
196
|
- name: Publish
|
|
172
197
|
working-directory: node
|
|
173
198
|
env:
|
|
@@ -175,5 +200,4 @@ jobs:
|
|
|
175
200
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
176
201
|
run: |
|
|
177
202
|
cp -f ../README.md .
|
|
178
|
-
npm ci
|
|
179
203
|
npm publish
|