1 | const parseMarkdown = require('./parse_markdown');
|
2 | const chalk = require('chalk');
|
3 | const path = require('path');
|
4 | const fs = require('fs');
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | module.exports = function sortDocs(comments, options) {
|
16 | if (!options || !options.toc) {
|
17 | return sortComments(comments, options && options.sortOrder);
|
18 | }
|
19 | let i = 0;
|
20 | const indexes = Object.create(null);
|
21 | const toBeSorted = Object.create(null);
|
22 | const paths = Object.create(null);
|
23 | const fixed = [];
|
24 | const walk = function(tocPath, val) {
|
25 | if (typeof val === 'object' && val.name) {
|
26 | val.kind = 'note';
|
27 | indexes[val.name] = i++;
|
28 | if (typeof val.file === 'string') {
|
29 | let filename = val.file;
|
30 | if (!path.isAbsolute(val.file)) {
|
31 | filename = path.join(process.cwd(), val.file);
|
32 | }
|
33 |
|
34 | try {
|
35 | val.description = fs.readFileSync(filename).toString();
|
36 | delete val.file;
|
37 | } catch (err) {
|
38 | process.stderr.write(chalk.red(`Failed to read file ${filename}`));
|
39 | }
|
40 | } else if (!val.description) {
|
41 | val.description = '';
|
42 | }
|
43 | if (typeof val.description === 'string') {
|
44 | val.description = parseMarkdown(val.description);
|
45 | }
|
46 | const childPath = tocPath.concat({ scope: 'static', name: val.name });
|
47 | val.path = childPath;
|
48 | if (val.children) {
|
49 | val.children.forEach(walk.bind(null, childPath));
|
50 | }
|
51 | fixed.push(val);
|
52 | } else {
|
53 | indexes[val] = i++;
|
54 | toBeSorted[val] = false;
|
55 | paths[val] = tocPath.concat({ scope: 'static', name: val, toc: true });
|
56 | }
|
57 | };
|
58 |
|
59 |
|
60 | options.toc.forEach(walk.bind(null, []));
|
61 | const unfixed = [];
|
62 | comments.forEach(function(comment) {
|
63 | let commentPath;
|
64 | if (!comment.memberof && (commentPath = paths[comment.name])) {
|
65 | comment.path = commentPath;
|
66 | delete paths[comment.name];
|
67 | }
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | if (comment.kind === 'note') {
|
73 | return;
|
74 | }
|
75 |
|
76 |
|
77 |
|
78 | if (!comment.memberof && indexes[comment.name] !== undefined) {
|
79 | fixed.push(comment);
|
80 | toBeSorted[comment.name] = true;
|
81 | } else {
|
82 | unfixed.push(comment);
|
83 | }
|
84 | });
|
85 | fixed.sort((a, b) => {
|
86 | if (indexes[a.name] !== undefined && indexes[b.name] !== undefined) {
|
87 | return indexes[a.name] - indexes[b.name];
|
88 | }
|
89 | return 0;
|
90 | });
|
91 | sortComments(unfixed, options.sortOrder);
|
92 | Object.keys(toBeSorted)
|
93 | .filter(key => toBeSorted[key] === false)
|
94 | .forEach(key => {
|
95 | process.stderr.write(
|
96 | chalk.red(
|
97 | 'Table of contents defined sorting of ' +
|
98 | key +
|
99 | ' but no documentation with that namepath was found\n'
|
100 | )
|
101 | );
|
102 | });
|
103 | return fixed.concat(unfixed);
|
104 | };
|
105 |
|
106 | function compareCommentsByName(a, b) {
|
107 | const akey = a.name;
|
108 | const bkey = b.name;
|
109 |
|
110 | if (akey && bkey) {
|
111 | return akey.localeCompare(bkey, undefined, { caseFirst: 'upper' });
|
112 | }
|
113 | return 0;
|
114 | }
|
115 |
|
116 | function compareCommentsBySourceLocation(a, b) {
|
117 | return a.context.sortKey.localeCompare(b.context.sortKey);
|
118 | }
|
119 |
|
120 | function sortComments(comments, sortOrder) {
|
121 | return comments.sort(
|
122 | sortOrder === 'alpha'
|
123 | ? compareCommentsByName
|
124 | : compareCommentsBySourceLocation
|
125 | );
|
126 | }
|