{"id":20651362,"url":"https://github.com/rapidjs-org/documenting","last_synced_at":"2026-01-22T07:33:50.728Z","repository":{"id":255440406,"uuid":"805112746","full_name":"rapidjs-org/documenting","owner":"rapidjs-org","description":"Headless Markdown documentation framework (push or pull) – with syntax extensions for software documentation.","archived":false,"fork":false,"pushed_at":"2024-10-09T17:00:31.000Z","size":174,"stargazers_count":1,"open_issues_count":9,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-23T13:00:58.186Z","etag":null,"topics":["documentation","documenting","framework","javascript","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rapidjs-org.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-05-23T22:56:24.000Z","updated_at":"2024-10-09T16:59:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"07d051f2-e3de-44e8-be98-01e60fa9d3ba","html_url":"https://github.com/rapidjs-org/documenting","commit_stats":null,"previous_names":["rapidjs-org/documenting"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/rapidjs-org/documenting","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rapidjs-org%2Fdocumenting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rapidjs-org%2Fdocumenting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rapidjs-org%2Fdocumenting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rapidjs-org%2Fdocumenting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rapidjs-org","download_url":"https://codeload.github.com/rapidjs-org/documenting/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rapidjs-org%2Fdocumenting/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28658107,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["documentation","documenting","framework","javascript","typescript"],"created_at":"2024-11-16T17:27:10.004Z","updated_at":"2026-01-22T07:33:50.723Z","avatar_url":"https://github.com/rapidjs-org.png","language":"JavaScript","readme":"# rJS Documenting\n\nHeadless Markdown documentation framework (push or pull) – with syntax extensions for software documentation.\n\n``` cli\nnpm install -D @rapidjs.org/documenting\n```\n\nDocumentation sites represent a content-heavy application type. It is thus common practice to maintain Markdown files that are eventually rendered to HTML for display. rJS Documenting is a powerful Markdown documentation framework with a headless API. The framework embodies two components: The essential component is a service agent to regularly render files from a designated source to a directory public to the web. This way, documentation files can be requested like ordinary files and used in an unopinionated way. The second (optional) component is a lean client module that can be loaded from a displaying site context. The client module simplifies access of the rendered documentation resources and the overall documentation structure.\n\n1. [Renderer](#renderer)\n1. [Agents](#agents)\n1. [Client](#client)\n\n## Renderer\n\nThe fundamental Markdown to HTML transpiler used with rJS Documenting is [markdown-it](https://github.com/markdown-it/markdown-it). It is abstracted by the `Renderer` class that can be configured just as *markdown-it* instances. Furthermore, extra rules can be disabled if desired. The renderer is activated from within individual agents.\n\n``` ts\nclass Renderer {\n  constructor(\n    configuration: markdownit.PresetName|markdownit.Options = \"commonmark\",\n    enableExtraRules: boolean = true\n  );\n}\n```\n\nUpon activation, the renderer reads the sourced file hierarchy and replicates it in a designated target directory. In addition, a table of contents file is generated as a JSON file (`toc.json`). In order to enforce a certain order in the filesystem, file names are supposed to be preceeded by numbers (`\u003cn\u003e. \u003cfile-name\u003e`). Such numeric indicators are stripped from rendered file names and identifiers. Also, files named `index` are always interpreted as the first subsection. In addition to the bare identifier, the `toc.json` file enriches the entries with a caption. If the entry is a Markdown file with a leading heading, the heading is used as the caption. Otherwise, the caption is the capitalised file name with spaces substituted dashes and underscores.\n\n```\n└─ /documentation\n  ├─ 1. basics\n  │  ├─ _assets\n  │  │  └─ img.png\n  │  ├─ 1. usage.md\n  │  ├─ index.md\n  │  └─ 2. commands.md\n  └─ 2. further-reading.md\n```\n\n```\n└─ /public/web\n  ├─ basics\n  │  ├─ commands.html\n  │  ├─ index.html\n  │  └─ usage.html\n  └─ further-reading.html\n```\n\n``` json\n[\n  {\n    \"title\": \"basics\",\n    \"caption\": \"Basics\",\n    \"sections\": [\n      {\n        \"title\": \"index\",\n        \"caption\": \"Basics\"\n      },\n      {\n        \"title\": \"usage\",\n        \"caption\": \"Usage\"\n      }\n      {\n        \"title\": \"commands\",\n        \"caption\": \"Commands List\"\n      }\n    ],\n  },\n  {\n    \"title\": \"further-reading\",\n    \"caption\": \"Further Reading\"\n  }\n]\n```\n\n``` ts\ninterface ISection {\n  title: string;\n  caption: string;\n  sections?: ISection[];\n}\n\ntype TTableOfContents = ISection[]\n```\n\n### Working with Assets\n\nrJS Documenting enables use of assets – like images or videos – in an opinionated way: Within the Markdown source directory, assets are supposed to be stored in a directories named `_assets`. From there, they can be relatively referenced as usual. Upon render, files are automatically copied and accessible from the client module.\n\n### Extra Rules\n\nExtra rules are an optional addition to ubiquitous Markdown syntax defined by rJS Documenting. They are designed after common elements used among software documentations. Extra rules result in a specific HTML element structure, and the parent element is assigned a descriptive class.\n\n#### Syntax Definition\n\nSyntax definitions – as used in ([MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#syntax)) – represent a specific type of fenced code block. Therefore, rJS Documenting defines the fenced code language `syntax`.\n\n```` md\n``` syntax\nhelloWorld(): string\n```\n````\n\n``` html\n\u003cdiv class=\"rJS__documenting--syntax\"\u003e\n  \u003ccode\u003e\n    helloWorld(): string\n  \u003c/code\u003e\n\u003c/div\u003e\n```\n\n#### Parameter Definition\n\nParameter definitions are a common supplement to syntax definitions. rJS Documenting defines a superordinate parameter definitions block rule. Parameter definitions are two column tables, but with a token instead of header information.\n\n``` md\n[ parameters ]\n| argument 1 | Example argument at pos 0. |\n| `arg2` | Example argument at pos 1. |\n```\n\n``` html\n\u003ctable class=\"rJS__documenting--parameter\"\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ccode\u003eargument 1\u003c/code\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cp\u003eExample argument at pos 0.\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003ccode\u003earg2\u003c/code\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cp\u003eExample argument at pos 1.\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n```\n\n## Agents\n\nrJS Documenting provides several agents to maintain an up to date documentation. The abstract distinction is between the orthogonal update strategies – push and pull. A pull agent periodically polls the source for updates in order to re-render the documentation. A push agent, on the other hand, waits for external events to trigger a re-rendering of the sourced Markdown files. Push agents are preferrable for documentation sites that are ought to reflect updates to the source instantly. Moreover, rJS Documenting supports different types of sources that serve the raw Markdown documentation files in a hierarchically fashion.\n\n``` ts\nabstract class Agent {\n  start(): Promise\u003cvoid\u003e;    // Method to be called for starting the agent\n}\n```\n\n### Filesystem Pull Agent\n\nThe simplest way to implement rJS Documenting is by using the Filesystem Pull Agent. This agent pulls from a directory on local disc in a specific interval.\n\n``` ts\nclass FSPullAgent extends Agent {\n  constructor(options: {\n    targetDirPath: string;  // Path to target directory\n    sourceDirPath: string;  // Path to source directory\n\t\tinterval?: number;      // Pull interval in ms\n  }, renderer?: Renderer)\n}\n```\n\n\u003e By default, pull agents request request updates every 12 hours.\n\n### GitHub Pull Agent\n\nInstead of pulling from local disc, the GitHub Pull Agent bases on a specified GitHub repository as source.\n\n``` ts\nclass GHPullAgent extends Agent  {\n  constructor(options: {\n    targetDirPath: string;  // Path to target file directory\n    account: string;        // GitHub user (or organisation) name\n    repository: string;     // GitHub repository name\n    rootPath?: string;      // Relative path to root directory in repository  (\".\" by default)\n    ref?: string;           // Repository reference ('main' by default)\n    auth?: string;          // GitHub API authentication token (if is private repository)\n\t\tinterval?: number;      // Pull interval in ms\n  }, renderer?: Renderer)\n}\n```\n\n### GitHub Push Agent\n\nOpen Source projects commonly provide the documentation as a meta project in a GitHub repository. The GitHub Push Agent listens for any directed webhook event triggered in a specified GitHub repository.\n\n\u003e Push encoding is supposed to be `application/json`.\n\n``` ts\nclass GHPushAgent extends Agent  {\n  constructor(options: {\n    targetDirPath: string;  // Path to target file directory\n    account: string;        // GitHub user (or organisation) name\n    repository: string;     // GitHub repository name\n    rootPath?: string;      // Relative path to root directory in repository  (\".\" by default)\n    ref?: string;           // Repository reference ('main' by default)\n    auth?: string;          // GitHub API authentication token (if is private repository)\n    secret?: string;        // GitHub webhook secret\n    port?: number;          // Port to listen for events on with HTTP (6001 by default)\n  }, renderer?: Renderer)\n}\n```\n\n\u003e A push agent filters requests to match the pathname `/`, `/documentation`, or `/docs`.\n\n### Example\n\n``` js\nnew GHPushAgent({\n    targetDirPath: \"./public/docs/\",\n    account: \"rapidjs-org\",\n    repository: \"documenting\",\n    secret: \"X5QgcpFc1a\"\n})\n.start()\n.then(() =\u003e console.log(\"Docs agent running…\"));\n```\n\n## Client\n\n``` html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/@rapidjs.org/documenting@latest/build/client/rjs.documenting.js\"\u003e\u003c/script\u003e\n```\n\nAs pointed out, rendered documentation files are supposed to reside in a public web directory. The documentation can inherently be presented based on those static files in a preferred way. However, the provided rJS Documenting client module helps with working with the documentation files through a simple API.\n\n``` ts\nclass rJS__documenting.Client {\n  data: TTableOfContents\n\n  constructor(\n    tocElementReference: HTMLElement,       // Table of contents parent element (DOM element or query string)\n    contentElementReference: HTMLElement,   // Article content parent element (DOM element or query string)\n    docsRootUrl: string = \"/docs\"           // Pathname of (render) target root directory on public host\n  )\n\n  // Load the table of contents\n  async loadTableOfContents(): void // (alias loadTOC())\n\n  // Load an article given an identifier nesting (e.g. [ \"basics\", \"usage\" ])\n  async loadSection(\n    nesting: string[] = \"index\",\n    muteEvent: boolean = false  // Whether to not emit the 'load' event\n  ): ISection \u0026 {\n    nesting: string[];\n    parent: ISection;\n    next?: ISection;\n    previous?: ISection;\n  } // (alias load())\n\n  // Bind an event listener\n  on(event: string, handlerCb: (...args) =\u003e void): this\n}\n```\n\n### Events\n\n#### `load`\n\nThe load event is invoked each time a section was attempted to be loaded. If an error has occurred, it is passed as the first argument to the handler. Subsequently, the loaded section object (`ISection`), and – if exists – a reference to the related anchor element in the table of contents element are passed.\n\n#### `ready`\n\nThe ready event is invoked once when the documentation data was fetched and processed. It is initiated from the constructor call of the `Client` class.\n\n### Example\n\n``` js\naddEventListener(\"DOMContentLoaded\", () =\u003e {\n  const docsClient = new rJS__documenting.Client(\n    \"#content\",\n    document.querySelector(\"#navigation\")\n  )\n  .on(\"load\", (err, newSection) =\u003e {\n    if(err) throw err;\n\n    window.history.pushState(\n      newSection.nesting, null,\n      `${document.location.pathname}?p=${newSection.nesting.join(\":\")}`\n    );\n  })\n  .on(\"ready\", client =\u003e {\n    client.loadTableOfContents();\n    client.loadSection(\n      (new URLSearchParams(window.location.search).get(\"p\") ?? \"\")\n      .split(/:/g)\n    );\n  });\n\n  addEventListener(\"popstate\", e =\u003e docsClient.loadSection(e.state, true));\n});\n```\n\n##\n\n\u003csub\u003e© Thassilo Martin Schiepanski\u003c/sub\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frapidjs-org%2Fdocumenting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frapidjs-org%2Fdocumenting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frapidjs-org%2Fdocumenting/lists"}