Repository: styleguidist/react-styleguidist
Pull request #1675 (2020-09-02 14:31:20)

Fix visibleName with dots
Fixes: https://github.com/styleguidist/react-docgen-typescript/issues/292

With react-docgen-typescript's version 1.20.4, components with `@visibleName` JSDoc tags are working. However, it changes the react component's `displayName` to the one specified in `@visibleName`, and when it contains a `.`, the code examples were not working. This was because Styleguidist was trying to import the component with the dot in its name in the code example which resulted in the syntax error.

Example:
```tsx
// ===== DialogTitle.tsx ======
/**
 * @visibleName Dialog.Title
 */
export const DialogTitle = props => (<h2 {...props} />);

// ===== Dialog.tsx ======
import DialogTitle from './DialogTitle.tsx';
const Dialog = ({ children }) => <div>{children}</div>;
Dialog.Title = DialogTitle;
export default Dialog;
```
This caused Styleguidist to try 
```jsx
const Dialog.Title$0 = require('./DialogTitle.tsx');
```
in the example code renderer, which resulted in `SyntaxError: Missing initializer in const declaration`.


311chaos: I had this issue come up, but with different characters. I had visible names with hyphens or commas that also stopped working. 
Lazyuki: Oh I didn't expect those characters to be in `@visibleName`, but I guess that's possible. I can modify this to exclude all non-alphabetical characters. 

Patch:
diff --git a/src/loaders/utils/resolveESModule.ts b/src/loaders/utils/resolveESModule.ts
index ef8d314f..d071cfe2 100644
--- a/src/loaders/utils/resolveESModule.ts
+++ b/src/loaders/utils/resolveESModule.ts
@@ -8,20 +8,26 @@ import requireIt from './requireIt';
  * @param name the name of the resulting variable
  * @returns AST
  */
-export default (requireRequest: string, name: string) => [
-	// const name$0 = require(path);
-	b.variableDeclaration('const', [
-		b.variableDeclarator(b.identifier(`${name}$0`), requireIt(requireRequest).toAST() as any),
-	]),
-	// const name = name$0.default || name$0[name] || name$0;
-	b.variableDeclaration('const', [
-		b.variableDeclarator(
-			b.identifier(name),
-			b.logicalExpression(
-				'||',
-				b.identifier(`${name}$0.default`),
-				b.logicalExpression('||', b.identifier(`${name}$0['${name}']`), b.identifier(`${name}$0`))
-			)
-		),
-	]),
-];
+export default (requireRequest: string, name: string) => {
+	// The name could possibly contain invalid characters for a JS variable name
+	// such as "." or "-". 
+	const safeName = name ? name.replace(/\W/, '') : name;
+
+	return [
+		// const safeName$0 = require(path);
+		b.variableDeclaration('const', [
+			b.variableDeclarator(b.identifier(`${safeName}$0`), requireIt(requireRequest).toAST() as any),
+		]),
+		// const safeName = safeName$0.default || safeName$0[safeName] || safeName$0;
+		b.variableDeclaration('const', [
+			b.variableDeclarator(
+				b.identifier(safeName),
+				b.logicalExpression(
+					'||',
+					b.identifier(`${safeName}$0.default`),
+					b.logicalExpression('||', b.identifier(`${safeName}$0['${safeName}']`), b.identifier(`${safeName}$0`))
+				)
+			),
+		]),
+	]
+};


Test patch:
diff --git a/src/loaders/__tests__/examples-loader.spec.ts b/src/loaders/__tests__/examples-loader.spec.ts
index 4ad67013..f1898903 100644
--- a/src/loaders/__tests__/examples-loader.spec.ts
+++ b/src/loaders/__tests__/examples-loader.spec.ts
@@ -9,7 +9,17 @@ const query = {
 	shouldShowDefaultExample: false,
 };
 
+const subComponentQuery = {
+	file: '../fooSub.js',
+	displayName: 'FooComponent.SubComponent',
+	shouldShowDefaultExample: false,
+};
+
+
 const getQuery = (options = {}) => encode({ ...query, ...options }, '?');
+const getSubComponentQuery = (options = {}) => encode({ ...subComponentQuery, ...options }, '?');
+
+
 
 it('should return valid, parsable JS', () => {
 	const exampleMarkdown = `
@@ -201,6 +211,23 @@ it('should prepend example code with component require()', () => {
 	);
 });
 
+it('should prepend example code with root component require() for sub components', () => {
+	const exampleMarkdown = `<X/>`;
+	const result = examplesLoader.call(
+		{
+			query: getSubComponentQuery(),
+			_styleguidist: {},
+		} as any,
+		exampleMarkdown
+	);
+
+	expect(result).toBeTruthy();
+	expect(() => new Function(result)).not.toThrowError(SyntaxError);
+	expect(result).toMatch(
+		`const FooComponentSubComponent$0 = require('../fooSub.js');\\nconst FooComponentSubComponent = FooComponentSubComponent$0.default || (FooComponentSubComponent$0['FooComponentSubComponent'] || FooComponentSubComponent$0);`
+	);
+});
+
 it('should allow explicit import of React and component module', () => {
 	const exampleMarkdown = `
     import React from 'react';