mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Port website dev docs generated content scripts from JS to Rust to avoid intermediate parsing (#3909)
* Remove the crate dependency graph website generation intermediate generation step * Remove the message system tree website generation intermediate generation step * Code cleanup * Remove cache system * Fix Windows comment URL error * Fix incorrect artifact download URLs * Add Flatpak to comment * Make Flatpak use debug/release mode choice instead of always release mode
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import fs from "fs";
|
||||
|
||||
import { instance } from "@viz-js/viz";
|
||||
|
||||
const [inputFile, outputFile] = process.argv.slice(2);
|
||||
if (!inputFile || !outputFile) {
|
||||
console.error("Usage: node generate-crate-hierarchy.ts <input.dot> <output.svg>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const dot = fs.readFileSync(inputFile, "utf-8");
|
||||
|
||||
const viz = await instance();
|
||||
const svg = viz.renderString(dot, { format: "svg" });
|
||||
|
||||
fs.writeFileSync(outputFile, svg);
|
||||
console.log(`SVG output written to: ${outputFile}`);
|
||||
@@ -1,122 +0,0 @@
|
||||
// TODO: Port this script to Rust as part of `tools/editor-message-tree/src/main.rs`
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
type Entry = { level: number; text: string; link: string | undefined };
|
||||
|
||||
/// Parses a single line of the input text.
|
||||
function parseLine(line: string) {
|
||||
const linkRegex = /`([^`]+)`$/;
|
||||
const linkMatch = line.match(linkRegex);
|
||||
let link = undefined;
|
||||
|
||||
if (linkMatch) {
|
||||
const filePath = linkMatch[1].replace(/\\/g, "/");
|
||||
link = `https://github.com/GraphiteEditor/Graphite/blob/master/${filePath}`;
|
||||
}
|
||||
|
||||
const textContent = line
|
||||
.replace(/^[\s│├└─]*/, "")
|
||||
.replace(linkRegex, "")
|
||||
.trim();
|
||||
const indentation = line.indexOf(textContent);
|
||||
// Each level of indentation is 4 characters.
|
||||
const level = Math.floor(indentation / 4);
|
||||
|
||||
return { level, text: textContent, link };
|
||||
}
|
||||
|
||||
/// Recursively builds the HTML list from the parsed nodes.
|
||||
function buildHtmlList(nodes: Entry[], currentIndex: number, currentLevel: number) {
|
||||
if (currentIndex >= nodes.length) {
|
||||
return { html: "", nextIndex: currentIndex };
|
||||
}
|
||||
|
||||
let html = "<ul>\n";
|
||||
let i = currentIndex;
|
||||
|
||||
while (i < nodes.length && nodes[i].level >= currentLevel) {
|
||||
const node = nodes[i];
|
||||
|
||||
if (node.level > currentLevel) {
|
||||
// This case handles malformed input, skip to next valid line
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const hasDirectChildren = i + 1 < nodes.length && nodes[i + 1].level > node.level;
|
||||
const hasDeeperChildren = hasDirectChildren && i + 2 < nodes.length && nodes[i + 2].level > nodes[i + 1].level;
|
||||
|
||||
const linkHtml = node.link ? `<a href="${node.link}" target="_blank">${path.basename(node.link.split("#L").join(":"))}</a>` : "";
|
||||
const fieldPieces = node.text.match(/([^:]*):(.*)/);
|
||||
let escapedText;
|
||||
if (fieldPieces && fieldPieces.length === 3) {
|
||||
escapedText = [escapeHtml(fieldPieces[1].trim()), escapeHtml(fieldPieces[2].trim())];
|
||||
} else {
|
||||
escapedText = [escapeHtml(node.text)];
|
||||
}
|
||||
|
||||
let role = "message";
|
||||
if (node.link) role = "subsystem";
|
||||
else if (hasDeeperChildren) role = "submessage";
|
||||
else if (escapedText.length === 2) role = "field";
|
||||
|
||||
const partOfMessageFromNamingConvention = ["Message", "MessageHandler", "MessageContext"].some((suffix) => node.text.replace(/(.*)<.*>/g, "$1").endsWith(suffix));
|
||||
const partOfMessageViolatesNamingConvention = node.link && !partOfMessageFromNamingConvention;
|
||||
const violatesNamingConvention = partOfMessageViolatesNamingConvention
|
||||
? "<span class=\"warn\">(violates naming convention — should end with 'Message', 'MessageHandler', or 'MessageContext')</span>"
|
||||
: "";
|
||||
|
||||
if (hasDirectChildren) {
|
||||
html += `<li><span class="tree-node"><span class="${role}">${escapedText}</span>${linkHtml}${violatesNamingConvention}</span>`;
|
||||
const childResult = buildHtmlList(nodes, i + 1, node.level + 1);
|
||||
html += `<div class="nested">${childResult.html}</div></li>\n`;
|
||||
i = childResult.nextIndex;
|
||||
} else if (role === "field") {
|
||||
html += `<li><span class="tree-leaf field">${escapedText[0]}</span>: <span>${escapedText[1]}</span>${linkHtml}</li>\n`;
|
||||
i++;
|
||||
} else {
|
||||
html += `<li><span class="tree-leaf ${role}">${escapedText[0]}</span>${linkHtml}${violatesNamingConvention}</li>\n`;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
html += "</ul>\n";
|
||||
return { html, nextIndex: i };
|
||||
}
|
||||
|
||||
function escapeHtml(text: string) {
|
||||
return text.replace(/</g, "<").replace(/>/g, ">");
|
||||
}
|
||||
|
||||
const inputFile = process.argv[2];
|
||||
const outputFile = process.argv[3];
|
||||
|
||||
if (!inputFile || !outputFile) {
|
||||
console.error("Error: Please provide the input text and output HTML file paths as arguments.");
|
||||
console.log("Usage: node generate-editor-structure.ts <input txt> <output html>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(inputFile)) {
|
||||
console.error(`Error: File not found at "${inputFile}"`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const fileContent = fs.readFileSync(inputFile, "utf-8");
|
||||
const lines = fileContent.split(/\r?\n/).filter((line) => line.trim() !== "" && !line.startsWith("// filepath:"));
|
||||
const parsedNodes = lines.map(parseLine);
|
||||
|
||||
const { html } = buildHtmlList(parsedNodes, 0, 0);
|
||||
|
||||
fs.writeFileSync(outputFile, html, "utf-8");
|
||||
|
||||
console.log(`Successfully generated HTML outline at: ${outputFile}`);
|
||||
} catch (error) {
|
||||
console.error("An error occurred during processing:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ The dispatcher lives at the root of the editor hierarchy and acts as the owner o
|
||||
cargo run explore editor
|
||||
```
|
||||
|
||||
Click to explore the outline of the editor subsystem hierarchy which forms the structure of the editor's subsystems, state, and interactions.
|
||||
Click to explore the outline of the editor subsystem hierarchy which forms the structure of the editor's subsystems, state, and interactions. Also available as a searchable <a href="/volunteer/guide/codebase-overview/hierarchical-message-system-tree.txt">plain text file</a>.
|
||||
|
||||
<div class="structure-outline">
|
||||
<!-- replacements::hierarchical_message_system_tree() -->
|
||||
|
||||
8
website/package-lock.json
generated
8
website/package-lock.json
generated
@@ -16,7 +16,6 @@
|
||||
"@eslint/eslintrc": "^3.3.3",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@types/node": "^25.0.9",
|
||||
"@viz-js/viz": "^3.25.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
@@ -1233,13 +1232,6 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@viz-js/viz": {
|
||||
"version": "3.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@viz-js/viz/-/viz-3.25.0.tgz",
|
||||
"integrity": "sha512-dM7zAYMdf7mcRz5Kdb+YJb6+qv5Rjk0rPZ18gROdpMrP/3S7RFOp8uxybeiz5RypHrE1zo1vccA8Twh4mIcLZw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"postinstall": "node .build-scripts/install.ts",
|
||||
"generate-editor-structure": "node .build-scripts/generate-editor-structure.ts generated/hierarchical_message_system_tree.txt generated/hierarchical_message_system_tree.html",
|
||||
"generate-crate-hierarchy": "node .build-scripts/generate-crate-hierarchy.ts generated/crate_hierarchy.dot generated/crate_hierarchy.svg",
|
||||
"check": "tsc --noEmit && eslint",
|
||||
"fix": "eslint --fix"
|
||||
},
|
||||
@@ -22,7 +20,6 @@
|
||||
"@eslint/eslintrc": "^3.3.3",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@types/node": "^25.0.9",
|
||||
"@viz-js/viz": "^3.25.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
|
||||
@@ -40,25 +40,21 @@
|
||||
{% endmacro text_balancer %}
|
||||
|
||||
{% macro hierarchical_message_system_tree() %}
|
||||
{%- set content = load_data(path = "../generated/hierarchical_message_system_tree.html", format = "plain", required = false) -%}
|
||||
{%- set content = load_data(path = "../generated/hierarchical-message-system-tree.html", format = "plain", required = false) -%}
|
||||
{%- set fallback = "<pre>THIS CONTENT IS FILLED IN WHEN CI BUILDS THE WEBSITE.
|
||||
|
||||
TO TEST IT LOCALLY, FROM THE ROOT OF THE PROJECT, RUN:
|
||||
|
||||
cargo run -p editor-message-tree -- website/generated/hierarchical_message_system_tree.txt
|
||||
cd website
|
||||
npm run generate-editor-structure</pre>" -%}
|
||||
cargo run -p editor-message-tree -- website/generated</pre>" -%}
|
||||
{{ content | default(value = fallback) | safe }}
|
||||
{% endmacro hierarchical_message_system_tree %}
|
||||
|
||||
{% macro crate_hierarchy() %}
|
||||
{%- set content = load_data(path = "../generated/crate_hierarchy.svg", format = "plain", required = false) -%}
|
||||
{%- set content = load_data(path = "../generated/crate-hierarchy.svg", format = "plain", required = false) -%}
|
||||
{%- set fallback = "<pre>THIS CONTENT IS FILLED IN WHEN CI BUILDS THE WEBSITE.
|
||||
|
||||
TO TEST IT LOCALLY, FROM THE ROOT OF THE PROJECT, RUN:
|
||||
|
||||
cargo run -p crate-hierarchy-viz -- website/generated/crate_hierarchy.dot
|
||||
cd website
|
||||
npm run generate-crate-hierarchy</pre>" -%}
|
||||
cargo run -p crate-hierarchy-viz -- website/generated</pre>" -%}
|
||||
{{ content | default(value = fallback) | safe }}
|
||||
{% endmacro crate_hierarchy %}
|
||||
|
||||
Reference in New Issue
Block a user