Repository: styleguidist/react-styleguidist
Pull request #1388 (2019-06-21 23:22:59)

Fix component name capitalization issue
iss: https://github.com/styleguidist/react-styleguidist/issues/1381

It is happening in a case when `react-docgen` (any propsParser) is failed
and we are trying to guess displayName based on the file path.

We capitalized every case in the string instead of just words separated
by `-` or started with a small letter.

So, by mistake `ButtonTS` in file name becomes `ButtonTs` display name for
component when we expect `ButtonTS`

mendrew: As a follow up of our discussion here: https://github.com/styleguidist/react-styleguidist/issues/1381#issuecomment-502829790
where the topic is 
> display an explicit warning for this case.

The only error we are getting is this one https://github.com/styleguidist/react-styleguidist/blob/5b9b517ac3a3ee6e1360ccc9acef60d3f36727a6/src/loaders/props-loader.js#L42-L46
It's pretty common and doesn't give us an idea of what is happening with displayName.

But it's might be an overhead for user to see one more warnings when it might be just an expected behavior. (when propsParser is failed and displayName is based on file path)
codecov-io: # [Codecov](https://codecov.io/gh/styleguidist/react-styleguidist/pull/1388?src=pr&el=h1) Report
> Merging [#1388](https://codecov.io/gh/styleguidist/react-styleguidist/pull/1388?src=pr&el=desc) into [master](https://codecov.io/gh/styleguidist/react-styleguidist/commit/5b9b517ac3a3ee6e1360ccc9acef60d3f36727a6?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

| [Impacted Files](https://codecov.io/gh/styleguidist/react-styleguidist/pull/1388?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/loaders/utils/getNameFromFilePath.js](https://codecov.io/gh/styleguidist/react-styleguidist/pull/1388/diff?src=pr&el=tree#diff-c3JjL2xvYWRlcnMvdXRpbHMvZ2V0TmFtZUZyb21GaWxlUGF0aC5qcw==) | `100% <100%> (ø)` | :arrow_up: |


Patch:
diff --git a/src/client/utils/getUrl.js b/src/client/utils/getUrl.js
index fa0b6d80..06df8da2 100644
--- a/src/client/utils/getUrl.js
+++ b/src/client/utils/getUrl.js
@@ -38,10 +38,11 @@ export default function getUrl(
 	}
 
 	if (hashPath) {
+		let encodedHashPath = hashPath.map(encodeURIComponent);
 		if (!id) {
-			hashPath = [...hashPath, encodedName];
+			encodedHashPath = [...encodedHashPath, encodedName];
 		}
-		url += `#/${hashPath.join('/')}`;
+		url += `#/${encodedHashPath.join('/')}`;
 	}
 
 	if (id) {
diff --git a/src/loaders/utils/getNameFromFilePath.js b/src/loaders/utils/getNameFromFilePath.js
index 1482a535..aeed02dc 100644
--- a/src/loaders/utils/getNameFromFilePath.js
+++ b/src/loaders/utils/getNameFromFilePath.js
@@ -1,11 +1,17 @@
 const path = require('path');
-const _ = require('lodash');
+const { startCase } = require('lodash');
+
+function transformFileNameToDisplayName(displayName) {
+	// ex: your-buttonTS -> Your Button TS -> YourButtonTS
+	// ex: your_button--TS -> Your Button TS -> YourButtonTS
+	return startCase(displayName).replace(/\s/g, '');
+}
 
 module.exports = function getNameFromFilePath(filePath) {
-	let displayName = path.basename(filePath, path.extname(filePath));
-	if (displayName === 'index') {
-		displayName = path.basename(path.dirname(filePath));
+	let fileName = path.basename(filePath, path.extname(filePath));
+	if (fileName === 'index') {
+		fileName = path.basename(path.dirname(filePath));
 	}
 
-	return _.upperFirst(_.camelCase(displayName));
+	return transformFileNameToDisplayName(fileName);
 };


Test patch:
diff --git a/src/client/utils/__tests__/getUrl.spec.js b/src/client/utils/__tests__/getUrl.spec.js
index e47f4038..6ae72866 100644
--- a/src/client/utils/__tests__/getUrl.spec.js
+++ b/src/client/utils/__tests__/getUrl.spec.js
@@ -74,6 +74,25 @@ describe('getUrl', () => {
 		expect(result).toBe('/styleguide/#/Documentation/%40foo%2Fcomponents');
 	});
 
+	it('should return a route path with encoded name if sections (hashPath) has inappropriate symbols', () => {
+		expect(
+			getUrl({ name: '@foo/components', slug, hashPath: ['@foo/bar-documentation'] }, loc)
+		).toBe('/styleguide/#/%40foo%2Fbar-documentation/%40foo%2Fcomponents');
+
+		expect(
+			getUrl(
+				{
+					name: '@foo/components',
+					slug,
+					hashPath: ['@foo/bar-documentation', '@foo/bar-activations-section'],
+				},
+				loc
+			)
+		).toBe(
+			'/styleguide/#/%40foo%2Fbar-documentation/%40foo%2Fbar-activations-section/%40foo%2Fcomponents'
+		);
+	});
+
 	it('should return a route path with a param id=foobar', () => {
 		const result = getUrl({ name, slug, hashPath: ['Documentation'], id: true }, loc);
 		expect(result).toBe('/styleguide/#/Documentation?id=foobar');
diff --git a/src/loaders/utils/__tests__/getNameFromFilePath.spec.js b/src/loaders/utils/__tests__/getNameFromFilePath.spec.js
index e52f4180..28825ae4 100644
--- a/src/loaders/utils/__tests__/getNameFromFilePath.spec.js
+++ b/src/loaders/utils/__tests__/getNameFromFilePath.spec.js
@@ -21,4 +21,20 @@ it('should capitalize the display name', () => {
 	expect(
 		getNameFromFilePath(path.join('an', 'absolute', 'path', 'to', 'your-component', 'index.js'))
 	).toEqual('YourComponent');
+
+	expect(
+		getNameFromFilePath(path.join('an', 'absolute', 'path', 'to', 'yourButtonTS.tsx'))
+	).toEqual('YourButtonTS');
+
+	expect(
+		getNameFromFilePath(path.join('an', 'absolute', 'path', 'to', 'your-buttonTS', 'index.tsx'))
+	).toEqual('YourButtonTS');
+
+	expect(
+		getNameFromFilePath(path.join('an', 'absolute', 'path', 'to', 'your_button--TS', 'index.tsx'))
+	).toEqual('YourButtonTS');
+
+	expect(
+		getNameFromFilePath(path.join('an', 'absolute', 'path', 'to', 'ButtonTS', 'index.tsx'))
+	).toEqual('ButtonTS');
 });