1 | const _ = require('lodash');
|
2 | const t = require('@babel/types');
|
3 | const parse = require('../parse');
|
4 | const walkComments = require('../extractors/comments');
|
5 | const walkExported = require('../extractors/exported');
|
6 | const util = require('util');
|
7 | const debuglog = util.debuglog('documentation');
|
8 | const findTarget = require('../infer/finders').findTarget;
|
9 | const { parseToAst } = require('./parse_to_ast');
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | function leftPad(str, width) {
|
20 | str = str.toString();
|
21 | while (str.length < width) {
|
22 | str = '0' + str;
|
23 | }
|
24 | return str;
|
25 | }
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | function parseJavaScript(data, config) {
|
36 | const visited = new Set();
|
37 | const commentsByNode = new Map();
|
38 |
|
39 | const ast = parseToAst(data.source, data.file);
|
40 | const addComment = _addComment.bind(null, visited, commentsByNode);
|
41 |
|
42 | return _.flatMap(
|
43 | config.documentExported
|
44 | ? [walkExported]
|
45 | : [
|
46 | walkComments.bind(null, 'leadingComments', true),
|
47 | walkComments.bind(null, 'innerComments', false),
|
48 | walkComments.bind(null, 'trailingComments', false)
|
49 | ],
|
50 | fn => fn(ast, data, addComment)
|
51 | ).filter(comment => comment && !comment.lends);
|
52 | }
|
53 |
|
54 | function _addComment(
|
55 | visited,
|
56 | commentsByNode,
|
57 | data,
|
58 | commentValue,
|
59 | commentLoc,
|
60 | path,
|
61 | nodeLoc,
|
62 | includeContext
|
63 | ) {
|
64 |
|
65 |
|
66 | const key =
|
67 | data.file + ':' + commentLoc.start.line + ':' + commentLoc.start.column;
|
68 | if (!visited.has(key)) {
|
69 | visited.add(key);
|
70 |
|
71 | const context |
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | = {
|
78 | loc: nodeLoc,
|
79 | file: data.file,
|
80 | sortKey: data.sortKey + ' ' + leftPad(nodeLoc.start.line, 8)
|
81 | };
|
82 |
|
83 | if (includeContext) {
|
84 |
|
85 |
|
86 | Object.defineProperty(context, 'ast', {
|
87 | configurable: true,
|
88 | enumerable: false,
|
89 | value: path
|
90 | });
|
91 |
|
92 | if (path.parentPath && path.parentPath.node) {
|
93 | const parentNode = path.parentPath.node;
|
94 | context.code = data.source.substring(parentNode.start, parentNode.end);
|
95 | }
|
96 | }
|
97 | const comment = parse(commentValue, commentLoc, context);
|
98 | if (includeContext) {
|
99 | commentsByNode.set((findTarget(path) || path).node, comment);
|
100 |
|
101 | if (t.isClassMethod(path) && path.node.kind === 'constructor') {
|
102 |
|
103 | if (
|
104 | comment.tags.some(
|
105 | tag => tag.title !== 'param' && tag.title !== 'hideconstructor'
|
106 | )
|
107 | ) {
|
108 | debuglog(
|
109 | 'A constructor was documented explicitly: document along with the class instead'
|
110 | );
|
111 | }
|
112 |
|
113 | const parentComment = commentsByNode.get(
|
114 | path.parentPath.parentPath.node
|
115 | );
|
116 | if (parentComment) {
|
117 | parentComment.constructorComment = comment;
|
118 | return;
|
119 | }
|
120 | if (comment.hideconstructor) {
|
121 | return;
|
122 | }
|
123 | }
|
124 | }
|
125 | return comment;
|
126 | }
|
127 | }
|
128 |
|
129 | module.exports = parseJavaScript;
|