From f701a62742a035125d57735ce56ab7d136a12093 Mon Sep 17 00:00:00 2001 From: Tomas Vik Date: Fri, 4 Aug 2023 21:28:19 +0200 Subject: [PATCH] feat: tags will get enclosed with [] --- README.md | 2 +- main.go | 30 ++++++++-------- main_test.go | 47 ++++++++++++++------------ parse.go | 7 +--- parse_test.go | 2 +- test/expected-output/logseq-pages/b.md | 1 + test/logseq-folder/pages/B.md | 1 + 7 files changed, 46 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index f397b32..dc39a90 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ logseq-export # list of logseq page properties that won't be quoted in the markdown front matter unquotedProperties: - date - - tags ``` #### Command example @@ -80,6 +79,7 @@ export BLOG_IMAGES_FOLDER="/assets/graph" - `public` - as soon as this page property is present (regardless of value), the page gets exported - `title` - either the `title::` is present and used as `title:` front matter attribute, or the page file name is unescaped (e.g. `%3A` changes to `:`) and used as the `title:` +- `tags` - Logseq uses comma separated values (`tags:: tag1, tag2`) but valid `yaml` in the front matter has to surround the value with square brackets (`tags: [tag1, tag2]`). The `tags` attribute is **always unquoted**. - `slug` used as a file name - `date` it's used as a file name prefix - if your logseq `date::` attributes contains the link brackets e.g. `[[2023-07-30]]`, `logseq-export` will remove them diff --git a/main.go b/main.go index 6040e22..bd4cfbb 100644 --- a/main.go +++ b/main.go @@ -143,7 +143,7 @@ func Run(args []string) error { err = afero.WriteFile( appFS, exportPath, - []byte(render(page.pc.attributes, contentWithAssets, config.UnquotedProperties)), + []byte(render(transformAttributes(page.pc.attributes, config.UnquotedProperties), contentWithAssets)), 0644, ) if err != nil { @@ -153,6 +153,19 @@ func Run(args []string) error { return nil } +func transformAttributes(attributes map[string]string, dontQuote []string) map[string]string { + dontQuote = append(dontQuote, "tags") + if _, ok := attributes["tags"]; ok { + attributes["tags"] = fmt.Sprintf("[%s]", attributes["tags"]) + } + for name, value := range attributes { + if !slices.Contains(dontQuote, name) { + attributes[name] = fmt.Sprintf("%q", value) + } + } + return attributes +} + func detectPageLinks(content string) []string { result := regexp.MustCompile(`\[\[([^\/\n\r]+?)]]`).FindAllStringSubmatch(content, -1) links := make([]string, 0, len(result)) @@ -204,14 +217,7 @@ func replaceAssetPaths(p parsedPage) string { return newContent } -func parseUnquotedProperties(param string) []string { - if param == "" { - return []string{} - } - return strings.Split(param, ",") -} - -func render(attributes map[string]string, content string, dontQuote []string) string { +func render(attributes map[string]string, content string) string { sortedKeys := make([]string, 0, len(attributes)) for k := range attributes { sortedKeys = append(sortedKeys, k) @@ -219,11 +225,7 @@ func render(attributes map[string]string, content string, dontQuote []string) st slices.Sort(sortedKeys) attributeBuilder := strings.Builder{} for _, key := range sortedKeys { - if slices.Contains(dontQuote, key) { - attributeBuilder.WriteString(fmt.Sprintf("%s: %s\n", key, attributes[key])) - } else { - attributeBuilder.WriteString(fmt.Sprintf("%s: %q\n", key, attributes[key])) - } + attributeBuilder.WriteString(fmt.Sprintf("%s: %s\n", key, attributes[key])) } return fmt.Sprintf("---\n%s---\n%s", attributeBuilder.String(), content) } diff --git a/main_test.go b/main_test.go index b15b93c..97813e7 100644 --- a/main_test.go +++ b/main_test.go @@ -85,6 +85,22 @@ var expectedPages = []string{ filepath.Join("logseq-pages", "b.md"), } +func TestTransformAttributes(t *testing.T) { + attributes := map[string]string{ + "tags": "tag1, another-tag", + "quoted": "quoted", + "unquoted": "unquoted", + } + + result := transformAttributes(attributes, []string{"unquoted"}) + + require.Equal(t, map[string]string{ + "tags": "[tag1, another-tag]", + "quoted": "\"quoted\"", + "unquoted": "unquoted", + }, result) +} + func TestFullTransformation(t *testing.T) { deleteTestOutputFolder(t) testLogseqFolder := filepath.Join(testDir, "test", "logseq-folder") @@ -129,10 +145,10 @@ func TestRender(t *testing.T) { "second": "2", } content := "page text" - result := render(attributes, content, []string{}) + result := render(attributes, content) require.Equal(t, `--- -first: "1" -second: "2" +first: 1 +second: 2 --- page text`, result) }) @@ -145,26 +161,13 @@ page text`, result) "a": "1", } content := "page text" - result := render(attributes, content, []string{}) - require.Equal(t, `--- -a: "1" -b: "1" -c: "1" -d: "1" -e: "1" ---- -page text`, result) - }) - t.Run("it renders attributes without quotes", func(t *testing.T) { - attributes := map[string]string{ - "first": "1", - "second": "2", - } - content := "page text" - result := render(attributes, content, []string{"first", "second"}) + result := render(attributes, content) require.Equal(t, `--- -first: 1 -second: 2 +a: 1 +b: 1 +c: 1 +d: 1 +e: 1 --- page text`, result) }) diff --git a/parse.go b/parse.go index 69f7c4f..5acfd83 100644 --- a/parse.go +++ b/parse.go @@ -103,12 +103,8 @@ func firstBulletPointsToParagraphs(from string) string { return regexp.MustCompile(`(?m:^- )`).ReplaceAllString(from, "\n") } -func secondToFirstBulletPoints(from string) string { - return regexp.MustCompile(`(?m:^\t-)`).ReplaceAllString(from, "\n-") -} - func removeTabFromMultiLevelBulletPoints(from string) string { - return regexp.MustCompile(`(?m:^\t{2,}-)`).ReplaceAllStringFunc(from, func(s string) string { + return regexp.MustCompile(`(?m:^\t{1,}-)`).ReplaceAllStringFunc(from, func(s string) string { return s[1:] }) } @@ -152,7 +148,6 @@ func parseContent(rawContent string) parsedContent { removeEmptyBulletPoints, unindentMultilineStrings, firstBulletPointsToParagraphs, - secondToFirstBulletPoints, removeTabFromMultiLevelBulletPoints, ) return parsedContent{ diff --git a/parse_test.go b/parse_test.go index 5cb24a0..11f7512 100644 --- a/parse_test.go +++ b/parse_test.go @@ -154,7 +154,7 @@ func TestParseContent(t *testing.T) { t.Run("turns second level bullet points into first level", func(t *testing.T) { result := parseContent("\t- hello\n\t- world") - require.Equal(t, "\n- hello\n\n- world", result.content) // TODO: maybe remove the duplicated new line + require.Equal(t, "- hello\n- world", result.content) }) t.Run("removes one tab from multi-level bullet points", func(t *testing.T) { diff --git a/test/expected-output/logseq-pages/b.md b/test/expected-output/logseq-pages/b.md index 58e58b2..e18c705 100644 --- a/test/expected-output/logseq-pages/b.md +++ b/test/expected-output/logseq-pages/b.md @@ -1,6 +1,7 @@ --- public: true slug: "b" +tags: [tag1, another-tag] title: "Hello World" --- diff --git a/test/logseq-folder/pages/B.md b/test/logseq-folder/pages/B.md index 22eed0a..b99df10 100644 --- a/test/logseq-folder/pages/B.md +++ b/test/logseq-folder/pages/B.md @@ -1,5 +1,6 @@ title:: Hello World public:: true +tags:: tag1, another-tag - ![pngimg](../assets/picture-2.png) - ![test that we don't fail on non-existing-image](../assets/image-that-doesnt-exist.png)