From e0a0d3bdd17f7d0c6e068710e0ccfd6834e484f8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 01:16:37 +0000
Subject: [PATCH 1/3] Initial plan
From 511e8db971bc0261d2908e6918ab3099962e390f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 01:28:57 +0000
Subject: [PATCH 2/3] Add wiki pages support with @wiki, @header, @text, @br,
@code tags
Co-authored-by: ventz-lgtm <4554439+ventz-lgtm@users.noreply.github.com>
---
builder/src/components/App/index.tsx | 3 +
builder/src/pages/WikiPage/index.tsx | 92 +++++++++++++++++++
builder/src/util/parsed.ts | 19 +++-
parser/examples/wikis/getting_started.lua | 21 +++++
parser/src/classes/Project/Category.ts | 22 +++--
parser/src/classes/Project/CategoryProject.ts | 12 +++
parser/src/classes/Project/WikiPage.ts | 85 +++++++++++++++++
7 files changed, 247 insertions(+), 7 deletions(-)
create mode 100644 builder/src/pages/WikiPage/index.tsx
create mode 100644 parser/examples/wikis/getting_started.lua
create mode 100644 parser/src/classes/Project/WikiPage.ts
diff --git a/builder/src/components/App/index.tsx b/builder/src/components/App/index.tsx
index 9df2678..7f853ca 100644
--- a/builder/src/components/App/index.tsx
+++ b/builder/src/components/App/index.tsx
@@ -9,6 +9,7 @@ import { project, title } from "../../util/parsed";
import FunctionPage from "../../pages/FunctionPage";
import TablePage from "../../pages/TablePage";
import CategoryPage from "../../pages/CategoryPage";
+import WikiPage from "../../pages/WikiPage";
import { dark } from "../../styles/themes/dark";
import { Helmet } from "react-helmet";
@@ -29,6 +30,8 @@ const RouteController: React.FC<{}> = () => {
if (item.item.startsWith("category")) {
return ;
+ } else if (item.item === "wiki") {
+ return ;
} else if (item.item.endsWith("table")) {
return ;
}
diff --git a/builder/src/pages/WikiPage/index.tsx b/builder/src/pages/WikiPage/index.tsx
new file mode 100644
index 0000000..1e3cb8a
--- /dev/null
+++ b/builder/src/pages/WikiPage/index.tsx
@@ -0,0 +1,92 @@
+import React from "react";
+import Page from "../Page";
+import { useParams } from "react-router-dom";
+import { project, WikiPage as WikiPageObject, WikiContent } from "../../util/parsed";
+import marked from "../../util/marked";
+import { SectionContainer, Section } from "../Page/styles";
+import Prism from "prismjs";
+import "prismjs/components/prism-lua";
+
+const WikiPage: React.FC<{}> = () => {
+ const { tab, category } = useParams();
+ const category_object = project[tab]?.subcategories?.[category];
+ const item = category_object as WikiPageObject;
+ const description = item.description;
+ const content: WikiContent[] = item.content ?? [];
+
+ function markedDescription() {
+ return {
+ __html: marked(description as string),
+ };
+ }
+
+ function renderContent() {
+ const elements: JSX.Element[] = [];
+ let currentParagraph: string[] = [];
+
+ const flushParagraph = () => {
+ if (currentParagraph.length > 0) {
+ const text = currentParagraph.join(" ");
+ elements.push(
+
+ );
+ currentParagraph = [];
+ }
+ };
+
+ content.forEach((item, index) => {
+ switch (item.type) {
+ case "header":
+ flushParagraph();
+ elements.push(
+
+ );
+ break;
+ case "text":
+ currentParagraph.push(item.content);
+ break;
+ case "br":
+ flushParagraph();
+ break;
+ case "code":
+ flushParagraph();
+ const highlighted = Prism.highlight(
+ item.content,
+ Prism.languages.lua,
+ "lua"
+ );
+ elements.push(
+
+
+
+ );
+ break;
+ }
+ });
+
+ flushParagraph();
+ return elements;
+ }
+
+ return (
+
+ {description && (
+ <>
+
+
+ >
+ )}
+ {renderContent()}
+
+ );
+};
+
+export default WikiPage;
diff --git a/builder/src/util/parsed.ts b/builder/src/util/parsed.ts
index b3a7fe4..7f7ea4c 100644
--- a/builder/src/util/parsed.ts
+++ b/builder/src/util/parsed.ts
@@ -7,6 +7,7 @@ import {
mdiFormatListNumbered,
mdiHook,
mdiViewQuilt,
+ mdiFileDocument,
} from "@mdi/js";
import * as mdiIcons from "@mdi/js";
@@ -51,6 +52,21 @@ export interface TablePage {
item: "table";
}
+export interface WikiContent {
+ type: "header" | "text" | "code" | "br";
+ content: string;
+}
+
+export interface WikiPage {
+ name: string;
+ description?: string;
+ content: WikiContent[];
+ realm?: string;
+ internal?: boolean;
+ deprecated?: boolean;
+ item: "wiki";
+}
+
export interface Category {
name: string;
description?: string;
@@ -64,7 +80,7 @@ export interface Category {
item: "category";
}
-export type ValidSubcategory = Category | FunctionPage | TablePage;
+export type ValidSubcategory = Category | FunctionPage | TablePage | WikiPage;
export interface ProjectStructure {
[key: string]: Category;
@@ -90,6 +106,7 @@ export const icons: {
panels: mdiViewQuilt,
enums: mdiFormatListNumbered,
structs: mdiDatabase,
+ wikis: mdiFileDocument,
default: mdiCursorDefault,
};
diff --git a/parser/examples/wikis/getting_started.lua b/parser/examples/wikis/getting_started.lua
new file mode 100644
index 0000000..ba465eb
--- /dev/null
+++ b/parser/examples/wikis/getting_started.lua
@@ -0,0 +1,21 @@
+-- @wiki Getting Started
+-- This wiki page explains how to get started with the project.
+--
+-- @header Introduction
+-- @text Welcome to the documentation. This guide will help you understand
+-- @text how to use the wiki pages feature in gdocs.
+-- @br
+-- @text Wiki pages allow you to create rich documentation with headers,
+-- @text text paragraphs, and code examples.
+--
+-- @header Example Code
+-- @text Here is an example of how to use the library:
+-- @code
+-- local function example()
+-- print("Hello, World!")
+-- end
+--
+-- @header Another Section
+-- @text This is another section with more text.
+-- @br
+-- @text After a break, we start a new paragraph.
diff --git a/parser/src/classes/Project/Category.ts b/parser/src/classes/Project/Category.ts
index ae78d1e..31a7f0f 100644
--- a/parser/src/classes/Project/Category.ts
+++ b/parser/src/classes/Project/Category.ts
@@ -4,10 +4,11 @@ import { DocBlock } from "../Parser/Tags.ts";
import { get_multiple, get_unique } from "../../utils/functions.ts";
import AliasTag from "../Tags/AliasTag.ts";
import TablePage, { FieldInfo } from "./TablePage.ts";
+import WikiPage from "./WikiPage.ts";
-export type ValidSubcategory = Category | FunctionPage | TablePage;
+export type ValidSubcategory = Category | FunctionPage | TablePage | WikiPage;
-export type ValidPageTypes = "function" | "table";
+export type ValidPageTypes = "function" | "table" | "wiki";
export default class Category {
readonly subcategories: {
@@ -72,17 +73,26 @@ export default class Category {
.map((tag) => tag[0])
.join("\n\n")
.trim();
- const page = this.pageType === "function"
- ? new FunctionPage(
+ let page: FunctionPage | TablePage | WikiPage;
+ if (this.pageType === "wiki") {
+ page = new WikiPage(
name,
description != "" ? description : undefined,
block,
- )
- : new TablePage(
+ );
+ } else if (this.pageType === "table") {
+ page = new TablePage(
name,
description != "" ? description : undefined,
block,
);
+ } else {
+ page = new FunctionPage(
+ name,
+ description != "" ? description : undefined,
+ block,
+ );
+ }
if (has_subcategory) {
const subcategory = get_unique(block, "subcategory") as string;
diff --git a/parser/src/classes/Project/CategoryProject.ts b/parser/src/classes/Project/CategoryProject.ts
index 07a2d09..a0fcb2a 100644
--- a/parser/src/classes/Project/CategoryProject.ts
+++ b/parser/src/classes/Project/CategoryProject.ts
@@ -39,6 +39,11 @@ export default class CategoryProject {
this.add_tag(new BooleanTag("internal"));
this.add_tag(new BooleanTag("deprecated"));
this.add_tag(new BooleanTag("stub"));
+ /* Wiki-specific tags */
+ this.add_tag(new Tag("header", 1, false));
+ this.add_tag(new Tag("text", 1, false, false, true));
+ this.add_tag(new Tag("code", 1, false, false, true));
+ this.add_tag(new Tag("br", 0, false));
this.add_tag(
new AliasTag("hook", 2, ([subcategory, name]) => [
"@category hooks",
@@ -84,6 +89,13 @@ export default class CategoryProject {
false,
true,
);
+ this.add_category(
+ new Category("Wikis", "wiki"),
+ false,
+ "wiki",
+ false,
+ true,
+ );
/* Default categories that define types. */
this.add_category_type("Classes");
diff --git a/parser/src/classes/Project/WikiPage.ts b/parser/src/classes/Project/WikiPage.ts
new file mode 100644
index 0000000..5e6cb66
--- /dev/null
+++ b/parser/src/classes/Project/WikiPage.ts
@@ -0,0 +1,85 @@
+import { DocBlock, TagInfo } from "../Parser/Tags.ts";
+import { get_unique } from "../../utils/functions.ts";
+
+export interface WikiContent {
+ type: "header" | "text" | "code" | "br";
+ content: string;
+}
+
+export default class WikiPage {
+ readonly item: "wiki";
+ readonly content: WikiContent[];
+ readonly realm?: string;
+ readonly internal?: boolean;
+ readonly deprecated?: boolean;
+
+ constructor(
+ public readonly name: string,
+ public readonly description?: string,
+ block: DocBlock = {},
+ ) {
+ // Collect all content items with their line numbers for ordering
+ const contentItems: { line: number; type: WikiContent["type"]; content: string }[] = [];
+
+ // Process headers
+ if (block["header"]) {
+ block["header"].forEach((tag: TagInfo) => {
+ contentItems.push({
+ line: tag.line,
+ type: "header",
+ content: tag.args?.[0] ?? "",
+ });
+ });
+ }
+
+ // Process text blocks
+ if (block["text"]) {
+ block["text"].forEach((tag: TagInfo) => {
+ contentItems.push({
+ line: tag.line,
+ type: "text",
+ content: tag.args?.[0] ?? "",
+ });
+ });
+ }
+
+ // Process code blocks
+ if (block["code"]) {
+ block["code"].forEach((tag: TagInfo) => {
+ contentItems.push({
+ line: tag.line,
+ type: "code",
+ content: tag.args?.[0] ?? "",
+ });
+ });
+ }
+
+ // Process br (break) tags
+ if (block["br"]) {
+ block["br"].forEach((tag: TagInfo) => {
+ contentItems.push({
+ line: tag.line,
+ type: "br",
+ content: "",
+ });
+ });
+ }
+
+ // Sort by line number to preserve original order
+ contentItems.sort((a, b) => a.line - b.line);
+
+ // Convert to WikiContent format
+ this.content = contentItems.map(({ type, content }) => ({ type, content }));
+ this.realm = get_unique(block, "realm");
+ this.internal = get_unique(block, "internal") === "true" ? true : undefined;
+ this.deprecated = get_unique(block, "deprecated") === "true"
+ ? true
+ : undefined;
+
+ this.item = "wiki";
+ }
+
+ print(level = 0) {
+ console.log(" ".repeat(level) + this.name);
+ }
+}
From 8f506991a1ce671e1306227dfd09938a69d2d03f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 01:33:39 +0000
Subject: [PATCH 3/3] Address code review feedback: extract code rendering, add
error handling
Co-authored-by: ventz-lgtm <4554439+ventz-lgtm@users.noreply.github.com>
---
builder/src/pages/WikiPage/index.tsx | 32 +++++++++++++++++-----------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/builder/src/pages/WikiPage/index.tsx b/builder/src/pages/WikiPage/index.tsx
index 1e3cb8a..ea01388 100644
--- a/builder/src/pages/WikiPage/index.tsx
+++ b/builder/src/pages/WikiPage/index.tsx
@@ -7,6 +7,24 @@ import { SectionContainer, Section } from "../Page/styles";
import Prism from "prismjs";
import "prismjs/components/prism-lua";
+const CODE_LANGUAGE = "lua";
+const CODE_CLASS = `language-${CODE_LANGUAGE}`;
+
+const renderCodeBlock = (code: string, key: string) => {
+ const language = Prism.languages[CODE_LANGUAGE];
+ const highlighted = language
+ ? Prism.highlight(code, language, CODE_LANGUAGE)
+ : code;
+ return (
+
+
+
+ );
+};
+
const WikiPage: React.FC<{}> = () => {
const { tab, category } = useParams();
const category_object = project[tab]?.subcategories?.[category];
@@ -53,19 +71,7 @@ const WikiPage: React.FC<{}> = () => {
break;
case "code":
flushParagraph();
- const highlighted = Prism.highlight(
- item.content,
- Prism.languages.lua,
- "lua"
- );
- elements.push(
-
-
-
- );
+ elements.push(renderCodeBlock(item.content, `code-${index}`));
break;
}
});