diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..4a4a4e9 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,53 @@ +name: Docs + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: github-pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-python@v6 + with: + python-version: "3.x" + + - name: Configure Pages + uses: actions/configure-pages@v6 + + - name: Install docs dependencies + run: | + python -m pip install --upgrade pip + python -m pip install mkdocs mkdocs-material pymdown-extensions + + - name: Build site + run: | + mkdocs build --clean + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v5 + with: + path: site + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v5 diff --git a/README.md b/README.md index 1da2e1a..bb07b75 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![License](https://img.shields.io/badge/License-BSD\%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) [![Build Status](https://app.travis-ci.com/AlexandrovLab/SigProfilerSimulator.svg?branch=master)](https://app.travis-ci.com/AlexandrovLab/SigProfilerSimulator) +SigProfilerSimulator + # SigProfilerSimulator SigProfilerSimulator allows realistic simulations of mutational signatures in cancer genomes. The tool can simulate signatures of single base substitutions, double base substitutions, and insertions/deletions across the whole genome or user-defined regions. SigProfilerSimulator makes use of [SigProfilerMatrixGenerator](https://github.com/SigProfilerSuite/SigProfilerMatrixGenerator) and [SigProfilerPlotting](https://github.com/SigProfilerSuite/SigProfilerPlotting), seamlessly integrating with other tools in [SigProfilerSuite](https://github.com/SigProfilerSuite). @@ -50,4 +52,4 @@ Released Jan 2011. Last updated March 2012. This genome was downloaded from ENSE rn6 (Rnor_6.0) INSDC Assembly GCA_000001895.4, Jul 2014. Released Jun 2015. Last updated Jan 2017. This genome was downloaded from ENSEMBL database version 96.6. -yeast (Saccharomyces cerevisiae S288C; assembly R64-2-1). Released Nov 2014. +yeast (Saccharomyces cerevisiae S288C; assembly R64-2-1). Released Nov 2014. diff --git a/ci.yml b/ci.yml index f1ce0ec..38168d6 100644 --- a/ci.yml +++ b/ci.yml @@ -21,10 +21,10 @@ jobs: python-version: ['3.9', '3.14'] steps: - - uses: actions/checkout@v4 - + - uses: actions/checkout@v6 + - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -38,7 +38,7 @@ jobs: python -m pip install --upgrade pip setuptools packaging - name: Cache src directory - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ github.workspace }}/src/ key: ${{ runner.os }}-src-grch37 diff --git a/docs/1_installation.md b/docs/1_installation.md new file mode 100644 index 0000000..2c8ae79 --- /dev/null +++ b/docs/1_installation.md @@ -0,0 +1,74 @@ +# Installation + + +---------- + + +This section will help you set up the necessary software and packages required to run SigProfilerSimulator. + +---------- + + +## Prerequisites ## + +- [Python][1] version >= 3.9 +- [SigProfilerMatrixGenerator][2] with a downloaded reference genome +- Other dependencies are installed automatically during package installation + +## Installation ## + +SigProfilerSimulator can be executed on any Windows/macOS/Unix system. First follow the [SigProfilerMatrixGenerator][2] guide for installing `Python` and `pip`. Next, follow the instructions below for the latest stable release or the current GitHub version. + +### Installation with `pip` ### + +Install the latest `SigProfilerSimulator` PyPI version using `pip`: +``` +$ pip install SigProfilerSimulator +``` + +To upgrade an existing installation to the most recent version: +``` +$ pip install SigProfilerSimulator --upgrade +``` + +### Install specific GitHub Release ### + +First, download the [zip file][3] or clone the GitHub repository: +``` +$ git clone https://github.com/SigProfilerSuite/SigProfilerSimulator.git +``` + +Next, enter the downloaded directory and install the package: +``` +$ cd SigProfilerSimulator +$ pip install . +``` + +## Download Reference Genome ## + +SigProfilerSimulator requires a reference genome to perform simulations. To install the reference genome/s, use [SigProfilerMatrixGenerator][2]. + +The last PyPI [SigProfilerMatrixGenerator][2] version is installed with SigProfilerSimulator by default. Install your desired reference genome from the command line/terminal as follows. + +### Installation from command line ### + +``` +$ SigProfilerMatrixGenerator install GRCh37 +``` + +### Installation from Python terminal ### + +``` python +$ python +>>> from SigProfilerMatrixGenerator import install as genInstall +>>> genInstall.install('GRCh37', rsync=False, bash=True) +``` + +If you have a firewall on your server, you may need to install `rsync` and use the `rsync=True` parameter. If bash is not available, use `bash=False`. + +For a full list of supported reference genomes, refer to the [Supported Genomes][4] section. + + [1]: https://www.python.org/downloads + [2]: https://sigprofilersuite.github.io/SigProfilerMatrixGenerator/ + [3]: https://github.com/SigProfilerSuite/SigProfilerSimulator/releases + [4]: https://sigprofilersuite.github.io/SigProfilerSimulator/6_supported_genomes.html diff --git a/docs/2_quick_start_example.md b/docs/2_quick_start_example.md new file mode 100644 index 0000000..666602d --- /dev/null +++ b/docs/2_quick_start_example.md @@ -0,0 +1,54 @@ +# Quick Start Example + + +---------- + + +This section provides a minimal example to get started with SigProfilerSimulator. The following example generates 100 simulations from a VCF input using the GRCh37 reference genome and the SBS-96 context. + +---------- + +## Prerequisites ## + +This tutorial requires that you have completed all steps in the [installation guide][1], specifically: + +- Installed SigProfilerSimulator +- Downloaded the **GRCh37** reference genome using [SigProfilerMatrixGenerator][2] + +## Input data ## + +SigProfilerSimulator accepts four input file formats: VCF, MAF, simple text file, and ICGC format. Input files must be placed in an `input/` subdirectory within the project folder: + +``` +path/to/project/ +└── input/ + ├── sample1.vcf + └── sample2.vcf +``` + +## Running SigProfilerSimulator ## + +Start a Python interactive shell and import SigProfilerSimulator: + +``` python +$ python +>>> from SigProfilerSimulator import SigProfilerSimulator as sigSim +``` + +Run the simulator on your data. **Note**: Update `"path/to/project/"` with the actual path to your project directory. + +``` python +>>> sigSim.SigProfilerSimulator("my_project", "path/to/project/", "GRCh37", + contexts=["96"], simulations=100, chrom_based=True) +``` + +After SigProfilerSimulator has finished, the simulated mutation files will be placed in the `output/` subdirectory of your project folder, organized by context and simulation number. + +## Additional Information ## + +In the above example, unspecified parameters use their default values. All function arguments are described in detail in the [Using the Tool][3] section. For the full list of supported reference genomes, refer to the [Supported Genomes][4] section. + + [1]: https://sigprofilersuite.github.io/SigProfilerSimulator/1_installation.html + [2]: https://sigprofilersuite.github.io/SigProfilerMatrixGenerator/ + [3]: https://sigprofilersuite.github.io/SigProfilerSimulator/4_using_the_tool_input.html + [4]: https://sigprofilersuite.github.io/SigProfilerSimulator/6_supported_genomes.html diff --git a/docs/3_workflow.md b/docs/3_workflow.md new file mode 100644 index 0000000..3b01ac3 --- /dev/null +++ b/docs/3_workflow.md @@ -0,0 +1,37 @@ +# Workflow + + +---------- + + +This section describes the methodology used by SigProfilerSimulator to generate realistic simulations of somatic mutations. + +---------- + +## Overview ## + +SigProfilerSimulator takes real somatic mutations as input and produces simulated samples by randomly redistributing those mutations across the genome. The redistribution is performed in an unbiased manner, preserving three biological properties of the original data: + +- **Sequence context** — each mutation is placed in a position with the same local nucleotide context as the original +- **Transcriptional strand bias** — the strand orientation of each mutation relative to the direction of transcription is maintained +- **Chromosomal mutation burden** — the number of mutations assigned to each chromosome reflects the same proportional distribution as the input + +This approach ensures that simulated samples are realistic null hypothesis models of the original mutation landscape, suitable as background distributions for downstream statistical analyses. + +## Simulation Procedure ## + +For each simulation, SigProfilerSimulator performs the following steps: + +1. **Input parsing** — the input file (VCF, MAF, simple text, or ICGC format) is parsed and mutations are catalogued by sample, chromosome, and mutational context. + +2. **Context distribution** — the genomic distribution of available positions for each mutation context is computed from the reference genome. If a BED file or exome restriction is provided, only the targeted regions are considered. + +3. **Random placement** — each mutation is randomly assigned to a new position selected from the pool of positions sharing its original context. The number of mutations per chromosome is preserved by sampling within each chromosome independently. + +4. **Output generation** — simulated mutations are written to MAF or VCF files (one per simulation). Parallel execution across chromosomes accelerates this step for large genomes. + +## Use With SigProfilerClusters ## + +Simulated datasets produced by SigProfilerSimulator are directly used as the background model in [SigProfilerClusters][1]. For this use case, the `chrom_based=True` parameter must be set to ensure per-chromosome normalisation of mutation burden. + + [1]: https://sigprofilersuite.github.io/SigProfilerClusters/ diff --git a/docs/4_using_the_tool_input.md b/docs/4_using_the_tool_input.md new file mode 100644 index 0000000..1c15cca --- /dev/null +++ b/docs/4_using_the_tool_input.md @@ -0,0 +1,80 @@ +# Using SigProfilerSimulator - Input + + +---------- + + +This section describes SigProfilerSimulator's main function and all available parameters. + +---------- + +## Function ## + +The main function in SigProfilerSimulator is `SigProfilerSimulator`. It randomizes the position of each somatic mutation across the genome while preserving the sequence context, transcriptional strand bias, and chromosomal mutational burden of the input data. + +### Input files ### + +SigProfilerSimulator accepts four input file formats: + +- **VCF** — one file per sample. +- **MAF** — standard Mutation Annotation Format file. +- **Simple text file** — tab-delimited plain text format as described in [SigProfilerMatrixGenerator][1]. +- **ICGC Format** — ICGC simple somatic mutation format. + +Input files must be placed in an `input/` subdirectory within the project folder. + +### Running the function ### + +First, start a Python interactive shell and import SigProfilerSimulator: + +``` python +$ python +>>> from SigProfilerSimulator import SigProfilerSimulator as sigSim +``` + +Then call the function with the required parameters: + +``` python +>>> sigSim.SigProfilerSimulator(project, project_path, genome, contexts) +``` + +### Required parameters ### + +| Parameter | Variable Type | Parameter Description | +|-----------|---------------|-----------------------| +| `project` | String | Unique name for the given project | +| `project_path` | String | Path to the project directory. The `input/` subfolder containing the mutation files must exist within this path | +| `genome` | String | Reference genome to use. Must be installed using [SigProfilerMatrixGenerator][1]. Supported genomes: GRCh37, GRCh38, mm9, mm10, rn6, yeast | +| `contexts` | List of Strings | Mutational contexts to simulate. Must be provided as a list (e.g., `["96"]`, `["96", "ID"]`). See the full list of supported contexts below | + +### Optional parameters ### + +| Parameter | Variable Type | Parameter Description | +|-----------|---------------|-----------------------| +| `simulations` | Integer | Number of simulations to generate. Default: `1` | +| `exome` | Boolean | Restrict simulations to exome regions. Default: `None` (whole genome) | +| `chrom_based` | Boolean | Normalize mutation burden on a per-chromosome basis. Recommended when using the output as background model for [SigProfilerClusters][2]. Default: `False` | +| `gender` | String | Determines whether the Y chromosome is included. Accepted values: `"female"` (default, Y excluded), `"male"` (Y included) | +| `bed_file` | String | Path to a BED file to restrict simulations to user-defined genomic regions. Default: `None` | +| `vcf` | Boolean | Output simulated mutations as VCF files. When `False`, output is in MAF format. Default: `False` | +| `seqInfo` | Boolean | Save the sequence context information for each simulated mutation. Default: `False` | +| `seed_file` | String | Path to a file containing seeds for reproducible simulations. Default: `None` | +| `noisePoisson` | Boolean | Add Poisson-distributed noise to the simulated mutations. Default: `False` | +| `noiseUniform` | Float | Add uniform noise to the simulated mutations. Default: `0` | +| `spacing` | Integer | Minimum spacing (in bp) enforced between simulated mutations. Default: `1` | +| `cushion` | Integer | Cushion (in bp) around the edges of BED file regions within which mutations will not be placed. Default: `100` | +| `overlap` | Boolean | Allow simulated mutations to overlap. Default: `False` | +| `updating` | Boolean | Update mutation types during simulation. Default: `False` | +| `region` | String | Restrict simulations to a single chromosome (e.g., `"1"`). Default: `None` | +| `mask` | String | Path to a mask file to exclude specific genomic regions from simulations. Default: `None` | + +### Supported contexts ### + +| Mutation type | Accepted context values | +|---------------|------------------------| +| Single Base Substitutions (SBS) | `"6"`, `"24"`, `"96"`, `"288"`, `"384"`, `"1536"`, `"6144"` | +| Insertions and Deletions (ID) | `"ID"`, `"ID415"` | +| Double Base Substitutions (DBS) | `"DBS"`, `"DBS186"` | + + [1]: https://sigprofilersuite.github.io/SigProfilerMatrixGenerator/ + [2]: https://sigprofilersuite.github.io/SigProfilerClusters/ diff --git a/docs/5_using_the_tool_output.md b/docs/5_using_the_tool_output.md new file mode 100644 index 0000000..54057de --- /dev/null +++ b/docs/5_using_the_tool_output.md @@ -0,0 +1,98 @@ +# Using SigProfilerSimulator - Output + + +---------- + + +This section describes the output files and directories produced by SigProfilerSimulator. All results are written under the project directory specified in `project_path`. + +---------- + +## Output Overview ## + +After a successful run, the project directory contains the following structure: + +``` +[project_path]/ +├── input/ +│ └── [input mutation files] +├── output/ +│ └── simulations/ +│ └── [project]_simulations_[genome]_[contexts]/ +│ ├── 1.maf +│ ├── 2.maf +│ └── ... +└── logs/ + ├── SigProfilerSimulator_[project]_[genome]_[date].err + └── SigProfilerSimulator_[project]_[genome]_[date].out +``` + +The output subdirectory name includes a suffix depending on the simulation scope: + +| Condition | Output subdirectory suffix | +|-----------|---------------------------| +| Whole genome (default) | `[project]_simulations_[genome]_[contexts]/` | +| BED file restricted (`bed_file`) | `[project]_simulations_[genome]_[contexts]_BED/` | +| Exome restricted (`exome=True`) | `[project]_simulations_[genome]_[contexts]_exome/` | + +## Simulation Files ## + +### MAF format (default) ### + +When `vcf=False` (default), one MAF file is produced per simulation, named `1.maf`, `2.maf`, etc. Each file contains all samples for that simulation iteration. + +MAF files contain the following 17 columns: + +| Column | Description | +|--------|-------------| +| `Hugo_symbol` | Gene symbol | +| `Entrez_gene_ID` | Entrez gene identifier | +| `Center` | Sequencing center | +| `Genome` | Reference genome used | +| `Chrom` | Chromosome | +| `Start_position` | Mutation start position (1-based) | +| `End_position` | Mutation end position (1-based) | +| `Strand` | Genomic strand | +| `Variant_Classification` | Mutation functional class | +| `Variant_Type` | Mutation type (SNP, INS, DEL) | +| `Reference_Allele` | Reference base(s) | +| `Tumor_Seq_Allele1` | First tumor allele | +| `Tumor_Seq_Allele2` | Second tumor allele | +| `dbSNP_RS` | dbSNP RS identifier | +| `dbSNP_Val_Status` | dbSNP validation status | +| `Tumor_Sample_Barcode` | Sample identifier | +| `matGenClass` | Mutational context classification | + +### VCF format ### + +When `vcf=True`, a separate subdirectory is created per sample within the output folder. Each subdirectory contains one VCF file per simulation: + +``` +[project]_simulations_[genome]_[contexts]/ +├── [sample_1]/ +│ ├── [sample_1]_1.vcf +│ ├── [sample_1]_2.vcf +│ └── ... +└── [sample_2]/ + ├── [sample_2]_1.vcf + └── ... +``` + +## Log Files ## + +Two log files are saved per run in the `logs/` subdirectory: + +| File | Description | +|------|-------------| +| `SigProfilerSimulator_[project]_[genome]_[date].out` | Progress checkpoints and run parameters | +| `SigProfilerSimulator_[project]_[genome]_[date].err` | Error messages and warnings | + +## Sequence Context Files ## + +When `seqInfo=True`, additional files containing the sequence context of each simulated mutation are saved under: + +``` +[project_path]/output/vcf_files/simulations/[context]/ +``` + +One file is saved per sample, chromosome, and simulation: `[sample]_[chrom]_seqinfo_[n].txt`. diff --git a/docs/6_supported_genomes.md b/docs/6_supported_genomes.md new file mode 100644 index 0000000..a016765 --- /dev/null +++ b/docs/6_supported_genomes.md @@ -0,0 +1,41 @@ +# Supported Genomes + + +---------- + + +This section lists all reference genomes currently supported by SigProfilerSimulator. Reference genomes must be installed using [SigProfilerMatrixGenerator][1] before running simulations. + +---------- + +## Available Reference Genomes ## + +| Genome ID | Assembly | Species | Source | Last updated | +|-----------|----------|---------|--------|--------------| +| `GRCh38` | GRCh38.p12 (GCA_000001405.27) | *Homo sapiens* | ENSEMBL v93.38 | January 2018 | +| `GRCh37` | GRCh37.p13 (GCA_000001405.14) | *Homo sapiens* | ENSEMBL v93.37 | September 2013 | +| `mm10` | GRCm38.p6 (GCA_000001635.8) | *Mus musculus* | ENSEMBL v93.38 | March 2018 | +| `mm9` | GRCm37 (GCA_000001635.18) | *Mus musculus* | ENSEMBL release 67 | March 2012 | +| `rn6` | Rnor_6.0 (GCA_000001895.4) | *Rattus norvegicus* | ENSEMBL v96.6 | January 2017 | +| `yeast` | R64-2-1 | *Saccharomyces cerevisiae* S288C | NCBI | November 2014 | + +## Installation ## + +Install a reference genome from the command line: + +``` +$ SigProfilerMatrixGenerator install GRCh37 +``` + +Or from a Python terminal: + +``` python +$ python +>>> from SigProfilerMatrixGenerator import install as genInstall +>>> genInstall.install('GRCh37', rsync=False, bash=True) +``` + +Multiple genomes can be installed independently. For full installation details, refer to the [Installation][2] section. + + [1]: https://sigprofilersuite.github.io/SigProfilerMatrixGenerator/ + [2]: https://sigprofilersuite.github.io/SigProfilerSimulator/1_installation.html diff --git a/docs/assets/images/SigProfilerSimulator.png b/docs/assets/images/SigProfilerSimulator.png new file mode 100644 index 0000000..dd21b00 Binary files /dev/null and b/docs/assets/images/SigProfilerSimulator.png differ diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css new file mode 100644 index 0000000..8b3e941 --- /dev/null +++ b/docs/assets/stylesheets/extra.css @@ -0,0 +1,29 @@ +:root { + --md-text-font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; +} + +.md-main__inner { + max-width: 80%; +} + +.md-grid { + max-width: 80%; +} + + +/* Improve readability of long tables from OSF wiki. */ +.md-typeset table:not([class]) { + display: block; + overflow-x: auto; + white-space: nowrap; +} + +/* Make big OSF screenshots feel less cramped. */ +.md-typeset img { + border-radius: 8px; +} + +p { + text-align: justify +} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..60df180 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,31 @@ +# SigProfilerSimulator + +![Logo](assets/images/SigProfilerSimulator.png) + +---------- + +**SigProfilerSimulator** is a Python framework for generating realistic simulations of mutational signatures in cancer genomes. The tool can simulate single base substitutions (SBS), double base substitutions (DBS), and insertions/deletions (ID) across complete genomes or user-defined genomic regions, using an unbiased random distribution methodology that preserves the sequence context, transcriptional strand bias, and chromosomal mutational burden of the input data. + +Simulated datasets are widely used as background models for downstream statistical analyses and hypothesis testing, including clustered mutation detection with [SigProfilerClusters][1]. + +**SigProfilerSimulator** makes use of [SigProfilerMatrixGenerator][2] and [SigProfilerPlotting][3], enabling seamless integration with other tools in the SigProfiler suite. + +The SigProfilerSimulator library is available on [GitHub](https://github.com/SigProfilerSuite/SigProfilerSimulator) and [PyPI](https://pypi.org/project/SigProfilerSimulator). + +---------- + +### Citation + +Bergstrom EN, Barnes M, Martincorena I, Alexandrov LB. Generating realistic null hypothesis of cancer mutational landscapes using SigProfilerSimulator. *BMC Bioinformatics*. 2020;21(1):438. [https://doi.org/10.1186/s12859-020-03772-3](https://doi.org/10.1186/s12859-020-03772-3) + +### License + +This software is copyrighted © 2020 by Erik Bergstrom, Alexandrov Lab. SigProfilerSimulator is distributed under the terms of the GNU General Public License. The software is provided in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +### Contact + +For questions, support requests, or bug reports, please contact the SigProfilerSuite team via GitHub [issues](https://github.com/SigProfilerSuite/SigProfilerSimulator/issues) or by email at [contact@sigprofilersuite.org](mailto:contact@sigprofilersuite.org). + + [1]: https://sigprofilersuite.github.io/SigProfilerClusters/ + [2]: https://sigprofilersuite.github.io/SigProfilerMatrixGenerator/ + [3]: https://github.com/SigProfilerSuite/SigProfilerPlotting diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..e888929 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,62 @@ +site_name: SigProfilerSimulator +repo_name: SigProfilerSuite/SigProfilerSimulator +repo_url: https://github.com/SigProfilerSuite/SigProfilerSimulator + +docs_dir: docs +site_url: https://sigprofilersuite.github.io/SigProfilerSimulator/ + +use_directory_urls: false + +theme: + name: material + features: + - navigation.instant + - navigation.tracking + - navigation.tabs + - navigation.sections + - navigation.top + - toc.follow + - content.code.copy + palette: + - scheme: default + primary: indigo + accent: indigo + - scheme: slate + primary: indigo + accent: indigo + toggle: + icon: material/weather-night + name: Switch to dark mode + +nav: + - Home: index.md + - Getting Started: + - '1. Installation': '1_installation.md' + - '2. Quick Start Example': '2_quick_start_example.md' + - How It Works: + - '3. Workflow': '3_workflow.md' + - Using The Tool: + - '4. Using the Tool - Input': '4_using_the_tool_input.md' + - '5. Using the Tool - Output': '5_using_the_tool_output.md' + - Reference: + - '6. Supported Genomes': '6_supported_genomes.md' + +plugins: + - search + +markdown_extensions: + - toc: + permalink: true + - attr_list + - md_in_html + - admonition + - pymdownx.superfences + - pymdownx.details + - pymdownx.tabbed: + alternate_style: true + +extra_css: + - assets/stylesheets/extra.css + +hooks: + - mkdocs_hooks.py diff --git a/mkdocs_hooks.py b/mkdocs_hooks.py new file mode 100644 index 0000000..9c8e57b --- /dev/null +++ b/mkdocs_hooks.py @@ -0,0 +1,13 @@ +import re + + +_OSF_TOC_RE = re.compile(r"^\s*@\[toc\]\([^)]+\)\s*$", re.IGNORECASE) + + +def on_page_markdown(markdown: str, /, *, page, config, files): + # OSF wiki pages contain a non-standard marker like `@[toc](Sections)` which MkDocs + # otherwise renders as a broken relative link. We keep the source files unchanged + # (to match OSF) and strip the marker at build time. + lines = markdown.splitlines() + filtered = [line for line in lines if not _OSF_TOC_RE.match(line)] + return "\n".join(filtered) + ("\n" if markdown.endswith("\n") else "")