From 97854e5386d152d02f6c22d9f1abb69c07bc9220 Mon Sep 17 00:00:00 2001 From: "Azzedine E." <54241944+Arsero@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:48:21 +0100 Subject: [PATCH] Squashed commit of the following: commit 7ec59ff47d521a910f8b0d861d47d7f012ce0bb2 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Fri Nov 22 20:48:07 2024 +0100 Update README.md commit 747c5f240167465907208511a0213dafb0b4f4d3 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 21:46:57 2024 +0100 refactor: update id from nodes commit c2f3ca5e14c920b041d4615c40a7f3ada0ec9400 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 21:15:14 2024 +0100 refactor: add devlopment mode commit 7f9d6e6fd46a73276f8cfc0c96db927f19dc8f74 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 20:51:18 2024 +0100 refactor: add tad parameters commit f44997b3b38d8dc5671098d833e4c6d477559970 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 20:35:34 2024 +0100 refactor: rename categories to sources commit dea1814db0d485c57bc31475d91740dabdf3b2ad Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 20:29:52 2024 +0100 refactor: names params commit ac5feaa4173b45e39094f50e07144dd4be9ce78b Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 19:37:44 2024 +0100 refactor: update params plugin - add build path commit fde2478b7bc9b0c270c70697e07b658eb89d59d5 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 18:52:05 2024 +0100 refactor: title is name of file when no header commit 54cd17565b76eb11f4ce16cb20e60000b0fa9488 Author: Azzedine E. <54241944+Arsero@users.noreply.github.com> Date: Thu Nov 21 18:19:17 2024 +0100 refactor: mdUtils --- README.md | 96 ++----- demo/docs/tutorial-basics/congratulations.md | 2 +- .../tutorial-basics/create-a-blog-post.md | 3 +- .../docs/tutorial-basics/create-a-document.md | 14 +- demo/docs/tutorial-basics/create-a-page.md | 6 +- demo/docs/tutorial-basics/deploy-your-site.md | 2 +- .../tutorial-extras/manage-docs-versions.md | 4 +- .../tutorial-extras/translate-your-site.md | 8 +- demo/docusaurus.config.ts | 258 +++++++++--------- demo/static/docusaurus-graph.json | 48 ++-- demo/yarn.lock | 2 +- package.json | 3 +- src/index.ts | 129 ++++----- src/theme/defaults.ts | 8 + src/theme/mdUtils.ts | 204 +++++++------- tests/content/docs/congratulations.md | 2 +- tests/content/docs/deploy-your-site.md | 2 +- tests/content/intro/create-a-blog-post.md | 2 +- tests/content/intro/create-a-document.md | 14 +- tests/content/intro/doc-without-title.md | 30 ++ tests/utils.spec.ts | 42 +-- 21 files changed, 448 insertions(+), 431 deletions(-) create mode 100644 src/theme/defaults.ts create mode 100644 tests/content/intro/doc-without-title.md diff --git a/README.md b/README.md index 5f1a6b8..4dcecfa 100644 --- a/README.md +++ b/README.md @@ -77,31 +77,10 @@ yarn add docusaurus-graph ```js module.exports = { // Other Docusaurus configurations... - plugins: [ - [ - 'docusaurus-graph', - { - path: 'docs', // Specify the folder of your documentation - }, - ], - ], + plugins: ['docusaurus-graph'], }; ``` -> The default path is `docs`. - -3. Build the project to create the data file. - -```sh -npm run build -``` - -or - -```sh -yarn build -``` - ## Usage Once the plugin is installed and configured, it will automatically generate a graph view of your documentation. You can access the graph view from a new button at the top right of your Docusaurus site. @@ -123,47 +102,34 @@ module.exports = { [ 'docusaurus-graph', { - path: 'docs', // Specify the folder of your documentation + docsDir: "docs", + buildDir: "build", + sourcesTag: "sources", + referencesTag: "references", }, ], ], }; ``` -- `path`: (default: `docs`) The folder containing your documentation files. +- `docsDir [default: docs]`: Specifies the path of the folder containing your documentation files. +- `buildDir [default: build]`: Specifies the path of the output build folder. +- `sourcesTag [default: sources]`: Specifies the sources tag name for .md files. +- `referencesTag [default: references]`: Specifies the references tag name for .md files. ### Markdown files To create link between files, there are 2 tags : -#### Categories - -Set the categories tag to a markdown file or a name (a file that doesn't exist). Example: - -To a markdown file (intro.md): - -```md -## [comment]: <> (congratulations.md) - -sidebar_position: 6 -categories: intro - ---- - -# Congratulations! - -You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. - -Docusaurus has **much more to offer**! -``` +#### Sources -To a name: +Set the categories tag to a markdown file or a name. Example: ```md ## [comment]: <> (congratulations.md) sidebar_position: 6 -categories: tutorial-basics +sources: tutorial-basics --- @@ -174,7 +140,7 @@ You have just learned the **basics of Docusaurus** and made some changes to the Docusaurus has **much more to offer**! ``` -Result : +**Result :**

graphview @@ -186,7 +152,7 @@ Result : ## [comment]: <> (congratulations.md) sidebar_position: 6 -categories: +sources: - intro - tutorial-basics @@ -196,33 +162,7 @@ categories: #### References -Set the references tag to a markdown file or a name (a file that doesn't exist). Example: - -To a markdown file (intro.md): - -```md -## [comment]: <> (congratulations.md) - -sidebar_position: 6 -references: intro - ---- - -#### Differences - -What's the difference between categories and references ? - -See the categories like a parent or a chapter. Example : Car -> Engine. -The references is more like a child. Example : Wheel -> Car. - -# Congratulations! - -You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. - -Docusaurus has **much more to offer**! -``` - -To a name: +Set the references tag to a markdown file or a name. Example: ```md ## [comment]: <> (congratulations.md) @@ -239,7 +179,7 @@ You have just learned the **basics of Docusaurus** and made some changes to the Docusaurus has **much more to offer**! ``` -Result : +**Result :**

graphview @@ -247,14 +187,14 @@ Result : ## How it works -The Docusaurus GraphView Plugin works by parsing your Docusaurus documentation files located in the specified `path` and creating a visual graph representation based on the relationships between them. Here’s a high-level overview of the process: +The Docusaurus GraphView Plugin works by parsing your Docusaurus documentation files located in the specified `docsDir` and creating a visual graph representation based on the relationships between them. Here’s a high-level overview of the process: - **File Parsing**: The plugin scans the documentation files in your specified folder (path) to identify references between documents. - **Graph Construction**: Using the parsed data, the plugin constructs a graph data structure where nodes represent documents and edges represent references between them. - **Graph Visualization**: The constructed graph is then rendered using a graph visualization library (such as note-graph (D3.js)), applying the configured layout and styles. - **Interactive Elements**: The generated graph is interactive, allowing users to zoom in/out and drag nodes for better viewing. -> After the Docusaurus build process completes, the Docusaurus GraphView Plugin generates a data file containing the parsed documentation structure. This file, typically named `docusaurus-graph.json`, includes all the necessary information to construct the graph view, such as nodes (documents) and edges (links between documents). The file is created in the `build` directory of your Docusaurus project. +> After the Docusaurus build process completes, the Docusaurus GraphView Plugin generates a data file containing the parsed documentation structure. This file, typically named `docusaurus-graph.json`, includes all the necessary information to construct the graph view, such as nodes (documents) and edges (links between documents). ## Development diff --git a/demo/docs/tutorial-basics/congratulations.md b/demo/docs/tutorial-basics/congratulations.md index a2a34e2..adfc204 100644 --- a/demo/docs/tutorial-basics/congratulations.md +++ b/demo/docs/tutorial-basics/congratulations.md @@ -1,6 +1,6 @@ --- sidebar_position: 6 -categories: tutorial-extras +sources: tutorial-extras references: tutorial-basics --- diff --git a/demo/docs/tutorial-basics/create-a-blog-post.md b/demo/docs/tutorial-basics/create-a-blog-post.md index 585e562..d79fd27 100644 --- a/demo/docs/tutorial-basics/create-a-blog-post.md +++ b/demo/docs/tutorial-basics/create-a-blog-post.md @@ -1,6 +1,7 @@ --- sidebar_position: 3 -categories: tutorial-basics +sources: tutorial-basics +references: create-a-page --- # Create a Blog Post diff --git a/demo/docs/tutorial-basics/create-a-document.md b/demo/docs/tutorial-basics/create-a-document.md index e8cce13..67dea12 100644 --- a/demo/docs/tutorial-basics/create-a-document.md +++ b/demo/docs/tutorial-basics/create-a-document.md @@ -1,6 +1,6 @@ --- sidebar_position: 2 -categories: tutorial-basics +sources: tutorial-basics --- # Create a Document @@ -31,7 +31,7 @@ Add metadata to customize the sidebar label and position: ```md title="docs/hello.md" {1-4} --- -sidebar_label: 'Hi!' +sidebar_label: "Hi!" sidebar_position: 3 --- @@ -45,13 +45,13 @@ It is also possible to create your sidebar explicitly in `sidebars.js`: ```js title="sidebars.js" export default { tutorialSidebar: [ - 'intro', + "intro", // highlight-next-line - 'hello', + "hello", { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], + type: "category", + label: "Tutorial", + items: ["tutorial-basics/create-a-document"], }, ], }; diff --git a/demo/docs/tutorial-basics/create-a-page.md b/demo/docs/tutorial-basics/create-a-page.md index 6e4b997..4195b4a 100644 --- a/demo/docs/tutorial-basics/create-a-page.md +++ b/demo/docs/tutorial-basics/create-a-page.md @@ -1,6 +1,6 @@ --- sidebar_position: 1 -categories: tutorial-basics +sources: tutorial-basics --- # Create a Page @@ -16,8 +16,8 @@ Add **Markdown or React** files to `src/pages` to create a **standalone page**: Create a file at `src/pages/my-react-page.js`: ```jsx title="src/pages/my-react-page.js" -import React from 'react'; -import Layout from '@theme/Layout'; +import React from "react"; +import Layout from "@theme/Layout"; export default function MyReactPage() { return ( diff --git a/demo/docs/tutorial-basics/deploy-your-site.md b/demo/docs/tutorial-basics/deploy-your-site.md index eee935d..e512ad5 100644 --- a/demo/docs/tutorial-basics/deploy-your-site.md +++ b/demo/docs/tutorial-basics/deploy-your-site.md @@ -1,6 +1,6 @@ --- sidebar_position: 5 -categories: tutorial-basics +sources: tutorial-basics references: tutorial-extras --- diff --git a/demo/docs/tutorial-extras/manage-docs-versions.md b/demo/docs/tutorial-extras/manage-docs-versions.md index ed1389b..35ed761 100644 --- a/demo/docs/tutorial-extras/manage-docs-versions.md +++ b/demo/docs/tutorial-extras/manage-docs-versions.md @@ -1,6 +1,6 @@ --- sidebar_position: 1 -categories: tutorial-extras +sources: tutorial-extras --- # Manage Docs Versions @@ -35,7 +35,7 @@ export default { items: [ // highlight-start { - type: 'docsVersionDropdown', + type: "docsVersionDropdown", }, // highlight-end ], diff --git a/demo/docs/tutorial-extras/translate-your-site.md b/demo/docs/tutorial-extras/translate-your-site.md index 86f9071..da2b42a 100644 --- a/demo/docs/tutorial-extras/translate-your-site.md +++ b/demo/docs/tutorial-extras/translate-your-site.md @@ -1,6 +1,6 @@ --- sidebar_position: 2 -categories: tutorial-extras +sources: tutorial-extras references: tutorial-basics --- @@ -15,8 +15,8 @@ Modify `docusaurus.config.js` to add support for the `fr` locale: ```js title="docusaurus.config.js" export default { i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], + defaultLocale: "en", + locales: ["en", "fr"], }, }; ``` @@ -62,7 +62,7 @@ export default { items: [ // highlight-start { - type: 'localeDropdown', + type: "localeDropdown", }, // highlight-end ], diff --git a/demo/docusaurus.config.ts b/demo/docusaurus.config.ts index c7d4804..1a4ebe7 100644 --- a/demo/docusaurus.config.ts +++ b/demo/docusaurus.config.ts @@ -1,135 +1,145 @@ -import { themes as prismThemes } from 'prism-react-renderer'; -import type { Config } from '@docusaurus/types'; -import type * as Preset from '@docusaurus/preset-classic'; -import path from 'path'; +import { themes as prismThemes } from "prism-react-renderer"; +import type { Config } from "@docusaurus/types"; +import type * as Preset from "@docusaurus/preset-classic"; +import path from "path"; const config: Config = { - title: 'My Site', - tagline: 'Dinosaurs are cool', - favicon: 'img/favicon.ico', + title: "My Site", + tagline: "Dinosaurs are cool", + favicon: "img/favicon.ico", - // Set the production url of your site here - url: 'https://your-docusaurus-site.example.com', - // Set the // pathname under which your site is served - // For GitHub pages deployment, it is often '//' - baseUrl: '/', + // Set the production url of your site here + url: "https://your-docusaurus-site.example.com", + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: "/", - // GitHub pages deployment config. - // If you aren't using GitHub pages, you don't need these. - organizationName: 'facebook', // Usually your GitHub org/user name. - projectName: 'docusaurus', // Usually your repo name. + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: "facebook", // Usually your GitHub org/user name. + projectName: "docusaurus", // Usually your repo name. - onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'warn', + onBrokenLinks: "throw", + onBrokenMarkdownLinks: "warn", - // Even if you don't use internationalization, you can use this field to set - // useful metadata like html lang. For example, if your site is Chinese, you - // may want to replace "en" with "zh-Hans". - i18n: { - defaultLocale: 'en', - locales: ['en'], - }, + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: "en", + locales: ["en"], + }, - presets: [ - [ - 'classic', - { - docs: { - sidebarPath: './sidebars.ts', - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', - }, - blog: { - showReadingTime: true, - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', - }, - theme: { - customCss: './src/css/custom.css', - }, - } satisfies Preset.Options, - ], - ], + presets: [ + [ + "classic", + { + docs: { + sidebarPath: "./sidebars.ts", + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/", + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/", + }, + theme: { + customCss: "./src/css/custom.css", + }, + } satisfies Preset.Options, + ], + ], - themeConfig: { - // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', - navbar: { - title: 'My Site', - logo: { - alt: 'My Site Logo', - src: 'img/logo.svg', - }, - items: [ - { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Tutorial', - }, - { to: '/blog', label: 'Blog', position: 'left' }, - { - href: 'https://github.com/facebook/docusaurus', - label: 'GitHub', - position: 'right', - }, - ], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Docs', - items: [ - { - label: 'Tutorial', - to: '/docs/intro', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', - }, - { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', - }, - { - label: 'Twitter', - href: 'https://twitter.com/docusaurus', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Blog', - to: '/blog', - }, - { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', - }, - ], - }, - ], - copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, - }, - prism: { - theme: prismThemes.github, - darkTheme: prismThemes.dracula, - }, - } satisfies Preset.ThemeConfig, - plugins: ['docusaurus-graph'], + themeConfig: { + // Replace with your project's social card + image: "img/docusaurus-social-card.jpg", + navbar: { + title: "My Site", + logo: { + alt: "My Site Logo", + src: "img/logo.svg", + }, + items: [ + { + type: "docSidebar", + sidebarId: "tutorialSidebar", + position: "left", + label: "Tutorial", + }, + { to: "/blog", label: "Blog", position: "left" }, + { + href: "https://github.com/facebook/docusaurus", + label: "GitHub", + position: "right", + }, + ], + }, + footer: { + style: "dark", + links: [ + { + title: "Docs", + items: [ + { + label: "Tutorial", + to: "/docs/intro", + }, + ], + }, + { + title: "Community", + items: [ + { + label: "Stack Overflow", + href: "https://stackoverflow.com/questions/tagged/docusaurus", + }, + { + label: "Discord", + href: "https://discordapp.com/invite/docusaurus", + }, + { + label: "Twitter", + href: "https://twitter.com/docusaurus", + }, + ], + }, + { + title: "More", + items: [ + { + label: "Blog", + to: "/blog", + }, + { + label: "GitHub", + href: "https://github.com/facebook/docusaurus", + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + } satisfies Preset.ThemeConfig, + plugins: [ + [ + "docusaurus-graph", + { + docsDir: "docs", + buildDir: "build", + sourcesTag: "sources", + referencesTag: "references", + }, + ], + ], }; export default config; diff --git a/demo/static/docusaurus-graph.json b/demo/static/docusaurus-graph.json index 2907199..0dd3b91 100644 --- a/demo/static/docusaurus-graph.json +++ b/demo/static/docusaurus-graph.json @@ -1,12 +1,12 @@ [ { - "id": "Tutorial Intro", + "id": "intro", "title": "Tutorial Intro", "linkTo": [], "referencedBy": [] }, { - "id": "Congratulations!", + "id": "congratulations", "title": "Congratulations!", "linkTo": [ "tutorial-basics" @@ -19,54 +19,56 @@ "id": "tutorial-basics", "title": "tutorial-basics", "linkTo": [ - "Create a Blog Post", - "Create a Document", - "Create a Page", - "Deploy your site" + "create-a-blog-post", + "create-a-document", + "create-a-page", + "deploy-your-site" ], "referencedBy": [ - "Congratulations!", - "Translate your site" + "congratulations", + "translate-your-site" ] }, { "id": "tutorial-extras", "title": "tutorial-extras", "linkTo": [ - "Congratulations!", - "Manage Docs Versions", - "Translate your site" + "congratulations", + "manage-docs-versions", + "translate-your-site" ], "referencedBy": [ - "Deploy your site" + "deploy-your-site" ] }, { - "id": "Create a Blog Post", + "id": "create-a-blog-post", "title": "Create a Blog Post", - "linkTo": [], + "linkTo": [ + "create-a-page" + ], "referencedBy": [ "tutorial-basics" ] }, { - "id": "Create a Document", - "title": "Create a Document", + "id": "create-a-page", + "title": "create-a-page", "linkTo": [], "referencedBy": [ - "tutorial-basics" + "create-a-blog-post" ] }, { - "id": "Create a Page", - "title": "Create a Page", + "id": "create-a-document", + "title": "Create a Document", "linkTo": [], "referencedBy": [ "tutorial-basics" ] }, { - "id": "Deploy your site", + "id": "deploy-your-site", "title": "Deploy your site", "linkTo": [ "tutorial-extras" @@ -76,13 +78,13 @@ ] }, { - "id": "Markdown Features", + "id": "markdown-features", "title": "Markdown Features", "linkTo": [], "referencedBy": [] }, { - "id": "Manage Docs Versions", + "id": "manage-docs-versions", "title": "Manage Docs Versions", "linkTo": [], "referencedBy": [ @@ -90,7 +92,7 @@ ] }, { - "id": "Translate your site", + "id": "translate-your-site", "title": "Translate your site", "linkTo": [ "tutorial-basics" diff --git a/demo/yarn.lock b/demo/yarn.lock index cc7d105..3e0ba22 100644 --- a/demo/yarn.lock +++ b/demo/yarn.lock @@ -3560,7 +3560,7 @@ dns-packet@^5.2.2: dependencies: "@leichtgewicht/ip-codec" "^2.0.1" -"docusaurus-graph@link:../": +"docusaurus-graph@link:..": version "0.0.0" uid "" diff --git a/package.json b/package.json index e2a287b..b445f67 100644 --- a/package.json +++ b/package.json @@ -22,5 +22,6 @@ }, "peerDependencies": { "@docusaurus/core": "^3.3.2" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/src/index.ts b/src/index.ts index 20ace08..d59fe8c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,63 +1,68 @@ -import templates from './theme/templates'; -import { readMarkdownFiles } from './theme/mdUtils'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; - -export default async function docusaurusGraph(context: any) { - const { siteConfig } = context; - return { - name: 'docusaurus-graph', - async loadContent() { - const themeConfig = siteConfig.themeConfig; - themeConfig.navbar.items.push({ - type: 'html', - position: 'right', - value: templates.graphButton, - }); - }, - - async contentLoaded() {}, - - async postBuild({ plugins }: any) { - const option = plugins.find((p: any) => p.name === 'docusaurus-graph') - .options['path']; - - const directoryPath = option ? option : 'docs'; - const nodes = readMarkdownFiles(directoryPath); - - const nodeString = JSON.stringify(nodes, null, 2); - fs.writeFile( - path.join('build', 'docusaurus-graph.json'), - nodeString, - 'utf8', - (err) => { - if (err) { - console.error('Error writing to file :', err); - } - } - ); - }, - - injectHtmlTags() { - return { - headTags: [...templates.headGraph], - preBodyTags: [ - { - tagName: 'style', - innerHTML: templates.styleGraph, - }, - ], - postBodyTags: [ - { - tagName: 'div', - innerHTML: templates.containerGraph, - }, - { - tagName: 'script', - innerHTML: templates.scriptGraph, - }, - ], - }; - }, - }; +import templates from "./theme/templates"; +import { readMarkdownFiles } from "./theme/mdUtils"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import defaults from "./theme/defaults"; + +async function Process(options: any, isDevelopment = true) { + const docsDir = options.docsDir ?? defaults.docsDir; + const sourcesTag = options.sourcesTag ?? defaults.sourcesTag; + const referencesTag = options.referencesTag ?? defaults.referencesTag; + const nodes = readMarkdownFiles(docsDir, sourcesTag, referencesTag); + + let filePath = path.join(defaults.staticDir, defaults.filename); + if (!isDevelopment) { + filePath = path.join( + options.buildDir ?? defaults.buildDir, + defaults.filename, + ); + } + const nodeString = JSON.stringify(nodes, null, 2); + await fs.promises.writeFile(path.join(filePath), nodeString, "utf8"); +} + +export default async function docusaurusGraph(context: any, options: any) { + const { siteConfig } = context; + return { + name: "docusaurus-graph", + + async loadContent() { + const themeConfig = siteConfig.themeConfig; + themeConfig.navbar.items.push({ + type: "html", + position: "right", + value: templates.graphButton, + }); + + Process(options); + }, + + async contentLoaded() {}, + + async postBuild() { + Process(options, false); + }, + + injectHtmlTags() { + return { + headTags: [...templates.headGraph], + preBodyTags: [ + { + tagName: "style", + innerHTML: templates.styleGraph, + }, + ], + postBodyTags: [ + { + tagName: "div", + innerHTML: templates.containerGraph, + }, + { + tagName: "script", + innerHTML: templates.scriptGraph, + }, + ], + }; + }, + }; } diff --git a/src/theme/defaults.ts b/src/theme/defaults.ts new file mode 100644 index 0000000..a551409 --- /dev/null +++ b/src/theme/defaults.ts @@ -0,0 +1,8 @@ +export default { + filename: "docusaurus-graph.json", + docsDir: "docs", + sourcesTag: "sources", + referencesTag: "references", + buildDir: "build", + staticDir: "static", +}; diff --git a/src/theme/mdUtils.ts b/src/theme/mdUtils.ts index fee0d0e..74fa8cd 100644 --- a/src/theme/mdUtils.ts +++ b/src/theme/mdUtils.ts @@ -1,107 +1,121 @@ -import * as fs from 'node:fs'; -import * as path from 'node:path'; -import * as marked from 'marked'; -import matter from 'gray-matter'; +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as marked from "marked"; +import matter from "gray-matter"; interface Node { - id: string; - title: string; - linkTo: string[]; - referencedBy: string[]; + id: string; + title: string; + linkTo: string[]; + referencedBy: string[]; } -export function validName(name: string): boolean { - return name[0] !== '_'; +function validName(name: string): boolean { + return name[0] !== "_"; } -export function extractTitleFromMarkdown(content: string): string | null { - const tokens = marked.lexer(content); - const firstHeader = tokens.find( - (token: marked.Token) => token.type === 'heading' && token.depth === 1 - ); +function extractTitleFromMarkdown(content: string): string | null { + const tokens = marked.lexer(content); + const firstHeader = tokens.find( + (token: marked.Token) => token.type === "heading" && token.depth === 1, + ); - return firstHeader ? firstHeader.raw.substring(2).trim() : null; + return firstHeader ? firstHeader.raw.substring(2).trim() : null; } -export function isMdOrMdxFile(file: string): boolean { - return ( - path.extname(file).toLowerCase() === '.md' || - path.extname(file).toLowerCase() === '.mdx' - ); +function extractTitleFromPath(filename: string): string { + return path.basename(filename).split(".")[0]; } -export function readMarkdownFiles(directoryPath: string): Node[] { - const nodes: Node[] = []; - - function getNode(id: string): Node | undefined { - return nodes.find((item) => item.id === id); - } - - function readDirectory(currentPath: string): void { - const items = fs.readdirSync(currentPath); - - items.forEach((item) => { - if (!validName(item)) return; - - const itemPath = path.join(currentPath, item); - const stat = fs.statSync(itemPath); - - if (stat.isDirectory()) { - readDirectory(itemPath); - } else if (isMdOrMdxFile(itemPath)) { - const fileContent = fs.readFileSync(itemPath, 'utf-8'); - const { data } = matter(fileContent); - const title = extractTitleFromMarkdown(fileContent) as string; - - if (typeof data.references === 'string') - data.references = [data.references]; - - if (typeof data.categories === 'string') - data.categories = [data.categories]; - - nodes.push({ - id: title, - title, - linkTo: [...(data.references || [])], - referencedBy: [...(data.categories || [])], - }); - - if (data.references) { - data.references.forEach((reference: string) => { - const node = getNode(reference); - if (node) { - node.referencedBy.push(title); - } else { - nodes.push({ - id: reference, - title: reference, - linkTo: [], - referencedBy: [title], - }); - } - }); - } - - if (data.categories) { - data.categories.forEach((categorie: string) => { - const node = getNode(categorie); - if (node) { - node.linkTo.push(title); - } else { - nodes.push({ - id: categorie, - title: categorie, - linkTo: [title], - referencedBy: [], - }); - } - }); - } - } - }); - } - - readDirectory(directoryPath); - - return nodes; +function isMdOrMdxFile(file: string): boolean { + return ( + path.extname(file).toLowerCase() === ".md" || + path.extname(file).toLowerCase() === ".mdx" + ); +} + +export function readMarkdownFiles( + directoryPath: string, + sourceTag = "sources", + referenceTag = "references", +): Node[] { + const nodes: Node[] = []; + + function getNode(id: string): Node | undefined { + return nodes.find((item) => item.id === id); + } + + function readDirectory(currentPath: string): void { + const items = fs.readdirSync(currentPath); + + for (const item of items) { + if (!validName(item)) return; + + const itemPath = path.join(currentPath, item); + const stat = fs.statSync(itemPath); + + if (stat.isDirectory()) { + readDirectory(itemPath); + } else if (isMdOrMdxFile(itemPath)) { + const fileContent = fs.readFileSync(itemPath, "utf-8"); + const { data } = matter(fileContent); + const id = extractTitleFromPath(itemPath); + const title = (extractTitleFromMarkdown(fileContent) as string) ?? id; + + if (typeof data[referenceTag] === "string") + data[referenceTag] = [data[referenceTag]]; + + if (typeof data[sourceTag] === "string") + data[sourceTag] = [data[sourceTag]]; + + const node = getNode(id); + if (node) { + node.title = title; + } else { + nodes.push({ + id, + title, + linkTo: [...(data[referenceTag] || [])], + referencedBy: [...(data[sourceTag] || [])], + }); + } + + if (data[referenceTag]) { + for (const reference of data[referenceTag]) { + const node = getNode(reference); + if (node) { + node.referencedBy.push(id); + } else { + nodes.push({ + id: reference, + title: reference, + linkTo: [], + referencedBy: [id], + }); + } + } + } + + if (data[sourceTag]) { + for (const source of data[sourceTag]) { + const node = getNode(source); + if (node) { + node.linkTo.push(id); + } else { + nodes.push({ + id: source, + title: source, + linkTo: [id], + referencedBy: [], + }); + } + } + } + } + } + } + + readDirectory(directoryPath); + + return nodes; } diff --git a/tests/content/docs/congratulations.md b/tests/content/docs/congratulations.md index 357858b..1178313 100644 --- a/tests/content/docs/congratulations.md +++ b/tests/content/docs/congratulations.md @@ -1,6 +1,6 @@ --- sidebar_position: 6 -categories: docs +sources: docs --- # Congratulations! diff --git a/tests/content/docs/deploy-your-site.md b/tests/content/docs/deploy-your-site.md index c0c80e2..2663ba6 100644 --- a/tests/content/docs/deploy-your-site.md +++ b/tests/content/docs/deploy-your-site.md @@ -1,6 +1,6 @@ --- sidebar_position: 5 -categories: docs +sources: docs references: intro --- diff --git a/tests/content/intro/create-a-blog-post.md b/tests/content/intro/create-a-blog-post.md index 567f06e..92d1614 100644 --- a/tests/content/intro/create-a-blog-post.md +++ b/tests/content/intro/create-a-blog-post.md @@ -1,6 +1,6 @@ --- sidebar_position: 3 -categories: intro +sources: intro --- # Create a Blog Post diff --git a/tests/content/intro/create-a-document.md b/tests/content/intro/create-a-document.md index 9fc8231..93215eb 100644 --- a/tests/content/intro/create-a-document.md +++ b/tests/content/intro/create-a-document.md @@ -1,6 +1,6 @@ --- sidebar_position: 2 -categories: intro +sources: intro --- # Create a Document @@ -31,7 +31,7 @@ Add metadata to customize the sidebar label and position: ```md title="docs/hello.md" {1-4} --- -sidebar_label: 'Hi!' +sidebar_label: "Hi!" sidebar_position: 3 --- @@ -45,13 +45,13 @@ It is also possible to create your sidebar explicitly in `sidebars.js`: ```js title="sidebars.js" export default { tutorialSidebar: [ - 'intro', + "intro", // highlight-next-line - 'hello', + "hello", { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], + type: "category", + label: "Tutorial", + items: ["tutorial-basics/create-a-document"], }, ], }; diff --git a/tests/content/intro/doc-without-title.md b/tests/content/intro/doc-without-title.md new file mode 100644 index 0000000..8319098 --- /dev/null +++ b/tests/content/intro/doc-without-title.md @@ -0,0 +1,30 @@ +--- +sidebar_position: 5 +references: intro +--- + +Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). + +It builds your site as simple **static HTML, JavaScript and CSS files**. + +## Build your site + +Build your site **for production**: + +```bash +npm run build +``` + +The static files are generated in the `build` folder. + +## Deploy your site + +Test your production build locally: + +```bash +npm run serve +``` + +The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). + +You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). diff --git a/tests/utils.spec.ts b/tests/utils.spec.ts index e368f4f..04cb261 100644 --- a/tests/utils.spec.ts +++ b/tests/utils.spec.ts @@ -1,27 +1,33 @@ -import { readMarkdownFiles } from '../src/theme/mdUtils'; +import { readMarkdownFiles } from "../src/theme/mdUtils"; -const nodes = readMarkdownFiles('tests/content'); +const nodes = readMarkdownFiles("tests/content"); console.log(nodes); -test('create all nodes from folder', () => { - expect(nodes.length).toBe(6); +test("create all nodes from folder", () => { + expect(nodes.length).toBe(7); }); -test('link nodes from categories tag', () => { - expect( - nodes[0].id === 'Congratulations!' && nodes[0].referencedBy[0] === 'docs' - ).toBe(true); - expect( - nodes[1].id === 'docs' && nodes[1].linkTo[0] === 'Congratulations!' - ).toBe(true); +test("link nodes from categories tag", () => { + expect( + nodes[0].id === "congratulations" && nodes[0].referencedBy[0] === "docs", + ).toBe(true); + expect( + nodes[1].id === "docs" && nodes[1].linkTo[0] === "congratulations", + ).toBe(true); }); -test('link nodes from references tag', () => { - expect( - nodes[2].id === 'Deploy your site' && nodes[2].linkTo[0] === 'intro' - ).toBe(true); - expect( - nodes[3].id === 'intro' && nodes[3].referencedBy[0] === 'Deploy your site' - ).toBe(true); +test("link nodes from references tag", () => { + expect( + nodes[2].id === "deploy-your-site" && nodes[2].linkTo[0] === "intro", + ).toBe(true); + expect( + nodes[3].id === "intro" && nodes[3].referencedBy[0] === "deploy-your-site", + ).toBe(true); +}); + +test("title without header", () => { + expect( + nodes[6].id === "doc-without-title" && nodes[6].linkTo[0] === "intro", + ).toBe(true); });