diff --git a/src/extractors/exported.js b/src/extractors/exported.js index 4470cb452..da6f8955b 100644 --- a/src/extractors/exported.js +++ b/src/extractors/exported.js @@ -15,6 +15,8 @@ const traverse = babelTraverse.default || babelTraverse; * and inserting blank comments into documentation.js's processing stream. * Through inference steps, these comments gain more information and are automatically * documented as well as we can. + * @param {Object} config + * @param {Object} [config.extensions] extensions to try when resolving * @param {Object} ast the babel-parsed syntax tree * @param {Object} data the name of the file * @param {Function} addComment a method that creates a new comment if necessary @@ -22,6 +24,7 @@ const traverse = babelTraverse.default || babelTraverse; * @private */ export default function walkExported( + config /* { extensions?: string[] } */, ast, data /*: { file: string @@ -120,7 +123,8 @@ export default function walkExported( local, exportKind, filename, - source.value + source.value, + config.extensions ); bindingPath = tmp.ast; specData = tmp.data; @@ -181,16 +185,40 @@ function traverseExportedSubtree(path, data, addComments, overrideName) { } } -function getCachedData(dataCache, filePath) { - let path = filePath; - if (!nodePath.extname(path)) { - path = require.resolve(path); +function resolveFile(filePath, extensions = []) { + try { + // First try resolving the file with the default extensions. + return require.resolve(filePath); + } catch { + // If that fails, try resolving the file with the extensions passed in. } + // Then try all other extensions in order. + for (const extension of extensions) { + try { + return require.resolve( + `${filePath}${extension.startsWith('.') ? extension : `.${extension}`}` + ); + } catch { + continue; + } + } + + throw new Error( + `Could not resolve \`${filePath}\` with any of the extensions: ${[ + ...require.extensions, + ...extensions + ].join(', ')}` + ); +} + +function getCachedData(dataCache, filePath, extensions) { + const path = resolveFile(filePath, extensions); + let value = dataCache.get(path); if (!value) { const input = fs.readFileSync(path, 'utf-8'); - const ast = parseToAst(input, filePath); + const ast = parseToAst(input, path); value = { data: { file: path, @@ -209,10 +237,11 @@ function findExportDeclaration( name, exportKind, referrer, - filename + filename, + extensions ) { const depPath = nodePath.resolve(nodePath.dirname(referrer), filename); - const tmp = getCachedData(dataCache, depPath); + const tmp = getCachedData(dataCache, depPath, extensions); const ast = tmp.ast; let data = tmp.data; @@ -273,7 +302,8 @@ function findExportDeclaration( local, exportKind, depPath, - source.value + source.value, + extensions ); rv = tmp.ast; data = tmp.data; diff --git a/src/parsers/javascript.js b/src/parsers/javascript.js index d4a72399d..880af6547 100644 --- a/src/parsers/javascript.js +++ b/src/parsers/javascript.js @@ -24,9 +24,13 @@ export default function parseJavaScript(data, config) { const ast = parseToAst(data.source, data.file); const addComment = _addComment.bind(null, visited, commentsByNode); + const extensions = [] + .concat(config.parseExtension, config.requireExtension) + .filter(Boolean); + return _.flatMap( config.documentExported - ? [walkExported] + ? [walkExported.bind(null, { extensions })] : [ walkComments.bind(null, 'leadingComments', true), walkComments.bind(null, 'innerComments', false),