markdown-patch 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -0
- package/dist/cli.js +108 -0
- package/{src/constants.ts → dist/constants.js} +7 -8
- package/dist/debug.js +50 -0
- package/dist/index.js +1 -75
- package/dist/map.js +144 -0
- package/dist/patch.js +191 -0
- package/dist/tests/map.test.js +202 -0
- package/dist/tests/patch.test.js +222 -0
- package/dist/types.js +1 -0
- package/package.json +9 -4
- package/.tool-versions +0 -1
- package/.vscode/launch.json +0 -21
- package/document.md +0 -11
- package/document.mdpatch.json +0 -8
- package/jest.config.ts +0 -9
- package/src/debug.ts +0 -75
- package/src/index.ts +0 -88
- package/src/map.ts +0 -200
- package/src/patch.ts +0 -326
- package/src/tests/map.test.ts +0 -212
- package/src/tests/patch.test.ts +0 -297
- package/src/tests/sample.md +0 -81
- package/src/tests/sample.patch.block.append.md +0 -82
- package/src/tests/sample.patch.block.prepend.md +0 -82
- package/src/tests/sample.patch.block.replace.md +0 -81
- package/src/tests/sample.patch.block.targetBlockTypeBehavior.table.append.md +0 -82
- package/src/tests/sample.patch.block.targetBlockTypeBehavior.table.prepend.md +0 -82
- package/src/tests/sample.patch.block.targetBlockTypeBehavior.table.replace.md +0 -77
- package/src/tests/sample.patch.heading.append.md +0 -82
- package/src/tests/sample.patch.heading.document.append.md +0 -82
- package/src/tests/sample.patch.heading.document.prepend.md +0 -82
- package/src/tests/sample.patch.heading.prepend.md +0 -82
- package/src/tests/sample.patch.heading.replace.md +0 -81
- package/src/tests/sample.patch.heading.trimTargetWhitespace.append.md +0 -80
- package/src/tests/sample.patch.heading.trimTargetWhitespace.prepend.md +0 -80
- package/src/types.ts +0 -155
- package/tsconfig.json +0 -18
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
# Problems
|
|
11
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
12
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
13
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
14
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
15
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
16
|
-
|
|
17
|
-
# Actions
|
|
18
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
19
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
20
|
-
| `update` | Find the referenced `target` and replace the content at that region. | ✅ | ✅ | ✅ |
|
|
21
|
-
| `append` | Find the referenced `target` and add content to the end of its region. | ✅ | ✅ | ✅ |
|
|
22
|
-
| `prepend` | Find the referenced `target` and add content to the beginning of its region. | ✅ | ✅ | ✅ |
|
|
23
|
-
| `insert` | Find the path leading to the referenced `target` and add the specified content under a the specified name. This will create a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
24
|
-
| `upsert` | Find the path leading to the referenced `target` and either replace the content under the specified name, or add new content with a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
25
|
-
|
|
26
|
-
^2c67a6
|
|
27
|
-
|
|
28
|
-
# Headers
|
|
29
|
-
| Header | Explanation |
|
|
30
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
32
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
33
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
34
|
-
|
|
35
|
-
^1d6271
|
|
36
|
-
|
|
37
|
-
# Page Targets
|
|
38
|
-
|
|
39
|
-
## Heading
|
|
40
|
-
|
|
41
|
-
| Heading | Value |
|
|
42
|
-
| ------------- | ----------------------------------------------------- |
|
|
43
|
-
| `Target-Type` | `heading` |
|
|
44
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
45
|
-
|
|
46
|
-
^bfec1f
|
|
47
|
-
|
|
48
|
-
| Position | Where |
|
|
49
|
-
| -------- | -------------------------------------------------------------- |
|
|
50
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
51
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
52
|
-
| | |
|
|
53
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
54
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
55
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
56
|
-
## Block
|
|
57
|
-
| Position | Where |
|
|
58
|
-
| -------- | ------------------------------------------------------ |
|
|
59
|
-
| Start | Beginning of line for specified block. |
|
|
60
|
-
| End | Last character (including newline) of specified block. |
|
|
61
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
62
|
-
### Use Cases
|
|
63
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
64
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
65
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
66
|
-
- I want to be able to add new rows to an existing table.
|
|
67
|
-
- I want to be able to add new content to the end of a line.
|
|
68
|
-
|
|
69
|
-
## Frontmatter Field
|
|
70
|
-
|
|
71
|
-
| Position | Where |
|
|
72
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
73
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
74
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
75
|
-
### Use Cases
|
|
76
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
77
|
-
- ✅: ...replacing the content of an existing frontmatter field. ^259a73
|
|
78
|
-
- OK
|
|
79
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
80
|
-
## Document Properties (Exploratory)
|
|
81
|
-
|
|
82
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
# Problems
|
|
11
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
12
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
13
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
14
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
15
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
16
|
-
|
|
17
|
-
# Actions
|
|
18
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
19
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
20
|
-
| `update` | Find the referenced `target` and replace the content at that region. | ✅ | ✅ | ✅ |
|
|
21
|
-
| `append` | Find the referenced `target` and add content to the end of its region. | ✅ | ✅ | ✅ |
|
|
22
|
-
| `prepend` | Find the referenced `target` and add content to the beginning of its region. | ✅ | ✅ | ✅ |
|
|
23
|
-
| `insert` | Find the path leading to the referenced `target` and add the specified content under a the specified name. This will create a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
24
|
-
| `upsert` | Find the path leading to the referenced `target` and either replace the content under the specified name, or add new content with a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
25
|
-
|
|
26
|
-
^2c67a6
|
|
27
|
-
|
|
28
|
-
# Headers
|
|
29
|
-
| Header | Explanation |
|
|
30
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
32
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
33
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
34
|
-
|
|
35
|
-
^1d6271
|
|
36
|
-
|
|
37
|
-
# Page Targets
|
|
38
|
-
|
|
39
|
-
## Heading
|
|
40
|
-
|
|
41
|
-
| Heading | Value |
|
|
42
|
-
| ------------- | ----------------------------------------------------- |
|
|
43
|
-
| `Target-Type` | `heading` |
|
|
44
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
45
|
-
|
|
46
|
-
^bfec1f
|
|
47
|
-
|
|
48
|
-
| Position | Where |
|
|
49
|
-
| -------- | -------------------------------------------------------------- |
|
|
50
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
51
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
52
|
-
| | |
|
|
53
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
54
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
55
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
56
|
-
## Block
|
|
57
|
-
| Position | Where |
|
|
58
|
-
| -------- | ------------------------------------------------------ |
|
|
59
|
-
| Start | Beginning of line for specified block. |
|
|
60
|
-
| End | Last character (including newline) of specified block. |
|
|
61
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
62
|
-
### Use Cases
|
|
63
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
64
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
65
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
66
|
-
- I want to be able to add new rows to an existing table.
|
|
67
|
-
- I want to be able to add new content to the end of a line.
|
|
68
|
-
|
|
69
|
-
## Frontmatter Field
|
|
70
|
-
|
|
71
|
-
| Position | Where |
|
|
72
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
73
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
74
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
75
|
-
### Use Cases
|
|
76
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
77
|
-
- OK ^259a73
|
|
78
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
79
|
-
## Document Properties (Exploratory)
|
|
80
|
-
|
|
81
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
# Problems
|
|
11
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
12
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
13
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
14
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
15
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
16
|
-
|
|
17
|
-
# Actions
|
|
18
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
19
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
20
|
-
| `update` | Find the referenced `target` and replace the content at that region. | ✅ | ✅ | ✅ |
|
|
21
|
-
| `append` | Find the referenced `target` and add content to the end of its region. | ✅ | ✅ | ✅ |
|
|
22
|
-
| `prepend` | Find the referenced `target` and add content to the beginning of its region. | ✅ | ✅ | ✅ |
|
|
23
|
-
| `insert` | Find the path leading to the referenced `target` and add the specified content under a the specified name. This will create a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
24
|
-
| `upsert` | Find the path leading to the referenced `target` and either replace the content under the specified name, or add new content with a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
25
|
-
| `something else` | Some other application | ✅ | ✅ | ✅ |
|
|
26
|
-
|
|
27
|
-
^2c67a6
|
|
28
|
-
|
|
29
|
-
# Headers
|
|
30
|
-
| Header | Explanation |
|
|
31
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
32
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
33
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
34
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
35
|
-
|
|
36
|
-
^1d6271
|
|
37
|
-
|
|
38
|
-
# Page Targets
|
|
39
|
-
|
|
40
|
-
## Heading
|
|
41
|
-
|
|
42
|
-
| Heading | Value |
|
|
43
|
-
| ------------- | ----------------------------------------------------- |
|
|
44
|
-
| `Target-Type` | `heading` |
|
|
45
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
46
|
-
|
|
47
|
-
^bfec1f
|
|
48
|
-
|
|
49
|
-
| Position | Where |
|
|
50
|
-
| -------- | -------------------------------------------------------------- |
|
|
51
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
52
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
53
|
-
| | |
|
|
54
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
55
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
56
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
57
|
-
## Block
|
|
58
|
-
| Position | Where |
|
|
59
|
-
| -------- | ------------------------------------------------------ |
|
|
60
|
-
| Start | Beginning of line for specified block. |
|
|
61
|
-
| End | Last character (including newline) of specified block. |
|
|
62
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
63
|
-
### Use Cases
|
|
64
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
65
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
66
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
67
|
-
- I want to be able to add new rows to an existing table.
|
|
68
|
-
- I want to be able to add new content to the end of a line.
|
|
69
|
-
|
|
70
|
-
## Frontmatter Field
|
|
71
|
-
|
|
72
|
-
| Position | Where |
|
|
73
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
74
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
75
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
76
|
-
### Use Cases
|
|
77
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
78
|
-
- ✅: ...replacing the content of an existing frontmatter field. ^259a73
|
|
79
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
80
|
-
## Document Properties (Exploratory)
|
|
81
|
-
|
|
82
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
# Problems
|
|
11
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
12
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
13
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
14
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
15
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
16
|
-
|
|
17
|
-
# Actions
|
|
18
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
19
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
20
|
-
| `something else` | Some other application | ✅ | ✅ | ✅ |
|
|
21
|
-
| `update` | Find the referenced `target` and replace the content at that region. | ✅ | ✅ | ✅ |
|
|
22
|
-
| `append` | Find the referenced `target` and add content to the end of its region. | ✅ | ✅ | ✅ |
|
|
23
|
-
| `prepend` | Find the referenced `target` and add content to the beginning of its region. | ✅ | ✅ | ✅ |
|
|
24
|
-
| `insert` | Find the path leading to the referenced `target` and add the specified content under a the specified name. This will create a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
25
|
-
| `upsert` | Find the path leading to the referenced `target` and either replace the content under the specified name, or add new content with a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
26
|
-
|
|
27
|
-
^2c67a6
|
|
28
|
-
|
|
29
|
-
# Headers
|
|
30
|
-
| Header | Explanation |
|
|
31
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
32
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
33
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
34
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
35
|
-
|
|
36
|
-
^1d6271
|
|
37
|
-
|
|
38
|
-
# Page Targets
|
|
39
|
-
|
|
40
|
-
## Heading
|
|
41
|
-
|
|
42
|
-
| Heading | Value |
|
|
43
|
-
| ------------- | ----------------------------------------------------- |
|
|
44
|
-
| `Target-Type` | `heading` |
|
|
45
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
46
|
-
|
|
47
|
-
^bfec1f
|
|
48
|
-
|
|
49
|
-
| Position | Where |
|
|
50
|
-
| -------- | -------------------------------------------------------------- |
|
|
51
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
52
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
53
|
-
| | |
|
|
54
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
55
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
56
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
57
|
-
## Block
|
|
58
|
-
| Position | Where |
|
|
59
|
-
| -------- | ------------------------------------------------------ |
|
|
60
|
-
| Start | Beginning of line for specified block. |
|
|
61
|
-
| End | Last character (including newline) of specified block. |
|
|
62
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
63
|
-
### Use Cases
|
|
64
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
65
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
66
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
67
|
-
- I want to be able to add new rows to an existing table.
|
|
68
|
-
- I want to be able to add new content to the end of a line.
|
|
69
|
-
|
|
70
|
-
## Frontmatter Field
|
|
71
|
-
|
|
72
|
-
| Position | Where |
|
|
73
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
74
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
75
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
76
|
-
### Use Cases
|
|
77
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
78
|
-
- ✅: ...replacing the content of an existing frontmatter field. ^259a73
|
|
79
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
80
|
-
## Document Properties (Exploratory)
|
|
81
|
-
|
|
82
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
# Problems
|
|
11
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
12
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
13
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
14
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
15
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
16
|
-
|
|
17
|
-
# Actions
|
|
18
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
19
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
20
|
-
| `something else` | Some other application | ✅ | ✅ | ✅ |
|
|
21
|
-
|
|
22
|
-
^2c67a6
|
|
23
|
-
|
|
24
|
-
# Headers
|
|
25
|
-
| Header | Explanation |
|
|
26
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
28
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
29
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
30
|
-
|
|
31
|
-
^1d6271
|
|
32
|
-
|
|
33
|
-
# Page Targets
|
|
34
|
-
|
|
35
|
-
## Heading
|
|
36
|
-
|
|
37
|
-
| Heading | Value |
|
|
38
|
-
| ------------- | ----------------------------------------------------- |
|
|
39
|
-
| `Target-Type` | `heading` |
|
|
40
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
41
|
-
|
|
42
|
-
^bfec1f
|
|
43
|
-
|
|
44
|
-
| Position | Where |
|
|
45
|
-
| -------- | -------------------------------------------------------------- |
|
|
46
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
47
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
48
|
-
| | |
|
|
49
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
50
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
51
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
52
|
-
## Block
|
|
53
|
-
| Position | Where |
|
|
54
|
-
| -------- | ------------------------------------------------------ |
|
|
55
|
-
| Start | Beginning of line for specified block. |
|
|
56
|
-
| End | Last character (including newline) of specified block. |
|
|
57
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
58
|
-
### Use Cases
|
|
59
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
60
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
61
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
62
|
-
- I want to be able to add new rows to an existing table.
|
|
63
|
-
- I want to be able to add new content to the end of a line.
|
|
64
|
-
|
|
65
|
-
## Frontmatter Field
|
|
66
|
-
|
|
67
|
-
| Position | Where |
|
|
68
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
69
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
70
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
71
|
-
### Use Cases
|
|
72
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
73
|
-
- ✅: ...replacing the content of an existing frontmatter field. ^259a73
|
|
74
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
75
|
-
## Document Properties (Exploratory)
|
|
76
|
-
|
|
77
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
Beep Boop
|
|
11
|
-
# Problems
|
|
12
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
13
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
14
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
15
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
16
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
17
|
-
|
|
18
|
-
# Actions
|
|
19
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
20
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
21
|
-
| `update` | Find the referenced `target` and replace the content at that region. | ✅ | ✅ | ✅ |
|
|
22
|
-
| `append` | Find the referenced `target` and add content to the end of its region. | ✅ | ✅ | ✅ |
|
|
23
|
-
| `prepend` | Find the referenced `target` and add content to the beginning of its region. | ✅ | ✅ | ✅ |
|
|
24
|
-
| `insert` | Find the path leading to the referenced `target` and add the specified content under a the specified name. This will create a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
25
|
-
| `upsert` | Find the path leading to the referenced `target` and either replace the content under the specified name, or add new content with a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
26
|
-
|
|
27
|
-
^2c67a6
|
|
28
|
-
|
|
29
|
-
# Headers
|
|
30
|
-
| Header | Explanation |
|
|
31
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
32
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
33
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
34
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
35
|
-
|
|
36
|
-
^1d6271
|
|
37
|
-
|
|
38
|
-
# Page Targets
|
|
39
|
-
|
|
40
|
-
## Heading
|
|
41
|
-
|
|
42
|
-
| Heading | Value |
|
|
43
|
-
| ------------- | ----------------------------------------------------- |
|
|
44
|
-
| `Target-Type` | `heading` |
|
|
45
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
46
|
-
|
|
47
|
-
^bfec1f
|
|
48
|
-
|
|
49
|
-
| Position | Where |
|
|
50
|
-
| -------- | -------------------------------------------------------------- |
|
|
51
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
52
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
53
|
-
| | |
|
|
54
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
55
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
56
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
57
|
-
## Block
|
|
58
|
-
| Position | Where |
|
|
59
|
-
| -------- | ------------------------------------------------------ |
|
|
60
|
-
| Start | Beginning of line for specified block. |
|
|
61
|
-
| End | Last character (including newline) of specified block. |
|
|
62
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
63
|
-
### Use Cases
|
|
64
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
65
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
66
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
67
|
-
- I want to be able to add new rows to an existing table.
|
|
68
|
-
- I want to be able to add new content to the end of a line.
|
|
69
|
-
|
|
70
|
-
## Frontmatter Field
|
|
71
|
-
|
|
72
|
-
| Position | Where |
|
|
73
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
74
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
75
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
76
|
-
### Use Cases
|
|
77
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
78
|
-
- ✅: ...replacing the content of an existing frontmatter field. ^259a73
|
|
79
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
80
|
-
## Document Properties (Exploratory)
|
|
81
|
-
|
|
82
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
aliases:
|
|
3
|
-
- Structured Markdown Patch
|
|
4
|
-
project-type: Technical
|
|
5
|
-
repository: https://github.com/coddingtonbear/markdown-patch
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Overview
|
|
9
|
-
I came up with this project for supporting [[Obsidian Local Rest API]] (and via that [[Obsidian Web]]) because I often need to shove data into Markdown documents for posterity, but want to be able to do that programmatically with more care than just shoving content to the end of a file.
|
|
10
|
-
# Problems
|
|
11
|
-
- ~~It would be nice for the mechanism to be able to handle something like `upsert` for frontmatter fields. See [[#^e6068e]] in addition to what we already support [[#^259a73]].~~
|
|
12
|
-
- This was solved by making every content block directly-addressable. All interactions treat the document as a key-value mapping.
|
|
13
|
-
- ~~You can't use our earlier header delimiter `::` in an HTTP header; how did I not notice that? I've had a [conversation with ChatGPT](https://chatgpt.com/share/117b262a-f534-40e6-bc05-287758706f34) to land on a choice of `@#@` instead, but there aren't obvious good options. See [[#^1d6271]]~~
|
|
14
|
-
- I changed my mind in the end and went with the more-likely-to-collide-but-at-least-not-bizarre `///`.
|
|
15
|
-
- Should we allow partial matches? The pros are that it would make the usual, garden path of just wanting to push content into a section very easy. The cons are that it makes it kind of unclear what's going to happen when you do an `upsert` or `insert` for a particular value. (See [[#^bfec1f]] for more).
|
|
16
|
-
|
|
17
|
-
# Actions
|
|
18
|
-
| Name | Description | Heading? | Frontmatter? | Block |
|
|
19
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------ | ------------------- |
|
|
20
|
-
| `update` | Find the referenced `target` and replace the content at that region. | ✅ | ✅ | ✅ |
|
|
21
|
-
| `append` | Find the referenced `target` and add content to the end of its region. | ✅ | ✅ | ✅ |
|
|
22
|
-
| `prepend` | Find the referenced `target` and add content to the beginning of its region. | ✅ | ✅ | ✅ |
|
|
23
|
-
| `insert` | Find the path leading to the referenced `target` and add the specified content under a the specified name. This will create a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
24
|
-
| `upsert` | Find the path leading to the referenced `target` and either replace the content under the specified name, or add new content with a new header or frontmatter field if necessary. | ✅ | ✅ | ❌[^block-ambiguity] |
|
|
25
|
-
|
|
26
|
-
^2c67a6
|
|
27
|
-
|
|
28
|
-
# Headers
|
|
29
|
-
| Header | Explanation |
|
|
30
|
-
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
-
| `Target-Type` | `heading`, `block`, `frontmatter` |
|
|
32
|
-
| `Target` | Name of the target:<br>- `heading`: The `///`-delimited path to the heading to replace the content of. E.g. `Page Targets///Block///Use Cases`. This value should be URL-encoded. |
|
|
33
|
-
| `Target-Delimiter` | By default, we use `///` to delimit a `Target`, but it's remotely possible that this value might be present in a header. If it is, you can specify a different delimiter to use for `Target`. |
|
|
34
|
-
|
|
35
|
-
^1d6271
|
|
36
|
-
|
|
37
|
-
# Page Targets
|
|
38
|
-
|
|
39
|
-
## Heading
|
|
40
|
-
|
|
41
|
-
| Heading | Value |
|
|
42
|
-
| ------------- | ----------------------------------------------------- |
|
|
43
|
-
| `Target-Type` | `heading` |
|
|
44
|
-
| `Target` | The path to the heading you would like to append to. |
|
|
45
|
-
|
|
46
|
-
^bfec1f
|
|
47
|
-
|
|
48
|
-
| Position | Where |
|
|
49
|
-
| -------- | -------------------------------------------------------------- |
|
|
50
|
-
| Start | Beginning of line immediately following line named by heading |
|
|
51
|
-
| End | Last newline before heading of same or higher priority or EOF. |
|
|
52
|
-
| | |
|
|
53
|
-
Unlike with [[#Heading]], this targets the *content* of the heading and does not include the heading iself.
|
|
54
|
-
- ✅: ...replacing the content specified by a particular heading.
|
|
55
|
-
- ✅: ...appending content to a block specified by a particular heading.
|
|
56
|
-
## Block
|
|
57
|
-
| Position | Where |
|
|
58
|
-
| -------- | ------------------------------------------------------ |
|
|
59
|
-
| Start | Beginning of line for specified block. |
|
|
60
|
-
| End | Last character (including newline) of specified block. |
|
|
61
|
-
A "Block" in Obsidian can be any *block*-type element. This might mean a paragraph, but it could also mean a table, but how block references are marked differs in Obsidian depending upon what kind of block is being marked.
|
|
62
|
-
### Use Cases
|
|
63
|
-
- ✅: ...replacing the content specified by a particular block ID.
|
|
64
|
-
- I want to be able to replace a whole table or whole paragraph with new content.
|
|
65
|
-
- ✅: ...appending content to a block specified by a particular block ID.
|
|
66
|
-
- I want to be able to add new rows to an existing table.
|
|
67
|
-
- I want to be able to add new content to the end of a line.
|
|
68
|
-
|
|
69
|
-
## Frontmatter Field
|
|
70
|
-
|
|
71
|
-
| Position | Where |
|
|
72
|
-
| -------- | ------------------------------------------------------------------------ |
|
|
73
|
-
| Start | First character of content referenced by a particular frontmatter field. |
|
|
74
|
-
| End | Last character of content referenced by a particular frontmatter field. |
|
|
75
|
-
### Use Cases
|
|
76
|
-
- ✅: ...appending content to an existing frontmatter field.
|
|
77
|
-
- ✅: ...replacing the content of an existing frontmatter field. ^259a73
|
|
78
|
-
- ✅: ...adding a new frontmatter field. ^e6068e
|
|
79
|
-
## Document Properties (Exploratory)
|
|
80
|
-
|
|
81
|
-
[^block-ambiguity]: There is currently no obvious place to plop a block were we to create a new one. So, I might implement this such that these actions *work*, but will just add the block to the end of a file. This isn't great, but it's at least consistent?
|
|
82
|
-
Beep Boop
|