Skip to content

Commit ff15459

Browse files
Handle modules outside module root
1 parent 4116d7a commit ff15459

1 file changed

Lines changed: 32 additions & 35 deletions

File tree

index.js

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ const addInherited = require('jsdoc/augment').addInherited; // eslint-disable-li
77
const config = env.conf.typescript;
88
if (!config) {
99
throw new Error(
10-
'Configuration "typescript" for jsdoc-plugin-typescript missing.',
10+
'Configuration "typescript" for jsdoc-plugin-typescript missing.'
1111
);
1212
}
1313
if (!('moduleRoot' in config)) {
1414
throw new Error(
15-
'Configuration "typescript.moduleRoot" for jsdoc-plugin-typescript missing.',
15+
'Configuration "typescript.moduleRoot" for jsdoc-plugin-typescript missing.'
1616
);
1717
}
1818
const moduleRoot = config.moduleRoot;
@@ -21,7 +21,7 @@ if (!fs.existsSync(moduleRootAbsolute)) {
2121
throw new Error(
2222
'Directory "' +
2323
moduleRootAbsolute +
24-
'" does not exist. Check the "typescript.moduleRoot" config option for jsdoc-plugin-typescript',
24+
'" does not exist. Check the "typescript.moduleRoot" config option for jsdoc-plugin-typescript'
2525
);
2626
}
2727

@@ -31,6 +31,7 @@ const typedefRegEx = /@typedef \{[^\}]*\} (\S+)/g;
3131
const noClassdescRegEx = /@(typedef|module|type)/;
3232
const extensionReplaceRegEx = /\.m?js$/;
3333
const slashRegEx = /\\/g;
34+
const leadingPathSegmentRegEx = /^(.?.[/\\])+/;
3435

3536
const moduleInfos = {};
3637
const fileNodes = {};
@@ -44,11 +45,7 @@ function getExtension(absolutePath) {
4445
function getModuleInfo(moduleId, extension, parser) {
4546
if (!moduleInfos[moduleId]) {
4647
if (!fileNodes[moduleId]) {
47-
const absolutePath = path.join(
48-
process.cwd(),
49-
moduleRoot,
50-
moduleId + extension,
51-
);
48+
const absolutePath = path.join(moduleRootAbsolute, moduleId + extension);
5249
if (!fs.existsSync(absolutePath)) {
5350
return null;
5451
}
@@ -91,6 +88,13 @@ function getDelimiter(moduleId, symbol, parser) {
9188
return getModuleInfo(moduleId, parser).namedExports[symbol] ? '.' : '~';
9289
}
9390

91+
function getModuleId(modulePath) {
92+
return path
93+
.relative(moduleRootAbsolute, modulePath)
94+
.replace(extensionReplaceRegEx, '')
95+
.replace(leadingPathSegmentRegEx, '');
96+
}
97+
9498
exports.defineTags = function (dictionary) {
9599
['type', 'typedef', 'property', 'return', 'param', 'template'].forEach(
96100
function (tagName) {
@@ -135,17 +139,14 @@ exports.defineTags = function (dictionary) {
135139
}
136140
throw new Error("Missing closing '}'");
137141
};
138-
},
142+
}
139143
);
140144
};
141145

142146
exports.astNodeVisitor = {
143147
visitNode: function (node, e, parser, currentSourceName) {
144148
if (node.type === 'File') {
145-
const modulePath = path
146-
.relative(path.join(process.cwd(), moduleRoot), currentSourceName)
147-
.replace(extensionReplaceRegEx, '');
148-
fileNodes[modulePath] = node;
149+
fileNodes[getModuleId(currentSourceName)] = node;
149150
const identifiers = {};
150151
if (node.program && node.program.body) {
151152
const nodes = node.program.body;
@@ -229,10 +230,10 @@ exports.astNodeVisitor = {
229230
if (
230231
leadingComments.length === 0 ||
231232
(leadingComments[leadingComments.length - 1].value.indexOf(
232-
'@classdesc',
233+
'@classdesc'
233234
) === -1 &&
234235
noClassdescRegEx.test(
235-
leadingComments[leadingComments.length - 1].value,
236+
leadingComments[leadingComments.length - 1].value
236237
))
237238
) {
238239
// Create a suitable comment node if we don't have one on the class yet
@@ -250,7 +251,7 @@ exports.astNodeVisitor = {
250251
if (node.superClass) {
251252
// Remove the `@extends` tag because JSDoc does not does not handle generic type. (`@extends {Base<Type>}`)
252253
const extendsIndex = lines.findIndex((line) =>
253-
line.includes('@extends'),
254+
line.includes('@extends')
254255
);
255256
if (extendsIndex !== -1) {
256257
lines.splice(extendsIndex, 1);
@@ -262,13 +263,12 @@ exports.astNodeVisitor = {
262263
if (identifier) {
263264
const absolutePath = path.resolve(
264265
path.dirname(currentSourceName),
265-
identifier.value,
266+
identifier.value
266267
);
267268
// default to js extension since .js extention is assumed implicitly
268269
const extension = getExtension(absolutePath);
269-
const moduleId = path
270-
.relative(path.join(process.cwd(), moduleRoot), absolutePath)
271-
.replace(extensionReplaceRegEx, '');
270+
const moduleId = getModuleId(absolutePath);
271+
272272
if (getModuleInfo(moduleId, extension, parser)) {
273273
const exportName = identifier.defaultImport
274274
? getDefaultExportName(moduleId, parser)
@@ -295,7 +295,7 @@ exports.astNodeVisitor = {
295295
// Replace typeof Foo with Class<Foo>
296296
comment.value = comment.value.replace(
297297
/typeof ([^,\|\}\>]*)([,\|\}\>])/g,
298-
'Class<$1>$2',
298+
'Class<$1>$2'
299299
);
300300

301301
// Remove `@override` annotations to avoid JSDoc breaking the inheritance chain
@@ -323,7 +323,7 @@ exports.astNodeVisitor = {
323323
if (replaceAttempt > 100) {
324324
// infinite loop protection
325325
throw new Error(
326-
`Invalid docstring ${comment.value} in ${currentSourceName}.`,
326+
`Invalid docstring ${comment.value} in ${currentSourceName}.`
327327
);
328328
}
329329
} else {
@@ -332,13 +332,12 @@ exports.astNodeVisitor = {
332332
lastImportPath = importExpression;
333333
const rel = path.resolve(
334334
path.dirname(currentSourceName),
335-
importSource,
335+
importSource
336336
);
337337
// default to js extension since .js extention is assumed implicitly
338338
const extension = getExtension(rel);
339-
const moduleId = path
340-
.relative(path.join(process.cwd(), moduleRoot), rel)
341-
.replace(extensionReplaceRegEx, '');
339+
const moduleId = getModuleId(rel);
340+
342341
if (getModuleInfo(moduleId, extension, parser)) {
343342
const name =
344343
exportName === 'default'
@@ -356,7 +355,7 @@ exports.astNodeVisitor = {
356355
if (replacement) {
357356
comment.value = comment.value.replace(
358357
importExpression,
359-
replacement + remainder,
358+
replacement + remainder
360359
);
361360
}
362361
}
@@ -377,13 +376,13 @@ exports.astNodeVisitor = {
377376
Object.keys(identifiers).forEach((key) => {
378377
const eventRegex = new RegExp(
379378
`@(event |fires )${key}([^A-Za-z])`,
380-
'g',
379+
'g'
381380
);
382381
replace(eventRegex);
383382

384383
const typeRegex = new RegExp(
385384
`@(.*[{<|,(!?:]\\s*)${key}([^A-Za-z].*?\}|\})`,
386-
'g',
385+
'g'
387386
);
388387
replace(typeRegex);
389388

@@ -392,13 +391,11 @@ exports.astNodeVisitor = {
392391
const identifier = identifiers[key];
393392
const absolutePath = path.resolve(
394393
path.dirname(currentSourceName),
395-
identifier.value,
394+
identifier.value
396395
);
397396
// default to js extension since .js extention is assumed implicitly
398397
const extension = getExtension(absolutePath);
399-
const moduleId = path
400-
.relative(path.join(process.cwd(), moduleRoot), absolutePath)
401-
.replace(extensionReplaceRegEx, '');
398+
const moduleId = getModuleId(absolutePath);
402399
if (getModuleInfo(moduleId, extension, parser)) {
403400
const exportName = identifier.defaultImport
404401
? getDefaultExportName(moduleId, parser)
@@ -408,11 +405,11 @@ exports.astNodeVisitor = {
408405
: getDelimiter(moduleId, exportName, parser);
409406
const replacement = `module:${moduleId.replace(
410407
slashRegEx,
411-
'/',
408+
'/'
412409
)}${exportName ? delimiter + exportName : ''}`;
413410
comment.value = comment.value.replace(
414411
regex,
415-
'@$1' + replacement + '$2',
412+
'@$1' + replacement + '$2'
416413
);
417414
}
418415
}

0 commit comments

Comments
 (0)