Skip to content

Commit

Permalink
feat: groups in toc (#895)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhendric authored and tmcw committed Sep 4, 2017
1 parent 7a07d51 commit c94412a
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 45 deletions.
49 changes: 49 additions & 0 deletions __tests__/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,55 @@ World
"
`;

exports[`config with nested sections 1`] = `
"<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
## Alpha
### third
This function is third
### first
This function is first
## Bravo
Contains a subsection!
### Charlie
Second is in here
#### second
This class has some members
##### foo
second::foo
**Parameters**
- \`pork\`
##### bar
second::bar
**Parameters**
- \`beans\`
- \`rice\`
"
`;

exports[`external modules option 1`] = `
Array [
Object {
Expand Down
12 changes: 12 additions & 0 deletions __tests__/fixture/sections.config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
toc:
- name: Alpha
children:
- third
- first
- name: Bravo
description: Contains a subsection!
children:
- name: Charlie
description: Second is in here
children:
- second
24 changes: 24 additions & 0 deletions __tests__/fixture/sections.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* This function is first
*/
function first() {}

/**
* This class has some members
*/
function second() {}

/**
* second::foo
*/
second.prototype.foo = function(pork) {};

/**
* second::bar
*/
second.prototype.bar = function(beans, rice) {};

/**
* This function is third
*/
function third() {}
66 changes: 65 additions & 1 deletion __tests__/lib/__snapshots__/sort.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,67 @@
exports[`sort toc with files 1`] = `
Array [
Object {
"file": "test/fixture/snowflake.md",
"description": Object {
"children": Array [
Object {
"children": Array [
Object {
"position": Position {
"end": Object {
"column": 16,
"line": 1,
"offset": 15,
},
"indent": Array [],
"start": Object {
"column": 3,
"line": 1,
"offset": 2,
},
},
"type": "text",
"value": "The Snowflake",
},
],
"depth": 1,
"position": Position {
"end": Object {
"column": 16,
"line": 1,
"offset": 15,
},
"indent": Array [],
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
},
"type": "heading",
},
],
"position": Object {
"end": Object {
"column": 1,
"line": 2,
"offset": 16,
},
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
},
"type": "root",
},
"kind": "note",
"name": "snowflake",
"path": Array [
Object {
"name": "snowflake",
"scope": "static",
},
],
},
Object {
"context": Object {
Expand Down Expand Up @@ -86,6 +144,12 @@ Array [
},
"kind": "note",
"name": "snowflake",
"path": Array [
Object {
"name": "snowflake",
"scope": "static",
},
],
},
Object {
"context": Object {
Expand Down
18 changes: 15 additions & 3 deletions __tests__/lib/sort.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,13 @@ test('sort stream with configuration and a section', function() {
}
}
},
kind: 'note'
kind: 'note',
path: [
{
name: 'This is the banana type',
scope: 'static'
}
]
};

expect(
Expand Down Expand Up @@ -161,7 +167,13 @@ test('sort an already-sorted stream containing a section/description', function(
}
}
},
kind: 'note'
kind: 'note',
path: [
{
name: 'This is the banana type',
scope: 'static'
}
]
};

var config = {
Expand All @@ -180,7 +192,7 @@ test('sort toc with files', function() {

var snowflake = {
name: 'snowflake',
file: 'test/fixture/snowflake.md'
file: path.join(__dirname, '../fixture/snowflake.md')
};

expect(
Expand Down
9 changes: 9 additions & 0 deletions __tests__/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ test('config', async function() {
expect(md).toMatchSnapshot();
});

test('config with nested sections', async function() {
var file = path.join(__dirname, 'fixture', 'sections.input.js');
const out = await documentation.build([file], {
config: path.join(__dirname, 'fixture', 'sections.config.yml')
});
const md = await outputMarkdown(out, {});
expect(md).toMatchSnapshot();
});

test('multi-file input', async function() {
const result = await documentation.build(
[
Expand Down
19 changes: 19 additions & 0 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,22 @@ and areas on the sphere.
```

it would produce the same output as the previous example.

## Groups

The `children` property can be used to group content under headings instead of just arranging them in order. Example:

```yml
toc:
- name: Geography
children:
- Map
- LngLat
- LngLatBounds
- name: Navigation
description: |
Here are some helper functions for navigation.
children:
- shortestPath
- salesman
```
71 changes: 54 additions & 17 deletions src/hierarchy.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,39 +55,73 @@ module.exports = function(comments) {
members: getMembers()
};

const namesToUnroot = [];

comments.forEach(comment => {
var path = [];
let path = comment.path;
if (!path) {
path = [];

if (comment.memberof) {
// TODO: full namepath parsing
path = comment.memberof
.split('.')
.map(segment => ({ scope: 'static', name: segment }));
}

if (comment.memberof) {
// TODO: full namepath parsing
path = comment.memberof.split('.').map(segment => ['static', segment]);
}
if (!comment.name) {
comment.errors.push({
message: 'could not determine @name for hierarchy'
});
}

if (!comment.name) {
comment.errors.push({
message: 'could not determine @name for hierarchy'
path.push({
scope: comment.scope || 'static',
name: comment.name || 'unknown_' + id++
});
}

path.push([comment.scope || 'static', comment.name || 'unknown_' + id++]);

var node = root;

while (path.length) {
var segment = path.shift(), scope = segment[0], name = segment[1];
var segment = path.shift(),
scope = segment.scope,
name = segment.name;

if (!hasOwnProperty.call(node.members[scope], name)) {
node.members[scope][name] = {
comments: [],
members: getMembers()
};
// If segment.toc is true, everything up to this point in the path
// represents how the documentation should be nested, but not how the
// actual code is nested. To ensure that child members end up in the
// right places in the tree, we temporarily push the same node a second
// time to the root of the tree, and unroot it after all the comments
// have found their homes.
if (
segment.toc &&
node !== root &&
hasOwnProperty.call(root.members[scope], name)
) {
node.members[scope][name] = root.members[scope][name];
namesToUnroot.push(name);
} else {
const newNode = (node.members[scope][name] = {
comments: [],
members: getMembers()
});
if (segment.toc && node !== root) {
root.members[scope][name] = newNode;
namesToUnroot.push(name);
}
}
}

node = node.members[scope][name];
}

node.comments.push(comment);
});
namesToUnroot.forEach(function(name) {
delete root.members.static[name];
});

/*
* Massage the hierarchy into a format more suitable for downstream consumers:
Expand All @@ -107,7 +141,8 @@ module.exports = function(comments) {
* Person~say // the inner method named "say."
*/
function toComments(nodes, root, hasUndefinedParent, path) {
var result = [], scope;
var result = [],
scope;

path = path || [];

Expand All @@ -119,7 +154,9 @@ module.exports = function(comments) {
node.members[scope],
root || result,
!node.comments.length,
node.comments.length ? path.concat(node.comments[0]) : []
node.comments.length && node.comments[0].kind !== 'note'
? path.concat(node.comments[0])
: []
);
}

Expand Down
13 changes: 10 additions & 3 deletions src/output/markdown_ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,16 @@ function buildMarkdownAST(
}

if (comment.kind === 'note') {
return [u('heading', { depth }, [u('text', comment.name || '')])].concat(
comment.description
);
return [u('heading', { depth }, [u('text', comment.name || '')])]
.concat(comment.description)
.concat(
!!comment.members.static.length &&
comment.members.static.reduce(
(memo, child) => memo.concat(generate(depth + 1, child)),
[]
)
)
.filter(Boolean);
}

return [u('heading', { depth }, [u('text', comment.name || '')])]
Expand Down
Loading

0 comments on commit c94412a

Please sign in to comment.