Skip to content

Commit

Permalink
feat(gatsby-remark-code-repls): include matching css option (CodePen) (
Browse files Browse the repository at this point in the history
…#12110)

<!--
  Have any questions? Check out the contributing docs at https://gatsby.app/contribute, or
  ask in this Pull Request and a Gatsby maintainer will be happy to help :)
-->

## Description

Currently it's possible to upload multiple files only by using CodeSandbox.

This PR adds an option that allows adding CSS files to CodePen examples by setting the `css` property in the `payload` object. 

Ref: https://blog.codepen.io/documentation/api/prefill/

Matching CSS means that if the user is linking to `example.js` and the option is set to true, if `example.css` is present in the same directory, its content is sent to CodePen.

- The default behaviour is left untouched
- If the option is set to `true` and the matched file doesn't exist, nothing changes
- tests included

## Related Issues

<!--
  Link to the issue that is fixed by this PR (if there is one)
  e.g. Fixes #1234, Addresses #1234, Related to #1234, etc.
-->
  • Loading branch information
deblasis authored and wardpeet committed Apr 12, 2019
1 parent 900454e commit 1b8d93e
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/gatsby-remark-code-repls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ specified examples directory. (This will avoid broken links at runtime.)
// Note that if a target is specified, "noreferrer" will also be added.
// eg <a href="..." target="_blank" rel="noreferrer">...</a>
target: '_blank',

// Include CSS with matching name.
// This option only applies to REPLs that support it (eg Codepen).
// If set to `true`, when specifying `file1.js` as example file,
// it will try to inject the CSS in `file1.css` if the file exists,
// otherwise the default behaviour is preserved
includeMatchingCSS: false,
},
},
```
106 changes: 106 additions & 0 deletions packages/gatsby-remark-code-repls/src/__tests__/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const createPagesParams = {
reporter,
}

const throwFileNotFoundErr = path => {
const err = new Error(`no such file or directory '${path}'`)
err.code = `ENOENT`
throw err
}

describe(`gatsby-remark-code-repls`, () => {
beforeEach(() => {
fs.existsSync.mockReset()
Expand Down Expand Up @@ -198,5 +204,105 @@ describe(`gatsby-remark-code-repls`, () => {

expect(html).toBe(`<span id="foo"></span>`)
})

it(`should support includeMatchingCSS = "true" when matching file exists`, async () => {
readdir.mockResolvedValue([`file.js`, `file.css`])
fs.readFileSync.mockReset()
fs.readFileSync.mockImplementation((path, options) => {
if (path === `file.js`) {
return `const foo = "bar";`
} else if (path === `file.css`) {
return `html { color: red; }`
} else {
throwFileNotFoundErr(path)
}
return null
})

await createPages(createPagesParams, {
includeMatchingCSS: true,
})

const { css, js } = JSON.parse(
createPage.mock.calls[0][0].context.payload
)

expect(js).toBe(`const foo = "bar";`)
expect(css).toBe(`html { color: red; }`)
})

it(`should support includeMatchingCSS = "false" when matching file exists`, async () => {
readdir.mockResolvedValue([`file.js`, `file.css`])
fs.readFileSync.mockReset()
fs.readFileSync.mockImplementation((path, options) => {
if (path === `file.js`) {
return `const foo = "bar";`
} else if (path === `file.css`) {
return `html { color: red; }`
} else {
throwFileNotFoundErr(path)
}
return null
})

await createPages(createPagesParams, {
includeMatchingCSS: false,
})

const { css, js } = JSON.parse(
createPage.mock.calls[0][0].context.payload
)

expect(js).toBe(`const foo = "bar";`)
expect(css).toBe(undefined)
})

it(`should support includeMatchingCSS = "true" when matching file doesn't exist`, async () => {
readdir.mockResolvedValue([`file.js`])
fs.readFileSync.mockReset()
fs.readFileSync.mockImplementation((path, options) => {
if (path === `file.js`) {
return `const foo = "bar";`
} else {
throwFileNotFoundErr(path)
}
return null
})

await createPages(createPagesParams, {
includeMatchingCSS: true,
})

const { css, js } = JSON.parse(
createPage.mock.calls[0][0].context.payload
)

expect(js).toBe(`const foo = "bar";`)
expect(css).toBe(undefined)
})

it(`should support includeMatchingCSS = "false" when matching file doesn't exist`, async () => {
readdir.mockResolvedValue([`file.js`])
fs.readFileSync.mockReset()
fs.readFileSync.mockImplementation((path, options) => {
if (path === `file.js`) {
return `const foo = "bar";`
} else {
throwFileNotFoundErr(path)
}
return null
})

await createPages(createPagesParams, {
includeMatchingCSS: false,
})

const { css, js } = JSON.parse(
createPage.mock.calls[0][0].context.payload
)

expect(js).toBe(`const foo = "bar";`)
expect(css).toBe(undefined)
})
})
})
15 changes: 15 additions & 0 deletions packages/gatsby-remark-code-repls/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,21 @@ describe(`gatsby-remark-code-repls`, () => {
}
})

it(`supports includeMatchingCSS`, () => {
const markdownAST = remark.parse(
`[](${protocol}path/to/nested/file.js)`
)
const runPlugin = () =>
plugin(
{ markdownAST },
{
directory: `examples`,
includeMatchingCSS: true,
}
)
expect(runPlugin).not.toThrow()
})

if (protocol === PROTOCOL_CODE_SANDBOX) {
it(`supports custom html config option for index html`, () => {
const markdownAST = remark.parse(
Expand Down
1 change: 1 addition & 0 deletions packages/gatsby-remark-code-repls/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
OPTION_DEFAULT_REDIRECT_TEMPLATE_PATH: normalizePath(
join(__dirname, `default-redirect-template.js`)
),
OPTION_DEFAULT_INCLUDE_MATCHING_CSS: false,
PROTOCOL_BABEL: `babel://`,
PROTOCOL_CODEPEN: `codepen://`,
PROTOCOL_CODE_SANDBOX: `codesandbox://`,
Expand Down
15 changes: 15 additions & 0 deletions packages/gatsby-remark-code-repls/src/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
OPTION_DEFAULT_LINK_TEXT,
OPTION_DEFAULT_HTML,
OPTION_DEFAULT_REDIRECT_TEMPLATE_PATH,
OPTION_DEFAULT_INCLUDE_MATCHING_CSS,
} = require(`./constants`)

exports.createPages = async (
Expand All @@ -18,6 +19,7 @@ exports.createPages = async (
externals = [],
html = OPTION_DEFAULT_HTML,
redirectTemplate = OPTION_DEFAULT_REDIRECT_TEMPLATE_PATH,
includeMatchingCSS = OPTION_DEFAULT_INCLUDE_MATCHING_CSS,
} = {}
) => {
if (!directory.endsWith(`/`)) {
Expand Down Expand Up @@ -51,6 +53,18 @@ exports.createPages = async (
.replace(new RegExp(`^${directory}`), `redirect-to-codepen/`)
const code = fs.readFileSync(file, `utf8`)

let css
if (includeMatchingCSS === true) {
try {
css = fs.readFileSync(file.replace(extname(file), `.css`), `utf8`)
} catch (err) {
// If the file doesn't exist, we gracefully ignore the error
if (err.code !== `ENOENT`) {
throw err
}
}
}

// Codepen configuration.
// https://blog.codepen.io/documentation/api/prefill/
const action = `https://codepen.io/pen/define`
Expand All @@ -61,6 +75,7 @@ exports.createPages = async (
js_external: externals.join(`;`),
js_pre_processor: `babel`,
layout: `left`,
css,
})

createPage({
Expand Down

0 comments on commit 1b8d93e

Please sign in to comment.