Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: unescaped quotes breaking zk json output #403

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/core/note_format.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package core
import (
"encoding/json"
"fmt"
"os"
"regexp"
"slices"
"strings"
"time"
)

Expand Down Expand Up @@ -44,6 +47,15 @@ func newNoteFormatter(basePath string, template Template, linkFormatter LinkForm
return ""
}
link, _ := linkFormatter(context)
// `"` chars in note titles break links on `--format json` output
// Quick and dirty solution for now. Should use Kong / *cli
// container?
if slices.Contains(os.Args[1:], `--format=json`) ||
slices.Contains(os.Args[1:], `json`) &&
(slices.Contains(os.Args[1:], `--format`) ||
slices.Contains(os.Args[1:], `-f`)) {
link = strings.ReplaceAll(link, `"`, `\"`)
}
return link
}),
Lead: note.Lead,
Expand Down
197 changes: 197 additions & 0 deletions tests/fixtures/issue-389/.zk/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# zk configuration file
#
# Uncomment the properties you want to customize.

# NOTE SETTINGS
#
# Defines the default options used when generating new notes.
[note]

# Language used when writing notes.
# This is used to generate slugs or with date formats.
#language = "en"

# The default title used for new note, if no `--title` flag is provided.
#default-title = "Untitled"

# Template used to generate a note's filename, without extension.
#filename = "{{id}}"

# The file extension used for the notes.
#extension = "md"

# Template used to generate a note's content.
# If not an absolute path, it is relative to .zk/templates/
template = "default.md"

# Path globs ignored while indexing existing notes.
#ignore = [
# "drafts/*",
# "log.md"
#]

# Configure random ID generation.

# The charset used for random IDs. You can use:
# * letters: only letters from a to z.
# * numbers: 0 to 9
# * alphanum: letters + numbers
# * hex: hexadecimal, from a to f and 0 to 9
# * custom string: will use any character from the provided value
#id-charset = "alphanum"

# Length of the generated IDs.
#id-length = 4

# Letter case for the random IDs, among lower, upper or mixed.
#id-case = "lower"


# EXTRA VARIABLES
#
# A dictionary of variables you can use for any custom values when generating
# new notes. They are accessible in templates with {{extra.<key>}}
[extra]

#key = "value"


# GROUP OVERRIDES
#
# You can override global settings from [note] and [extra] for a particular
# group of notes by declaring a [group."<name>"] section.
#
# Specify the list of directories which will automatically belong to the group
# with the optional `paths` property.
#
# Omitting `paths` is equivalent to providing a single path equal to the name of
# the group. This can be useful to quickly declare a group by the name of the
# directory it applies to.

#[group."<NAME>"]
#paths = ["<DIR1>", "<DIR2>"]
#[group."<NAME>".note]
#filename = "{{format-date now}}"
#[group."<NAME>".extra]
#key = "value"


# MARKDOWN SETTINGS
[format.markdown]

# Format used to generate links between notes.
# Either "wiki", "markdown" or a custom template. Default is "markdown".
#link-format = "wiki"
# Indicates whether a link's path will be percent-encoded.
# Defaults to true for "markdown" format and false for "wiki" format.
#link-encode-path = true
# Indicates whether a link's path file extension will be removed.
# Defaults to true.
#link-drop-extension = true

# Enable support for #hashtags.
hashtags = false
# Enable support for :colon:separated:tags:.
colon-tags = false
# Enable support for Bear's #multi-word tags#
# Hashtags must be enabled for multi-word tags to work.
multiword-tags = false


# EXTERNAL TOOLS
[tool]

# Default editor used to open notes. When not set, the EDITOR or VISUAL
# environment variables are used.
#editor = "vim"

# Pager used to scroll through long output. If you want to disable paging
# altogether, set it to an empty string "".
#pager = "less -FIRX"

# Command used to preview a note during interactive fzf mode.
# Set it to an empty string "" to disable preview.

# bat is a great tool to render Markdown document with syntax highlighting.
#https://github.com/sharkdp/bat
#fzf-preview = "bat -p --color always {-1}"


# LSP
#
# Configure basic editor integration for LSP-compatible editors.
# See https://github.com/zk-org/zk/blob/main/docs/editors-integration.md
#
[lsp]

[lsp.diagnostics]
# Each diagnostic can have for value: none, hint, info, warning, error

# Report titles of wiki-links as hints.
#wiki-title = "hint"
# Warn for dead links between notes.
dead-link = "error"

[lsp.completion]
# Customize the completion pop-up of your LSP client.

# Show the note title in the completion pop-up, or fallback on its path if empty.
#note-label = ""
# Filter out the completion pop-up using the note title or its path.
#note-filter-text = " "
# Show the note filename without extension as detail.
#note-detail = ""


# NAMED FILTERS
#
# A named filter is a set of note filtering options used frequently together.
#
[filter]

# Matches the notes created the last two weeks. For example:
# $ zk list recents --limit 15
# $ zk edit recents --interactive
#recents = "--sort created- --created-after 'last two weeks'"


# COMMAND ALIASES
#
# Aliases are user commands called with `zk <alias> [<flags>] [<args>]`.
#
# The alias will be executed with `$SHELL -c`, please refer to your shell's
# man page to see the available syntax. In most shells:
# * $@ can be used to expand all the provided flags and arguments
# * you can pipe commands together with the usual | character
#
[alias]
# Here are a few aliases to get you started.

# Shortcut to a command.
#ls = "zk list $@"

# Default flags for an existing command.
#list = "zk list --quiet $@"

# Edit the last modified note.
#editlast = "zk edit --limit 1 --sort modified- $@"

# Edit the notes selected interactively among the notes created the last two weeks.
# This alias doesn't take any argument, so we don't use $@.
#recent = "zk edit --sort created- --created-after 'last two weeks' --interactive"

# Print paths separated with colons for the notes found with the given
# arguments. This can be useful to expand a complex search query into a flag
# taking only paths. For example:
# zk list --link-to "`zk path -m potatoe`"
#path = "zk list --quiet --format {{path}} --delimiter , $@"

# Show a random note.
#lucky = "zk list --quiet --format full --sort random --limit 1"

# Returns the Git history for the notes found with the given arguments.
# Note the use of a pipe and the location of $@.
#hist = "zk list --format path --delimiter0 --quiet $@ | xargs -t -0 git log --patch --"

# Edit this configuration file.
#conf = '$EDITOR "$ZK_NOTEBOOK_DIR/.zk/config.toml"'
3 changes: 3 additions & 0 deletions tests/fixtures/issue-389/.zk/templates/default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# {{title}}

{{content}}
6 changes: 6 additions & 0 deletions tests/fixtures/issue-389/no-quotes-in-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: no quoted word in title
date: 2024-05-10
---

This note should _not_ break json graph output, and it doesn't (2024-05-10).
7 changes: 7 additions & 0 deletions tests/fixtures/issue-389/quotes-in-h1-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
date: 2024-05-10
---

# quoted "word" in h1 title

This note should _not_ break json graph output, and it _does_ (2024-05-10).
6 changes: 6 additions & 0 deletions tests/fixtures/issue-389/quotes-in-yaml-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: quoted "word" in yaml title
date: 2024-05-10
---

This note should _not_ break json graph output, and it _does_ (2024-05-10).
7 changes: 7 additions & 0 deletions tests/fixtures/issue-389/single-quotes-in-h1-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
date: 2024-05-10
---

# quoted 'word' in h1 title

This note should _not_ break json graph output, and it doesn't (2024-05-10).
6 changes: 6 additions & 0 deletions tests/fixtures/issue-389/single-quotes-in-yaml-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: quoted 'word' in h1 title
date: 2024-05-10
---

This note should _not_ break json graph output, and it doesn't (2024-05-10).
16 changes: 16 additions & 0 deletions tests/issue-389.tesh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$ cd issue-389

# should output valid json. Currently term ENV variables are printed to stdout
$ zk graph -q --format json
>{
> "notes": [
> {"filename":"no-quotes-in-title.md","filenameStem":"no-quotes-in-title","path":"no-quotes-in-title.md","absPath":"{{working-dir}}/no-quotes-in-title.md","title":"no quoted word in title","link":"[no quoted word in title](no-quotes-in-title)","lead":"This note should _not_ break json graph output, and it doesn't (2024-05-10).","body":"This note should _not_ break json graph output, and it doesn't (2024-05-10).","snippets":["This note should _not_ break json graph output, and it doesn't (2024-05-10)."],"rawContent":"---\ntitle: no quoted word in title\ndate: 2024-05-10\n---\n\nThis note should _not_ break json graph output, and it doesn't (2024-05-10).\n","wordCount":22,"tags":[],"metadata":{"date":"2024-05-10","title":"no quoted word in title"},"created":"2024-05-10T00:00:00Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"c2590b3a4381b0fd5f2d9309ef54b17e3dff0aa12f07cdbc89e3afcd50aa4e98"},
> {"filename":"quotes-in-h1-title.md","filenameStem":"quotes-in-h1-title","path":"quotes-in-h1-title.md","absPath":"{{working-dir}}/quotes-in-h1-title.md","title":"quoted \"word\" in h1 title","link":"[quoted \"word\" in h1 title](quotes-in-h1-title)","lead":"This note should _not_ break json graph output, and it _does_ (2024-05-10).","body":"This note should _not_ break json graph output, and it _does_ (2024-05-10).","snippets":["This note should _not_ break json graph output, and it _does_ (2024-05-10)."],"rawContent":"---\ndate: 2024-05-10\n---\n\n# quoted \"word\" in h1 title\n\nThis note should _not_ break json graph output, and it _does_ (2024-05-10).\n","wordCount":22,"tags":[],"metadata":{"date":"2024-05-10"},"created":"2024-05-10T00:00:00Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"3701543d5a66b3d3751f31fe9890eb73b45c316531a29c6b59ed18b4f4e0c0e5"},
> {"filename":"quotes-in-yaml-title.md","filenameStem":"quotes-in-yaml-title","path":"quotes-in-yaml-title.md","absPath":"{{working-dir}}/quotes-in-yaml-title.md","title":"quoted \"word\" in yaml title","link":"[quoted \"word\" in yaml title](quotes-in-yaml-title)","lead":"This note should _not_ break json graph output, and it _does_ (2024-05-10).","body":"This note should _not_ break json graph output, and it _does_ (2024-05-10).","snippets":["This note should _not_ break json graph output, and it _does_ (2024-05-10)."],"rawContent":"---\ntitle: quoted \"word\" in yaml title\ndate: 2024-05-10\n---\n\nThis note should _not_ break json graph output, and it _does_ (2024-05-10).\n","wordCount":22,"tags":[],"metadata":{"date":"2024-05-10","title":"quoted \"word\" in yaml title"},"created":"2024-05-10T00:00:00Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"3a27fa46a7f7a3ae9f69a416d1868925d3f64fedce18f8c6bb8fa2f8a696769a"},
> {"filename":"single-quotes-in-h1-title.md","filenameStem":"single-quotes-in-h1-title","path":"single-quotes-in-h1-title.md","absPath":"{{working-dir}}/single-quotes-in-h1-title.md","title":"quoted 'word' in h1 title","link":"[quoted 'word' in h1 title](single-quotes-in-h1-title)","lead":"This note should _not_ break json graph output, and it doesn't (2024-05-10).","body":"This note should _not_ break json graph output, and it doesn't (2024-05-10).","snippets":["This note should _not_ break json graph output, and it doesn't (2024-05-10)."],"rawContent":"---\ndate: 2024-05-10\n---\n\n# quoted 'word' in h1 title\n\nThis note should _not_ break json graph output, and it doesn't (2024-05-10).\n","wordCount":22,"tags":[],"metadata":{"date":"2024-05-10"},"created":"2024-05-10T00:00:00Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"5170dfeba776aabfa57d96d373d4db74e4e168c9e9a6256e28d7d049d966c173"},
> {"filename":"single-quotes-in-yaml-title.md","filenameStem":"single-quotes-in-yaml-title","path":"single-quotes-in-yaml-title.md","absPath":"{{working-dir}}/single-quotes-in-yaml-title.md","title":"quoted 'word' in h1 title","link":"[quoted 'word' in h1 title](single-quotes-in-yaml-title)","lead":"This note should _not_ break json graph output, and it doesn't (2024-05-10).","body":"This note should _not_ break json graph output, and it doesn't (2024-05-10).","snippets":["This note should _not_ break json graph output, and it doesn't (2024-05-10)."],"rawContent":"---\ntitle: quoted 'word' in h1 title\ndate: 2024-05-10\n---\n\nThis note should _not_ break json graph output, and it doesn't (2024-05-10).\n","wordCount":22,"tags":[],"metadata":{"date":"2024-05-10","title":"quoted 'word' in h1 title"},"created":"2024-05-10T00:00:00Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"a5ccc8085070bb796c81aec07b31002aaddd474006865334f0c83f54fd1c85c1"}
> ],
> "links": [
>
> ]
>}