-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Support for relative links Fixes #25 * Error logging fixes * Better regexp
- Loading branch information
Showing
6 changed files
with
150 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package mark | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
"regexp" | ||
|
||
"github.com/kovetskiy/mark/pkg/confluence" | ||
) | ||
|
||
type Link struct { | ||
MDLink string | ||
Link string | ||
} | ||
|
||
// ResolveRelativeLinks finds links in the markdown, and replaces one pointing | ||
// to other Markdowns either by own link (if not created to Confluence yet) or | ||
// witn actual Confluence link | ||
func ResolveRelativeLinks( | ||
api *confluence.API, | ||
markdown []byte, | ||
base string, | ||
) (links []Link, collectedErrors error) { | ||
currentMarkdownMetadata, onlyMarkdown, err := ExtractMeta(markdown) | ||
if err != nil { | ||
return links, fmt.Errorf("unable to get metadata from handled markdown file. Error %w", err) | ||
} | ||
|
||
currentPageLinkString, collectedErrors := getConfluenceLink(api, currentMarkdownMetadata.Space, currentMarkdownMetadata.Title, collectedErrors) | ||
|
||
submatchall := collectLinksFromMarkdown(string(onlyMarkdown)) | ||
|
||
for _, element := range submatchall { | ||
link := Link{ | ||
MDLink: element[1], | ||
Link: currentPageLinkString, | ||
} | ||
// If link points to markdown like target, we build link for that in Confluence | ||
if len(element[2]) > 0 { | ||
possibleMDFile := element[2] | ||
filepath := filepath.Join(base, possibleMDFile) | ||
if _, err := os.Stat(filepath); err == nil { | ||
linkMarkdown, err := ioutil.ReadFile(filepath) | ||
if err != nil { | ||
collectedErrors = fmt.Errorf("%w\n unable to read markdown file "+filepath, collectedErrors) | ||
continue | ||
} | ||
// This helps to determine if found link points to file that's not markdown | ||
// or have mark required metadata | ||
meta, _, err := ExtractMeta(linkMarkdown) | ||
if err != nil { | ||
collectedErrors = fmt.Errorf("%w\n unable to get metadata from markdown file "+filepath, collectedErrors) | ||
continue | ||
} | ||
|
||
link.Link, collectedErrors = getConfluenceLink(api, meta.Space, meta.Title, collectedErrors) | ||
} | ||
} | ||
|
||
if len(element[3]) > 0 { | ||
link.Link = currentPageLinkString + "#" + element[2] | ||
} | ||
|
||
links = append(links, link) | ||
} | ||
return links, collectedErrors | ||
} | ||
|
||
// ReplaceRelativeLinks replaces relative links between md files (in same | ||
// directory structure) with links working in Confluence | ||
func ReplaceRelativeLinks(markdown []byte, links []Link) []byte { | ||
for _, link := range links { | ||
markdown = bytes.ReplaceAll( | ||
markdown, | ||
[]byte(fmt.Sprintf("](%s)", link.MDLink)), | ||
[]byte(fmt.Sprintf("](%s)", link.Link)), | ||
) | ||
} | ||
return markdown | ||
} | ||
|
||
// collectLinksFromMarkdown collects all links from given markdown file | ||
// (including images and external links) | ||
func collectLinksFromMarkdown(markdown string) [][]string { | ||
re := regexp.MustCompile("\\[[^\\]]+\\]\\((([^\\)#]+)?#?([^\\)]+)?)\\)") | ||
return re.FindAllStringSubmatch(markdown, -1) | ||
} | ||
|
||
// getConfluenceLink build (to be) link for Conflunce, and tries to verify from API if there's real link available | ||
func getConfluenceLink(api *confluence.API, space, title string, collectedErrors error) (string, error) { | ||
link := fmt.Sprintf("%s/display/%s/%s", api.BaseURL, space, url.QueryEscape(title)) | ||
confluencePage, err := api.FindPage(space, title) | ||
if err != nil { | ||
collectedErrors = fmt.Errorf("%w\n "+err.Error(), collectedErrors) | ||
} else if confluencePage != nil { | ||
// Needs baseURL, as REST api response URL doesn't contain subpath ir confluence is server from that | ||
link = api.BaseURL + confluencePage.Links.Full | ||
} | ||
|
||
return link, collectedErrors | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package mark | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestLinkFind(t *testing.T) { | ||
markdown := ` | ||
[example1](../path/to/example.md#second-heading) | ||
[example2](../path/to/example.md) | ||
[example3](#heading-in-document) | ||
[Text link that should be put as attachment](../path/to/example.txt) | ||
[Image link that should be put as attachment](../path/to/example.png) | ||
` | ||
|
||
links := collectLinksFromMarkdown(markdown) | ||
|
||
assert.Equal(t, "../path/to/example.md#second-heading", links[0][1]) | ||
assert.Equal(t, "../path/to/example.md", links[0][2]) | ||
assert.Equal(t, "second-heading", links[0][3]) | ||
|
||
assert.Equal(t, "../path/to/example.md", links[1][1]) | ||
assert.Equal(t, "../path/to/example.md", links[1][2]) | ||
assert.Equal(t, "", links[1][3]) | ||
|
||
assert.Equal(t, "#heading-in-document", links[2][1]) | ||
assert.Equal(t, "", links[2][2]) | ||
assert.Equal(t, "heading-in-document", links[2][3]) | ||
|
||
assert.Equal(t, len(links), 5) | ||
} |