From 1b470f246389d2a4b7dd69564366d4e447008dff Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Wed, 31 Oct 2018 14:55:00 -0500 Subject: [PATCH 1/4] feat: get mostly working --- .../src/__fixtures__/highlight-html.html | 9 ++ .../src/__fixtures__/highlight-jsx-comment.js | 9 ++ .../__fixtures__/highlight-kitchen-sink.js | 28 ++++++ .../src/__fixtures__/highlight-line.js | 3 + .../src/__fixtures__/highlight-next-line.js | 4 + .../src/__fixtures__/highlight-start-end.js | 6 ++ .../highlight-start-without-end.js | 3 + .../src/__fixtures__/highlight-yaml.yaml | 3 + .../src/__fixtures__/index.js | 14 +++ .../highlight-line-range.js.snap | 20 ++++ .../src/__tests__/highlight-line-range.js | 93 +++++++++++++++++++ .../src/highlight-code.js | 2 + .../src/highlight-line-range.js | 78 ++++++++++++++++ yarn.lock | 12 +-- 14 files changed, 277 insertions(+), 7 deletions(-) create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-html.html create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-line.js create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-next-line.js create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-end.js create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-without-end.js create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/highlight-yaml.yaml create mode 100644 packages/gatsby-remark-prismjs/src/__fixtures__/index.js create mode 100644 packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/highlight-line-range.js.snap create mode 100644 packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js create mode 100644 packages/gatsby-remark-prismjs/src/highlight-line-range.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-html.html b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-html.html new file mode 100644 index 0000000000000..693ff853ae4d6 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-html.html @@ -0,0 +1,9 @@ + + + + Helloooooooooo + + +

hello world

+ + diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js new file mode 100644 index 0000000000000..9ff0289bf8faa --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js @@ -0,0 +1,9 @@ +import React from "react" + +export default function Button() { + return ( +
+ {/* highlight-line */} +
+ ) +} diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js new file mode 100644 index 0000000000000..ecb1fb8a7c433 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js @@ -0,0 +1,28 @@ +import React, { Component } from "react" // highlight-line + +export default class Counter extends Component { + /* highlight-start */ + state = { + count: 0, + } + // highlight-end + + updateCount = () => { + this.setState(state => ({ + // highlight-next-line + count: state.count + 1, + })) + } + + render() { + const { count } = this.state // highlight-line + return ( +
+ clicked {count} + {/* highlight-start */} + + {/* highlight-end */} +
+ ) + } +} diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-line.js b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-line.js new file mode 100644 index 0000000000000..456927b8594d9 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-line.js @@ -0,0 +1,3 @@ +function test() { + return "hello world" // highlight-line +} diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-next-line.js b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-next-line.js new file mode 100644 index 0000000000000..30ac3c772a11e --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-next-line.js @@ -0,0 +1,4 @@ +function test() { + // highlight-next-line + return "hello world" +} diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-end.js b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-end.js new file mode 100644 index 0000000000000..14160d19f3f60 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-end.js @@ -0,0 +1,6 @@ +function test() { + // highlight-start + var a = "b" + return a + "hello world" + // highlight-end +} diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-without-end.js b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-without-end.js new file mode 100644 index 0000000000000..136d2ee035755 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-without-end.js @@ -0,0 +1,3 @@ +// highlight-start +var a = "b" +return a + "hello world" diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-yaml.yaml b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-yaml.yaml new file mode 100644 index 0000000000000..6e7bcf216cc56 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-yaml.yaml @@ -0,0 +1,3 @@ +- title: uno +- title: dos +- title: catorce # highlight-line diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/index.js b/packages/gatsby-remark-prismjs/src/__fixtures__/index.js new file mode 100644 index 0000000000000..052ddf4f1b159 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__fixtures__/index.js @@ -0,0 +1,14 @@ +const fs = require("fs-extra") +const path = require("path") + +const base = __dirname + +module.exports = fs.readdirSync(base).reduce((lookup, file) => { + if (file !== "index.js") { + const name = file + .replace(/-(\w)/g, (_, char) => char.toUpperCase()) + .replace(/\..+/, "") + lookup[name] = fs.readFileSync(path.join(base, file), "utf8") + } + return lookup +}, {}) 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 new file mode 100644 index 0000000000000..062a8d6740688 --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__tests__/__snapshots__/highlight-line-range.js.snap @@ -0,0 +1,20 @@ +// 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-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 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__/highlight-line-range.js new file mode 100644 index 0000000000000..202739591abae --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js @@ -0,0 +1,93 @@ +const highlightLineRange = require("../highlight-line-range") +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", () => { + describe("highlight-line", () => { + it("strips directive", () => { + const highlights = highlightLineRange(fixtures.highlightLine) + expect(output(highlights)).not.toContain("highlight-line") + }) + + it("highlights line", () => { + const highlights = highlightLineRange(fixtures.highlightLine) + + expect(output(getHighlighted(highlights))).toMatchSnapshot() + }) + }) + + describe("highlight-next-line", () => { + it("strips directive", () => { + const highlights = highlightLineRange(fixtures.highlightNextLine) + + expect(output(highlights)).not.toContain("highlight-next-line") + }) + + it("highlights correct line", () => { + const highlights = highlightLineRange(fixtures.highlightNextLine) + + expect(output(getHighlighted(highlights))).toMatchSnapshot() + }) + }) + + describe("highlight-start / highlight-end", () => { + it("strips directives", () => { + const highlights = highlightLineRange(fixtures.highlightStartEnd) + + const code = output(highlights) + ;["highlight-start", "highlight-end"].forEach(directive => { + expect(code).not.toContain(directive) + }) + }) + + it("highlights correct lines", () => { + const highlights = highlightLineRange(fixtures.highlightStartEnd) + + expect(output(getHighlighted(highlights))).toMatchSnapshot() + }) + + it("highlights without end directive", () => { + const highlights = highlightLineRange(fixtures.highlightStartWithoutEnd) + + expect(output(getHighlighted(highlights))).toMatchSnapshot() + }) + }) + + describe("jsx comment", () => { + it("removes directive", () => { + const highlights = highlightLineRange(fixtures.highlightJsxComment) + + expect(output(highlights)).not.toContain("highlight-line") + }) + + it("highlights comment line", () => { + const highlights = highlightLineRange(fixtures.highlightJsxComment) + + expect(output(getHighlighted(highlights))).toMatchSnapshot() + }) + }) + + describe("yaml", () => { + it("strips directive", () => { + const highlights = highlightLineRange(fixtures.highlightYaml) + + expect(highlights).not.toContain("highlight-line") + }) + + it("highlights yaml", () => { + const highlights = highlightLineRange(fixtures.highlightYaml) + + expect(output(getHighlighted(highlights))).toMatchSnapshot() + }) + }) + + describe("kitchen sink", () => { + it.skip("strips directives", () => { + const highlights = highlightLineRange(fixtures.highlightKitchenSink) + + console.log(output(highlights)) + }) + }) +}) diff --git a/packages/gatsby-remark-prismjs/src/highlight-code.js b/packages/gatsby-remark-prismjs/src/highlight-code.js index 9935a92694ef8..5e8f3f0e4fe81 100644 --- a/packages/gatsby-remark-prismjs/src/highlight-code.js +++ b/packages/gatsby-remark-prismjs/src/highlight-code.js @@ -4,6 +4,8 @@ const _ = require(`lodash`) const loadPrismLanguage = require(`./load-prism-language`) const plainTextWithLFTest = /[^<]*\n[^<]*<\/span>/g +const wrap = line => + ['', `${line}\n`, ""].join("") module.exports = (language, code, lineNumbersHighlight = []) => { // (Try to) load languages on demand. diff --git a/packages/gatsby-remark-prismjs/src/highlight-line-range.js b/packages/gatsby-remark-prismjs/src/highlight-line-range.js new file mode 100644 index 0000000000000..c4fc57e611fac --- /dev/null +++ b/packages/gatsby-remark-prismjs/src/highlight-line-range.js @@ -0,0 +1,78 @@ +const COMMENT_START = /(#|\/\/|\{\/\*|\/\*+||\*\/\}|\*\/)?/ +const DIRECTIVE = /highlight-(next-line|line|start|end)/ +const END_DIRECTIVE = /highlight-end/ + +const stripComment = line => + line.replace( + new RegExp( + `\\s*${COMMENT_START.source}\\s*${DIRECTIVE.source}\\s*${ + COMMENT_END.source + }` + ), + "" + ) + +const getHighlights = (line, code, index) => { + const [, directive] = line.match(DIRECTIVE) + switch (directive) { + case "next-line": + return [ + { + code: code[index + 1], + highlighted: true, + }, + index + 1, + ] + case "start": + const endIndex = code.findIndex(line => END_DIRECTIVE.test(line)) + const end = endIndex === -1 ? code.length : endIndex + const highlighted = code.slice(index + 1, end).map(line => ({ + code: stripComment(line), + highlighted: true, + })) + + return [highlighted, end] + case "line": + default: + return [ + { + code: stripComment(line), + highlighted: true, + }, + index, + ] + } +} + +module.exports = function highlightLineRange(code, highlights = []) { + let highlighted = [] + const split = code.split("\n") + + if (highlights.length > 0) { + return split.map((line, i) => { + if (highlights.includes(i + 1)) { + return { + highlighted: true, + code: line, + } + } + return { code: line } + }) + } + + 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, + }) + } + } + + return highlighted +} diff --git a/yarn.lock b/yarn.lock index 75c9464ba602d..1febe6cb2d1b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2928,13 +2928,6 @@ babel-plugin-lodash@^3.2.11: lodash "^4.17.10" require-package-name "^2.0.1" -babel-plugin-macros@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.4.0.tgz#6c5f9836e1f6c0a9743b3bab4af29f73e437e544" - integrity sha512-flIBfrqAdHWn+4l2cS/4jZEyl+m5EaBHVzTb0aOF+eu/zR7E41/MoCFHPhDNL8Wzq1nyelnXeT+vcL2byFLSZw== - dependencies: - cosmiconfig "^5.0.5" - babel-plugin-macros@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.4.2.tgz#21b1a2e82e2130403c5ff785cba6548e9b644b28" @@ -11330,6 +11323,11 @@ json-stable-stringify@^1.0.0: dependencies: jsonify "~0.0.0" +json-stream-stringify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/json-stream-stringify/-/json-stream-stringify-2.0.1.tgz#8bc0e65ff94567d9010e14c27c043a951cb14939" + integrity sha512-5XymtJXPmzRWZ1UdLQQQXbjHV/E7NAanSClikEqORbkZKOYLSYLNHqRuooyju9W90kJUzknFhX2xvWn4cHluHQ== + json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" From 7c778b775c5c1ece2c4d46df66d9f1c4330365de Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 1 Nov 2018 09:30:01 -0500 Subject: [PATCH 2/4] feat: keep iterating --- .../__fixtures__/highlight-jsx-comment.js | 36 +++++++ .../__fixtures__/highlight-kitchen-sink.js | 74 ++++++++++++++ .../__fixtures__/highlight-line.js | 5 + .../__fixtures__/highlight-next-line.js | 6 ++ .../__fixtures__/highlight-start-end.js | 7 ++ .../__fixtures__/index.js | 17 ++++ .../highlight-line-range.js | 99 +++++++++++++++++++ .../__fixtures__/highlight-html.html | 0 .../__fixtures__/highlight-jsx-comment.js | 0 .../__fixtures__/highlight-kitchen-sink.js | 0 .../__fixtures__/highlight-line.js | 0 .../__fixtures__/highlight-next-line.js | 0 .../__fixtures__/highlight-start-end.js | 0 .../highlight-start-without-end.js | 0 .../__fixtures__/highlight-yaml.yaml | 0 .../src/{ => __tests__}/__fixtures__/index.js | 0 .../src/__tests__/highlight-line-range.js | 2 +- .../src/highlight-code.js | 45 +++------ .../src/highlight-line-range.js | 18 +++- 19 files changed, 274 insertions(+), 35 deletions(-) create mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js create mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js create mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js create mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js create mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js create mode 100644 packages/gatsby-remark-prismjs/__fixtures__/index.js create mode 100644 packages/gatsby-remark-prismjs/highlight-line-range.js rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-html.html (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-jsx-comment.js (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-kitchen-sink.js (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-line.js (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-next-line.js (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-start-end.js (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-start-without-end.js (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/highlight-yaml.yaml (100%) rename packages/gatsby-remark-prismjs/src/{ => __tests__}/__fixtures__/index.js (100%) diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js new file mode 100644 index 0000000000000..a9aacef94710e --- /dev/null +++ b/packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js @@ -0,0 +1,36 @@ +"use strict" + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault") + +exports.__esModule = true +exports.default = Button + +var _react = _interopRequireDefault(require("react")) + +var _jsxFileName = + "/Users/dschau/Code/Work/gatsby/gatsby/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js" + +function Button() { + return _react.default.createElement( + "div", + { + __source: { + fileName: _jsxFileName, + lineNumber: 5, + }, + __self: this, + }, + _react.default.createElement( + "button", + { + __source: { + fileName: _jsxFileName, + lineNumber: 6, + }, + __self: this, + }, + "sup" + ), + " " + ) +} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js new file mode 100644 index 0000000000000..5cdc56c788261 --- /dev/null +++ b/packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js @@ -0,0 +1,74 @@ +"use strict" + +var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault") + +var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard") + +exports.__esModule = true +exports.default = void 0 + +var _defineProperty2 = _interopRequireDefault( + require("@babel/runtime/helpers/defineProperty") +) + +var _react = _interopRequireWildcard(require("react")) + +var _jsxFileName = + "/Users/dschau/Code/Work/gatsby/gatsby/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js" + +// highlight-line +class Counter extends _react.Component { + constructor(...args) { + super(...args) + ;(0, _defineProperty2.default)(this, "state", { + count: 0, // highlight-end + }) + ;(0, _defineProperty2.default)(this, "updateCount", () => { + this.setState(state => ({ + // highlight-next-line + count: state.count + 1, + })) + }) + } + + render() { + const { count } = this.state // highlight-line + + return _react.default.createElement( + "div", + { + __source: { + fileName: _jsxFileName, + lineNumber: 20, + }, + __self: this, + }, + _react.default.createElement( + "span", + { + __source: { + fileName: _jsxFileName, + lineNumber: 21, + }, + __self: this, + }, + "clicked ", + count + ), + _react.default.createElement( + "button", + { + onClick: this.updateCount, + __source: { + fileName: _jsxFileName, + lineNumber: 23, + }, + __self: this, + }, + "Click me" + ) + ) + } +} + +exports.default = Counter diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js new file mode 100644 index 0000000000000..a03b83d926ffd --- /dev/null +++ b/packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js @@ -0,0 +1,5 @@ +"use strict" + +function test() { + return "hello world" // highlight-line +} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js new file mode 100644 index 0000000000000..a7d31d1fac052 --- /dev/null +++ b/packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js @@ -0,0 +1,6 @@ +"use strict" + +function test() { + // highlight-next-line + return "hello world" +} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js new file mode 100644 index 0000000000000..8a19d3cf310df --- /dev/null +++ b/packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js @@ -0,0 +1,7 @@ +"use strict" + +function test() { + // highlight-start + var a = "b" + return a + "hello world" // highlight-end +} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/index.js b/packages/gatsby-remark-prismjs/__fixtures__/index.js new file mode 100644 index 0000000000000..0e273e6cc60ae --- /dev/null +++ b/packages/gatsby-remark-prismjs/__fixtures__/index.js @@ -0,0 +1,17 @@ +"use strict" + +const fs = require("fs-extra") + +const path = require("path") + +const base = __dirname +module.exports = fs.readdirSync(base).reduce((lookup, file) => { + if (file !== "index.js") { + const name = file + .replace(/-(\w)/g, (_, char) => char.toUpperCase()) + .replace(/\..+/, "") + lookup[name] = fs.readFileSync(path.join(base, file), "utf8") + } + + return lookup +}, {}) diff --git a/packages/gatsby-remark-prismjs/highlight-line-range.js b/packages/gatsby-remark-prismjs/highlight-line-range.js new file mode 100644 index 0000000000000..9a30c836223e1 --- /dev/null +++ b/packages/gatsby-remark-prismjs/highlight-line-range.js @@ -0,0 +1,99 @@ +"use strict" + +const COMMENT_START = /(#|\/\/|\{\/\*|\/\*+||\*\/\}|\*\/)?/ +const DIRECTIVE = /highlight-(next-line|line|start|end)/ +const END_DIRECTIVE = /highlight-end/ +const plainTextWithLFTest = /[^<]*\n[^<]*<\/span>/g + +const stripComment = line => + line.replace( + new RegExp( + `\\s*${COMMENT_START.source}\\s*${DIRECTIVE.source}\\s*${ + COMMENT_END.source + }` + ), + "" + ) + +const wrap = line => + [ + ``, + `${stripComment(line)}\n`, + ``, + ].join("") + +const getHighlights = (line, code, index) => { + const [, directive] = line.match(DIRECTIVE) + + switch (directive) { + case "next-line": + return [ + { + code: code[index + 1], + highlighted: true, + }, + index + 1, + ] + + case "start": + const endIndex = code.findIndex(line => END_DIRECTIVE.test(line)) + const end = endIndex === -1 ? code.length : endIndex + const highlighted = code.slice(index + 1, end).map(line => ({ + code: wrap(line), + highlighted: true, + })) + return [highlighted, end] + + case "line": + default: + return [ + { + code: wrap(line), + highlighted: true, + }, + index, + ] + } +} + +module.exports = function highlightLineRange(code, highlights = []) { + let highlighted = [] + const split = code.split("\n") + + if (highlights.length > 0) { + // 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(plainTextWithLFTest, match => + match.replace(/\n/g, `\n`) + ) + return split.map((line, i) => { + if (highlights.includes(i + 1)) { + return { + highlighted: true, + code: line, + } + } + + return { + code: line, + } + }) + } + + 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, + }) + } + } + + return highlighted +} diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-html.html b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-html.html similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-html.html rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-html.html diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-jsx-comment.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-jsx-comment.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-kitchen-sink.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-kitchen-sink.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-line.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-line.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-line.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-line.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-next-line.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-next-line.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-next-line.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-next-line.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-end.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-start-end.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-end.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-start-end.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-without-end.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-start-without-end.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-start-without-end.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-start-without-end.js diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-yaml.yaml b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-yaml.yaml similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/highlight-yaml.yaml rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/highlight-yaml.yaml diff --git a/packages/gatsby-remark-prismjs/src/__fixtures__/index.js b/packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/index.js similarity index 100% rename from packages/gatsby-remark-prismjs/src/__fixtures__/index.js rename to packages/gatsby-remark-prismjs/src/__tests__/__fixtures__/index.js diff --git a/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js b/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js index 202739591abae..4197ce5625015 100644 --- a/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js +++ b/packages/gatsby-remark-prismjs/src/__tests__/highlight-line-range.js @@ -1,5 +1,5 @@ const highlightLineRange = require("../highlight-line-range") -const fixtures = require("../__fixtures__") +const fixtures = require("./__fixtures__") const output = highlighted => highlighted.map(({ code }) => code).join("\n") const getHighlighted = lines => lines.filter(line => line.highlighted) diff --git a/packages/gatsby-remark-prismjs/src/highlight-code.js b/packages/gatsby-remark-prismjs/src/highlight-code.js index 5e8f3f0e4fe81..d3751cc3a97ae 100644 --- a/packages/gatsby-remark-prismjs/src/highlight-code.js +++ b/packages/gatsby-remark-prismjs/src/highlight-code.js @@ -2,10 +2,7 @@ const Prism = require(`prismjs`) const _ = require(`lodash`) const loadPrismLanguage = require(`./load-prism-language`) - -const plainTextWithLFTest = /[^<]*\n[^<]*<\/span>/g -const wrap = line => - ['', `${line}\n`, ""].join("") +const highlightLineRange = require(`./highlight-line-range`) module.exports = (language, code, lineNumbersHighlight = []) => { // (Try to) load languages on demand. @@ -24,35 +21,19 @@ module.exports = (language, code, lineNumbersHighlight = []) => { const grammar = Prism.languages[language] - let highlightedCode = Prism.highlight(code, grammar, language) - if (lineNumbersHighlight.length > 0) { - // 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 - highlightedCode = highlightedCode.replace(plainTextWithLFTest, match => - match.replace(/\n/g, `\n`) - ) + const highlighted = Prism.highlight(code, grammar, language) + const codeSplits = highlightLineRange(highlighted, lineNumbersHighlight) - const codeSplits = highlightedCode.split(`\n`).map((split, i) => { - if (_.includes(lineNumbersHighlight, i + 1)) { - return { - highlighted: true, - code: `${split}\n`, - } - } else { - return { code: split } - } - }) + let finalCode = `` - highlightedCode = `` - const lastIdx = codeSplits.length - 1 - // 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 - ? (highlightedCode += split.code) - : (highlightedCode += `${split.code}${idx == lastIdx ? `` : `\n`}`) - }) - } + const lastIdx = codeSplits.length - 1 + // 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 + ? (finalCode += split.code) + : (finalCode += `${split.code}${idx == lastIdx ? `` : `\n`}`) + }) - return highlightedCode + return finalCode } diff --git a/packages/gatsby-remark-prismjs/src/highlight-line-range.js b/packages/gatsby-remark-prismjs/src/highlight-line-range.js index c4fc57e611fac..62ecc9f9ea2b0 100644 --- a/packages/gatsby-remark-prismjs/src/highlight-line-range.js +++ b/packages/gatsby-remark-prismjs/src/highlight-line-range.js @@ -2,6 +2,7 @@ const COMMENT_START = /(#|\/\/|\{\/\*|\/\*+||\*\/\}|\*\/)?/ const DIRECTIVE = /highlight-(next-line|line|start|end)/ const END_DIRECTIVE = /highlight-end/ +const plainTextWithLFTest = /[^<]*\n[^<]*<\/span>/g const stripComment = line => line.replace( @@ -13,6 +14,13 @@ const stripComment = line => "" ) +const wrap = line => + [ + ``, + `${stripComment(line)}\n`, + ``, + ].join("") + const getHighlights = (line, code, index) => { const [, directive] = line.match(DIRECTIVE) switch (directive) { @@ -28,7 +36,7 @@ const getHighlights = (line, code, index) => { const endIndex = code.findIndex(line => END_DIRECTIVE.test(line)) const end = endIndex === -1 ? code.length : endIndex const highlighted = code.slice(index + 1, end).map(line => ({ - code: stripComment(line), + code: wrap(line), highlighted: true, })) @@ -37,7 +45,7 @@ const getHighlights = (line, code, index) => { default: return [ { - code: stripComment(line), + code: wrap(line), highlighted: true, }, index, @@ -50,6 +58,12 @@ module.exports = function highlightLineRange(code, highlights = []) { const split = code.split("\n") if (highlights.length > 0) { + // 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(plainTextWithLFTest, match => + match.replace(/\n/g, `\n`) + ) + return split.map((line, i) => { if (highlights.includes(i + 1)) { return { From ba8804ee4ff5202952ce1e25366c185ba2053cec Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 1 Nov 2018 09:30:11 -0500 Subject: [PATCH 3/4] chore: update From 7ded2f7380794fcfbae623508d8d38851381a61f Mon Sep 17 00:00:00 2001 From: Dustin Schau Date: Thu, 1 Nov 2018 11:42:51 -0500 Subject: [PATCH 4/4] chore: remove unneeded fixtures --- .../__fixtures__/highlight-jsx-comment.js | 36 --------- .../__fixtures__/highlight-kitchen-sink.js | 74 ------------------- .../__fixtures__/highlight-line.js | 5 -- .../__fixtures__/highlight-next-line.js | 6 -- .../__fixtures__/highlight-start-end.js | 7 -- .../__fixtures__/index.js | 17 ----- 6 files changed, 145 deletions(-) delete mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js delete mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js delete mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js delete mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js delete mode 100644 packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js delete mode 100644 packages/gatsby-remark-prismjs/__fixtures__/index.js diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js deleted file mode 100644 index a9aacef94710e..0000000000000 --- a/packages/gatsby-remark-prismjs/__fixtures__/highlight-jsx-comment.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict" - -var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault") - -exports.__esModule = true -exports.default = Button - -var _react = _interopRequireDefault(require("react")) - -var _jsxFileName = - "/Users/dschau/Code/Work/gatsby/gatsby/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-jsx-comment.js" - -function Button() { - return _react.default.createElement( - "div", - { - __source: { - fileName: _jsxFileName, - lineNumber: 5, - }, - __self: this, - }, - _react.default.createElement( - "button", - { - __source: { - fileName: _jsxFileName, - lineNumber: 6, - }, - __self: this, - }, - "sup" - ), - " " - ) -} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js deleted file mode 100644 index 5cdc56c788261..0000000000000 --- a/packages/gatsby-remark-prismjs/__fixtures__/highlight-kitchen-sink.js +++ /dev/null @@ -1,74 +0,0 @@ -"use strict" - -var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault") - -var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard") - -exports.__esModule = true -exports.default = void 0 - -var _defineProperty2 = _interopRequireDefault( - require("@babel/runtime/helpers/defineProperty") -) - -var _react = _interopRequireWildcard(require("react")) - -var _jsxFileName = - "/Users/dschau/Code/Work/gatsby/gatsby/packages/gatsby-remark-prismjs/src/__fixtures__/highlight-kitchen-sink.js" - -// highlight-line -class Counter extends _react.Component { - constructor(...args) { - super(...args) - ;(0, _defineProperty2.default)(this, "state", { - count: 0, // highlight-end - }) - ;(0, _defineProperty2.default)(this, "updateCount", () => { - this.setState(state => ({ - // highlight-next-line - count: state.count + 1, - })) - }) - } - - render() { - const { count } = this.state // highlight-line - - return _react.default.createElement( - "div", - { - __source: { - fileName: _jsxFileName, - lineNumber: 20, - }, - __self: this, - }, - _react.default.createElement( - "span", - { - __source: { - fileName: _jsxFileName, - lineNumber: 21, - }, - __self: this, - }, - "clicked ", - count - ), - _react.default.createElement( - "button", - { - onClick: this.updateCount, - __source: { - fileName: _jsxFileName, - lineNumber: 23, - }, - __self: this, - }, - "Click me" - ) - ) - } -} - -exports.default = Counter diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js deleted file mode 100644 index a03b83d926ffd..0000000000000 --- a/packages/gatsby-remark-prismjs/__fixtures__/highlight-line.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict" - -function test() { - return "hello world" // highlight-line -} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js deleted file mode 100644 index a7d31d1fac052..0000000000000 --- a/packages/gatsby-remark-prismjs/__fixtures__/highlight-next-line.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict" - -function test() { - // highlight-next-line - return "hello world" -} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js b/packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js deleted file mode 100644 index 8a19d3cf310df..0000000000000 --- a/packages/gatsby-remark-prismjs/__fixtures__/highlight-start-end.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict" - -function test() { - // highlight-start - var a = "b" - return a + "hello world" // highlight-end -} diff --git a/packages/gatsby-remark-prismjs/__fixtures__/index.js b/packages/gatsby-remark-prismjs/__fixtures__/index.js deleted file mode 100644 index 0e273e6cc60ae..0000000000000 --- a/packages/gatsby-remark-prismjs/__fixtures__/index.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict" - -const fs = require("fs-extra") - -const path = require("path") - -const base = __dirname -module.exports = fs.readdirSync(base).reduce((lookup, file) => { - if (file !== "index.js") { - const name = file - .replace(/-(\w)/g, (_, char) => char.toUpperCase()) - .replace(/\..+/, "") - lookup[name] = fs.readFileSync(path.join(base, file), "utf8") - } - - return lookup -}, {})