Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test case for sub components (demonstrates invalid syntax in output) #60

Closed
wants to merge 10 commits into from
6 changes: 4 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ name: Node CI
on:
push:
branches:
- master
- main
- next
pull_request:
branches:
- master
- main
- next
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think I cloned Storybook's fork of this project. Some of these changes are unrelated. But check out the snapshot below :)


jobs:
build:
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
"flat-cache": "^3.0.4",
"micromatch": "^4.0.2",
"react-docgen-typescript": "^1.22.0",
"tslib": "^2.0.0",
"webpack-sources": "^2.2.0"
"tslib": "^2.0.0"
},
"devDependencies": {
"@types/debug": "^4.1.5",
Expand All @@ -50,7 +49,6 @@
"@types/micromatch": "^4.0.1",
"@types/node": "^14.0.12",
"@types/react": "^17.0.0",
"@types/webpack-sources": "^2.1.0",
"@typescript-eslint/eslint-plugin": "^4.9.0",
"@typescript-eslint/parser": "^4.9.0",
"auto": "^10.2.3",
Expand Down
11 changes: 11 additions & 0 deletions src/__tests__/__fixtures__/SubComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from "react";

export default function Root(props: { name: string }) {
return <span>root {props.name}</span>;
}

function Sub(props: { name: string }) {
return <span>sub {props.name}</span>;
}

Root.Sub = Sub;
29 changes: 29 additions & 0 deletions src/__tests__/__snapshots__/generateDocgenCodeBlock.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,35 @@ try {
catch (__react_docgen_typescript_loader_error) { }"
`;

exports[`component fixture SubComponent.tsx has code block generated 1`] = `
"import * as React from \\"react\\";

export default function Root(props: { name: string }) {
return <span>root {props.name}</span>;
}

function Sub(props: { name: string }) {
return <span>sub {props.name}</span>;
}

Root.Sub = Sub;

try {
// @ts-ignore
SubComponent.displayName = \\"SubComponent\\";
// @ts-ignore
SubComponent.__docgenInfo = { \\"description\\": \\"\\", \\"displayName\\": \\"SubComponent\\", \\"props\\": { \\"name\\": { \\"defaultValue\\": null, \\"description\\": \\"\\", \\"name\\": \\"name\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"string\\" } } } };
}
catch (__react_docgen_typescript_loader_error) { }
try {
// @ts-ignore
default.Sub.displayName = \\"default.Sub\\";
// @ts-ignore
default.Sub.__docgenInfo = { \\"description\\": \\"\\", \\"displayName\\": \\"default.Sub\\", \\"props\\": { \\"name\\": { \\"defaultValue\\": null, \\"description\\": \\"\\", \\"name\\": \\"name\\", \\"required\\": true, \\"type\\": { \\"name\\": \\"string\\" } } } };
Comment on lines +234 to +236
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Syntax errors here (so even the defensive try/catch doesn't help :(

}
catch (__react_docgen_typescript_loader_error) { }"
`;

exports[`component fixture TextOnlyComponent.tsx has code block generated 1`] = `
"import * as React from \\"react\\";

Expand Down
5 changes: 5 additions & 0 deletions src/dependency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class DocGenDependency extends NullDependency {
this.codeBlock = codeBlock;
}

getModuleEvaluationSideEffectsState(): boolean {
return false;
}

updateHash: webpack.dependencies.NullDependency["updateHash"] = (hash) => {
hash.update(this.codeBlock);
};
Expand Down Expand Up @@ -46,6 +50,7 @@ class DocGenTemplate extends NullDependency.Template
};
}

// eslint-disable-next-line
// @ts-ignore TODO: How to type this correctly?
DocGenDependency.Template = DocGenTemplate;

Expand Down
201 changes: 158 additions & 43 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ export default class DocgenPlugin implements webpack.WebpackPluginInstance {
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irrelevant file, sorry again!


apply(compiler: webpack.Compiler): void {
// Property compiler.version is set only starting from webpack 5
const webpackVersion = compiler.webpack?.version || "";
const isWebpack5 = parseInt(webpackVersion.split(".")[0], 10) >= 5;

if (isWebpack5) {
this.applyWebpack5(compiler);
} else {
this.applyWebpack4(compiler);
}
}

applyWebpack5(compiler: webpack.Compiler): void {
const pluginName = "DocGenPlugin";
const {
docgenOptions,
Expand All @@ -156,29 +168,24 @@ export default class DocgenPlugin implements webpack.WebpackPluginInstance {
const { exclude = [], include = ["**/**.tsx"] } = this.options;
const isExcluded = matchGlob(exclude);
const isIncluded = matchGlob(include);
// Property compiler.version is set only starting from webpack 5
const webpackVersion = compiler.webpack?.version || "";
const isWebpack5 = parseInt(webpackVersion.split(".")[0], 10) >= 5;

compiler.hooks.compilation.tap(
pluginName,
(compilation: webpack.Compilation) => {
if (isWebpack5) {
// Since this file is needed only for webpack 5, load it only then
// to simplify the implementation of the file.
//
// eslint-disable-next-line
const { DocGenDependency } = require("./dependency");
// Since this file is needed only for webpack 5, load it only then
// to simplify the implementation of the file.
//
// eslint-disable-next-line
const { DocGenDependency } = require("./dependency");

compilation.dependencyTemplates.set(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
DocGenDependency,
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
new DocGenDependency.Template()
);
}
compilation.dependencyTemplates.set(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
DocGenDependency,
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
new DocGenDependency.Template()
);

compilation.hooks.seal.tap(pluginName, () => {
const modulesToProcess: [string, webpack.Module][] = [];
Expand All @@ -191,6 +198,30 @@ export default class DocgenPlugin implements webpack.WebpackPluginInstance {

const nameForCondition = module.nameForCondition() || "";

// Ignore already built modules for webpack 5
if (!compilation.builtModules.has(module)) {
debugExclude(`Ignoring un-built module: ${nameForCondition}`);
return;
}

// Ignore external modules
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (module.external) {
debugExclude(`Ignoring external module: ${nameForCondition}`);
return;
}

// Ignore raw requests
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (!module.rawRequest) {
debugExclude(
`Ignoring module without "rawRequest": ${nameForCondition}`
);
return;
}

if (isExcluded(nameForCondition)) {
debugExclude(
`Module not matched in "exclude": ${nameForCondition}`
Expand All @@ -217,38 +248,122 @@ export default class DocgenPlugin implements webpack.WebpackPluginInstance {
// 3. Process and parse each module and add the type information
// as a dependency
modulesToProcess.forEach(([name, module]) => {
if (isWebpack5) {
// Since this file is needed only for webpack 5, load it only then
// to simplify the implementation of the file.
//
// Since this file is needed only for webpack 5, load it only then
// to simplify the implementation of the file.
//
// eslint-disable-next-line
const { DocGenDependency } = require("./dependency");

module.addDependency(
// eslint-disable-next-line
const { DocGenDependency } = require("./dependency");

module.addDependency(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
new DocGenDependency(
generateDocgenCodeBlock({
filename: name,
source: name,
componentDocs: docGenParser.parseWithProgramProvider(
name,
() => tsProgram
),
...generateOptions,
}).substring(name.length)
)
);
} else {
// Assume webpack 4 or earlier
processModule(docGenParser, module, tsProgram, generateOptions);
}
// @ts-ignore: Webpack 4 type
new DocGenDependency(
generateDocgenCodeBlock({
filename: name,
source: name,
componentDocs: docGenParser.parseWithProgramProvider(
name,
() => tsProgram
),
...generateOptions,
}).substring(name.length)
)
);
});
});
}
);
}

applyWebpack4(compiler: webpack.Compiler): void {
const { docgenOptions, compilerOptions } = this.getOptions();
const parser = docGen.withCompilerOptions(compilerOptions, docgenOptions);
const { exclude = [], include = ["**/**.tsx"] } = this.options;
const isExcluded = matchGlob(exclude);
const isIncluded = matchGlob(include);

compiler.hooks.make.tap(this.name, (compilation) => {
compilation.hooks.seal.tap(this.name, () => {
const modulesToProcess: webpack.Module[] = [];

compilation.modules.forEach((module: webpack.Module) => {
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (!module.built) {
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
debugExclude(`Ignoring un-built module: ${module.userRequest}`);
return;
}

// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (module.external) {
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
debugExclude(`Ignoring external module: ${module.userRequest}`);
return;
}

// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (!module.rawRequest) {
debugExclude(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
`Ignoring module without "rawRequest": ${module.userRequest}`
);
return;
}

// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (isExcluded(module.userRequest)) {
debugExclude(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
`Module not matched in "exclude": ${module.userRequest}`
);
return;
}

// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
if (!isIncluded(module.userRequest)) {
debugExclude(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
`Module not matched in "include": ${module.userRequest}`
);
return;
}

// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
debugInclude(module.userRequest);
modulesToProcess.push(module);
});

const tsProgram = ts.createProgram(
// eslint-disable-next-line
// @ts-ignore: Webpack 4 type
modulesToProcess.map((v) => v.userRequest),
compilerOptions
);

modulesToProcess.forEach((m) =>
processModule(parser, m, tsProgram, {
docgenCollectionName: "STORYBOOK_REACT_CLASSES",
setDisplayName: true,
typePropName: "type",
})
);

cache.save();
});
});
}

getOptions(): {
docgenOptions: docGen.ParserOptions;
generateOptions: {
Expand Down
16 changes: 1 addition & 15 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -982,25 +982,11 @@
"@types/prop-types" "*"
csstype "^3.0.2"

"@types/source-list-map@*":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==

"@types/stack-utils@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==

"@types/webpack-sources@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.1.0.tgz#8882b0bd62d1e0ce62f183d0d01b72e6e82e8c10"
integrity sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==
dependencies:
"@types/node" "*"
"@types/source-list-map" "*"
source-map "^0.7.3"

"@types/yargs-parser@*":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
Expand Down Expand Up @@ -6377,7 +6363,7 @@ webpack-merge@^5.7.3:
clone-deep "^4.0.1"
wildcard "^2.0.0"

webpack-sources@^2.1.1, webpack-sources@^2.2.0:
webpack-sources@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac"
integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==
Expand Down