Skip to content
34 changes: 27 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
# docfx-tools

A docfx template for package documentation, patching the modern template to provide stylesheets and scripts for rendering custom workflow containers with copy functionality.
A repository of docfx tools for Bonsai package documentation:
- Docfx Workflow Container template patching the modern template to provide stylesheets and scripts for rendering custom workflow containers with copy functionality.
- Docfx API TOC template that groups nodes by operator type in the table of contents(TOC) on API pages.
- Powershell Scripts that automate several content generation steps for package documentation websites.

## How to use
## How to include

To include this template in a docfx website, first clone this repository as a submodule:
To include this repo in a docfx website, first clone this repository as a submodule:

```
git submodule add https://github.com/bonsai-rx/docfx-tools bonsai
```

Then modify `docfx.json` to include the template immediately after the modern template:
## Using Workflow Container Template

Modify `docfx.json` to include the template immediately after the modern template:

```json
"template": [
Expand Down Expand Up @@ -38,12 +43,27 @@ export default {
}
}
```
## Using API TOC Template

The local installation of docfx needs to be updated to >= v2.77.0.

## Powershell Scripts
```ps1
dotnet tool update docfx
```

This repository also provides helper scripts to automate several content generation steps for package documentation websites.
Modify `docfx.json` to include the api-toc template (note both the workflow container and API TOC template have to be added separately).

```json
"template": [
"default",
"modern",
"bonsai/template",
"bonsai/template/apitoc",
"template"
]
```

### Exporting workflow images
## Powershell Scripts - Exporting workflow images

Exporting SVG images for all example workflows can be automated by placing all `.bonsai` files in a `workflows` folder and calling the below script pointing to the bin directory to include. A bonsai environment is assumed to be available in the `.bonsai` folder in the repository root.

Expand Down
5 changes: 5 additions & 0 deletions template/apitoc/ManagedReference.overwrite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.getOptions = function (model) {
return {
isShared: true
};
}
86 changes: 86 additions & 0 deletions template/apitoc/toc.extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

function defineOperatorType(model){
// Define Bonsai operator types in documentation by checking for an explicit Category tag. If the class does not provide one,
// check the inheritance tree of the class.

const checkForCategory = (category) => model.syntax?.content[0].value.includes(`[WorkflowElementCategory(ElementCategory.${category})]`);
const checkInheritance = (inheritance) => model.inheritance?.some(inherited => inherited.uid.includes(inheritance));

source = checkForCategory('Source') || checkInheritance('Bonsai.Source');
sink = checkForCategory('Sink') || checkInheritance('Bonsai.Sink') || checkInheritance('Bonsai.IO.StreamSink') || checkInheritance('Bonsai.IO.FileSink');
combinator = checkForCategory('Combinator') || checkInheritance('Bonsai.Combinator') || checkInheritance('Bonsai.WindowCombinator');
transform = checkForCategory('Transform') || checkInheritance('Bonsai.Transform') || checkInheritance('Bonsai.Transform');

let operatorType = {}
operatorType.type = sink ? 'sink' : source ? 'source' : transform ? 'transform' : combinator ? 'combinator' : false ;

return operatorType;
}

/**
* This method will be called at the start of exports.transform in toc.html.js and toc.json.js
*/
exports.preTransform = function (model) {

// Checks and applies TOC customisation only to API page
if (model._key === 'api/toc.yml') {

//Setups operator mapping
const typeIndexMap = {
'source': 0,
'transform': 0,
'sink': 0,
'combinator': 0
};

// Iterates through each namespace for packages with multiple namespaces
for (namespace of model.items) {
if (namespace.items) {
itemsItemsLength = namespace.items.length;

// Setups operator categories
let items = [{
'name': 'Operators',
'items': []}, {
'name': 'Classes',
'items': []}, {
'name': 'Enums',
'items': []
}];

// Iterates through each item in the namespace and sorts them into categories
for (let i = 0; i < itemsItemsLength; i++) {
globalYml = '~/api/' + namespace.items[i].topicUid + '.yml';
if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'class'){
operatorType = defineOperatorType(model.__global._shared[globalYml]);

const index = typeIndexMap[operatorType.type]
if (index !== undefined) {
items[index].items.push(namespace.items[i]);
}
else {
items[1].items.push(namespace.items[i]);
}
}
if (model.__global._shared[globalYml] && model.__global._shared[globalYml].type === 'enum'){
items[2].items.push(namespace.items[i]);
}
}

// Filters out empty TOC categories and sets namespace TOC items
items = items.filter(item => item.items.length > 0);
namespace.items = items;
}
}
}
return model;
}

/**
* This method will be called at the end of exports.transform in toc.html.js and toc.json.js
*/
exports.postTransform = function (model) {
return model;
}