Skip to content

Commit f701a62

Browse files
committed
feat: tags will get enclosed with []
1 parent a9bc58e commit f701a62

File tree

7 files changed

+46
-44
lines changed

7 files changed

+46
-44
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ logseq-export
4040
# list of logseq page properties that won't be quoted in the markdown front matter
4141
unquotedProperties:
4242
- date
43-
- tags
4443
```
4544
4645
#### Command example
@@ -80,6 +79,7 @@ export BLOG_IMAGES_FOLDER="/assets/graph"
8079

8180
- `public` - as soon as this page property is present (regardless of value), the page gets exported
8281
- `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:`
82+
- `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**.
8383
- `slug` used as a file name
8484
- `date` it's used as a file name prefix
8585
- if your logseq `date::` attributes contains the link brackets e.g. `[[2023-07-30]]`, `logseq-export` will remove them

main.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func Run(args []string) error {
143143
err = afero.WriteFile(
144144
appFS,
145145
exportPath,
146-
[]byte(render(page.pc.attributes, contentWithAssets, config.UnquotedProperties)),
146+
[]byte(render(transformAttributes(page.pc.attributes, config.UnquotedProperties), contentWithAssets)),
147147
0644,
148148
)
149149
if err != nil {
@@ -153,6 +153,19 @@ func Run(args []string) error {
153153
return nil
154154
}
155155

156+
func transformAttributes(attributes map[string]string, dontQuote []string) map[string]string {
157+
dontQuote = append(dontQuote, "tags")
158+
if _, ok := attributes["tags"]; ok {
159+
attributes["tags"] = fmt.Sprintf("[%s]", attributes["tags"])
160+
}
161+
for name, value := range attributes {
162+
if !slices.Contains(dontQuote, name) {
163+
attributes[name] = fmt.Sprintf("%q", value)
164+
}
165+
}
166+
return attributes
167+
}
168+
156169
func detectPageLinks(content string) []string {
157170
result := regexp.MustCompile(`\[\[([^\/\n\r]+?)]]`).FindAllStringSubmatch(content, -1)
158171
links := make([]string, 0, len(result))
@@ -204,26 +217,15 @@ func replaceAssetPaths(p parsedPage) string {
204217
return newContent
205218
}
206219

207-
func parseUnquotedProperties(param string) []string {
208-
if param == "" {
209-
return []string{}
210-
}
211-
return strings.Split(param, ",")
212-
}
213-
214-
func render(attributes map[string]string, content string, dontQuote []string) string {
220+
func render(attributes map[string]string, content string) string {
215221
sortedKeys := make([]string, 0, len(attributes))
216222
for k := range attributes {
217223
sortedKeys = append(sortedKeys, k)
218224
}
219225
slices.Sort(sortedKeys)
220226
attributeBuilder := strings.Builder{}
221227
for _, key := range sortedKeys {
222-
if slices.Contains(dontQuote, key) {
223-
attributeBuilder.WriteString(fmt.Sprintf("%s: %s\n", key, attributes[key]))
224-
} else {
225-
attributeBuilder.WriteString(fmt.Sprintf("%s: %q\n", key, attributes[key]))
226-
}
228+
attributeBuilder.WriteString(fmt.Sprintf("%s: %s\n", key, attributes[key]))
227229
}
228230
return fmt.Sprintf("---\n%s---\n%s", attributeBuilder.String(), content)
229231
}

main_test.go

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ var expectedPages = []string{
8585
filepath.Join("logseq-pages", "b.md"),
8686
}
8787

88+
func TestTransformAttributes(t *testing.T) {
89+
attributes := map[string]string{
90+
"tags": "tag1, another-tag",
91+
"quoted": "quoted",
92+
"unquoted": "unquoted",
93+
}
94+
95+
result := transformAttributes(attributes, []string{"unquoted"})
96+
97+
require.Equal(t, map[string]string{
98+
"tags": "[tag1, another-tag]",
99+
"quoted": "\"quoted\"",
100+
"unquoted": "unquoted",
101+
}, result)
102+
}
103+
88104
func TestFullTransformation(t *testing.T) {
89105
deleteTestOutputFolder(t)
90106
testLogseqFolder := filepath.Join(testDir, "test", "logseq-folder")
@@ -129,10 +145,10 @@ func TestRender(t *testing.T) {
129145
"second": "2",
130146
}
131147
content := "page text"
132-
result := render(attributes, content, []string{})
148+
result := render(attributes, content)
133149
require.Equal(t, `---
134-
first: "1"
135-
second: "2"
150+
first: 1
151+
second: 2
136152
---
137153
page text`, result)
138154
})
@@ -145,26 +161,13 @@ page text`, result)
145161
"a": "1",
146162
}
147163
content := "page text"
148-
result := render(attributes, content, []string{})
149-
require.Equal(t, `---
150-
a: "1"
151-
b: "1"
152-
c: "1"
153-
d: "1"
154-
e: "1"
155-
---
156-
page text`, result)
157-
})
158-
t.Run("it renders attributes without quotes", func(t *testing.T) {
159-
attributes := map[string]string{
160-
"first": "1",
161-
"second": "2",
162-
}
163-
content := "page text"
164-
result := render(attributes, content, []string{"first", "second"})
164+
result := render(attributes, content)
165165
require.Equal(t, `---
166-
first: 1
167-
second: 2
166+
a: 1
167+
b: 1
168+
c: 1
169+
d: 1
170+
e: 1
168171
---
169172
page text`, result)
170173
})

parse.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,8 @@ func firstBulletPointsToParagraphs(from string) string {
103103
return regexp.MustCompile(`(?m:^- )`).ReplaceAllString(from, "\n")
104104
}
105105

106-
func secondToFirstBulletPoints(from string) string {
107-
return regexp.MustCompile(`(?m:^\t-)`).ReplaceAllString(from, "\n-")
108-
}
109-
110106
func removeTabFromMultiLevelBulletPoints(from string) string {
111-
return regexp.MustCompile(`(?m:^\t{2,}-)`).ReplaceAllStringFunc(from, func(s string) string {
107+
return regexp.MustCompile(`(?m:^\t{1,}-)`).ReplaceAllStringFunc(from, func(s string) string {
112108
return s[1:]
113109
})
114110
}
@@ -152,7 +148,6 @@ func parseContent(rawContent string) parsedContent {
152148
removeEmptyBulletPoints,
153149
unindentMultilineStrings,
154150
firstBulletPointsToParagraphs,
155-
secondToFirstBulletPoints,
156151
removeTabFromMultiLevelBulletPoints,
157152
)
158153
return parsedContent{

parse_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func TestParseContent(t *testing.T) {
154154

155155
t.Run("turns second level bullet points into first level", func(t *testing.T) {
156156
result := parseContent("\t- hello\n\t- world")
157-
require.Equal(t, "\n- hello\n\n- world", result.content) // TODO: maybe remove the duplicated new line
157+
require.Equal(t, "- hello\n- world", result.content)
158158
})
159159

160160
t.Run("removes one tab from multi-level bullet points", func(t *testing.T) {

test/expected-output/logseq-pages/b.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
public: true
33
slug: "b"
4+
tags: [tag1, another-tag]
45
title: "Hello World"
56
---
67

test/logseq-folder/pages/B.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
title:: Hello World
22
public:: true
3+
tags:: tag1, another-tag
34

45
- ![pngimg](../assets/picture-2.png)
56
- ![test that we don't fail on non-existing-image](../assets/image-that-doesnt-exist.png)

0 commit comments

Comments
 (0)