Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(remark-embed-snippet): embed specific lines #21907

Merged
merged 5 commits into from
Apr 10, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(remark-embed-snippet): parse numeric range
  • Loading branch information
danpoq committed Mar 19, 2020
commit b7594aaded8be89097b6d5c8495ef99325785bb6
46 changes: 43 additions & 3 deletions packages/gatsby-remark-embed-snippet/README.md
Original file line number Diff line number Diff line change
@@ -185,9 +185,8 @@ The resulting HTML generated from the markdown file above would look something l

### Highlighting Lines

You can also specify specific lines for Prism to highlight using
`highlight-line` and `highlight-next-line` comments. You can also specify a
range of lines to highlight, relative to a `highlight-range` comment.
You can specify specific lines for Prism to highlight using
`highlight-line` and `highlight-next-line` comments. You can also specify a range of lines to highlight, relative to a `highlight-range` comment.

**JavaScript example**:

@@ -250,8 +249,49 @@ quz: "highlighted"

It's also possible to specify a range of lines to be hidden.

You can either specify line ranges in the embed using the syntax:

- #Lx - Embed one line from a file
- #Lx-y - Embed a range of lines from a file
- #Lx-y,a-b - Embed non-consecutive ranges of lines from a file

**Markdown example**:

```markdown
This is the JSX of my app:

`embed:App.js#L6-8`
```

With this example snippet:

```js
import React from "react"
import ReactDOM from "react-dom"

function App() {
return (
<div className="App">
<h1>Hello world</h1>
</div>
)
}
```

Will produce something like this:

```markdown
This is the JSX of my app:

<div className="App">
<h1>Hello world</h1>
</div>
```

**JavaScript example**:

You can also add `// hide-range` comments to your files.

```jsx
// hide-range{1-2}
import React from "react"
43 changes: 0 additions & 43 deletions packages/gatsby-remark-embed-snippet/src/__tests__/get-lines.js

This file was deleted.

22 changes: 21 additions & 1 deletion packages/gatsby-remark-embed-snippet/src/__tests__/index.js
Original file line number Diff line number Diff line change
@@ -58,14 +58,34 @@ ${codeBlockValue}
${codeBlockValue}
}`)

const markdownAST = remark.parse(`\`embed:hello-world.js#L2-L4\``)
const markdownAST = remark.parse(`\`embed:hello-world.js#L2-4\``)
const transformed = plugin({ markdownAST }, { directory: `examples` })

const codeBlock = transformed.children[0].children[0]

expect(codeBlock.value).toEqual(codeBlockValue)
})

it(`should display a code block of a range of non-consecutive lines`, () => {
const notInSnippet = `lineShouldNotBeInSnippet();`
fs.readFileSync.mockReturnValue(`function test() {
if (window.location.search.indexOf('query') > -1) {
console.log('The user is searching')
}
}
${notInSnippet}
window.addEventListener('resize', () => {
test();
})`)

const markdownAST = remark.parse(`\`embed:hello-world.js#L2-4,7-9\``)
const transformed = plugin({ markdownAST }, { directory: `examples` })

const codeBlock = transformed.children[0].children[0]

expect(codeBlock.value).not.toContain(notInSnippet)
})

it(`should error if an invalid file path is specified`, () => {
fs.existsSync.mockImplementation(path => path !== `examples/hello-world.js`)

48 changes: 41 additions & 7 deletions packages/gatsby-remark-embed-snippet/src/index.js
Original file line number Diff line number Diff line change
@@ -4,9 +4,34 @@ const path = require(`path`)
const fs = require(`fs`)
const normalizePath = require(`normalize-path`)
const visit = require(`unist-util-visit`)
const rangeParser = require(`parse-numeric-range`)

const getLanguage = require(`./utils/get-language`)
const getLines = require(`./utils/get-lines`)
// Language defaults to extension.toLowerCase();
// This map tracks languages that don't match their extension.
const FILE_EXTENSION_TO_LANGUAGE_MAP = {
js: `jsx`,
md: `markup`,
sh: `bash`,
rb: `ruby`,
py: `python`,
ps1: `powershell`,
psm1: `powershell`,
bat: `batch`,
h: `c`,
tex: `latex`,
}

const getLanguage = file => {
if (!file.includes(`.`)) {
return `none`
}

const extension = file.split(`.`).pop()

return FILE_EXTENSION_TO_LANGUAGE_MAP.hasOwnProperty(extension)
? FILE_EXTENSION_TO_LANGUAGE_MAP[extension]
: extension.toLowerCase()
}

module.exports = ({ markdownAST, markdownNode }, { directory } = {}) => {
if (!directory) {
@@ -26,10 +51,16 @@ module.exports = ({ markdownAST, markdownNode }, { directory } = {}) => {

// Embed specific lines numbers of a file
let lines = []
if (snippetPath.indexOf(`#L`) > -1) {
lines = snippetPath.match(/L\d+/g).map(l => l.replace(`L`, ``))
// Remove everything after line hash from file path
snippetPath = snippetPath.slice(0, snippetPath.indexOf(`#L`))
const rangePrefixIndex = snippetPath.indexOf(`#L`)
if (rangePrefixIndex > -1) {
const range = snippetPath.slice(rangePrefixIndex + 2)
if (range.length === 1) {
lines = [Number.parseInt(range, 10)]
} else {
lines = rangeParser.parse(range)
}
// Remove everything after the range prefix from file path
snippetPath = snippetPath.slice(0, rangePrefixIndex)
}

if (!fs.existsSync(snippetPath)) {
@@ -38,7 +69,10 @@ module.exports = ({ markdownAST, markdownNode }, { directory } = {}) => {

let code = fs.readFileSync(snippetPath, `utf8`).trim()
if (lines.length) {
code = getLines(snippetPath, code, lines)
code = code
.split(`\n`)
.filter((_, lineNumber) => lines.includes(lineNumber + 1))
.join(`\n`)
}

// PrismJS's theme styles are targeting pre[class*="language-"]
30 changes: 0 additions & 30 deletions packages/gatsby-remark-embed-snippet/src/utils/get-language.js

This file was deleted.

29 changes: 0 additions & 29 deletions packages/gatsby-remark-embed-snippet/src/utils/get-lines.js

This file was deleted.