diff --git a/spec/link_utils_spec.js b/spec/link_utils_spec.js index 7b6f286..00b8968 100644 --- a/spec/link_utils_spec.js +++ b/spec/link_utils_spec.js @@ -29,7 +29,41 @@ describe('linkUtils.getAbsolute', () => { }); }); -xdescribe('linkUtils.resolveLinks', () => { +describe('linkUtils.getRelative', () => { + const files = [ + { + actualUrl: 'https://www.github.com/user/repo/blob/master/docs/doc.md', + name: 'doc.md', + path: 'docs/doc.md', + relativePath: './doc.md', + repo: 'repo' + }, + { + actualUrl: 'https://www.github.com/user/repo/blob/master/docs/subdir/doc.md', + name: 'doc.md', + path: 'docs/subdir/doc.md', + relativePath: './subdir/doc.md', + repo: 'repo' + }, + { + actualUrl: 'https://www.github.com/user/repo2/blob/master/docs/sub/doc.md', + name: 'doc.md', + path: 'docs/sub/doc.md', + relativePath: './sub/docs.md', + repo: 'repo2' + } + ]; + + it('returns a relative path from one absolute location to another within the same repo', () => { + expect(linkUtils.getRelative(files[1], files[0])).toEqual('../doc.md'); + }); + + it('returns a relative path from one absolute location to another within another known repo', () => { + expect(linkUtils.getRelative(files[2], files[0])).toEqual('../../repo/doc.md'); + }); +}); + +describe('linkUtils.resolveLinks', () => { describe('given markdown content', () => { const unkownRelativeMarkdown = ` # headline @@ -56,7 +90,24 @@ xdescribe('linkUtils.resolveLinks', () => { const knownLocations = [ { actualUrl: 'https://www.github.com/user/repo/blob/master/docs/doc.md', - path: 'docs/doc.md' + name: 'doc.md', + path: 'docs/doc.md', + relativePath: './doc.md', + repo: 'repo' + }, + { + actualUrl: 'https://www.github.com/user/repo/blob/master/docs/doc.md', + name: 'docs/doc.md', + path: 'docs/doc.md', + relativePath: './doc.md', + repo: 'repo' + }, + { + actualUrl: 'https://www.github.com/user/repo2/blob/master/docs/sub/doc.md', + name: 'doc.md', + path: 'docs/sub/doc.md', + relativePath: './sub/docs.md', + repo: 'repo2' } ]; @@ -64,7 +115,7 @@ xdescribe('linkUtils.resolveLinks', () => { const output = linkUtils.resolveLinks( unkownRelativeMarkdown, knownLocations, - 'https://www.github.com/user/repo/blob/master/docs/' + knownLocations[0] ); expect(output).toContain( 'Some content with an unknown [link](https://www.github.com/user/repo/blob/master/images/thing.png)' @@ -75,7 +126,7 @@ xdescribe('linkUtils.resolveLinks', () => { const output = linkUtils.resolveLinks( knownRelativeMarkdown, knownLocations, - 'https://www.github.com/user/repo/blob/master/' + knownLocations[1] ); expect(output).toContain('Some content with a known [link](./doc.md)'); }); @@ -84,26 +135,24 @@ xdescribe('linkUtils.resolveLinks', () => { const output = linkUtils.resolveLinks( knownRelativeMarkdownInCurrentDir, knownLocations, - 'https://www.github.com/user/repo/blob/master/docs/' + knownLocations[0] ); expect(output).toContain('a known [link](./doc.md)'); }); - it('updates known exact links to be relative', () => { - const output = linkUtils.resolveLinks( - absoluteMarkdown, - knownLocations, - 'https://www.github.com/user/repo/blob/master/docs/' - ); + it('updates known exact links to be relative within the same repo', () => { + const output = linkUtils.resolveLinks(absoluteMarkdown, knownLocations, knownLocations[0]); expect(output).toContain('a [known doc](./doc.md)'); }); + it('updates known exact links to be relative from another repo', () => { + // Go back out to root, then back in on another project + const output = linkUtils.resolveLinks(absoluteMarkdown, knownLocations, knownLocations[2]); + expect(output).toContain('a [known doc](../../repo/doc.md)'); + }); + it('does not update local header references', () => { - const output = linkUtils.resolveLinks( - localMarkdown, - knownLocations, - 'https://www.github.com/user/repo/blob/master/docs/' - ); + const output = linkUtils.resolveLinks(localMarkdown, knownLocations, knownLocations[0]); expect(output).toEqual(localMarkdown); }); }); diff --git a/src/link_utils.js b/src/link_utils.js index f1f69e0..c0a355f 100644 --- a/src/link_utils.js +++ b/src/link_utils.js @@ -30,7 +30,29 @@ const getAbsolute = (baseUrl, path) => { return stack.join('/'); }; -const resolveLinks = (markdownContent, knownFiles, absoluteLocation) => { +const getRelative = (fromLink, toLink) => { + let fromLinkRelative = ''; + const removeFirstTwoChars = toLink.relativePath.slice(0, 2) === './'; + let toLinkRelative = removeFirstTwoChars + ? toLink.relativePath.slice(2, toLink.relativePath.length) + : toLink.relativePath; + + const fromDirCount = fromLink.relativePath.split('/').length - 2; + + for (let index = 0; index < fromDirCount; index++) { + fromLinkRelative += '../'; + } + + if (fromLink.repo !== toLink.repo) { + toLinkRelative = `../${toLink.repo}/${toLinkRelative}`; + } + + const result = (fromLinkRelative || './') + toLinkRelative; + + return result; +}; + +const resolveLinks = (markdownContent, knownFiles, currentFile) => { const markdownLinkMatcher = /\[([^[\]]+)\]\(([^)]+)/gm; let markdownContentCopy = markdownContent; let match; @@ -39,11 +61,15 @@ const resolveLinks = (markdownContent, knownFiles, absoluteLocation) => { const linkIsLocalHeader = match[2][0] === '#'; if (linkIsLocalHeader) return markdownContentCopy; - const absoluteUrl = getAbsolute(absoluteLocation, match[2]); + const absLocation = currentFile.actualUrl.replace(currentFile.name, ''); + const absoluteUrl = getAbsolute(absLocation, match[2]); const knownFile = knownFiles.find(fileData => fileData.actualUrl === absoluteUrl); if (knownFile) { - markdownContentCopy = markdownContentCopy.replace(match[2], `${knownFile.relativePath}`); + markdownContentCopy = markdownContentCopy.replace( + match[2], + getRelative(currentFile, knownFile) + ); } else { markdownContentCopy = markdownContentCopy.replace(match[2], absoluteUrl); } @@ -54,5 +80,6 @@ const resolveLinks = (markdownContent, knownFiles, absoluteLocation) => { module.exports = { getAbsolute, + getRelative, resolveLinks }; diff --git a/src/resolve_links.js b/src/resolve_links.js index d8785a6..a5e08f1 100644 --- a/src/resolve_links.js +++ b/src/resolve_links.js @@ -20,8 +20,7 @@ const resolveLinks = fileList => { return reject(readError); } - const absLocation = file.actualUrl.replace(file.name, ''); - const resolvedData = linkUtils.resolveLinks(data, fileList, absLocation); + const resolvedData = linkUtils.resolveLinks(data, fileList, file); fs.writeFile(fileUtils.findLocalFilePath(file), resolvedData, writeError => { if (writeError) {