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 77dc92c55b127..15661be036605 100644 --- a/packages/gatsby-remark-copy-linked-files/src/__tests__/index.js +++ b/packages/gatsby-remark-copy-linked-files/src/__tests__/index.js @@ -170,6 +170,18 @@ describe(`gatsby-remark-copy-linked-files`, () => { expect(fsExtra.copy).toHaveBeenCalled() }) + it(`can copy HTML videos from video elements with the src attribute`, async () => { + const path = `videos/sample-video.mp4` + + const markdownAST = remark.parse( + `` + ) + + await plugin({ files: getFiles(path), markdownAST, markdownNode, getNode }) + + expect(fsExtra.copy).toHaveBeenCalled() + }) + it(`can copy HTML videos when some siblings are in ignore extensions`, async () => { const path = `videos/sample-video.mp4` const path1 = `images/sample-image.jpg` diff --git a/packages/gatsby-remark-copy-linked-files/src/index.js b/packages/gatsby-remark-copy-linked-files/src/index.js index 0615ad2fcfbb7..7e1c8011fed71 100644 --- a/packages/gatsby-remark-copy-linked-files/src/index.js +++ b/packages/gatsby-remark-copy-linked-files/src/index.js @@ -206,127 +206,69 @@ module.exports = ( visit(markdownAST, `html`, node => { const $ = cheerio.load(node.value) - // Handle Images - const imageRefs = [] - $(`img`).each(function() { - try { - if (isRelativeUrl($(this).attr(`src`))) { - imageRefs.push($(this)) - } - } catch (err) { - // Ignore - } - }) - - for (let thisImg of imageRefs) { + function processUrl({ url }) { try { - const ext = thisImg - .attr(`src`) - .split(`.`) - .pop() - if (!options.ignoreFileExtensions.includes(ext)) { - generateImagesAndUpdateNode(thisImg, node) - } - } catch (err) { - // Ignore - } - } - - // Handle video tags. - const videoRefs = [] - $(`video source`).each(function() { - try { - if (isRelativeUrl($(this).attr(`src`))) { - videoRefs.push($(this)) - } - } catch (err) { - // Ignore - } - }) - - for (let thisVideo of videoRefs) { - try { - const ext = thisVideo - .attr(`src`) - .split(`.`) - .pop() + const ext = url.split(`.`).pop() if (!options.ignoreFileExtensions.includes(ext)) { // The link object will be modified to the new location so we'll // use that data to update our ref - const link = { url: thisVideo.attr(`src`) } + const link = { url } visitor(link) - node.value = node.value.replace( - new RegExp(thisVideo.attr(`src`), `g`), - link.url - ) + node.value = node.value.replace(new RegExp(url, `g`), link.url) } } catch (err) { // Ignore } } - // Handle audio tags. - const audioRefs = [] - $(`audio source`).each(function() { - try { - if (isRelativeUrl($(this).attr(`src`))) { - audioRefs.push($(this)) - } - } catch (err) { - // Ignore - } - }) - - for (let thisAudio of audioRefs) { - try { - const ext = thisAudio - .attr(`src`) - .split(`.`) - .pop() - if (!options.ignoreFileExtensions.includes(ext)) { - const link = { url: thisAudio.attr(`src`) } - visitor(link) - node.value = node.value.replace( - new RegExp(thisAudio.attr(`src`), `g`), - link.url - ) - } - } catch (err) { - // Ignore - } + // extracts all elements that have the provided url attribute + function extractUrlAttributeAndElement(selection, attribute) { + return ( + selection + // extract the elements that have the attribute + .map(function() { + const element = $(this) + const url = $(this).attr(attribute) + if (url && isRelativeUrl(url)) { + return { url, element } + } + return undefined + }) + // cheerio object -> array + .toArray() + // filter out empty or undefined values + .filter(Boolean) + ) } - // Handle a tags. - const aRefs = [] - $(`a`).each(function() { - try { - if (isRelativeUrl($(this).attr(`href`))) { - aRefs.push($(this)) + // Handle Images + extractUrlAttributeAndElement($(`img[src]`), `src`).forEach( + ({ url, element }) => { + try { + const ext = url.split(`.`).pop() + if (!options.ignoreFileExtensions.includes(ext)) { + generateImagesAndUpdateNode(element, node) + } + } catch (err) { + // Ignore } - } catch (err) { - // Ignore } - }) + ) - for (let thisATag of aRefs) { - try { - const ext = thisATag - .attr(`href`) - .split(`.`) - .pop() - if (!options.ignoreFileExtensions.includes(ext)) { - const link = { url: thisATag.attr(`href`) } - visitor(link) + // Handle video tags. + extractUrlAttributeAndElement( + $(`video source[src], video[src]`), + `src` + ).forEach(processUrl) - node.value = node.value.replace( - new RegExp(thisATag.attr(`href`), `g`), - link.url - ) - } - } catch (err) { - // Ignore - } - } + // Handle audio tags. + extractUrlAttributeAndElement( + $(`audio source[src], audio[src]`), + `src` + ).forEach(processUrl) + + // Handle a tags. + extractUrlAttributeAndElement($(`a[href]`), `href`).forEach(processUrl) return })