mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
143 lines
4.9 KiB
JavaScript
143 lines
4.9 KiB
JavaScript
/**
|
|
* Functions for generating the sections for the style guide. Has the old style doc glob and a
|
|
* recursive tree-walker that looks through the components folder and tries to arrange found
|
|
* markdown docs in a tree.
|
|
*/
|
|
|
|
const path = require("path");
|
|
const fs = require("fs");
|
|
const glob = require("glob");
|
|
const { humanize, titleize } = require("underscore.string");
|
|
|
|
/**
|
|
* Gets the table of contents sections for documentation in the components folder.
|
|
*
|
|
* @param {string} rootPath absolute path to components folder
|
|
* @return {Object} Rootnode, section map, childMap
|
|
*/
|
|
function getDocSections(rootPath, options = {}) {
|
|
const { ignore = [], docSelector = "*.@(vue|md)" } = options;
|
|
|
|
const sections = new Map(); // absolute section directory path -> section object
|
|
const childToParent = new Map(); // absolute child path -> absolute parent path
|
|
|
|
// create root node
|
|
const rootNode = newSection(rootPath, ignore);
|
|
sections.set(rootPath, rootNode);
|
|
childToParent.set(rootPath, null);
|
|
|
|
// get all matching doc files
|
|
const selector = path.join(rootPath, "**", docSelector);
|
|
const allFiles = glob.sync(selector, { ignore });
|
|
|
|
allFiles.forEach((file) => {
|
|
const p = path.parse(file);
|
|
|
|
// intermediate dir names between this dir and root
|
|
const relPath = path.relative(rootPath, p.dir);
|
|
const midFolders = relPath.split(path.sep);
|
|
|
|
// build intermediate parent sections in the event that this is deeply-nested
|
|
while (midFolders.length) {
|
|
const sectionPath = path.join(rootPath, ...midFolders);
|
|
if (!sections.has(sectionPath)) {
|
|
// create new section
|
|
const section = newSection(sectionPath, ignore);
|
|
sections.set(sectionPath, section);
|
|
// register relationship for tree-build later
|
|
const parentPath = path.join(sectionPath, "..");
|
|
childToParent.set(sectionPath, parentPath);
|
|
}
|
|
midFolders.pop();
|
|
}
|
|
|
|
// if it's a MD file, add to parent as a subsection
|
|
const section = sections.get(p.dir);
|
|
if (section && isSubsection(section, file)) {
|
|
section.children.add({
|
|
name: titleize(humanize(p.name)),
|
|
content: file,
|
|
});
|
|
}
|
|
});
|
|
|
|
// assemble recursive section tree under rootNode
|
|
buildSectionTree(sections, childToParent);
|
|
|
|
// rootNode is the main result, returning the maps so the user has the option to manipulate the
|
|
// tree before handing it over to the styleguide configs
|
|
return { sections, childToParent, rootNode };
|
|
}
|
|
|
|
function isSubsection(section, file) {
|
|
const p = path.parse(file);
|
|
|
|
// it's not a subsection if it's not a markdown file
|
|
if (p.ext !== ".md") return false;
|
|
|
|
// it's not a subsection if it's the same file as the section content
|
|
if (file === section.content) return false;
|
|
|
|
// it's not a subsection if it's an example for an existing component
|
|
const matchingComponentPath = path.join(p.dir, `${p.name}.vue`);
|
|
const componentExists = fs.existsSync(matchingComponentPath);
|
|
if (componentExists) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Creates a new section in the TOC from passed path.
|
|
*
|
|
* @param {string} dir absolute directory path
|
|
* @return {Object} section object
|
|
*/
|
|
function newSection(dir, ignore = []) {
|
|
const section = {
|
|
name: titleize(humanize(path.basename(dir))),
|
|
components: () => glob.sync(path.join(dir, "*.vue"), { ignore }),
|
|
children: new Set(),
|
|
sectionDepth: 1,
|
|
};
|
|
|
|
// summary doc is readme/docs/index.md
|
|
const summarySelector = path.join(dir, "@(readme|docs|index).md");
|
|
const summaryDocs = glob.sync(summarySelector, { ignore, nocase: true });
|
|
if (summaryDocs.length) {
|
|
section.content = summaryDocs[0];
|
|
}
|
|
|
|
return section;
|
|
}
|
|
|
|
/**
|
|
* Turns the pair of maps into a nested object for use in the styleguide config script. Operates on
|
|
* sections array by reference.
|
|
*
|
|
* @param {Map} sections Map of path -> section object
|
|
* @param {Map} childToParent Map of childPath -> parentPath
|
|
*/
|
|
function buildSectionTree(sections, childToParent) {
|
|
// add each child to its parent
|
|
for (const [childPath, parentPath] of childToParent) {
|
|
const child = sections.get(childPath);
|
|
const parent = sections.get(parentPath);
|
|
if (child && parent && parent.children) {
|
|
parent.children.add(child);
|
|
}
|
|
}
|
|
// convert child Sets to arrays now that de-dupe not required
|
|
for (const section of sections.values()) {
|
|
section.sections = Array.from(section.children).sort((a, b) => a.name.localeCompare(b.name));
|
|
delete section.children;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
// public function
|
|
getDocSections,
|
|
// exporting these in case user wants to tweak the result tree and rebuild it
|
|
buildSectionTree,
|
|
newSection,
|
|
};
|