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(gatsby-remark-copy-linked-files): change default destinationDir and allow override via config #16508

Merged
merged 2 commits into from
Aug 10, 2019
Merged
Show file tree
Hide file tree
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
82 changes: 72 additions & 10 deletions packages/gatsby-remark-copy-linked-files/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ describe(`gatsby-remark-copy-linked-files`, () => {
describe(`options.destinationDir`, () => {
const imagePath = `images/sample-image.gif`

it(`throws an error if the destination directory is not within 'public'`, async () => {
it(`throws an error if the destination supplied by destinationDir points outside of the root dir`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const invalidDestinationDir = `../destination`
expect.assertions(2)
Expand All @@ -280,14 +280,31 @@ describe(`gatsby-remark-copy-linked-files`, () => {
})
})

it(`copies file to destinationDir when supplied`, async () => {
it(`throws an error if the destination supplied by the destinationDir function points outside of the root dir`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const invalidDestinationDir = `../destination`
const customDestinationDir = f =>
`../destination/${f.hash}/${f.name}/${f.notexist}`
expect.assertions(2)
return plugin(
{ files: getFiles(imagePath), markdownAST, markdownNode, getNode },
{
destinationDir: customDestinationDir,
}
).catch(e => {
expect(e).toEqual(expect.stringContaining(invalidDestinationDir))
expect(fsExtra.copy).not.toHaveBeenCalled()
})
})

it(`copies file to the destination supplied by destinationDir`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const validDestinationDir = `path/to/dir`
const expectedNewPath = path.posix.join(
process.cwd(),
`public`,
validDestinationDir,
`/undefined-undefined.gif`
`/undefined/undefined.gif`
)
expect.assertions(3)
await plugin(
Expand All @@ -299,20 +316,38 @@ describe(`gatsby-remark-copy-linked-files`, () => {
expect(v).toBeDefined()
expect(fsExtra.copy).toHaveBeenCalledWith(imagePath, expectedNewPath)
expect(imageURL(markdownAST)).toEqual(
`/path/to/dir/undefined-undefined.gif`
`/path/to/dir/undefined/undefined.gif`
)
})
})

it(`copies file to the destination supplied by the destinationDir function`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const customDestinationDir = f => `foo/${f.hash}--bar`
const expectedDestination = `foo/undefined--bar.gif`
expect.assertions(3)
await plugin(
{ files: getFiles(imagePath), markdownAST, markdownNode, getNode },
{ destinationDir: customDestinationDir }
).then(v => {
const expectedNewPath = path.posix.join(
...[process.cwd(), `public`, expectedDestination]
)
expect(v).toBeDefined()
expect(fsExtra.copy).toHaveBeenCalledWith(imagePath, expectedNewPath)
expect(imageURL(markdownAST)).toEqual(`/${expectedDestination}`)
})
})

it(`copies file to destinationDir when supplied (with pathPrefix)`, async () => {
it(`copies file to the destination supplied by destinationDir (with pathPrefix)`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const pathPrefix = `/blog`
const validDestinationDir = `path/to/dir`
const expectedNewPath = path.posix.join(
process.cwd(),
`public`,
validDestinationDir,
`/undefined-undefined.gif`
`/undefined/undefined.gif`
)
expect.assertions(3)
await plugin(
Expand All @@ -330,17 +365,44 @@ describe(`gatsby-remark-copy-linked-files`, () => {
expect(v).toBeDefined()
expect(fsExtra.copy).toHaveBeenCalledWith(imagePath, expectedNewPath)
expect(imageURL(markdownAST)).toEqual(
`${pathPrefix}/path/to/dir/undefined-undefined.gif`
`${pathPrefix}/path/to/dir/undefined/undefined.gif`
)
})
})

it(`copies file to the destination supplied by the destinationDir function (with pathPrefix)`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const pathPrefix = `/blog`
const customDestinationDir = f => `hello${f.name}123`
const expectedDestination = `helloundefined123.gif`
expect.assertions(3)
await plugin(
{
files: getFiles(imagePath),
markdownAST,
markdownNode,
pathPrefix,
getNode,
},
{ destinationDir: customDestinationDir }
).then(v => {
const expectedNewPath = path.posix.join(
...[process.cwd(), `public`, expectedDestination]
)
expect(v).toBeDefined()
expect(fsExtra.copy).toHaveBeenCalledWith(imagePath, expectedNewPath)
expect(imageURL(markdownAST)).toEqual(
`${pathPrefix}/${expectedDestination}`
)
})
})

it(`copies file to root dir when not supplied'`, async () => {
it(`copies file to the root dir when destinationDir is not supplied'`, async () => {
const markdownAST = remark.parse(`![some absolute image](${imagePath})`)
const expectedNewPath = path.posix.join(
process.cwd(),
`public`,
`/undefined-undefined.gif`
`/undefined/undefined.gif`
)
expect.assertions(3)
await plugin({
Expand All @@ -351,7 +413,7 @@ describe(`gatsby-remark-copy-linked-files`, () => {
}).then(v => {
expect(v).toBeDefined()
expect(fsExtra.copy).toHaveBeenCalledWith(imagePath, expectedNewPath)
expect(imageURL(markdownAST)).toEqual(`/undefined-undefined.gif`)
expect(imageURL(markdownAST)).toEqual(`/undefined/undefined.gif`)
})
})
})
Expand Down
78 changes: 48 additions & 30 deletions packages/gatsby-remark-copy-linked-files/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,56 @@ const DEPLOY_DIR = `public`
const invalidDestinationDirMessage = dir =>
`[gatsby-remark-copy-linked-files You have supplied an invalid destination directory. The destination directory must be a child but was: ${dir}`

// dir must be a child
const destinationDirIsValid = dir => !path.relative(`./`, dir).startsWith(`..`)

const validateDestinationDir = dir =>
!dir || (dir && destinationDirIsValid(dir))

const newFileName = linkNode =>
`${linkNode.name}-${linkNode.internal.contentDigest}.${linkNode.extension}`

const newPath = (linkNode, destinationDir) => {
if (destinationDir) {
return path.posix.join(
process.cwd(),
DEPLOY_DIR,
destinationDir,
newFileName(linkNode)
)
// dest must be a child
const destinationIsValid = dest => !path.relative(`./`, dest).startsWith(`..`)

const validateDestinationDir = dir => {
if (typeof dir === `undefined`) {
return true
} else if (typeof dir === `string`) {
// need to pass dummy data for validation to work
return destinationIsValid(`${dir}/h/n`)
} else if (_.isFunction(dir)) {
// need to pass dummy data for validation to work
return destinationIsValid(`${dir({ name: `n`, hash: `h` })}`)
} else {
return false
}
return path.posix.join(process.cwd(), DEPLOY_DIR, newFileName(linkNode))
}

const newLinkURL = (linkNode, destinationDir, pathPrefix) => {
const linkPaths = [
`/`,
pathPrefix,
destinationDir,
newFileName(linkNode),
].filter(function(lpath) {
if (lpath) return true
return false
})
const defaultDestination = linkNode =>
`${linkNode.internal.contentDigest}/${linkNode.name}.${linkNode.extension}`

const getDestination = (linkNode, dir) => {
if (_.isFunction(dir)) {
// need to pass dummy data for validation to work
const isValidFunction = `${dir({ name: `n`, hash: `h` })}` !== `${dir({})}`
return isValidFunction
? `${dir({
name: linkNode.name,
hash: linkNode.internal.contentDigest,
})}.${linkNode.extension}`
: `${dir()}/${defaultDestination(linkNode)}`
} else if (_.isString(dir)) {
return `${dir}/${defaultDestination(linkNode)}`
} else {
return defaultDestination(linkNode)
}
}

const newPath = (linkNode, options) => {
const { destinationDir } = options
const destination = getDestination(linkNode, destinationDir)
const paths = [process.cwd(), DEPLOY_DIR, destination]
return path.posix.join(...paths)
}

const newLinkURL = (linkNode, options, pathPrefix) => {
const { destinationDir } = options
const destination = getDestination(linkNode, destinationDir)
const linkPaths = [`/`, pathPrefix, destination].filter(lpath =>
lpath ? true : false
)
return path.posix.join(...linkPaths)
}

Expand Down Expand Up @@ -89,12 +107,12 @@ module.exports = (
return null
})
if (linkNode && linkNode.absolutePath) {
const newFilePath = newPath(linkNode, options.destinationDir)
const newFilePath = newPath(linkNode, options)

// Prevent uneeded copying
if (linkPath === newFilePath) return

const linkURL = newLinkURL(linkNode, options.destinationDir, pathPrefix)
const linkURL = newLinkURL(linkNode, options, pathPrefix)
link.url = linkURL
filesToCopy.set(linkPath, newFilePath)
}
Expand Down