diff --git a/.gitignore b/.gitignore
index 4da20aeb..4f2586e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,4 +92,6 @@ Thumbs.db
.cache
-docs
\ No newline at end of file
+docs
+static/scripts/app.min.js
+static/styles/app.min.css
diff --git a/README.md b/README.md
index 0a8dddfa..2b77f10b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,64 @@
-Documentation toolbox for your **javascript** / **typescript** projects based on JSDoc3 with **@category**, **@component** and **@optional** plugins.
+A Documentation toolbox for your **javascript** / **typescript**, **react**, or **react-native** projects based on JSDoc3 with tags such as
+**@category**, **@component**, **@lifecycle**, **@renders**, **@table**, **@optional**, **@inheritDesc**, **@inheritSummary**, **@inheritProperties**,
+and **@inheritParams** plugins. This template also implements several helpful options to better control the behavior of the generated web documentation
+such as, nested categorization with accordian style folding, automatically opening external `@link` tags in a new browser tab, and inheriting
+documentation from parent(s) in extended classes.
+
+# OpenSource SoftwareBrothers community
+
+- [Join the community](https://adminbro.slack.com/) to get help and be inspired.
+- subscribe to our [newsletter](http://opensource.softwarebrothers.co)
+
+# Contents
+- [Example](#example)
+- [Theme Installation](#theme-installation)
+- [Theme Usage](#theme-usage)
+- [Template Options](#template-options)
+ - [Options List](#template-options-option-list)
+ - [Using Template Options](#using-template-options)
+- [TypeScript Support](#typescript-support)
+ - [Installation](#typescript-support-installation)
+ - [How It Works](#typescript-support-how-it-works)
+ - [Examples](#typescript-support-examples)
+- Plugins
+ - [@category Plugin](#category-plugin)
+ - [Inatallation](#category-plugin-installation)
+ - [Usage](#category-plugin-usage)
+ - [@component Plugin](#component-plugin)
+ - [Installation](#component-installation)
+ - [Usage](#component-usage)
+ - [Preview](#component-preview)
+ - [Mixing Components In Preview](#component-mixing-components-in-preview)
+ - [Wrapper Component](#component-wrapper-component)
+ - [Installation](#component-wrapper-component-installation)
+ - [Usage](#component-wrapper-component-usage)
+ - [Styling React Examples](#component-styling-react-examples)
+ - [Adding commands to bundle entry file](#component-adding-commands-to-bundle-entry-file)
+ - [@lifecycle Plugin](#lifecycle-plugin)
+ - [Installation](#lifecycle-installation)
+ - [Usage](#lifecycle-usage)
+ - [@table Plugin](#table-plugin)
+ - [Installation](#table-installation)
+ - [Usage](#table-usage)
+ - ['inheritable' Plugin](#inheritable-plugin)
+ - [Installation](#inheritable-installation)
+ - [Supported Tags](#inheritable-supported-tags)
+ - [Usage](#inheritable-usage)
+ - [Using With Standard Tags](#inheritable-using-with-standard-tags)
+ - [Value Inheritance](#inheritable-value-inheritance)
+ - [Params](#inheritable-params)
+ - [Examples](#inheritable-examples)
+ - ['@typedef import' Plugin](#typedef-import-plugin)
+ - [Installation](#typedef-import-installation)
+- [Setting Up For Development](#setting-up-for-development)
+- [License](#license)
+
+
+# Example
+
+Example documentation can be found here: [](https://softwarebrothers.github.io/example-design-system/index.html)
This is how it looks:
@@ -18,21 +76,14 @@ This is how it looks:
-# Example
-
-Example documentation can be found here: https://softwarebrothers.github.io/example-design-system/index.html
-
-# OpenSource SoftwareBrothers community
-
-- [Join the community](https://join.slack.com/t/adminbro/shared_invite/zt-czfb79t1-0U7pn_KCqd5Ts~lbJK0_RA) to get help and be inspired.
-- subscribe to our [newsletter](http://opensource.softwarebrothers.co)
-
-# Installation
+
+# Theme Installation
```sh
npm install --save-dev better-docs
```
+
# Theme Usage
## With command line
@@ -61,11 +112,175 @@ in your `jsdoc.json` file, set the template:
}
```
+
+# Template Options
+
+First of all, let me state that better-docs extends the `default` template. That is why default template parameters can be used in addition to the template options
+provided by better-docs.
+
+To customize the better-docs pass `options` to `templates['better-docs']`. section in your `jsdoc configuration file`.
+
+
+## Option List
+
+[BETA]: You must explicitly set the `search` option of the `default` template to `true` to enable search
+
+better-docs has several template options which are helpful in controlling the way documentation generation behaves:
+- `name` - Text to be used as the "site title" in the header of the generated docs
+- `logo` - The path to a logo to include in the top navigation header of the generated docs
+- `title` - Text to be used as the `
"+(inherited.description ? inherited.description+"
" : '')+
+ description+
+ (inherited.inheritable.types.desc.append ? "
"+inherited.inheritable.types.desc.append : '')+"
"+description+
+ (inherited.inheritable.types.desc.append ? "
"+inherited.inheritable.types.desc.append : '')+
+ (inherited.description ? "
"+inherited.description : '')+"
"+(inherited.summary ? inherited.summary+"
" : '')+
+ summary+
+ (inherited.inheritable.types.summary.append ? "
"+inherited.inheritable.types.summary.append : '')+"
"+summary+
+ (inherited.inheritable.types.summary.append ? "
"+inherited.inheritable.types.summary.append : '')+
+ (inherited.summary ? "
"+inherited.summary : '')+"
'){ + string = string.substring(3); + } + if(string.substring(string.length-4) == '
'){ + string = string.substring(0, string.length-4); + } + return string; +} + +function mergeProps(first, second, prepend){ + second = second ? second : []; + first = first ? first : []; + + if(first.length == 0 && second.length == 0){ + //both are empty + return []; + }else if(first.length == 0 && second.length > 0){ + //first is empty, second is not + return second; + }else if(first.length > 0 && second.length == 0){ + //second is empty, first is not + return first; + }else{ + //first and second have elements + let merged=[]; + //put any elements in first that are not in second into merged + //leave second alone, and we will append/prepend afterwards + //this way we can keep the params grouped by where they are defined + for(var x=0; x?) and now look like http(s):\\/\\/
+ if((/(http|ftp)s?:/).test(longname)){
+ external = true;
+ link = link.replace(text, text.replace(/\\\\\//ig, '/'));
+ }
+ if(matches[2] && matches[2].trim()){
+ text = matches[2].trim();
+ }
+ }
+ return {
+ text: text,
+ link: link,
+ external: external,
+ inline: inline.isInlineTag(longname)
+ };
+ };
+ const origLinkto = helper.linkto;
+ //Override this function so we can automatically open inline link tags to URL's in a new tab
+ linkto = helper.linkto = function(longname, linkText, cssClass, fragmentId){
+ let parsed = parseLink(longname);
+
+ if(parsed.inline && parsed.external){
+ //This is an external link, so let's add a target to the anchor so it will open in another window
+ return util.format('%s',
+ encodeURI(parsed.link),
+ cssClass ? util.format(' class="%s"', cssClass) : '',
+ htmlsafe(parsed.text)
+ );
+ }else{
+ if(!linkText && parsed.text && parsed.text != longname){
+ linkText = parsed.text;
+ }
+ let link = longname;
+ if(parsed.link && parsed.link != longname){
+ link = parsed.link;
+ }
+ let rtn = origLinkto(link, linkText, cssClass, fragmentId);
+
+ let skip = [
+ 'null',
+ 'object',
+ 'string',
+ 'bool',
+ 'boolean',
+ 'function',
+ 'int',
+ 'float',
+ 'number',
+ 'undefined',
+ 'promise',
+ '*',
+ 'array',
+ 'uint8array',
+ 'arraybufferview',
+ 'arraybuffer',
+ 'date',
+ 'enum',
+ 'error',
+ ];
+
+ if(skip.indexOf(longname.toLowerCase()) < 0 && rtn.indexOf('= 0){
+ let matches = (new RegExp(/^(.*).<\(?(.*)[\)?]>/)).exec(longname);
+ if(matches && matches.length >= 1){
+ if(matches.length >= 2){
+ types = matches[2].split('|');
+ Object.keys(types).forEach(key => types[key] = types[key].trim());
+ }
+ if(matches[1].trim()){
+ types.unshift(matches[1].trim());
+ }
+ }
+ }
+ if(types.length <= 0){
+ skip.forEach(type => {
+ if('Array.<'+type+'>' == longname){
+ found=true;
+ }
+ });
+ if(!found){
+ console.log('Invalid link to '+longname, linkText);
+ }
+ }else{
+ types.forEach(type => {
+ if(skip.indexOf(type.toLowerCase()) < 0){
+ console.log('Invalid link to '+type+' for '+longname, linkText);
+ }
+ });
+ }
+
+ }
+
+ return rtn;
+ }
+ };
+ //save the original resolveLinks so we can use it after we are done with our alterations
+ const resolveLinks = helper.resolveLinks;
+ var visited=[];
+ //replace the inline tag with an actual link
+ const doReplace = (string, {completeTag, text, tag}) => {
+ let tagIndex = string.indexOf(completeTag);
+ if(visited.indexOf(tagIndex) < 0){
+ visited.push(tagIndex);
+ let parsed = parseLink(completeTag);
+ //Only operate on external links, and let the original resolveLinks handle the others later.
+ if(parsed.external){
+ let linkText = parsed.text && parsed.text != completeTag ? parsed.text : null;
+ let theLink = linkto(completeTag, linkText);
+
+ return string.replace( completeTag, theLink );
+ }else{
+ //if we return an unaltered string, then the processing of inline link tags will stop
+ //so we'll add a space to the end, and then remove them before calling the original resolveLinks
+ return string+' ';
+ }
+ }else{
+ //we don't want to get stuck in a loop continuously trying to parse the same tag
+ //but we can't return the same string or we'll never visit subsequent links
+ //so we'll replace the tag with an unknown tag, which will be put back to a link AFTER we've
+ //processed the whole file.
+
+ return string.replace( completeTag, completeTag.replace('{@'+tag, '{@betterdocsreplaced'+tag) );
+ }
+ };
+ const restoreBetterDocsReplaced = (string, {completeTag, text, tag}) => {
+ let type = tag.replace('betterdocsreplaced','');
+ return string.replace( completeTag, completeTag.replace('{@'+tag, '{@'+type) );
+ };
+
+ helper.resolveLinks = string => {
+ //let's handle the link tags that we are going to operate on
+ let processors = {
+ link: doReplace,
+ linkcode: doReplace,
+ linkplain: doReplace,
+ };
+ string = inline.replaceInlineTags(string, processors).newString;
+
+ //now let's put back the betterdocsreplaced tags that we added in doReplace
+ let betterDocsProcessors = {};
+ Object.keys(processors).forEach(name => {
+ betterDocsProcessors['betterdocsreplaced'+name] = restoreBetterDocsReplaced;
+ });
+ string = inline.replaceInlineTags(string, betterDocsProcessors).newString;
+
+ //Empty our visited so we're ready for the next file.
+ visited=[];
+ //Now let the original resolveLinks handle whatever we didn't
+ //doReplace may have added spaces to the end of the string, so we'll remove them with a trim()
+ return resolveLinks(string.trim());
+ };
+}
+
var resolveAuthorLinks = helper.resolveAuthorLinks
var hasOwnProp = Object.prototype.hasOwnProperty
@@ -199,6 +372,17 @@ function addSignatureTypes(f) {
function addAttribs(f) {
var attribs = helper.getAttribs(f)
+
+ //For the @lifecycle tag when using the lifecycle plugin
+ if(f.hasOwnProperty('lifecycle') && f.lifecycle){
+ attribs.push('React Lifecycle');
+ }
+
+ //For the @renders tag when using the lifecycle plugin
+ if(f.hasOwnProperty('renders') && f.renders){
+ attribs.push('Causes Render');
+ }
+
var attribsString = buildAttribsString(attribs)
f.attribs = util.format('%s', attribsString)
@@ -388,6 +572,9 @@ function linktoExternal(longName, name) {
}
function buildGroupNav (members, title) {
+ if (env.conf.templates.betterDocs.useNestedCategories) {
+ return buildGroupNavNested(members, title);
+ }
var globalNav
var seenTutorials = {}
var nav = ''
@@ -446,7 +633,10 @@ function buildGroupNav (members, title) {
function buildNav(members, navTypes = null, betterDocs) {
const href = betterDocs.landing ? 'docs.html' : 'index.html'
var nav = navTypes ? '' : `Documentation
`
-
+ if (env.conf.templates.betterDocs.includeTodoPage) {
+ let todoHref = 'Todo.html';
+ nav += `TODO
`;
+ }
var categorised = {}
var rootScope = {}
@@ -476,6 +666,222 @@ function buildNav(members, navTypes = null, betterDocs) {
return nav
}
+/**
+ *
+ * Build the navigation for a given set of members which belong to the category defined in the title
+ *
+ * @param {object} items The members that will be used to create the sidebar.
+ * @param {array