Enhance documentation structure and content across multiple guides

- Added frontmatter to various markdown files for better metadata handling.
- Updated site URLs in configuration files for consistency.
- Improved content organization and clarity in getting started, server extension, and client addon guides.
This commit is contained in:
Jacob Schmidt 2026-05-16 10:33:17 -05:00
parent 9ab4ff9fd9
commit a4d5c2fd4d
37 changed files with 325 additions and 170 deletions

View File

@ -29,7 +29,7 @@ request and response chunks through the extension transport module.
### Client Addons ### Client Addons
Client addons live under `arma/client/addons`. They own local player UX, Client addons live under `arma/client/addons`. They own local player UX,
keybinds, browser UI dialogs, and UI-to-SQF event handling. When a client needs` keybinds, browser UI dialogs, and UI-to-SQF event handling. When a client needs
durable or authoritative state, it routes work to the matching server addon durable or authoritative state, it routes work to the matching server addon
instead of touching persistence directly. instead of touching persistence directly.

View File

@ -4,7 +4,7 @@ const repoUrl =
const repoBranch = process.env.DOCS_REPO_BRANCH || 'master'; const repoBranch = process.env.DOCS_REPO_BRANCH || 'master';
const siteUrl = const siteUrl =
process.env.DOCS_SITE_URL || process.env.DOCS_SITE_URL ||
'https://innovativedevsolutions.github.io'; 'https://innovativedevsolutions.github.io/forge';
export default defineAppConfig({ export default defineAppConfig({
site: { site: {

View File

@ -1,6 +1,7 @@
# Getting Started ---
title: Getting Started
Use this section as the main entry point for the Forge framework. description: Use this section as the main entry point for the Forge framework.
---
Forge combines: Forge combines:

View File

@ -1,8 +1,7 @@
# Framework Architecture ---
title: "Framework Architecture"
Forge is organized around domain modules. A domain usually has SQF addon description: "Forge is organized around domain modules. A domain usually has SQF addon entry points, Rust models, repository traits, service logic, extension command handlers, and optional browser UI."
entry points, Rust models, repository traits, service logic, extension command ---
handlers, and optional browser UI.
## Runtime Flow ## Runtime Flow
@ -29,7 +28,7 @@ request and response chunks through the extension transport module.
### Client Addons ### Client Addons
Client addons live under `arma/client/addons`. They own local player UX, Client addons live under `arma/client/addons`. They own local player UX,
keybinds, browser UI dialogs, and UI-to-SQF event handling. When a client needs` keybinds, browser UI dialogs, and UI-to-SQF event handling. When a client needs
durable or authoritative state, it routes work to the matching server addon durable or authoritative state, it routes work to the matching server addon
instead of touching persistence directly. instead of touching persistence directly.

View File

@ -1,6 +1,7 @@
# Module Reference ---
title: "Module Reference"
This reference lists the main Forge modules and where each layer lives. description: "This reference lists the main Forge modules and where each layer lives."
---
## Directory Map ## Directory Map

View File

@ -1,6 +1,7 @@
# Development Guide ---
title: "Development Guide"
This guide covers the usual path for adding or changing a Forge module. description: "This guide covers the usual path for adding or changing a Forge module."
---
## Local Checks ## Local Checks

View File

@ -1,8 +1,7 @@
# SurrealDB Setup ---
title: "SurrealDB Setup"
Forge uses SurrealDB for durable storage. The Rust server extension connects to description: "Forge uses SurrealDB for durable storage. The Rust server extension connects to SurrealDB on startup and applies Forge schema modules automatically, so setup comes down to running a reachable database and matching the Forge config."
SurrealDB on startup and applies Forge schema modules automatically, so setup ---
comes down to running a reachable database and matching the Forge config.
## Choose the Right Path ## Choose the Right Path
@ -94,9 +93,9 @@ or live server and you are not changing Forge source code.
Official SurrealDB resources: Official SurrealDB resources:
- [Surrealist installation](https://surrealdb.com/docs/explore/surrealist/installation) - [Surrealist installation](https://surrealdb.com/docs/surrealist/installation)
- [Surrealist web app](https://app.surrealdb.com) - [Surrealist web app](https://app.surrealdb.com)
- [Surrealist local database serving](https://surrealdb.com/docs/explore/surrealist/concepts/local-database-serving) - [Surrealist local database serving](https://surrealdb.com/docs/surrealist/concepts/local-database-serving)
Recommended approach: Recommended approach:

View File

@ -1,8 +1,7 @@
# Forge Server Extension ---
title: "Forge Server Extension"
Forge Server is an arma-rs extension for Arma 3 server-side persistence and description: "Forge Server is an arma-rs extension for Arma 3 server-side persistence and domain services. It exposes game-facing commands and stores durable state in SurrealDB."
domain services. It exposes game-facing commands and stores durable state in ---
SurrealDB.
## Architecture ## Architecture

View File

@ -1,8 +1,7 @@
# Forge Server API Reference ---
title: "Forge Server API Reference"
The Forge server extension exposes domain-oriented commands through description: "The Forge server extension exposes domain-oriented commands through `callExtension`. Persistent data is stored through the configured SurrealDB connection and schema modules."
`callExtension`. Persistent data is stored through the configured SurrealDB ---
connection and schema modules.
## Core Commands ## Core Commands
@ -39,6 +38,7 @@ needed by `forge_server_addons_extension_fnc_extCall`.
- [Actor](/server-modules/actor) - [Actor](/server-modules/actor)
- [Bank](/server-modules/bank) - [Bank](/server-modules/bank)
- [CAD](/server-modules/cad) - [CAD](/server-modules/cad)
- [Economy](/server-modules/economy)
- [Garage](/server-modules/garage) - [Garage](/server-modules/garage)
- [Locker](/server-modules/locker) - [Locker](/server-modules/locker)
- [Organization](/server-modules/organization) - [Organization](/server-modules/organization)

View File

@ -1,7 +1,7 @@
# Forge Server Usage Examples ---
title: "Forge Server Usage Examples"
These examples use the domain command surface exposed by the extension. description: "These examples use the domain command surface exposed by the extension. Persistence is handled by the server through SurrealDB."
Persistence is handled by the server through SurrealDB. ---
## Status Check ## Status Check

View File

@ -1,9 +1,7 @@
# Forge Server Common ---
title: "Forge Server Common"
## Overview description: "The common addon provides shared SQF utilities used by server-side Forge addons. It contains lightweight helpers only; gameplay domain state belongs in the specific domain addons or the Rust extension."
The common addon provides shared SQF utilities used by server-side Forge ---
addons. It contains lightweight helpers only; gameplay domain state belongs in
the specific domain addons or the Rust extension.
## Dependencies ## Dependencies
- `forge_server_main` - `forge_server_main`

View File

@ -1,6 +1,7 @@
# Server Module Guides ---
title: Server Module Guides
These pages document the authoritative server-side workflows in Forge. description: These pages document the authoritative server-side workflows in Forge.
---
Most modules follow the same shape: Most modules follow the same shape:

View File

@ -1,8 +1,7 @@
# Actor Usage Guide ---
title: "Actor Usage Guide"
The actor module stores persistent player character data: identity, loadout, description: "The actor module stores persistent player character data: identity, loadout, position, direction, stance, contact fields, state, holster status, rank, and organization."
position, direction, stance, contact fields, state, holster status, rank, and ---
organization.
## Storage Model ## Storage Model

View File

@ -1,8 +1,7 @@
# Store Usage Guide ---
title: "Store Usage Guide"
The store module processes checkout requests. It charges a payment source and description: "The store module processes checkout requests. It charges a payment source and grants purchased items to the player locker, virtual arsenal locker, and virtual garage unlocks."
grants purchased items to the player locker, virtual arsenal locker, and ---
virtual garage unlocks.
## Server SQF Module ## Server SQF Module

View File

@ -1,8 +1,7 @@
# Task Usage Guide ---
title: "Task Usage Guide"
The task module stores transient mission task metadata for active server or description: "The task module stores transient mission task metadata for active server or mission lifecycle workflows. SQF still owns Arma-only runtime state such as objects and participants."
mission lifecycle workflows. SQF still owns Arma-only runtime state such as ---
objects and participants.
The server addon at `arma/server/addons/task` also owns task execution: The server addon at `arma/server/addons/task` also owns task execution:
creating BIS tasks, registering task entities, tracking participants, binding creating BIS tasks, registering task entities, tracking participants, binding

View File

@ -1,8 +1,7 @@
# Bank Usage Guide ---
title: "Bank Usage Guide"
The bank module stores player account balances, earnings, PINs, and transaction description: "The bank module stores player account balances, earnings, PINs, and transaction strings. The hot-state API also owns the active banking workflows used by the UI: deposit, withdraw, transfer, checkout charge, and PIN validation."
strings. The hot-state API also owns the active banking workflows used by the ---
UI: deposit, withdraw, transfer, checkout charge, and PIN validation.
## Storage Model ## Storage Model

View File

@ -1,9 +1,7 @@
# CAD Usage Guide ---
title: "CAD Usage Guide"
The CAD module stores transient operational state for dispatch activity, description: "The CAD module stores transient operational state for dispatch activity, assignments, dispatch orders, support requests, group profiles, grouped views, and hydrated UI payloads. CAD state is in-memory and follows the active server or mission lifecycle."
assignments, dispatch orders, support requests, group profiles, grouped views, ---
and hydrated UI payloads. CAD state is in-memory and follows the active server
or mission lifecycle.
## Data Model ## Data Model

View File

@ -1,9 +1,7 @@
# Economy Usage Guide ---
title: "Economy Usage Guide"
The economy server addon owns Arma-world service behavior for fuel, medical, description: "The economy server addon owns Arma-world service behavior for fuel, medical, and repair interactions. It does not own money state. Money mutations go through extension-backed bank and organization hot state before the world effect is applied."
and repair interactions. It does not own money state. Money mutations go ---
through extension-backed bank and organization hot state before the world
effect is applied.
## Dependencies ## Dependencies

View File

@ -1,8 +1,7 @@
# Garage Usage Guide ---
title: "Garage Usage Guide"
The garage module stores physical player vehicles. Each record keeps the description: "The garage module stores physical player vehicles. Each record keeps the vehicle classname, generated plate UUID, fuel, overall damage, and detailed hit point damage."
vehicle classname, generated plate UUID, fuel, overall damage, and detailed hit ---
point damage.
## Storage Model ## Storage Model

View File

@ -1,8 +1,7 @@
# Locker Usage Guide ---
title: "Locker Usage Guide"
The locker module stores physical player inventory items by classname. It is description: "The locker module stores physical player inventory items by classname. It is separate from the virtual arsenal unlock module documented in [Owned Storage Usage Guide](/server-modules/owned-storage)."
separate from the virtual arsenal unlock module documented in ---
[Owned Storage Usage Guide](/server-modules/owned-storage).
## Storage Model ## Storage Model

View File

@ -1,8 +1,7 @@
# Organization Usage Guide ---
title: "Organization Usage Guide"
The organization module stores organization records, members, assets, fleet description: "The organization module stores organization records, members, assets, fleet entries, and credit lines. Durable commands manage persisted records directly. Hot-state commands support the active organization UI workflows."
entries, and credit lines. Durable commands manage persisted records directly. ---
Hot-state commands support the active organization UI workflows.
## Storage Model ## Storage Model

View File

@ -1,8 +1,7 @@
# Owned Storage Usage Guide ---
title: "Owned Storage Usage Guide"
Owned storage covers the `owned:locker` and `owned:garage` extension command description: "Owned storage covers the `owned:locker` and `owned:garage` extension command groups. These modules store unlock lists rather than physical item or vehicle instances."
groups. These modules store unlock lists rather than physical item or vehicle ---
instances.
Use these modules for virtual arsenal and virtual garage unlocks. Use Use these modules for virtual arsenal and virtual garage unlocks. Use
[Locker Usage Guide](/server-modules/locker) and [Locker Usage Guide](/server-modules/locker) and

View File

@ -1,7 +1,7 @@
# Phone Usage Guide ---
title: "Phone Usage Guide"
The phone module stores contacts, messages, and emails for each UID. It is a description: "The phone module stores contacts, messages, and emails for each UID. It is a server-extension state module backed by SurrealDB."
server-extension state module backed by SurrealDB. ---
## Storage Model ## Storage Model

View File

@ -1,8 +1,7 @@
# Client Usage Guide ---
title: "Client Usage Guide"
Forge Client contains the Arma client-side addons that open player interfaces, description: "Forge Client contains the Arma client-side addons that open player interfaces, handle browser events, cache client-visible state, and forward authoritative requests to the server addons."
handle browser events, cache client-visible state, and forward authoritative ---
requests to the server addons.
Use this guide as the entry point for client-side integration. Domain data, Use this guide as the entry point for client-side integration. Domain data,
validation, persistence, rewards, ownership, and checkout behavior remain validation, persistence, rewards, ownership, and checkout behavior remain

View File

@ -1,7 +1,7 @@
# Client Main Usage Guide ---
title: "Client Main Usage Guide"
The client `main` addon provides the shared mod identity, version metadata, description: "The client `main` addon provides the shared mod identity, version metadata, CBA settings, and macro foundation used by the Forge client addons."
CBA settings, and macro foundation used by the Forge client addons. ---
## Purpose ## Purpose

View File

@ -1,8 +1,7 @@
# Client Phone Usage Guide ---
title: "Client Phone Usage Guide"
The client phone addon provides the in-game phone UI for contacts, SMS description: "The client phone addon provides the in-game phone UI for contacts, SMS messages, email, and local utility apps such as notes, calendar events, world clocks, and alarms."
messages, email, and local utility apps such as notes, calendar events, world ---
clocks, and alarms.
## Open Phone UI ## Open Phone UI
@ -26,11 +25,12 @@ Local utility app state is stored in `profileNamespace`:
- alarms - alarms
- theme/preferences - theme/preferences
## Phone Class ## Phone Repository
`forge_client_phone_fnc_initClass` creates `GVAR(PhoneClass)`. `forge_client_phone_fnc_initRepository` creates `GVAR(PhoneRepository)`.
The phone class currently owns local notes, events, and settings helpers. The phone repository owns local notes, events, clocks, alarms, and settings
helpers.
Contacts, messages, and emails continue to use server-backed request/response Contacts, messages, and emails continue to use server-backed request/response
events. events.

View File

@ -1,8 +1,7 @@
# Client Store Usage Guide ---
title: "Client Store Usage Guide"
The client store addon provides the storefront browser UI for catalog browsing, description: "The client store addon provides the storefront browser UI for catalog browsing, category hydration, payment source display, cart handling, and checkout requests."
category hydration, payment source display, cart handling, and checkout ---
requests.
## Open Store UI ## Open Store UI

View File

@ -1,7 +1,7 @@
# Client Common Usage Guide ---
title: "Client Common Usage Guide"
The client `common` addon contains shared browser UI bridge declarations and description: "The client `common` addon contains shared browser UI bridge declarations and common client-side browser integration patterns."
common client-side browser integration patterns. ---
## Purpose ## Purpose

View File

@ -1,8 +1,7 @@
# Client Actor Usage Guide ---
title: "Client Actor Usage Guide"
The client actor addon owns the player interaction menu and client-side actor description: "The client actor addon owns the player interaction menu and client-side actor repository. It is the main launcher for nearby player actions and other Forge client UIs."
repository. It is the main launcher for nearby player actions and other Forge ---
client UIs.
## Open the Actor Menu ## Open the Actor Menu

View File

@ -1,8 +1,7 @@
# Client Bank Usage Guide ---
title: "Client Bank Usage Guide"
The client bank addon opens the bank and ATM browser UI, forwards banking description: "The client bank addon opens the bank and ATM browser UI, forwards banking requests to the server bank addon, and pushes account updates back into the browser."
requests to the server bank addon, and pushes account updates back into the ---
browser.
## Open Bank UI ## Open Bank UI

View File

@ -1,8 +1,7 @@
# Client CAD Usage Guide ---
title: "Client CAD Usage Guide"
The client CAD addon provides the map and dispatch UI for groups, active description: "The client CAD addon provides the map and dispatch UI for groups, active tasks, task assignment, dispatch orders, support requests, and task acknowledge/decline workflows."
tasks, task assignment, dispatch orders, support requests, and task ---
acknowledge/decline workflows.
## Open CAD UI ## Open CAD UI

View File

@ -1,8 +1,7 @@
# Client Garage Usage Guide ---
title: "Client Garage Usage Guide"
The client garage addon provides player vehicle storage UI, vehicle description: "The client garage addon provides player vehicle storage UI, vehicle store/retrieve actions, selected nearby vehicle service requests, vehicle context building, and the virtual garage view."
store/retrieve actions, selected nearby vehicle service requests, vehicle ---
context building, and the virtual garage view.
## Open Garage UI ## Open Garage UI

View File

@ -1,7 +1,7 @@
# Client Locker Usage Guide ---
title: "Client Locker Usage Guide"
The client locker addon manages personal locker display state, local locker description: "The client locker addon manages personal locker display state, local locker container behavior, and virtual arsenal unlock state."
container behavior, and virtual arsenal unlock state. ---
## Repositories ## Repositories

View File

@ -1,7 +1,7 @@
# Client Notifications Usage Guide ---
title: "Client Notifications Usage Guide"
The client notifications addon owns the notification HUD, notification sound, description: "The client notifications addon owns the notification HUD, notification sound, and local notification service used by Forge client and server modules."
and local notification service used by Forge client and server modules. ---
## Runtime Behavior ## Runtime Behavior

View File

@ -1,8 +1,7 @@
# Client Organization Usage Guide ---
title: "Client Organization Usage Guide"
The client organization addon provides the organization portal UI and browser description: "The client organization addon provides the organization portal UI and browser bridge for login, registration, membership, invites, credit lines, leave and disband flows, assets, fleet, and treasury display."
bridge for login, registration, membership, invites, credit lines, leave and ---
disband flows, assets, fleet, and treasury display.
## Open Organization UI ## Open Organization UI
@ -24,6 +23,7 @@ through `forge_client_org_fnc_handleUIEvents`.
- create/login response routing - create/login response routing
- leave and disband requests - leave and disband requests
- credit-line assignment requests - credit-line assignment requests
- payroll and treasury transfer requests
- invite, accept invite, and decline invite requests - invite, accept invite, and decline invite requests
- targeted browser response events - targeted browser response events
@ -37,6 +37,8 @@ through `forge_client_org_fnc_handleUIEvents`.
| `org::disband::request` | Request disband on server. | | `org::disband::request` | Request disband on server. |
| `org::leave::request` | Request leave on server. | | `org::leave::request` | Request leave on server. |
| `org::credit::request` | Request credit-line assignment. | | `org::credit::request` | Request credit-line assignment. |
| `org::payroll::request` | Request payroll payout from the organization treasury. |
| `org::transfer::request` | Request treasury transfer to a member. |
| `org::invite::request` | Request member invite. | | `org::invite::request` | Request member invite. |
| `org::invite::accept` | Accept invite by org ID. | | `org::invite::accept` | Accept invite by org ID. |
| `org::invite::decline` | Decline invite by org ID. | | `org::invite::decline` | Decline invite by org ID. |
@ -83,6 +85,24 @@ Credit-line request payload:
} }
``` ```
Payroll request payload:
```json
{
"amount": 1000
}
```
Treasury transfer request payload:
```json
{
"memberUid": "76561198000000000",
"memberName": "Player Name",
"amount": 1000
}
```
Invite request payload: Invite request payload:
```json ```json

View File

@ -3,7 +3,10 @@ const baseURL =
(process.env.NODE_ENV === 'production' ? '/forge/' : '/'); (process.env.NODE_ENV === 'production' ? '/forge/' : '/');
const siteUrl = const siteUrl =
process.env.DOCS_SITE_URL || process.env.DOCS_SITE_URL ||
'https://innovativedevsolutions.github.io'; 'https://innovativedevsolutions.github.io/forge';
process.env.NUXT_SITE_URL ||= siteUrl;
process.env.NUXT_PUBLIC_SITE_URL ||= siteUrl;
export default defineNuxtConfig({ export default defineNuxtConfig({
extends: ['docus'], extends: ['docus'],

View File

@ -35,6 +35,10 @@ const generatedPages = [
source: 'arma/server/docs/usage-examples.md', source: 'arma/server/docs/usage-examples.md',
target: '2.server-extension/2.usage-examples.md' target: '2.server-extension/2.usage-examples.md'
}, },
{
source: 'arma/server/addons/common/README.md',
target: '2.server-extension/3.common.md'
},
{ {
source: 'docs/ACTOR_USAGE_GUIDE.md', source: 'docs/ACTOR_USAGE_GUIDE.md',
target: '3.server-modules/1.actor.md' target: '3.server-modules/1.actor.md'
@ -323,9 +327,10 @@ icon: i-lucide-rocket
}, },
{ {
target: '1.getting-started/0.index.md', target: '1.getting-started/0.index.md',
content: `# Getting Started content: `---
title: Getting Started
Use this section as the main entry point for the Forge framework. description: Use this section as the main entry point for the Forge framework.
---
Forge combines: Forge combines:
@ -421,9 +426,10 @@ icon: i-lucide-layers-3
}, },
{ {
target: '3.server-modules/0.index.md', target: '3.server-modules/0.index.md',
content: `# Server Module Guides content: `---
title: Server Module Guides
These pages document the authoritative server-side workflows in Forge. description: These pages document the authoritative server-side workflows in Forge.
---
Most modules follow the same shape: Most modules follow the same shape:
@ -555,7 +561,7 @@ for (const page of generatedPages) {
const sourceRel = toPosix(page.source); const sourceRel = toPosix(page.source);
const sourcePath = path.join(repoRoot, page.source); const sourcePath = path.join(repoRoot, page.source);
const rawContent = await fs.readFile(sourcePath, 'utf8'); const rawContent = await fs.readFile(sourcePath, 'utf8');
const content = rewriteMarkdownLinks(rawContent, sourceRel); const content = prepareGeneratedPageContent(rewriteMarkdownLinks(rawContent, sourceRel));
await writeContentFile(page.target, content); await writeContentFile(page.target, content);
} }
@ -591,6 +597,151 @@ function rewriteMarkdownLinks(content, sourceRel) {
}); });
} }
function prepareGeneratedPageContent(content) {
const title = extractFirstH1(content);
const description = extractLeadParagraph(content);
const body = stripMatchingLeadParagraph(stripFirstH1(content), description).trimStart();
const frontmatter = [
'---',
title ? `title: ${yamlString(title)}` : undefined,
description ? `description: ${yamlString(description)}` : undefined,
'---'
].filter(Boolean).join('\n');
return `${frontmatter}\n\n${body}`;
}
function extractFirstH1(content) {
const match = content.match(/^#\s+(.+?)\s*#*\s*$/m);
return match ? match[1].trim() : '';
}
function extractLeadParagraph(content) {
const lines = stripFirstH1(content).split(/\r?\n/);
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index].trim();
if (!line) {
continue;
}
if (!isParagraphStart(line)) {
continue;
}
const paragraph = [];
for (let paragraphIndex = index; paragraphIndex < lines.length; paragraphIndex += 1) {
const paragraphLine = lines[paragraphIndex].trim();
if (!paragraphLine) {
break;
}
paragraph.push(paragraphLine);
}
return normalizeParagraph(paragraph.join(' '));
}
return '';
}
function stripFirstH1(content) {
const lines = content.split(/\r?\n/);
const headingIndex = lines.findIndex((line) => /^#\s+.+/.test(line.trim()));
if (headingIndex === -1) {
return content;
}
lines.splice(headingIndex, 1);
while (headingIndex < lines.length && !lines[headingIndex].trim()) {
lines.splice(headingIndex, 1);
}
return lines.join('\n');
}
function stripMatchingLeadParagraph(content, description) {
if (!description) {
return content;
}
const lines = content.split(/\r?\n/);
let startIndex = 0;
while (startIndex < lines.length && !lines[startIndex].trim()) {
startIndex += 1;
}
if (startIndex < lines.length && /^##\s+overview\s*$/i.test(lines[startIndex].trim())) {
const sectionStart = startIndex;
startIndex += 1;
while (startIndex < lines.length && !lines[startIndex].trim()) {
startIndex += 1;
}
let sectionEnd = startIndex;
const sectionLines = [];
while (sectionEnd < lines.length && !/^#{2,}\s+/.test(lines[sectionEnd].trim())) {
if (lines[sectionEnd].trim()) {
sectionLines.push(lines[sectionEnd].trim());
}
sectionEnd += 1;
}
if (normalizeParagraph(sectionLines.join(' ')) === description) {
while (sectionEnd < lines.length && !lines[sectionEnd].trim()) {
sectionEnd += 1;
}
return [...lines.slice(0, sectionStart), ...lines.slice(sectionEnd)].join('\n');
}
startIndex = sectionStart;
}
if (startIndex >= lines.length || !isParagraphStart(lines[startIndex].trim())) {
return content;
}
let endIndex = startIndex;
const paragraph = [];
while (endIndex < lines.length && lines[endIndex].trim()) {
paragraph.push(lines[endIndex].trim());
endIndex += 1;
}
if (normalizeParagraph(paragraph.join(' ')) !== description) {
return content;
}
while (endIndex < lines.length && !lines[endIndex].trim()) {
endIndex += 1;
}
return [...lines.slice(0, startIndex), ...lines.slice(endIndex)].join('\n');
}
function isParagraphStart(line) {
return !(
line.startsWith('#') ||
line.startsWith('![') ||
line.startsWith('```') ||
line.startsWith(':::') ||
line.startsWith('::') ||
line.startsWith('|') ||
/^[-*+]\s+/.test(line) ||
/^\d+\.\s+/.test(line)
);
}
function normalizeParagraph(value) {
return value.replace(/\s+/g, ' ').trim();
}
function yamlString(value) {
return JSON.stringify(value);
}
function toRoute(target) { function toRoute(target) {
const withoutExt = toPosix(target).replace(/\.md$/i, ''); const withoutExt = toPosix(target).replace(/\.md$/i, '');
const parts = withoutExt.split('/'); const parts = withoutExt.split('/');