aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2019-04-11 15:06:52 +0200
committerSonarTech <sonartech@sonarsource.com>2019-04-12 20:21:04 +0200
commit0ff98114be62661af4c745d6110e6047a67adbe2 (patch)
tree13335d3f933c0280c19d75b459dcef84860ceb53 /server
parent4380a1d1594cb112f3d3e17b99f4a801c3d2fda8 (diff)
downloadsonarqube-0ff98114be62661af4c745d6110e6047a67adbe2.tar.gz
sonarqube-0ff98114be62661af4c745d6110e6047a67adbe2.zip
SONAR-11956 Correct TOC parsing logic, always show sticky TOC for pages
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/package.json1
-rw-r--r--server/sonar-web/src/main/js/@types/remark-toc.d.ts31
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx13
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocToc.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx12
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx21
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap175
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap29
-rw-r--r--server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.js2
-rw-r--r--server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js52
10 files changed, 11 insertions, 329 deletions
diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json
index 632f98c71a2..ad0b5780b38 100644
--- a/server/sonar-web/package.json
+++ b/server/sonar-web/package.json
@@ -43,7 +43,6 @@
"regenerator-runtime": "0.13.2",
"remark-custom-blocks": "2.3.0",
"remark-slug": "5.1.0",
- "remark-toc": "5.0.0",
"unist-util-visit": "1.4.0",
"valid-url": "1.0.9",
"whatwg-fetch": "2.0.4"
diff --git a/server/sonar-web/src/main/js/@types/remark-toc.d.ts b/server/sonar-web/src/main/js/@types/remark-toc.d.ts
deleted file mode 100644
index a2a0996d2d3..00000000000
--- a/server/sonar-web/src/main/js/@types/remark-toc.d.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'remark-toc' {
- interface Options {
- /** Heading to look for */
- heading?: string;
- /** Maximum heading depth, inclusive */
- maxDepth?: number;
- /** Display list-item tightly */
- tight?: boolean;
- }
-
- export default function remarkToc(options?: Options): JSX.Element;
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
index 92c34ad59b6..01b5f4c5b78 100644
--- a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
+++ b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
@@ -27,7 +27,6 @@ import DocLink from './DocLink';
import DocImg from './DocImg';
import DocToc from './DocToc';
import DocTooltipLink from './DocTooltipLink';
-import remarkToc from './plugins/remark-toc';
import DocCollapsibleBlock from './DocCollapsibleBlock';
import { separateFrontMatter, filterContent } from '../../helpers/markdown';
import { scrollToElement } from '../../helpers/scrolling';
@@ -60,8 +59,8 @@ export default class DocMarkdownBlock extends React.PureComponent<Props> {
render() {
const { childProps, content, className, displayH1, stickyToc, isTooltip } = this.props;
const parsed = separateFrontMatter(content || '');
- let filteredContent = filterContent(parsed.content);
- const tocContent = filteredContent;
+ const filteredContent = filterContent(parsed.content);
+
const md = remark();
// TODO find a way to replace these custom blocks with real Alert components
@@ -87,12 +86,6 @@ export default class DocMarkdownBlock extends React.PureComponent<Props> {
})
.use(slug);
- if (stickyToc) {
- filteredContent = filteredContent.replace(/#*\s*(toc|table[ -]of[ -]contents?).*/i, '');
- } else {
- md.use(remarkToc, { maxDepth: 3 });
- }
-
return (
<div
className={classNames('markdown', className, { 'has-toc': stickyToc })}
@@ -101,7 +94,7 @@ export default class DocMarkdownBlock extends React.PureComponent<Props> {
{displayH1 && <h1 className="documentation-title">{parsed.frontmatter.title}</h1>}
{md.processSync(filteredContent).contents}
</div>
- {stickyToc && <DocToc content={tocContent} onAnchorClick={this.handleAnchorClick} />}
+ {stickyToc && <DocToc content={filteredContent} onAnchorClick={this.handleAnchorClick} />}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/components/docs/DocToc.tsx b/server/sonar-web/src/main/js/components/docs/DocToc.tsx
index 6f2f2cac2f3..7ff1d48a12d 100644
--- a/server/sonar-web/src/main/js/components/docs/DocToc.tsx
+++ b/server/sonar-web/src/main/js/components/docs/DocToc.tsx
@@ -48,11 +48,11 @@ export default class DocToc extends React.PureComponent<Props, State> {
state: State = { anchors: [] };
- static getAnchors = memoize(content => {
+ static getAnchors = memoize((content: string) => {
const file: { contents: JSX.Element } = remark()
.use(reactRenderer)
.use(onlyToc)
- .processSync(content);
+ .processSync('\n## doctoc\n' + content);
if (file && file.contents.props.children) {
let list = file.contents;
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx
index afacbd5ec0a..3f276e19f52 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx
@@ -21,9 +21,7 @@ import * as React from 'react';
import { shallow } from 'enzyme';
import DocMarkdownBlock from '../DocMarkdownBlock';
-const CONTENT_WITH_TOC = `
-## Table of Contents
-
+const CONTENT = `
## Lorem ipsum
Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
@@ -84,14 +82,8 @@ it('should render with custom props for links', () => {
).toMatchSnapshot();
});
-it('should render a TOC if available', () => {
- const wrapper = shallowRender({ content: CONTENT_WITH_TOC });
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('ul').exists()).toBe(true);
-});
-
it('should render a sticky TOC if available', () => {
- const wrapper = shallowRender({ content: CONTENT_WITH_TOC, stickyToc: true });
+ const wrapper = shallowRender({ content: CONTENT, stickyToc: true });
expect(wrapper).toMatchSnapshot();
expect(wrapper.find('DocToc').exists()).toBe(true);
});
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx
index ce8f39319f2..39958cdfcca 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx
@@ -24,7 +24,7 @@ import { click, scrollTo } from '../../../helpers/testUtils';
const OFFSET = 300;
-const CONTENT_NO_TOC = `
+const CONTENT = `
## Lorem ipsum
Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
@@ -44,12 +44,6 @@ At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Don
Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
`;
-const CONTENT_WITH_TOC = `
-## toc
-
-${CONTENT_NO_TOC}
-`;
-
jest.mock('remark', () => {
const remark = require.requireActual('remark');
return { default: remark };
@@ -75,11 +69,6 @@ it('should render correctly', () => {
expect(wrapper).toMatchSnapshot();
});
-it('should render correctly if no TOC is available', () => {
- const wrapper = renderComponent({ content: CONTENT_NO_TOC });
- expect(wrapper).toMatchSnapshot();
-});
-
it('should trigger the handler when an anchor is clicked', () => {
const onAnchorClick = jest.fn();
const wrapper = renderComponent({ onAnchorClick });
@@ -99,7 +88,7 @@ it('should highlight anchors when scrolling', () => {
});
function renderComponent(props: Partial<DocToc['props']> = {}) {
- return mount(<DocToc content={CONTENT_WITH_TOC} onAnchorClick={jest.fn()} {...props} />);
+ return mount(<DocToc content={CONTENT} onAnchorClick={jest.fn()} {...props} />);
}
function mockDomEnv() {
@@ -109,11 +98,7 @@ function mockDomEnv() {
parent.appendChild(element);
let offset = OFFSET;
- (CONTENT_WITH_TOC.match(/^## .+$/gm) as Array<string>).forEach(match => {
- if (/toc/.test(match)) {
- return;
- }
-
+ (CONTENT.match(/^## .+$/gm) as Array<string>).forEach(match => {
const slug = match
.replace(/^#+ */, '')
.replace(' ', '-')
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
index ae537c7f712..6e5b67907c5 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
@@ -1,178 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render a TOC if available 1`] = `
-<div
- className="markdown"
->
- <div
- className="markdown-content"
- >
- <Block
- key="h-1"
- >
- <h2
- id="table-of-contents"
- key="h-2"
- >
- Table of Contents
- </h2>
-
-
- <ul
- key="h-3"
- >
-
-
- <li
- key="h-4"
- >
- <withChildProps
- href="#lorem-ipsum"
- key="h-5"
- >
- Lorem ipsum
- </withChildProps>
- </li>
-
-
- <li
- key="h-6"
- >
-
-
- <p
- key="h-7"
- >
- <withChildProps
- href="#sit-amet"
- key="h-8"
- >
- Sit amet
- </withChildProps>
- </p>
-
-
- <ul
- key="h-9"
- >
-
-
- <li
- key="h-10"
- >
- <withChildProps
- href="#maecenas-diam"
- key="h-11"
- >
- Maecenas diam
- </withChildProps>
- </li>
-
-
- <li
- key="h-12"
- >
- <withChildProps
- href="#integer"
- key="h-13"
- >
- Integer
- </withChildProps>
- </li>
-
-
- </ul>
-
-
- </li>
-
-
- <li
- key="h-14"
- >
- <withChildProps
- href="#nam-blandit"
- key="h-15"
- >
- Nam blandit
- </withChildProps>
- </li>
-
-
- </ul>
-
-
- <h2
- id="lorem-ipsum"
- key="h-16"
- >
- Lorem ipsum
- </h2>
-
-
- <p
- key="h-17"
- >
- Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
- </p>
-
-
- <h2
- id="sit-amet"
- key="h-18"
- >
- Sit amet
- </h2>
-
-
- <h3
- id="maecenas-diam"
- key="h-19"
- >
- Maecenas diam
- </h3>
-
-
- <p
- key="h-20"
- >
- Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
- </p>
-
-
- <h3
- id="integer"
- key="h-21"
- >
- Integer
- </h3>
-
-
- <p
- key="h-22"
- >
- At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
- </p>
-
-
- <h2
- id="nam-blandit"
- key="h-23"
- >
- Nam blandit
- </h2>
-
-
- <p
- key="h-24"
- >
- Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
- </p>
- </Block>
- </div>
-</div>
-`;
-
exports[`should render a sticky TOC if available 1`] = `
<div
className="markdown has-toc"
@@ -253,8 +80,6 @@ exports[`should render a sticky TOC if available 1`] = `
</div>
<DocToc
content="
-## Table of Contents
-
## Lorem ipsum
Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap
index c89f2c0a0d3..ea33e896b40 100644
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap
@@ -3,9 +3,6 @@
exports[`should render correctly 1`] = `
<DocToc
content="
-## toc
-
-
## Lorem ipsum
Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
@@ -23,7 +20,6 @@ At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Don
## Nam blandit
Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-
"
onAnchorClick={[MockFunction]}
>
@@ -64,28 +60,3 @@ Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, co
</div>
</DocToc>
`;
-
-exports[`should render correctly if no TOC is available 1`] = `
-<DocToc
- content="
-## Lorem ipsum
-
-Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-
-## Sit amet
-
-### Maecenas diam
-
-Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
-
-### Integer
-
-At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
-
-## Nam blandit
-
-Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-"
- onAnchorClick={[MockFunction]}
-/>
-`;
diff --git a/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.js b/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.js
index 3489d2d6273..521804fcec3 100644
--- a/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.js
+++ b/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.js
@@ -30,7 +30,7 @@ export default function onlyToc() {
return transformer;
function transformer(node) {
- const result = util(node, { heading: 'toc|table[ -]of[ -]contents?', maxDepth: 2 });
+ const result = util(node, { heading: 'doctoc', maxDepth: 2 });
if (result.index === null || result.index === -1 || !result.map) {
node.children = [];
diff --git a/server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js b/server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js
deleted file mode 100644
index 0182f769231..00000000000
--- a/server/sonar-web/src/main/js/components/docs/plugins/remark-toc.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import slug from 'remark-slug';
-import util from 'mdast-util-toc';
-
-const DEFAULT_HEADING = 'toc|table[ -]of[ -]contents?';
-
-/**
- * This comes from the remark-toc plugin: https://github.com/remarkjs/remark-toc
- * We cannot use it directly before the following issue gets fixed: https://github.com/remarkjs/remark-toc/issues/18
- */
-export default function toc(options) {
- const settings = options || {};
- const heading = settings.heading || DEFAULT_HEADING;
- const depth = settings.maxDepth || 6;
- const { tight } = settings;
-
- this.use(slug);
-
- return transformer;
-
- function transformer(node) {
- const result = util(node, { heading, maxDepth: depth, tight });
-
- if (result.index === null || result.index === -1 || !result.map) {
- return;
- }
-
- node.children = [].concat(
- node.children.slice(0, result.index),
- result.map,
- node.children.slice(result.index)
- );
- }
-}