Skip to content

Commit

Permalink
filter docgen import resolution files to only JS
Browse files Browse the repository at this point in the history
  • Loading branch information
ndelangen committed Feb 29, 2024
1 parent 524d657 commit 1d5e9f8
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 9 deletions.
3 changes: 2 additions & 1 deletion code/frameworks/react-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"@storybook/builder-vite": "workspace:*",
"@storybook/react": "workspace:*",
"magic-string": "^0.30.0",
"react-docgen": "^7.0.0"
"react-docgen": "^7.0.0",
"resolve": "^1.22.8"
},
"devDependencies": {
"@types/node": "^18.0.0",
Expand Down
60 changes: 60 additions & 0 deletions code/frameworks/react-vite/src/plugins/docgen-resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { extname } from 'path';
import resolve from 'resolve';

export class ReactDocgenResolveError extends Error {
// the magic string that react-docgen uses to check if a module is ignored
readonly code = 'MODULE_NOT_FOUND';

constructor(filename: string) {
super(`'${filename}' was ignored by react-docgen.`);
}
}

/* The below code was copied from:
* https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63
* because it wasn't exported from the react-docgen package.
*/

// These extensions are sorted by priority
// resolve() will check for files in the order these extensions are sorted
const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx'];

export function defaultLookupModule(filename: string, basedir: string): string {
const resolveOptions = {
basedir,
extensions: RESOLVE_EXTENSIONS,
// we do not need to check core modules as we cannot import them anyway
includeCoreModules: false,
};

try {
return resolve.sync(filename, resolveOptions);
} catch (error) {
const ext = extname(filename);
let newFilename: string;

// if we try to import a JavaScript file it might be that we are actually pointing to
// a TypeScript file. This can happen in ES modules as TypeScript requires to import other
// TypeScript files with .js extensions
// https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions
switch (ext) {
case '.js':
case '.mjs':
case '.cjs':
newFilename = `${filename.slice(0, -2)}ts`;
break;

case '.jsx':
newFilename = `${filename.slice(0, -3)}tsx`;
break;
default:
throw error;
}

return resolve.sync(newFilename, {
...resolveOptions,
// we already know that there is an extension at this point, so no need to check other extensions
extensions: [],
});
}
}
19 changes: 13 additions & 6 deletions code/frameworks/react-vite/src/plugins/react-docgen.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import path from 'path';
import path, { join } from 'path';
import { createFilter } from '@rollup/pluginutils';
import type { Documentation } from 'react-docgen';
import {
ERROR_CODES,
parse,
builtinHandlers as docgenHandlers,
builtinResolvers as docgenResolver,
builtinImporters as docgenImporters,
makeFsImporter,
} from 'react-docgen';
import MagicString from 'magic-string';
import type { PluginOption } from 'vite';
import actualNameHandler from './docgen-handlers/actualNameHandler';
import { ReactDocgenResolveError, defaultLookupModule } from './docgen-resolver';

type DocObj = Documentation & { actualName: string };

// TODO: None of these are able to be overridden, so `default` is aspirational here.
const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler);
const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver();
const defaultImporter = docgenImporters.fsImporter;
const handlers = [...defaultHandlers, actualNameHandler];

type Options = {
Expand All @@ -36,14 +36,21 @@ export function reactDocgen({
name: 'storybook:react-docgen-plugin',
enforce: 'pre',
async transform(src: string, id: string) {
const relPath = path.relative(cwd, id);
if (!filter(relPath)) return;
if (!filter(path.relative(cwd, id))) {
return;
}

try {
const docgenResults = parse(src, {
resolver: defaultResolver,
handlers,
importer: defaultImporter,
importer: makeFsImporter((filename, basedir) => {
if (!filter(path.relative(cwd, join(basedir, filename)))) {
throw new ReactDocgenResolveError(filename);
}

return defaultLookupModule(filename, basedir);
}),
filename: id,
}) as DocObj[];
const s = new MagicString(src);
Expand Down
5 changes: 3 additions & 2 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6491,6 +6491,7 @@ __metadata:
"@types/node": "npm:^18.0.0"
magic-string: "npm:^0.30.0"
react-docgen: "npm:^7.0.0"
resolve: "npm:^1.22.8"
typescript: "npm:^5.3.2"
vite: "npm:^4.0.0"
peerDependencies:
Expand Down Expand Up @@ -25657,7 +25658,7 @@ __metadata:
languageName: node
linkType: hard

"resolve@npm:1.22.8, resolve@npm:^1.10.0, resolve@npm:^1.13.1, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.4.0":
"resolve@npm:1.22.8, resolve@npm:^1.10.0, resolve@npm:^1.13.1, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:^1.4.0":
version: 1.22.8
resolution: "resolve@npm:1.22.8"
dependencies:
Expand All @@ -25683,7 +25684,7 @@ __metadata:
languageName: node
linkType: hard

"resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.13.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.15.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin<compat/resolve>":
"resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.13.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.15.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin<compat/resolve>":
version: 1.22.8
resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>::version=1.22.8&hash=c3c19d"
dependencies:
Expand Down

0 comments on commit 1d5e9f8

Please sign in to comment.