Skip to content

refactor(gatsby-remark-code-repls): move config per provider #12936

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

Merged
merged 20 commits into from
Jun 25, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
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
45 changes: 30 additions & 15 deletions packages/gatsby-remark-code-repls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,26 +134,11 @@ specified examples directory. (This will avoid broken links at runtime.)
// eg <a href="...">Click here</a>
defaultText: 'Click here',

// Optional runtime dependencies to load from NPM.
// This option only applies to REPLs that support it (eg CodeSandbox).
// eg ['react', 'react-dom'] or ['react@15', 'react-dom@15']
dependencies: [],

// Example code links are relative to this dir.
// eg examples/path/to/file.js
directory: `${__dirname}/examples/`,

// Optional externals to load from a CDN.
// This option only applies to REPLs that support it (eg Codepen).
// eg '//unpkg.com/react/umd/react.development.js'
externals: [],

// Optional HTML contents to inject into REPL.
// Defaults to `<div id="root"></div>`.
// This option only applies to REPLs that support it (eg Codepen, CodeSandbox).
// eg '<div id="root"></div>'
html: '',

// Optional path to a custom redirect template.
// The redirect page is only shown briefly,
// But you can use this setting to override its CSS styling.
Expand All @@ -163,6 +148,36 @@ 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',


// Provider specific options
codepen: {
// Optional HTML contents to inject into REPL.
// Defaults to `<div id="root"></div>`.
// eg '<div id="root"></div>'
html: '',

// Optional externals to load from a CDN.
// eg '//unpkg.com/react/umd/react.development.js'
externals: [],

// Include CSS with matching name.
// 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,
},

codesandbox: {
// Optional HTML contents to inject into REPL.
// Defaults to `<div id="root"></div>`.
// eg '<div id="root"></div>'
html: '',

// Optional runtime dependencies to load from NPM.
// eg ['react', 'react-dom'] or ['react@15', 'react-dom@15']
dependencies: [],
}
},
},
```
2 changes: 1 addition & 1 deletion packages/gatsby-remark-code-repls/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gatsby-remark-code-repls",
"description": "Gatsby plugin to auto-generate links to popular REPLs like Babel and Codepen",
"version": "2.0.8",
"version": "3.0.0",
"author": "Brian Vaughn <[email protected]>",
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
Expand Down
181 changes: 163 additions & 18 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 @@ -155,17 +161,166 @@ describe(`gatsby-remark-code-repls`, () => {
expect(js_external).toBe(``)
})

it(`should load custom externals if specified`, async () => {
readdir.mockResolvedValue([`file.js`])
describe(`codepen specific`, () => {
it(`should load custom externals if specified`, async () => {
readdir.mockResolvedValue([`file.js`])

await createPages(createPagesParams, {
codepen: {
externals: [`foo.js`, `bar.js`],
},
})
const { js_external } = JSON.parse(
createPage.mock.calls[0][0].context.payload
)

await createPages(createPagesParams, { externals: [`foo.js`, `bar.js`] })
expect(js_external).toContain(`foo.js`)
expect(js_external).toContain(`bar.js`)
})
it(`should support custom, user-defined HTML for index page`, async () => {
readdir.mockResolvedValue([`file.js`])

await createPages(createPagesParams, {
codepen: { html: `<span id="foo"></span>` },
})
const { html } = JSON.parse(createPage.mock.calls[0][0].context.payload)

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, {
codepen: {
includeMatchingCSS: true,
},
})

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

const { js_external } = 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, {
codepen: {
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, {
codepen: {
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, {
codepen: {
includeMatchingCSS: false,
},
})

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

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

describe(`codesandbox specific`, () => {
beforeEach(() => {
fs.existsSync.mockReset()
fs.existsSync.mockReturnValue(true)

fs.readFileSync.mockReset()
fs.readFileSync.mockReturnValue(`const foo = "bar";`)

readdir.mockReset()
readdir.mockResolvedValue([`file.js`])

createPage.mockReset()
})
it(`should support custom, user-defined HTML for index page`, async () => {
readdir.mockResolvedValue([`file.js`])

await createPages(createPagesParams, {
codepen: { html: `<span id="foo"></span>` },
})

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

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

it(`should inject the required prop-types for the Codepen prefill API`, async () => {
Expand All @@ -188,15 +343,5 @@ describe(`gatsby-remark-code-repls`, () => {

expect(html).toBe(OPTION_DEFAULT_HTML)
})

it(`should support custom, user-defined HTML for index page`, async () => {
readdir.mockResolvedValue([`file.js`])

await createPages(createPagesParams, { html: `<span id="foo"></span>` })

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

expect(html).toBe(`<span id="foo"></span>`)
})
})
})
35 changes: 28 additions & 7 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,23 @@ describe(`gatsby-remark-code-repls`, () => {
}
})

it(`supports includeMatchingCSS`, () => {
const markdownAST = remark.parse(
`[](${protocol}path/to/nested/file.js)`
)
const runPlugin = () =>
plugin(
{ markdownAST },
{
directory: `examples`,
codepen: {
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 All @@ -151,7 +168,9 @@ describe(`gatsby-remark-code-repls`, () => {
{ markdownAST },
{
directory: `examples`,
html: `<span id="foo"></span>`,
codesandbox: {
html: `<span id="foo"></span>`,
},
}
)

Expand All @@ -166,12 +185,14 @@ describe(`gatsby-remark-code-repls`, () => {
const transformed = plugin(
{ markdownAST },
{
dependencies: [
`react`,
`react-dom@next`,
`[email protected]`,
`@babel/[email protected]`,
],
codesandbox: {
dependencies: [
`react`,
`react-dom@next`,
`[email protected]`,
`@babel/[email protected]`,
],
},
directory: `examples`,
}
)
Expand Down
15 changes: 14 additions & 1 deletion packages/gatsby-remark-code-repls/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@
const { join } = require(`path`)
const normalizePath = require(`normalize-path`)

module.exports = {
const baseOptions = {
OPTION_DEFAULT_LINK_TEXT: `REPL`,
OPTION_DEFAULT_HTML: `<div id="root"></div>`,
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://`,
PROTOCOL_RAMDA: `ramda://`,
}
module.exports = {
...baseOptions,
OPTION_DEFAULT_CODEPEN: {
html: baseOptions.OPTION_DEFAULT_HTML,
externals: [],
includeMatchingCSS: baseOptions.OPTION_DEFAULT_INCLUDE_MATCHING_CSS,
},
OPTION_DEFAULT_CODESANDBOX: {
html: baseOptions.OPTION_DEFAULT_HTML,
dependencies: [],
},
}
Loading