Repository: styleguidist/react-styleguidist (ts)

Issue:
Include path in section props
I would like to add "Edit this doc" links to each section. It's easy enough to do so with a custom `ReactComponentRenderer` (eg, getting the path via `pathLine`) but less so with markdown sections (via `SectionRenderer`).

Any objections to including filepath as a prop [in processSection](https://github.com/styleguidist/react-styleguidist/blob/master/loaders/utils/getSections.js#L58)?

Pull request description:
Include filepath in props to Section/ReactComponentRenderer
Include filepath to applicable renderers. This was already the case with `ReactComponentRenderer`, but only via pathLine which may have been mutated by config. This allows renderers to do things like include an "Edit this document" link.

For the record, I don't think we should be overwriting `section.config` which starts as a path and then becomes the actual section content, but changing this would be a breaking change. So I stuck with a new property (`filepath`).

Closes #800 



Patch:
diff --git a/loaders/utils/getSections.js b/loaders/utils/getSections.js
index 76bf6c5d..7aec2f4f 100644
--- a/loaders/utils/getSections.js
+++ b/loaders/utils/getSections.js
@@ -23,6 +23,15 @@ function getSections(sections, config) {
 	return sections.map(section => processSection(section, config));
 }
 
+const getSectionComponents = (section, config) => {
+	let ignore = config.ignore ? _.castArray(config.ignore) : [];
+	if (section.ignore) {
+		ignore = ignore.concat(_.castArray(section.ignore));
+	}
+
+	return getComponents(getComponentFiles(section.components, config.configDir, ignore), config);
+};
+
 /**
  * Return an object for a given section with all components and subsections.
  * @param {object} section
@@ -30,31 +39,25 @@ function getSections(sections, config) {
  * @returns {object}
  */
 function processSection(section, config) {
+	const contentRelativePath = section.content;
+
 	// Try to load section content file
 	let content;
-	if (section.content) {
-		const filepath = path.resolve(config.configDir, section.content);
-		if (!fs.existsSync(filepath)) {
-			throw new Error(`Styleguidist: Section content file not found: ${filepath}`);
+	if (contentRelativePath) {
+		const contentAbsolutePath = path.resolve(config.configDir, contentRelativePath);
+		if (!fs.existsSync(contentAbsolutePath)) {
+			throw new Error(`Styleguidist: Section content file not found: ${contentAbsolutePath}`);
 		}
-		content = requireIt(`!!${examplesLoader}!${filepath}`);
-	}
-
-	let ignore = config.ignore ? _.castArray(config.ignore) : [];
-
-	if (section.ignore) {
-		ignore = ignore.concat(_.castArray(section.ignore));
+		content = requireIt(`!!${examplesLoader}!${contentAbsolutePath}`);
 	}
 
 	return {
 		name: section.name,
 		description: section.description,
 		slug: slugger.slug(section.name),
-		components: getComponents(
-			getComponentFiles(section.components, config.configDir, ignore),
-			config
-		),
 		sections: getSections(section.sections || [], config),
+		filepath: contentRelativePath,
+		components: getSectionComponents(section, config),
 		content,
 	};
 }
diff --git a/src/rsg-components/ReactComponent/ReactComponent.js b/src/rsg-components/ReactComponent/ReactComponent.js
index b44669d1..bb9e1bf8 100644
--- a/src/rsg-components/ReactComponent/ReactComponent.js
+++ b/src/rsg-components/ReactComponent/ReactComponent.js
@@ -45,7 +45,7 @@ export default class ReactComponent extends Component {
 		const { activeTab } = this.state;
 		const { displayMode } = this.context;
 		const { component, depth } = this.props;
-		const { name, slug, pathLine } = component;
+		const { name, slug, filepath, pathLine } = component;
 		const { description, examples = [], tags = {} } = component.props;
 		if (!name) {
 			return null;
@@ -55,6 +55,7 @@ export default class ReactComponent extends Component {
 			<ReactComponentRenderer
 				name={name}
 				slug={slug}
+				filepath={filepath}
 				pathLine={pathLine}
 				docs={<JsDoc {...tags} />}
 				description={description && <Markdown text={description} />}
diff --git a/src/rsg-components/ReactComponent/ReactComponentRenderer.js b/src/rsg-components/ReactComponent/ReactComponentRenderer.js
index affa18f7..c90aab28 100644
--- a/src/rsg-components/ReactComponent/ReactComponentRenderer.js
+++ b/src/rsg-components/ReactComponent/ReactComponentRenderer.js
@@ -60,6 +60,7 @@ ReactComponentRenderer.propTypes = {
 	classes: PropTypes.object.isRequired,
 	name: PropTypes.string.isRequired,
 	heading: PropTypes.node.isRequired,
+	filepath: PropTypes.string,
 	pathLine: PropTypes.string,
 	tabButtons: PropTypes.node,
 	tabBody: PropTypes.node,
diff --git a/src/rsg-components/Section/Section.js b/src/rsg-components/Section/Section.js
index 87b7e933..cc517ee9 100644
--- a/src/rsg-components/Section/Section.js
+++ b/src/rsg-components/Section/Section.js
@@ -7,7 +7,7 @@ import SectionRenderer from 'rsg-components/Section/SectionRenderer';
 import { DisplayModes } from '../../consts';
 
 export default function Section({ section, depth }, { displayMode }) {
-	const { name, slug, content, components, sections, description } = section;
+	const { name, slug, filepath, content, components, sections, description } = section;
 
 	const contentJsx = content && <Examples examples={content} name={name} />;
 	const componentsJsx = components && <Components components={components} depth={depth + 1} />;
@@ -18,6 +18,7 @@ export default function Section({ section, depth }, { displayMode }) {
 			description={description}
 			name={name}
 			slug={slug}
+			filepath={filepath}
 			content={contentJsx}
 			components={componentsJsx}
 			sections={sectionsJsx}
diff --git a/src/rsg-components/Section/SectionRenderer.js b/src/rsg-components/Section/SectionRenderer.js
index c39b47cf..695b6972 100644
--- a/src/rsg-components/Section/SectionRenderer.js
+++ b/src/rsg-components/Section/SectionRenderer.js
@@ -33,6 +33,7 @@ SectionRenderer.propTypes = {
 	name: PropTypes.string,
 	description: PropTypes.string,
 	slug: PropTypes.string,
+	filepath: PropTypes.string,
 	content: PropTypes.node,
 	components: PropTypes.node,
 	sections: PropTypes.node,


Test patch:
diff --git a/loaders/utils/__tests__/__snapshots__/getSections.spec.js.snap b/loaders/utils/__tests__/__snapshots__/getSections.spec.js.snap
index 693d9c77..57e8da85 100644
--- a/loaders/utils/__tests__/__snapshots__/getSections.spec.js.snap
+++ b/loaders/utils/__tests__/__snapshots__/getSections.spec.js.snap
@@ -8,6 +8,7 @@ Array [
       "require": "!!~/loaders/examples-loader.js!~/test/components/Button/Readme.md",
     },
     "description": undefined,
+    "filepath": "components/Button/Readme.md",
     "name": "Readme",
     "sections": Array [],
     "slug": "readme-1",
@@ -71,6 +72,7 @@ Array [
     ],
     "content": undefined,
     "description": undefined,
+    "filepath": undefined,
     "name": "Components",
     "sections": Array [],
     "slug": "components-1",
@@ -121,6 +123,7 @@ Array [
     ],
     "content": undefined,
     "description": undefined,
+    "filepath": undefined,
     "name": "Ignore",
     "sections": Array [],
     "slug": "ignore-1",
@@ -188,6 +191,7 @@ Object {
   ],
   "content": undefined,
   "description": undefined,
+  "filepath": undefined,
   "name": "Components",
   "sections": Array [],
   "slug": "components",
@@ -201,6 +205,7 @@ Object {
     "require": "!!~/loaders/examples-loader.js!~/test/components/Button/Readme.md",
   },
   "description": undefined,
+  "filepath": "components/Button/Readme.md",
   "name": "Readme",
   "sections": Array [],
   "slug": "readme",
@@ -254,6 +259,7 @@ Object {
   ],
   "content": undefined,
   "description": undefined,
+  "filepath": undefined,
   "name": "Ignore",
   "sections": Array [],
   "slug": "ignore",