]> source.dussan.org Git - sonarqube.git/commitdiff
DOC-131 Improve @include handling
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Tue, 8 Jan 2019 10:01:45 +0000 (11:01 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Jan 2019 08:42:57 +0000 (09:42 +0100)
server/sonar-docs/plugins/sonarsource-source-filesystem/index.js
server/sonar-docs/src/templates/page.js

index 4ed6bec103d7764baf78dcb448e440d8ec98916e..7bf46ef2567ee0306bf3c8dc994975301f98264f 100644 (file)
 const { createFilePath, createRemoteFileNode } = require('gatsby-source-filesystem');
 const fs = require('fs-extra');
 
-function loadNodeContent(fileNode) {
+function loadNodeContentSync(fileNode) {
   const content = fs.readFileSync(fileNode.absolutePath, 'utf-8');
-  return new Promise((resolve, reject) => {
-    let newContent = cutSonarCloudContent(content);
-    newContent = removeRemainingContentTags(newContent);
-    resolve(newContent);
-  });
+  let newContent = cutSonarCloudContent(content);
+  newContent = removeRemainingContentTags(newContent);
+  newContent = handleIncludes(newContent, fileNode);
+  return newContent;
+}
+
+function loadNodeContent(fileNode) {
+  return Promise.resolve(loadNodeContentSync(fileNode));
 }
 
 function removeRemainingContentTags(content) {
   const regexBase = '<!-- \\/?(sonarqube|sonarcloud|static) -->';
   return content
-    .replace(new RegExp(`^${regexBase}(\n|\r|\r\n|$)`, 'gm'), '') // First, remove single-line ones, including ending carriage-returns.
-    .replace(new RegExp(`${regexBase}`, 'g'), ''); // Now remove all remaining ones.
+    .replace(new RegExp(`^${regexBase}(\n|\r|\r\n|$)`, 'gm'), '')
+    .replace(new RegExp(`${regexBase}`, 'g'), '');
 }
 
 function cutSonarCloudContent(content) {
@@ -52,6 +55,27 @@ function cutSonarCloudContent(content) {
   return newContent;
 }
 
+function handleIncludes(content, fileNode) {
+  return content.replace(/@include (.*)/g, (_, path) => {
+    const relativePath = `${path}.md`;
+    const absolutePath = `${__dirname}/../../src/${relativePath}`;
+
+    if (relativePath === fileNode.relativePath) {
+      throw new Error(`Error in ${fileNode.relativePath}: The file is trying to include itself.`);
+    } else if (!fs.existsSync(absolutePath)) {
+      throw new Error(
+        `Error in ${fileNode.relativePath}: Couldn't load "${relativePath}" for inclusion.`
+      );
+    } else {
+      const fileContent = loadNodeContentSync({ absolutePath, relativePath });
+      return fileContent
+        .replace(/^---[\w\W]+?---$/m, '')
+        .replace(/^#+ *(toc|table[ -]of[ -]contents?)$/gim, '')
+        .trim();
+    }
+  });
+}
+
 exports.createFilePath = createFilePath;
 exports.createRemoteFileNode = createRemoteFileNode;
 exports.loadNodeContent = loadNodeContent;
index d627cd7a3380abe813793c414cb1fe9abcab2509..12d16defb241ff37cf07fa71adcc9ff52866bae7 100644 (file)
@@ -46,13 +46,10 @@ export default class Page extends React.PureComponent {
 
   render() {
     const page = this.props.data.markdownRemark;
-    let htmlWithInclusions = page.html.replace(/<p>@include (.*)<\/p>/, (_, path) => {
-      const chunk = data.allMarkdownRemark.edges.find(edge => edge.node.fields.slug === path);
-      return chunk ? chunk.node.html : '';
-    });
 
     const realHeadingsList = removeExtraHeadings(page.html, page.headings);
 
+    let htmlWithInclusions = page.html;
     htmlWithInclusions = removeTableOfContents(htmlWithInclusions);
     htmlWithInclusions = createAnchorForHeadings(htmlWithInclusions, realHeadingsList);
     htmlWithInclusions = replaceDynamicLinks(htmlWithInclusions);