diff --git a/docs/docs/gatsby-style-guide.md b/docs/docs/gatsby-style-guide.md index a4752335aaaf2..5a627b4e4b00d 100644 --- a/docs/docs/gatsby-style-guide.md +++ b/docs/docs/gatsby-style-guide.md @@ -296,7 +296,9 @@ designed for scientific communication but might help avoid overspecialized wording. ## Best practices + ### Support software versions + When Gatsby commits to support a specific version of software (e.g. Node 6 and up), this is reflected in documentation. Gatsby documentation should be usable by all people on supported software, which means we don't introduce any commands or practices that can't be used by people on versions we've committed to support. In rare circumstances, we'll consider mentioning a newly introduced command or practice as side notes. For example, npm 5.2.0 (which comes with Node 8) introduced a command called `npx` that is not available for versions of Node below 8. Since Gatsby supports Node 6 and up, documentation should only introduce `npx` as an optional command in a note like so: @@ -304,9 +306,11 @@ For example, npm 5.2.0 (which comes with Node 8) introduced a command called `np > npm 5.2.0--bundled with Node 8--introduced a command called `npx`. Gatsby supports Node 6 and up, so we introduce `npx` here as an optional command for users of npm 5.2.0 or greater. ### Share best practices whenever possible + When there are multiple ways to complete a task, the docs should explain the following: + 1. The most fundamental way of completing the task -2. The most common way of completing a task +2. The most common way of completing a task 3. The best way to complete the task on the lowest supported versions of software 4. The best practice and why is it the best (if different than 3) 5. Any tips on how to pick an option @@ -320,6 +324,7 @@ The main tutorial at `/tutorial/` is optimized for users who are not experts in ## Tutorial ### Tutorial audience + Through research, it's clear that developers of all skill levels read the tutorial and go back to reference it later. The tutorial should prioritize helping users with the following attributes and goals. @@ -337,6 +342,7 @@ Looking for: - a way to start a site and/or app project that uses React ### Tutorial purpose + By following the steps in the tutorial, a user should: - Experience the value of Gatsby as quickly as possible. With Gatsby, a user typically values that it takes fewer steps (and is therefore easier) to: diff --git a/examples/using-remark/gatsby-config.js b/examples/using-remark/gatsby-config.js index 2782c68b8a677..3d39c5f5ed7b9 100644 --- a/examples/using-remark/gatsby-config.js +++ b/examples/using-remark/gatsby-config.js @@ -52,6 +52,13 @@ module.exports = { dashes: `oldschool`, }, }, + { + resolve: `gatsby-remark-embed-snippet`, + options: { + // Example code links are relative to this dir. + directory: `${__dirname}/src/code-examples/`, + }, + }, `gatsby-remark-prismjs`, `gatsby-remark-autolink-headers`, `gatsby-remark-katex`, diff --git a/examples/using-remark/package.json b/examples/using-remark/package.json index 848a472b0eda6..a671e7a115e2b 100644 --- a/examples/using-remark/package.json +++ b/examples/using-remark/package.json @@ -16,6 +16,7 @@ "gatsby-plugin-typography": "^2.2.0", "gatsby-remark-autolink-headers": "^2.0.5", "gatsby-remark-copy-linked-files": "^2.0.5", + "gatsby-remark-embed-snippet": "^3.1.2", "gatsby-remark-images": "^2.0.1", "gatsby-remark-katex": "^2.0.5", "gatsby-remark-prismjs": "^3.0.0", diff --git a/examples/using-remark/src/code-examples/hide-and-highlight-lines.js b/examples/using-remark/src/code-examples/hide-and-highlight-lines.js new file mode 100644 index 0000000000000..3911947b1ebf0 --- /dev/null +++ b/examples/using-remark/src/code-examples/hide-and-highlight-lines.js @@ -0,0 +1,16 @@ +/* hide-range{1-3} */ +import React from "react" +import ReactDOM from "react-dom" + +// highlight-next-line +const name = `Brian` + +// highlight-range{4-5} +// hide-next-line +ReactDOM.render( +
`embed:plain.js`+ +This will look like: + +`embed:plain.js` + +## Highlight lines + +You can highlight specific lines by adding special comments to the source file. Let's see how this works in `src/code-examples/highlight-lines.js`. + +Take a look at the `highlight-line` comment on line 4 and the `highlight-range` comment on line 8: + +```{numberLines: true} +import React from "react" +import ReactDOM from "react-dom" + +const name = `Brian` // highlight-line + +ReactDOM.render( +
`embed:highlight-lines.js`+ +it will display like this: + +`embed:highlight-lines.js` + +## Hide lines + +You can use similar comments to hide specific lines. Here's another example, this time using `src/code-examples/hide-lines.js`. Check out the `hide-line` comments on lines 1, 7, 13 and 14: + +```{numberLines: true} +/* hide-range{1-3} */ +import React from "react" +import ReactDOM from "react-dom" + +const name = `Brian` + +// hide-next-line +ReactDOM.render( +
html {
-height: 100%;}
-
-* {
-box-sizing: border-box;}
- html {
-height: 100%;width: 100%;}
- <html></html>
- <html>
-<body>
-<h1>highlighted</h1><p>
-highlighted</p>
-</body>
-</html>
- <html>
-<body>
-<p>
-highlighted</p>
-</body>
-</html>
- const foo = \\"bar\\";
- <div>
-<button>Add Item</button>
-<ReactCSSTransitionGroup
-transitionName=\\"example\\"
-transitionEnterTimeout={500}
-transitionLeaveTimeout={300}>
-{items}</ReactCSSTransitionGroup>
-</div>
- import React from 'react';
-import ReactDOM from 'react-dom';
-
-ReactDOM.render(<h1>Hello, world!</h1>,
-document.getElementById('root')
-);
- ReactDOM.render(
-<h1>Hello, world!</h1>,document.getElementById('root'));
- <ul>
-<li>Not highlighted</li>
-<li>Highlighted</li><li>Highlighted</li><li>Highlighted</li><li>Not highlighted</li>
-</div>
- let notHighlighted;
-let highlighted;
-notHighlighted = 1;
-
-highlighted = 2;
-notHighlighted = 3;
-highlighted = 4;
- # Hi
- name: Brian Vaughn
- foo: \\"highlighted\\"bar: \\"not highlighted\\"
-baz: \\"highlighted\\"qux: \\"not highlighted\\"
+ <html></html>
foo: \\"highlighted\\"bar: \\"not highlighted\\"
-baz: \\"highlighted\\"
+ const foo = \\"bar\\";
pwd
+ # Hi
# Yarn
-yarn init
-yarn add react react-dom
-# NPM
-npm init
-npm install --save react react-dom
+ name: Brian Vaughn
echo \\"not highlighted\\"
-echo \\"highlighted\\"echo \\"highlighted\\"echo \\"not highlighted\\"
+ pwd
const foo = \\"bar\\";
+ const foo = \\"bar\\";
console.log(\\"oops!\\");
+ const foo = \\"bar\\";
const foo = \\"bar\\";
- - - highlighted -
- - - ` - .replace(/^ +/gm, ``) - .trim() - ) - - const markdownAST = remark.parse(`\`embed:hello-world.html\``) - const transformed = plugin( - { markdownAST }, - { - directory: `examples`, - } - ) - - expect(transformed).toMatchSnapshot() - }) - - it(`should support highlight-range markers`, () => { - fs.readFileSync.mockReturnValue( - ` - - - -- highlighted -
- - - ` - .replace(/^ +/gm, ``) - .trim() - ) - - const markdownAST = remark.parse(`\`embed:hello-world.html\``) - const transformed = plugin( - { markdownAST }, - { - directory: `examples`, - } - ) - - expect(transformed).toMatchSnapshot() - }) - }) - - describe(`JavaScript files`, () => { - it(`should extract the correct Prism language`, () => { + it(`should set the correct Prism language for JavaScript files`, () => { fs.readFileSync.mockReturnValue(`const foo = "bar";`) const markdownAST = remark.parse(`\`embed:hello-world.js\``) @@ -237,148 +105,7 @@ describe(`gatsby-remark-embed-snippet`, () => { expect(transformed).toMatchSnapshot() }) - it(`should support highlight-line and highlight-next-line markers`, () => { - fs.readFileSync.mockReturnValue( - ` - import React from 'react'; - import ReactDOM from 'react-dom'; - - // highlight-next-line - ReactDOM.render( -${highlightCode(
- language,
- code
- )}
+ language,
+ code
+ ).trim()}
` with just the (syntax
highlighted) text of `.some-class { background-color: red }`
+### Disabling syntax highlighting
+
If you need to prevent any escaping or highlighting, you can use the `none`
language; the inner contents will not be changed at all.
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/directives.js.snap b/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/directives.js.snap
new file mode 100644
index 0000000000000..adb6b7280e85c
--- /dev/null
+++ b/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/directives.js.snap
@@ -0,0 +1,335 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`hiding lines should support hide markers in CSS 1`] = `
+Array [
+ Object {
+ "code": "html {",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " padding: 50px;",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "}",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+]
+`;
+
+exports[`hiding lines should support hide markers in HTML 1`] = `
+Array [
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " - not hidden
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+]
+`;
+
+exports[`hiding lines should support hide markers in JS 1`] = `
+Array [
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "ReactDOM.render(",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " - Not hidden
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " - Not hidden
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " - Not hidden
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ,",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": ");",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+]
+`;
+
+exports[`highlighting lines highlight kitchen sink highlights multiple directives 1`] = `
+"import React, { Component } from \\"react\\"
+ state = {
+ count: 0,
+ }
+ count: state.count + 1,
+ render() {
+ const { count } = this.state
+
+ "
+`;
+
+exports[`highlighting lines highlight-line highlights line 1`] = `" return \\"hello world\\""`;
+
+exports[`highlighting lines highlight-next-line highlights correct line 1`] = `" return \\"hello world\\""`;
+
+exports[`highlighting lines highlight-range does not highlight and warns if range is invalid 1`] = `""`;
+
+exports[`highlighting lines highlight-range highlights correct lines 1`] = `
+" a = 1 + 1
+ b = 2 + 2
+ return \\"hello world\\""
+`;
+
+exports[`highlighting lines highlight-range highlights until end of code block if ranges goes farther 1`] = `
+" a = 1 + 1
+ b = 2 + 2
+ return \\"hello world\\"
+}
+"
+`;
+
+exports[`highlighting lines highlight-start / highlight-end highlights correct lines 1`] = `
+" var a = \\"b\\"
+ return a + \\"hello world\\""
+`;
+
+exports[`highlighting lines highlight-start / highlight-end highlights without end directive 1`] = `
+"var a = \\"b\\"
+return a + \\"hello world\\"
+"
+`;
+
+exports[`highlighting lines jsx comment highlights comment line 1`] = `" "`;
+
+exports[`highlighting lines jsx comment highlights comment line after Prism highlighting 1`] = `" <button>sup</button>"`;
+
+exports[`highlighting lines yaml highlights yaml 1`] = `"- title: catorce"`;
+
+exports[`mixed highlight and hide lines should support mixed hide and highlight markers 1`] = `
+Array [
+ Object {
+ "code": "ReactDOM.render(",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " - Not hidden and highlighted
",
+ "flagSources": Array [
+ Object {
+ "directive": "highlight-range{6-8}",
+ "feature": "highlight",
+ "index": 1,
+ },
+ ],
+ "hide": false,
+ "highlight": true,
+ },
+ Object {
+ "code": " - Not hidden and highlighted
",
+ "flagSources": Array [
+ Object {
+ "directive": "highlight-range{6-8}",
+ "feature": "highlight",
+ "index": 1,
+ },
+ ],
+ "hide": false,
+ "highlight": true,
+ },
+ Object {
+ "code": " - Not hidden and highlighted
",
+ "flagSources": Array [
+ Object {
+ "directive": "highlight-range{6-8}",
+ "feature": "highlight",
+ "index": 1,
+ },
+ ],
+ "hide": false,
+ "highlight": true,
+ },
+ Object {
+ "code": "
",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " ,",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": " document.getElementById('root')",
+ "flagSources": Array [
+ Object {
+ "directive": "highlight-next-lineundefined",
+ "feature": "highlight",
+ "index": 15,
+ },
+ ],
+ "hide": false,
+ "highlight": true,
+ },
+ Object {
+ "code": ");",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+ Object {
+ "code": "",
+ "flagSources": Array [],
+ "hide": false,
+ "highlight": false,
+ },
+]
+`;
+
+exports[`mixed highlight and hide lines should support mixed hide and highlight markers 2`] = `
+" - Not hidden and highlighted
+ - Not hidden and highlighted
+ - Not hidden and highlighted
+ document.getElementById('root')"
+`;
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/highlight-line-range.js.snap b/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/highlight-line-range.js.snap
deleted file mode 100644
index da5f0b4180ffe..0000000000000
--- a/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/highlight-line-range.js.snap
+++ /dev/null
@@ -1,50 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`highlighting a line range highlight-line highlights line 1`] = `" return \\"hello world\\""`;
-
-exports[`highlighting a line range highlight-next-line highlights correct line 1`] = `" return \\"hello world\\""`;
-
-exports[`highlighting a line range highlight-range does not highlight and warns if range is invalid 1`] = `""`;
-
-exports[`highlighting a line range highlight-range highlights correct lines 1`] = `
-" a = 1 + 1
- b = 2 + 2
- return \\"hello world\\""
-`;
-
-exports[`highlighting a line range highlight-range highlights until end of code block if ranges goes farther 1`] = `
-" a = 1 + 1
- b = 2 + 2
- return \\"hello world\\"
-}
-"
-`;
-
-exports[`highlighting a line range highlight-start / highlight-end highlights correct lines 1`] = `
-" var a = \\"b\\"
- return a + \\"hello world\\""
-`;
-
-exports[`highlighting a line range highlight-start / highlight-end highlights without end directive 1`] = `
-"var a = \\"b\\"
-return a + \\"hello world\\"
-"
-`;
-
-exports[`highlighting a line range jsx comment highlights comment line 1`] = `" "`;
-
-exports[`highlighting a line range jsx comment highlights comment line after Prism highlighting 1`] = `" <button>sup</button>"`;
-
-exports[`highlighting a line range kitchen sink highlights multiple directives 1`] = `
-"import React, { Component } from \\"react\\"
- state = {
- count: 0,
- }
- count: state.count + 1,
- render() {
- const { count } = this.state
-
- "
-`;
-
-exports[`highlighting a line range yaml highlights yaml 1`] = `"- title: catorce"`;
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js b/packages/gatsby-remark-prismjs/src/__tests__/directives.js
similarity index 75%
rename from packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js
rename to packages/gatsby-remark-prismjs/src/__tests__/directives.js
index 659c50e2e0443..bee3d216c94b4 100644
--- a/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js
+++ b/packages/gatsby-remark-prismjs/src/__tests__/directives.js
@@ -1,8 +1,29 @@
-const highlightLineRange = require(`../highlight-line-range`)
+const highlightLineRange = require(`../directives`)
const fixtures = require(`./fixtures`)
const output = highlighted => highlighted.map(({ code }) => code).join(`\n`)
-const getHighlighted = lines => lines.filter(line => line.highlighted)
-describe(`highlighting a line range`, () => {
+const getHighlighted = lines => lines.filter(line => line.highlight)
+
+describe(`hiding lines`, () => {
+ it(`should support hide markers in CSS`, () => {
+ const processed = highlightLineRange(fixtures.hideLineCss)
+ expect(processed).toMatchSnapshot()
+ expect(processed.length).toEqual(4)
+ })
+
+ it(`should support hide markers in HTML`, () => {
+ const processed = highlightLineRange(fixtures.hideLineHtml)
+ expect(processed).toMatchSnapshot()
+ expect(processed.length).toEqual(10)
+ })
+
+ it(`should support hide markers in JS`, () => {
+ const processed = highlightLineRange(fixtures.hideLine)
+ expect(processed).toMatchSnapshot()
+ expect(processed.length).toEqual(14)
+ })
+})
+
+describe(`highlighting lines`, () => {
describe(`highlight-line`, () => {
it(`strips directive`, () => {
const highlights = highlightLineRange(fixtures.highlightLine)
@@ -13,6 +34,7 @@ describe(`highlighting a line range`, () => {
expect(output(getHighlighted(highlights))).toMatchSnapshot()
})
})
+
describe(`highlight-next-line`, () => {
it(`strips directive`, () => {
const highlights = highlightLineRange(fixtures.highlightNextLine)
@@ -23,6 +45,7 @@ describe(`highlighting a line range`, () => {
expect(output(getHighlighted(highlights))).toMatchSnapshot()
})
})
+
describe(`highlight-start / highlight-end`, () => {
it(`strips directives`, () => {
const highlights = highlightLineRange(fixtures.highlightStartEnd)
@@ -40,6 +63,7 @@ describe(`highlighting a line range`, () => {
expect(output(getHighlighted(highlights))).toMatchSnapshot()
})
})
+
describe(`highlight-range`, () => {
it(`strips directives`, () => {
const highlights = highlightLineRange(fixtures.highlightRange)
@@ -65,6 +89,7 @@ describe(`highlighting a line range`, () => {
expect(output(getHighlighted(highlights))).toMatchSnapshot()
})
})
+
describe(`jsx comment`, () => {
it(`removes directive`, () => {
const highlights = highlightLineRange(fixtures.highlightJsxComment)
@@ -81,6 +106,7 @@ describe(`highlighting a line range`, () => {
expect(output(getHighlighted(highlights))).toMatchSnapshot()
})
})
+
describe(`yaml`, () => {
it(`strips directive`, () => {
const highlights = highlightLineRange(fixtures.highlightYaml)
@@ -91,7 +117,8 @@ describe(`highlighting a line range`, () => {
expect(output(getHighlighted(highlights))).toMatchSnapshot()
})
})
- describe(`kitchen sink`, () => {
+
+ describe(`highlight kitchen sink`, () => {
it(`strips directives`, () => {
const highlights = highlightLineRange(fixtures.highlightKitchenSink)
const code = output(highlights)
@@ -111,3 +138,18 @@ describe(`highlighting a line range`, () => {
})
})
})
+
+describe(`mixed highlight and hide lines`, () => {
+ it(`should support mixed hide and highlight markers`, () => {
+ const processed = highlightLineRange(fixtures.hideAndHighlight)
+ expect(processed).toMatchSnapshot()
+ expect(processed.length).toEqual(11)
+ expect(output(getHighlighted(processed))).toMatchSnapshot()
+ })
+
+ it(`should error when hidden and highlighted lines overlap`, () => {
+ expect(() => highlightLineRange(fixtures.hideAndHighlightOverlap)).toThrow(
+ `Line 8 has been marked as both hidden and highlighted.\n - Line 1: hide ("hide-range{2-3,7}")\n - Line 2: highlight ("highlight-range{5-7,9}")`
+ )
+ })
+})
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-and-highlight-overlap.js b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-and-highlight-overlap.js
new file mode 100644
index 0000000000000..dedf83fb385f5
--- /dev/null
+++ b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-and-highlight-overlap.js
@@ -0,0 +1,13 @@
+// hide-range{2-3,7}
+// highlight-range{5-7,9}
+import React from 'react'
+import { render } from "react-dom"
+ReactDOM.render(
+
+
+ - hidden
+
+ ,
+ // highlight-next-line
+ document.getElementById('root')
+);
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-and-highlight.js b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-and-highlight.js
new file mode 100644
index 0000000000000..99f116c586d30
--- /dev/null
+++ b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-and-highlight.js
@@ -0,0 +1,19 @@
+// hide-range{2-3,10-12,18}
+// highlight-range{6-8}
+import React from 'react'
+import { render } from "react-dom"
+ReactDOM.render(
+
+
+ - Not hidden and highlighted
+ - Not hidden and highlighted
+ - Not hidden and highlighted
+ - Hidden
+ - Hidden
+ - Hidden
+
+ ,
+ // highlight-next-line
+ document.getElementById('root')
+);
+console.log('Hidden')
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line-css.css b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line-css.css
new file mode 100644
index 0000000000000..332a5708f7360
--- /dev/null
+++ b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line-css.css
@@ -0,0 +1,8 @@
+/* hide-range{2-3} */
+html {
+ height: 100%;
+ width: 100%;
+ padding: 50px;
+ /* hide-next-line */
+ background: red;
+}
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line-html.html b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line-html.html
new file mode 100644
index 0000000000000..b3f1503ef2778
--- /dev/null
+++ b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line-html.html
@@ -0,0 +1,17 @@
+
+
+
+
+ hidden
+ hidden
+
+
+
+ - hidden
+ - hidden
+ - not hidden
+
+
+ hidden
+
+
diff --git a/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line.js b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line.js
new file mode 100644
index 0000000000000..8c87f8eded189
--- /dev/null
+++ b/packages/gatsby-remark-prismjs/src/__tests__/fixtures/hide-line.js
@@ -0,0 +1,23 @@
+// hide-range{1-2}
+import React from 'react'
+import { render } from "react-dom"
+
+
+ReactDOM.render(
+
+
+ - Not hidden
+ - Not hidden
+ - Not hidden
+ // hide-range{1-3}
+ - Hidden
+ - Hidden
+ - Hidden
+
+ ,
+ document.getElementById('root') // hide-line
+);
+
+
+// hide-next-line
+console.log('Hidden')
diff --git a/packages/gatsby-remark-prismjs/src/highlight-line-range.js b/packages/gatsby-remark-prismjs/src/directives.js
similarity index 50%
rename from packages/gatsby-remark-prismjs/src/highlight-line-range.js
rename to packages/gatsby-remark-prismjs/src/directives.js
index 2c04883837a82..cc98b26e652db 100644
--- a/packages/gatsby-remark-prismjs/src/highlight-line-range.js
+++ b/packages/gatsby-remark-prismjs/src/directives.js
@@ -22,9 +22,17 @@ const COMMENT_START = new RegExp(
`(#|\\/\\/|\\{\\/\\*|\\/\\*+|${HIGHLIGHTED_HTML_COMMENT_START})`
)
+const createDirectiveRegExp = featureSelector =>
+ new RegExp(`${featureSelector}-(next-line|line|start|end|range)({([^}]+)})?`)
+
const COMMENT_END = new RegExp(`(-->|\\*\\/\\}|\\*\\/)?`)
-const DIRECTIVE = /highlight-(next-line|line|start|end|range)({([^}]+)})?/
-const END_DIRECTIVE = /highlight-end/
+const DIRECTIVE = createDirectiveRegExp(`(highlight|hide)`)
+const HIGHLIGHT_DIRECTIVE = createDirectiveRegExp(`highlight`)
+
+const END_DIRECTIVE = {
+ highlight: /highlight-end/,
+ hide: /hide-end/,
+}
const PLAIN_TEXT_WITH_LF_TEST = /[^<]*\n[^<]*<\/span>/g
@@ -46,98 +54,63 @@ const stripComment = line =>
``
)
-const wrap = line =>
+const highlightWrap = line =>
[``, line, ``].join(``)
+// const wrapAndStripComment = line => wrap(stripComment(line))
-const wrapAndStripComment = line => wrap(stripComment(line))
-
-const getHighlights = (line, code, index) => {
- const [, directive, directiveRange] = line.match(DIRECTIVE)
+const parseLine = (line, code, index, actions) => {
+ const [, feature, directive, directiveRange] = line.match(DIRECTIVE)
+ const flagSource = {
+ feature,
+ index,
+ directive: `${feature}-${directive}${directiveRange}`,
+ }
switch (directive) {
case `next-line`:
- return [
- {
- code: wrap(code[index + 1]),
- highlighted: true,
- },
- index + 1,
- ]
+ actions.flag(feature, index + 1, flagSource)
+ actions.hide(index)
+ break
case `start`: {
- // find the next `highlight-end` directive, starting from next line
+ // find the next `${feature}-end` directive, starting from next line
const endIndex = code.findIndex(
- (line, idx) => idx > index && END_DIRECTIVE.test(line)
+ (line, idx) => idx > index && END_DIRECTIVE[feature].test(line)
)
+
const end = endIndex === -1 ? code.length : endIndex
- const highlighted = code.slice(index + 1, end).map(line => {
- return {
- code: wrap(line),
- highlighted: true,
- }
- })
- return [highlighted, end]
+
+ actions.hide(index)
+ actions.hide(end)
+
+ for (let i = index + 1; i < end; i++) {
+ actions.flag(feature, i, flagSource)
+ }
+ break
}
case `line`:
- return [
- {
- code: wrapAndStripComment(line),
- highlighted: true,
- },
- index,
- ]
+ actions.flag(feature, index, flagSource)
+ actions.stripComment(index)
+ break
case `range`:
- // if range is not provided we ignore the directive
- if (!directiveRange) {
- console.warn(`Invalid match specified: "${line.trim()}"`)
- return [
- {
- code: code[index + 1],
- highlighted: false,
- },
- index + 1,
- ]
- } else {
+ actions.hide(index)
+
+ if (directiveRange) {
const strippedDirectiveRange = directiveRange.slice(1, -1)
const range = rangeParser.parse(strippedDirectiveRange)
if (range.length > 0) {
- // if current line is 10 and range is {1-5, 7}, lastLineIndexInRange === 17
- let lastLineIndexInRange = index + 1 + range[range.length - 1]
- // if range goes farther than code length, make lastLineIndexInRange equal to code length
- if (lastLineIndexInRange > code.length) {
- lastLineIndexInRange = code.length
- }
- const highlighted = code
- .slice(index + 1, lastLineIndexInRange)
- .map((line, idx) => {
- return {
- code: range.includes(idx + 1) ? wrap(line) : line,
- highlighted: range.includes(idx + 1),
- }
- })
- return [highlighted, lastLineIndexInRange - 1]
+ range.forEach(relativeIndex => {
+ actions.flag(feature, index + relativeIndex, flagSource)
+ })
+ break
}
- // if range is incorrect we ignore the directive
- console.warn(`Invalid match specified: "${line.trim()}"`)
- return [
- {
- code: code[index + 1],
- highlighted: false,
- },
- index + 1,
- ]
}
- default:
- return [
- {
- code: wrap(line),
- highlighted: true,
- },
- index,
- ]
+
+ console.warn(`Invalid match specified: "${line.trim()}"`)
+ break
}
}
module.exports = function highlightLineRange(code, highlights = []) {
- if (highlights.length > 0 || DIRECTIVE.test(code)) {
+ if (highlights.length > 0 || HIGHLIGHT_DIRECTIVE.test(code)) {
// HACK split plain-text spans with line separators inside into multiple plain-text spans
// separatered by line separator - this fixes line highlighting behaviour for jsx
code = code.replace(PLAIN_TEXT_WITH_LF_TEST, match =>
@@ -145,36 +118,67 @@ module.exports = function highlightLineRange(code, highlights = []) {
)
}
- let highlighted = []
const split = code.split(`\n`)
+ const lines = split.map(code => {
+ return { code, highlight: false, hide: false, flagSources: [] }
+ })
+
+ const actions = {
+ flag: (feature, line, flagSource) => {
+ if (line >= 0 && line < lines.length) {
+ const lineMeta = lines[line]
+ lineMeta[feature] = true
+ lineMeta.flagSources.push(flagSource)
+ }
+ },
+ hide: line => actions.flag(`hide`, line),
+ highlight: line => actions.flag(`highlight`, line),
+ stripComment: line => {
+ lines[line].code = stripComment(lines[line].code)
+ },
+ }
+
+ const transform = lines =>
+ lines
+ .filter(({ hide, highlight, flagSources }, index) => {
+ if (hide && highlight) {
+ const formattedSources = flagSources
+ .map(
+ ({ feature, index, directive }) =>
+ ` - Line ${index + 1}: ${feature} ("${directive}")`
+ )
+ .join(`\n`)
+ throw Error(
+ `Line ${index +
+ 1} has been marked as both hidden and highlighted.\n${formattedSources}`
+ )
+ }
+
+ return !hide
+ })
+ .map(line => {
+ if (line.highlight) {
+ line.code = highlightWrap(line.code)
+ }
+ return line
+ })
// If a highlight range is passed with the language declaration, e.g.
// ``jsx{1, 3-4}
// we only use that and do not try to parse highlight directives
if (highlights.length > 0) {
- return split.map((line, i) => {
- if (highlights.includes(i + 1)) {
- return {
- highlighted: true,
- code: wrap(line),
- }
- }
- return {
- code: line,
- }
+ highlights.forEach(lineNumber => {
+ actions.highlight(lineNumber - 1)
})
+ return transform(lines)
}
+
for (let i = 0; i < split.length; i++) {
const line = split[i]
if (DIRECTIVE.test(line)) {
- const [highlights, index] = getHighlights(line, split, i)
- highlighted = highlighted.concat(highlights)
- i = index
- } else {
- highlighted.push({
- code: line,
- })
+ parseLine(line, split, i, actions)
}
}
- return highlighted
+
+ return transform(lines)
}
diff --git a/packages/gatsby-remark-prismjs/src/highlight-code.js b/packages/gatsby-remark-prismjs/src/highlight-code.js
index d3751cc3a97ae..d8e1bb3f085e9 100644
--- a/packages/gatsby-remark-prismjs/src/highlight-code.js
+++ b/packages/gatsby-remark-prismjs/src/highlight-code.js
@@ -2,7 +2,7 @@ const Prism = require(`prismjs`)
const _ = require(`lodash`)
const loadPrismLanguage = require(`./load-prism-language`)
-const highlightLineRange = require(`./highlight-line-range`)
+const handleDirectives = require(`./directives`)
module.exports = (language, code, lineNumbersHighlight = []) => {
// (Try to) load languages on demand.
@@ -22,7 +22,7 @@ module.exports = (language, code, lineNumbersHighlight = []) => {
const grammar = Prism.languages[language]
const highlighted = Prism.highlight(code, grammar, language)
- const codeSplits = highlightLineRange(highlighted, lineNumbersHighlight)
+ const codeSplits = handleDirectives(highlighted, lineNumbersHighlight)
let finalCode = ``
@@ -30,7 +30,7 @@ module.exports = (language, code, lineNumbersHighlight = []) => {
// Don't add back the new line character after highlighted lines
// as they need to be display: block and full-width.
codeSplits.forEach((split, idx) => {
- split.highlighted
+ split.highlight
? (finalCode += split.code)
: (finalCode += `${split.code}${idx == lastIdx ? `` : `\n`}`)
})