From 69902ececcd4a32c1bde03218bd111d2ca565f64 Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Fri, 22 Jul 2022 14:21:23 +0200 Subject: [PATCH 1/5] Add relativeDirectory to destinationDir callback Supersedes https://github.com/gatsbyjs/gatsby/pull/27126 Ref: https://github.com/gatsbyjs/gatsby/issues/27097 Ref: https://github.com/gatsbyjs/gatsby/discussions/32735 --- packages/gatsby-remark-copy-linked-files/src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-remark-copy-linked-files/src/index.js b/packages/gatsby-remark-copy-linked-files/src/index.js index 35f766e60d50c..cef6d2da9b3ef 100644 --- a/packages/gatsby-remark-copy-linked-files/src/index.js +++ b/packages/gatsby-remark-copy-linked-files/src/index.js @@ -40,6 +40,7 @@ const getDestination = (linkNode, dir) => { ? `${dir({ name: linkNode.name, hash: linkNode.internal.contentDigest, + relativeDirectory: linkNode.relativeDirectory, })}.${linkNode.extension}` : `${dir()}/${defaultDestination(linkNode)}` } else if (_.isString(dir)) { From 95a8fcfa487d0c3e0cb46b5cce48d15d330175ea Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Tue, 6 Sep 2022 15:40:40 +0200 Subject: [PATCH 2/5] Switch to exposing absolutePath --- packages/gatsby-remark-copy-linked-files/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-remark-copy-linked-files/src/index.js b/packages/gatsby-remark-copy-linked-files/src/index.js index cef6d2da9b3ef..e88af20b87c76 100644 --- a/packages/gatsby-remark-copy-linked-files/src/index.js +++ b/packages/gatsby-remark-copy-linked-files/src/index.js @@ -40,7 +40,7 @@ const getDestination = (linkNode, dir) => { ? `${dir({ name: linkNode.name, hash: linkNode.internal.contentDigest, - relativeDirectory: linkNode.relativeDirectory, + absolutePath: linkNode.absolutePath, })}.${linkNode.extension}` : `${dir()}/${defaultDestination(linkNode)}` } else if (_.isString(dir)) { From 76002e2227c8bcc71e647057f08a5431f3362fe0 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 7 Sep 2022 08:56:14 +0200 Subject: [PATCH 3/5] add test, improve readme, make things work --- .../gatsby-remark-copy-linked-files/README.md | 33 +++++++++---------- .../src/__tests__/index.js | 23 +++++++++++++ .../src/index.js | 25 +++++++------- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/packages/gatsby-remark-copy-linked-files/README.md b/packages/gatsby-remark-copy-linked-files/README.md index 5f18d3d3cad30..49b8feeb602c3 100644 --- a/packages/gatsby-remark-copy-linked-files/README.md +++ b/packages/gatsby-remark-copy-linked-files/README.md @@ -22,20 +22,20 @@ The `my-awesome-pdf.pdf` file will be copied to the root directory (i.e., `publi --- -## Install plugin +## Installation -`npm install gatsby-remark-copy-linked-files` +```shell +npm install gatsby-remark-copy-linked-files +``` -## Add plugin to Gatsby Config +## Configuration **Default settings:** Add `gatsby-remark-copy-linked-files` plugin as a plugin to [`gatsby-transformer-remark`](https://www.gatsbyjs.com/plugins/gatsby-transformer-remark/): -```javascript +```js:title=gatsby-config.js // In your gatsby-config.js - -// add plugin by name only plugins: [ { resolve: `gatsby-transformer-remark`, @@ -48,10 +48,8 @@ plugins: [ **Custom settings:** -```js +```js:title=gatsby-config.js // In your gatsby-config.js - -// add plugin by name and options plugins: [ { resolve: `gatsby-transformer-remark`, @@ -70,13 +68,11 @@ plugins: [ ] ``` ---- - -## Custom set where to copy the files using `destinationDir` +## Option: `destinationDir` By default, all files will be copied to the root directory (i.e., `public` folder) in the following format: `contentHash/fileName.ext`. -> For example, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-pdf.pdf` to something like `public/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` +For example, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-pdf.pdf` to something like `public/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` ### Simple usage @@ -101,11 +97,11 @@ plugins: [ ] ``` -> So now, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-pdf.pdf` to `public/path/to/dir/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` +So now, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-pdf.pdf` to `public/path/to/dir/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` ### Advanced usage -For more advanced control, set `destinationDir` to a function expression using properties `name` and/or `hash` to specify the path. +For more advanced control, set `destinationDir` to a function expression using properties `name`, `hash`, and `absolutePath` to specify the path. **Examples:** @@ -129,8 +125,9 @@ destinationDir: f => `${f.name}/${f.hash}` destinationDir: f => `path/to/dir/hello-${f.name}+${f.hash}_world` ``` -> **Note:** Make sure you use either `name` or `hash` property in your function expression! -> If you don't include both `name` and `hash` properties in your function expression, `gatsby-remark-copy-linked-files` plugin will resolve the function expression to a string value and use default settings as a fallback mechanism to prevent your local files from getting copied with the same name (causing files to get overwritten). +**Please note:** Make sure you use either `name` or `hash` property in your function expression! + +If you don't include both `name` and `hash` properties in your function expression, `gatsby-remark-copy-linked-files` plugin will resolve the function expression to a string value and use default settings as a fallback mechanism to prevent your local files from getting copied with the same name (causing files to get overwritten). ```js # Note: `my-awesome-pdf.pdf` is saved to `public/hello/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` @@ -142,7 +139,7 @@ destinationDir: `hello` ### Caveat: Error thrown if `destinationDir` points outside the root directory (i.e. `public` folder) -> **Note:** An error will be thrown if the destination points outside the root directory (i.e. `public` folder). +**Please note:** An error will be thrown if the destination points outside the root directory (i.e. `public` folder). **Correct:** diff --git a/packages/gatsby-remark-copy-linked-files/src/__tests__/index.js b/packages/gatsby-remark-copy-linked-files/src/__tests__/index.js index fe979f9ae178a..60f88ddce1a2d 100644 --- a/packages/gatsby-remark-copy-linked-files/src/__tests__/index.js +++ b/packages/gatsby-remark-copy-linked-files/src/__tests__/index.js @@ -526,6 +526,29 @@ describe(`gatsby-remark-copy-linked-files`, () => { }) }) + it(`copies file to the destination supplied by the destinationDir function (using returned absolutePath)`, async () => { + const imgName = `sample-image` + const imgRelPath = `images/nested-dir/${imgName}.gif` + const imgPath = parentDir + imgRelPath + + const markdownAST = remark.parse(`![some absolute image](${imgRelPath})`) + const customDestinationDir = f => + `${path.dirname(f.absolutePath)}/${f.name}` + const expectedDestination = `images/nested-dir/sample-image.gif` + expect.assertions(3) + await plugin( + { files: getFiles(imgPath), markdownAST, markdownNode, getNode }, + { destinationDir: customDestinationDir } + ).then(v => { + const expectedNewPath = path.posix.join( + ...[process.cwd(), `public`, expectedDestination] + ) + expect(v).toBeDefined() + expect(fsExtra.copy).toHaveBeenCalledWith(imgPath, expectedNewPath) + expect(imageURL(markdownAST)).toEqual(`/${expectedDestination}`) + }) + }) + it(`copies file to the root dir when destinationDir is not supplied`, async () => { const markdownAST = remark.parse( `![some absolute image](${imageRelativePath})` diff --git a/packages/gatsby-remark-copy-linked-files/src/index.js b/packages/gatsby-remark-copy-linked-files/src/index.js index e88af20b87c76..3afc32ae607f3 100644 --- a/packages/gatsby-remark-copy-linked-files/src/index.js +++ b/packages/gatsby-remark-copy-linked-files/src/index.js @@ -20,10 +20,12 @@ const validateDestinationDir = dir => { return true } else if (typeof dir === `string`) { // need to pass dummy data for validation to work - return destinationIsValid(`${dir}/h/n`) + return destinationIsValid(`${dir}/n/h/a`) } else if (_.isFunction(dir)) { // need to pass dummy data for validation to work - return destinationIsValid(`${dir({ name: `n`, hash: `h` })}`) + return destinationIsValid( + `${dir({ name: `n`, hash: `h`, absolutePath: `a` })}` + ) } else { return false } @@ -34,15 +36,11 @@ const defaultDestination = linkNode => 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, - absolutePath: linkNode.absolutePath, - })}.${linkNode.extension}` - : `${dir()}/${defaultDestination(linkNode)}` + return `${dir({ + name: linkNode.name, + hash: linkNode.internal.contentDigest, + absolutePath: linkNode.absolutePath, + })}.${linkNode.extension}` } else if (_.isString(dir)) { return `${dir}/${defaultDestination(linkNode)}` } else { @@ -60,7 +58,10 @@ const newPath = (linkNode, options) => { const newLinkURL = (linkNode, options, pathPrefix) => { const { destinationDir } = options const destination = getDestination(linkNode, destinationDir) - return `${pathPrefix ? pathPrefix : ``}/${destination}` + const startsWithSlash = destination.startsWith(`/`) + return `${pathPrefix ? pathPrefix : ``}${ + startsWithSlash ? `` : `/` + }${destination}` } function toArray(buf) { From 95b346d841dddacd1c0f9cc4ae2afe705bb8409c Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 14 Sep 2022 08:22:37 +0200 Subject: [PATCH 4/5] update README --- .../gatsby-remark-copy-linked-files/README.md | 155 +++++++++--------- 1 file changed, 76 insertions(+), 79 deletions(-) diff --git a/packages/gatsby-remark-copy-linked-files/README.md b/packages/gatsby-remark-copy-linked-files/README.md index 49b8feeb602c3..3af3bc132eafb 100644 --- a/packages/gatsby-remark-copy-linked-files/README.md +++ b/packages/gatsby-remark-copy-linked-files/README.md @@ -1,6 +1,6 @@ # gatsby-remark-copy-linked-files -Copies local files linked to/from Markdown (`.md|.markdown`) files to the root directory (i.e., `public` folder). +Copies local files linked to/from Markdown (`.md|.markdown`) files to the `public` folder. **A sample markdown file:** @@ -16,12 +16,10 @@ Hey everyone, I just made a sweet PDF with lots of interesting stuff in it. **When you build your site:** -The `my-awesome-pdf.pdf` file will be copied to the root directory (i.e., `public/some-really-long-contenthash/my-awesome-pdf.pdf`) and the generated HTML page will be modified to point to it. +The `my-awesome-pdf.pdf` file will be copied to the `public` folder (i.e., `public/some-really-long-contenthash/my-awesome-pdf.pdf`) and the generated HTML page will be modified to point to it. > **Note**: The `my-awesome-pdf.pdf` file should be in the same directory as the markdown file. ---- - ## Installation ```shell @@ -30,47 +28,49 @@ npm install gatsby-remark-copy-linked-files ## Configuration -**Default settings:** +### Default settings Add `gatsby-remark-copy-linked-files` plugin as a plugin to [`gatsby-transformer-remark`](https://www.gatsbyjs.com/plugins/gatsby-transformer-remark/): ```js:title=gatsby-config.js -// In your gatsby-config.js -plugins: [ - { - resolve: `gatsby-transformer-remark`, - options: { - plugins: [`gatsby-remark-copy-linked-files`], +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: { + plugins: [`gatsby-remark-copy-linked-files`], + }, }, - }, -] + ], +} ``` -**Custom settings:** +### Custom settings ```js:title=gatsby-config.js -// In your gatsby-config.js -plugins: [ - { - resolve: `gatsby-transformer-remark`, - options: { - plugins: [ - { - resolve: `gatsby-remark-copy-linked-files`, - options: { - destinationDir: `path/to/dir`, - ignoreFileExtensions: [`png`, `jpg`, `jpeg`, `bmp`, `tiff`], +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: { + plugins: [ + { + resolve: `gatsby-remark-copy-linked-files`, + options: { + destinationDir: `path/to/dir`, + ignoreFileExtensions: [`png`, `jpg`, `jpeg`, `bmp`, `tiff`], + }, }, - }, - ], + ], + }, }, - }, -] + ], +} ``` ## Option: `destinationDir` -By default, all files will be copied to the root directory (i.e., `public` folder) in the following format: `contentHash/fileName.ext`. +By default, all files will be copied to the root of the `public` folder in the following format: `contentHash/fileName.ext`. For example, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-pdf.pdf` to something like `public/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` @@ -78,23 +78,20 @@ For example, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awes To change this, set `destinationDir` to a path of your own choosing (i.e., `path/to/dir`). -```js -// In your gatsby-config.js -plugins: [ - { - resolve: `gatsby-transformer-remark`, - options: { - plugins: [ - { - resolve: "gatsby-remark-copy-linked-files", - options: { - destinationDir: "path/to/dir", - }, +```js:title=gatsby-config.js +{ + resolve: `gatsby-transformer-remark`, + options: { + plugins: [ + { + resolve: "gatsby-remark-copy-linked-files", + options: { + destinationDir: "path/to/dir", }, - ], - }, + }, + ], }, -] +} ``` So now, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-pdf.pdf` to `public/path/to/dir/2a0039f3a61f4510f41678438e4c863a/my-awesome-pdf.pdf` @@ -103,6 +100,10 @@ So now, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-p For more advanced control, set `destinationDir` to a function expression using properties `name`, `hash`, and `absolutePath` to specify the path. +- `name`: The name of the file without the file extension +- `hash`: The `internal.contentDigest` on the `File` node (guarantees a unique identifier) +- `absolutePath`: The absolute path to the file, e.g. `/Users/your-name/example/project/src/pages/folder/my-awesome-pdf.pdf` + **Examples:** ```js @@ -123,6 +124,11 @@ destinationDir: f => `${f.name}/${f.hash}` # save `my-awesome-pdf.pdf` to `public/path/to/dir/hello-my-awesome-pdf+2a0039f3a61f4510f41678438e4c863a_world.pdf` destinationDir: f => `path/to/dir/hello-${f.name}+${f.hash}_world` + +# Given the file `my-awesome-pdf.pdf` at `src/pages/custom-folder` +# save `my-awesome-pdf.pdf` to `public/custom-folder/my-awesome-pdf.pdf` +# Note: You have to import `path` +destinationDir: f => `${path.dirname(path.relative(path.join(__dirname, `src`, `pages`), f.absolutePath))}/${f.name}` ``` **Please note:** Make sure you use either `name` or `hash` property in your function expression! @@ -137,9 +143,9 @@ destinationDir: _ => `hello` destinationDir: `hello` ``` -### Caveat: Error thrown if `destinationDir` points outside the root directory (i.e. `public` folder) +### Caveat: Error thrown if `destinationDir` points outside the `public` folder -**Please note:** An error will be thrown if the destination points outside the root directory (i.e. `public` folder). +**Please note:** An error will be thrown if the destination points outside the `public` folder. **Correct:** @@ -160,53 +166,44 @@ destinationDir: f => `${f.hash}` **Error thrown:** ```js -# cannot save outside root directory (i.e., outside `public` folder) +# cannot save outside `public` folder destinationDir: `../path/to/dir` destinationDir: _ => `../path/to/dir` destinationDir: f => `../path/to/dir/${f.name}` destinationDir: f => `../${f.hash}` ``` ---- - ### Custom set which file types to ignore using `ignoreFileExtensions` -By default, the file types that this plugin ignores are: `png`, `jpg`, `jpeg`, `bmp`, `tiff`. - -> For example, `[Download it now](image.png)` will be ignored and not copied to the root dir (i.e. `public` folder) +By default, the file types that this plugin ignores are: `png`, `jpg`, `jpeg`, `bmp`, `tiff`. For example, `[Download it now](image.png)` will be ignored and not copied to the root of the `public` folder. To change this, set `ignoreFileExtensions` to an array of extensions to ignore (i.e., an empty array `[]` to ignore nothing). -```javascript -// In your gatsby-config.js -plugins: [ - { - resolve: `gatsby-transformer-remark`, - options: { - plugins: [ - { - resolve: "gatsby-remark-copy-linked-files", - options: { - // `ignoreFileExtensions` defaults to [`png`, `jpg`, `jpeg`, `bmp`, `tiff`] - // as we assume you'll use gatsby-remark-images to handle - // images in markdown as it automatically creates responsive - // versions of images. - // - // If you'd like to not use gatsby-remark-images and just copy your - // original images to the public directory, set - // `ignoreFileExtensions` to an empty array. - ignoreFileExtensions: [], - }, +```js:title=gatsby-config.js +{ + resolve: `gatsby-transformer-remark`, + options: { + plugins: [ + { + resolve: "gatsby-remark-copy-linked-files", + options: { + // `ignoreFileExtensions` defaults to [`png`, `jpg`, `jpeg`, `bmp`, `tiff`] + // as we assume you'll use gatsby-remark-images to handle + // images in markdown as it automatically creates responsive + // versions of images. + // + // If you'd like to not use gatsby-remark-images and just copy your + // original images to the public directory, set + // `ignoreFileExtensions` to an empty array. + ignoreFileExtensions: [], }, - ], - }, + }, + ], }, -] +} ``` -> So now, `[Download it now](image.png)` will be copied to the root dir (i.e. `public` folder) - ---- +So now, `[Download it now](image.png)` will be copied to the root of the `public` folder. ### Supported Markdown tags From aea30ce6e3184b80aafa2efb88dca074ebf6d3b2 Mon Sep 17 00:00:00 2001 From: Lennart Date: Wed, 14 Sep 2022 11:19:48 +0200 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Karl Horky --- packages/gatsby-remark-copy-linked-files/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-remark-copy-linked-files/README.md b/packages/gatsby-remark-copy-linked-files/README.md index 3af3bc132eafb..c66655039a532 100644 --- a/packages/gatsby-remark-copy-linked-files/README.md +++ b/packages/gatsby-remark-copy-linked-files/README.md @@ -98,7 +98,7 @@ So now, `[Download it now](my-awesome-pdf.pdf)` will copy the file `my-awesome-p ### Advanced usage -For more advanced control, set `destinationDir` to a function expression using properties `name`, `hash`, and `absolutePath` to specify the path. +For more control, set `destinationDir` to a function expression using properties `name`, `hash`, and `absolutePath` to specify the path. - `name`: The name of the file without the file extension - `hash`: The `internal.contentDigest` on the `File` node (guarantees a unique identifier) @@ -125,9 +125,8 @@ destinationDir: f => `${f.name}/${f.hash}` # save `my-awesome-pdf.pdf` to `public/path/to/dir/hello-my-awesome-pdf+2a0039f3a61f4510f41678438e4c863a_world.pdf` destinationDir: f => `path/to/dir/hello-${f.name}+${f.hash}_world` -# Given the file `my-awesome-pdf.pdf` at `src/pages/custom-folder` -# save `my-awesome-pdf.pdf` to `public/custom-folder/my-awesome-pdf.pdf` -# Note: You have to import `path` +# save `src/pages/custom-folder/my-awesome-pdf.pdf` to `public/custom-folder/my-awesome-pdf.pdf` +# Note: Import `path` to use this example https://nodejs.org/api/path.html destinationDir: f => `${path.dirname(path.relative(path.join(__dirname, `src`, `pages`), f.absolutePath))}/${f.name}` ```