-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.js
More file actions
110 lines (91 loc) · 3.13 KB
/
Copy pathindex.js
File metadata and controls
110 lines (91 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
const logger = require('jsdoc/util/logger');
const path = require('path');
logger.debug('[JMN] Loaded jsdoc-memberof-namespace');
const kinds = ['class', 'constant', 'function', 'namespace'];
const namespaces = [];
const handlers = {
parseBegin: (event) => {
event.sourcefiles.sort((f1, f2) => isIndex(f1) === isIndex(f2) ? 0 : isIndex(f1) ? -1 : 1);
logger.debug('[JMN] Sorted', event.sourcefiles);
},
newDoclet: (event) => {
const doc = event.doclet;
const dsc = `${doc.kind} ${doc.longname} in ${doc.meta ? doc.meta.filename : '.'}`;
if (doc.undocumented) {
logger.verbose(`[JMN] Skipped undocumented ${dsc}`);
return;
}
if (doc.kind === 'namespace' && isEmpty(doc.meta.code)) {
if (namespaces.every(ns => ns.longname !== doc.longname)) {
logger.debug(`[JMN] Found ${dsc}`);
} else {
logger.warn(`[JMN] Found duplicate ${dsc}`);
}
namespaces.push(doc);
return;
}
if (!kinds.includes(doc.kind)) {
logger.debug(`[JMN] Skipped ${dsc}`);
return;
}
if (doc.memberof) {
logger.debug(`[JMN] Skipped ${dsc} member of ${doc.memberof}`);
return;
}
const namespace = getNamespace(doc.meta.filename, doc.meta.path);
if (!namespace) {
logger.warn(`[JMN] Namespace not found for ${dsc}`);
return;
}
doc.memberof = namespace.longname;
doc.longname = `${doc.memberof}.${doc.longname}`;
if (doc.scope === 'global') doc.scope = 'static';
logger.debug(`[JMN] Processed ${dsc} member of ${doc.memberof}`);
}
};
/**
* Check if value is falsy or empty
* @param {Object} value - Object
* @return {boolean} - True if falsy or empty, false otherwise
*/
function isEmpty(value) {
return !value || Object.keys(value).length === 0;
}
/**
* Check if file path is an index.js file
* @param {string} file - File path
* @return {boolean} True if file is index.js, false otherwise
*/
function isIndex(file) {
return path.basename(file).toLowerCase() === 'index.js';
}
/**
* Check if directory path is parent of a subdirectory path
* @param {string} parent - Directory path
* @param {string} child - Subdirectory path
* @return {boolean} - True if subdirectory is in directory, false otherwise
*/
function isParent(parent, child) {
return !path.relative(parent, child).startsWith('..');
}
/**
* Get closest namespace doclet previously parsed either from the same file as the doclet
* or from one of the index.js files present in the same directory or any of its parents
*
* @param {string} file - File name of the doclet
* @param {string} path - Directory path of the doclet
* @return {?Doclet} - Namespace doclet or null
*/
function getNamespace(file, path) {
const files = namespaces.filter(ns => ns.meta.filename === file && ns.meta.path === path);
if (files.length > 0) {
return files[files.length - 1];
}
const paths = namespaces.filter(ns => isIndex(ns.meta.filename) && isParent(ns.meta.path, path));
if (paths.length > 0) {
paths.sort((ns1, ns2) => ns1.meta.path.length - ns2.meta.path.length);
return paths[paths.length - 1];
}
return null;
}
module.exports = { handlers };