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
package/dist/patch.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { getDocumentMap } from "./map.js";
|
|
2
|
+
import * as marked from "marked";
|
|
3
|
+
export var PatchFailureReason;
|
|
4
|
+
(function (PatchFailureReason) {
|
|
5
|
+
PatchFailureReason["InvalidTarget"] = "invalid-target";
|
|
6
|
+
PatchFailureReason["ContentAlreadyPreexistsInTarget"] = "content-already-preexists-in-target";
|
|
7
|
+
PatchFailureReason["TableContentIncorrectColumnCount"] = "table-content-incorrect-column-count";
|
|
8
|
+
PatchFailureReason["RequestedBlockTypeBehaviorUnavailable"] = "requested-block-type-behavior-unavailable";
|
|
9
|
+
})(PatchFailureReason || (PatchFailureReason = {}));
|
|
10
|
+
export class PatchFailed extends Error {
|
|
11
|
+
constructor(reason, instruction, targetMap) {
|
|
12
|
+
super();
|
|
13
|
+
this.reason = reason;
|
|
14
|
+
this.instruction = instruction;
|
|
15
|
+
this.targetMap = targetMap;
|
|
16
|
+
this.name = "PatchFailed";
|
|
17
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class PatchError extends Error {
|
|
21
|
+
}
|
|
22
|
+
const replaceText = (document, instruction, target) => {
|
|
23
|
+
return [
|
|
24
|
+
document.slice(0, target.content.start),
|
|
25
|
+
instruction.content,
|
|
26
|
+
document.slice(target.content.end),
|
|
27
|
+
].join("");
|
|
28
|
+
};
|
|
29
|
+
const prependText = (document, instruction, target) => {
|
|
30
|
+
return [
|
|
31
|
+
document.slice(0, target.content.start),
|
|
32
|
+
instruction.content,
|
|
33
|
+
instruction.trimTargetWhitespace
|
|
34
|
+
? document.slice(target.content.start).trimStart()
|
|
35
|
+
: document.slice(target.content.start),
|
|
36
|
+
].join("");
|
|
37
|
+
};
|
|
38
|
+
const appendText = (document, instruction, target) => {
|
|
39
|
+
return [
|
|
40
|
+
instruction.trimTargetWhitespace
|
|
41
|
+
? document.slice(0, target.content.end).trimEnd()
|
|
42
|
+
: document.slice(0, target.content.end),
|
|
43
|
+
instruction.content,
|
|
44
|
+
document.slice(target.content.end),
|
|
45
|
+
].join("");
|
|
46
|
+
};
|
|
47
|
+
export class TablePartsNotFound extends Error {
|
|
48
|
+
}
|
|
49
|
+
const _getTableData = (document, target) => {
|
|
50
|
+
const targetTable = document.slice(target.content.start, target.content.end);
|
|
51
|
+
const tableToken = marked.lexer(targetTable)[0];
|
|
52
|
+
const match = /^(.*?)(?:\r?\n)(.*?)(\r?\n)/.exec(targetTable);
|
|
53
|
+
if (!(tableToken.type === "table") || !match) {
|
|
54
|
+
throw new TablePartsNotFound();
|
|
55
|
+
}
|
|
56
|
+
const lineEnding = match[3];
|
|
57
|
+
return {
|
|
58
|
+
token: tableToken,
|
|
59
|
+
lineEnding: match[3],
|
|
60
|
+
headerParts: match[1] + lineEnding + match[2] + lineEnding,
|
|
61
|
+
contentParts: targetTable.slice(match[0].length),
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
const replaceTable = (document, instruction, target) => {
|
|
65
|
+
try {
|
|
66
|
+
const table = _getTableData(document, target);
|
|
67
|
+
const tableRows = [table.headerParts];
|
|
68
|
+
for (const row of instruction.content) {
|
|
69
|
+
if (row.length !== table.token.header.length || typeof row === "string") {
|
|
70
|
+
throw new PatchFailed(PatchFailureReason.TableContentIncorrectColumnCount, instruction, target);
|
|
71
|
+
}
|
|
72
|
+
tableRows.push("| " + row.join(" | ") + " |" + table.lineEnding);
|
|
73
|
+
}
|
|
74
|
+
return [
|
|
75
|
+
document.slice(0, target.content.start),
|
|
76
|
+
tableRows.join(""),
|
|
77
|
+
document.slice(target.content.end),
|
|
78
|
+
].join("");
|
|
79
|
+
}
|
|
80
|
+
catch (TablePartsNotFound) {
|
|
81
|
+
throw new PatchFailed(PatchFailureReason.RequestedBlockTypeBehaviorUnavailable, instruction, target);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const prependTable = (document, instruction, target) => {
|
|
85
|
+
try {
|
|
86
|
+
const table = _getTableData(document, target);
|
|
87
|
+
const tableRows = [table.headerParts];
|
|
88
|
+
for (const row of instruction.content) {
|
|
89
|
+
if (row.length !== table.token.header.length || typeof row === "string") {
|
|
90
|
+
throw new PatchFailed(PatchFailureReason.TableContentIncorrectColumnCount, instruction, target);
|
|
91
|
+
}
|
|
92
|
+
tableRows.push("| " + row.join(" | ") + " |" + table.lineEnding);
|
|
93
|
+
}
|
|
94
|
+
tableRows.push(table.contentParts);
|
|
95
|
+
return [
|
|
96
|
+
document.slice(0, target.content.start),
|
|
97
|
+
tableRows.join(""),
|
|
98
|
+
document.slice(target.content.end),
|
|
99
|
+
].join("");
|
|
100
|
+
}
|
|
101
|
+
catch (TablePartsNotFound) {
|
|
102
|
+
throw new PatchFailed(PatchFailureReason.RequestedBlockTypeBehaviorUnavailable, instruction, target);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const appendTable = (document, instruction, target) => {
|
|
106
|
+
try {
|
|
107
|
+
const table = _getTableData(document, target);
|
|
108
|
+
const tableRows = [table.headerParts, table.contentParts];
|
|
109
|
+
for (const row of instruction.content) {
|
|
110
|
+
if (row.length !== table.token.header.length || typeof row === "string") {
|
|
111
|
+
throw new PatchFailed(PatchFailureReason.TableContentIncorrectColumnCount, instruction, target);
|
|
112
|
+
}
|
|
113
|
+
tableRows.push("| " + row.join(" | ") + " |" + table.lineEnding);
|
|
114
|
+
}
|
|
115
|
+
return [
|
|
116
|
+
document.slice(0, target.content.start),
|
|
117
|
+
tableRows.join(""),
|
|
118
|
+
document.slice(target.content.end),
|
|
119
|
+
].join("");
|
|
120
|
+
}
|
|
121
|
+
catch (TablePartsNotFound) {
|
|
122
|
+
throw new PatchFailed(PatchFailureReason.RequestedBlockTypeBehaviorUnavailable, instruction, target);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const replace = (document, instruction, target) => {
|
|
126
|
+
const targetBlockTypeBehavior = "targetBlockTypeBehavior" in instruction &&
|
|
127
|
+
instruction.targetBlockTypeBehavior
|
|
128
|
+
? instruction.targetBlockTypeBehavior
|
|
129
|
+
: "text";
|
|
130
|
+
switch (targetBlockTypeBehavior) {
|
|
131
|
+
case "text":
|
|
132
|
+
return replaceText(document, instruction, target);
|
|
133
|
+
case "table":
|
|
134
|
+
return replaceTable(document, instruction, target);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const prepend = (document, instruction, target) => {
|
|
138
|
+
const targetBlockTypeBehavior = "targetBlockTypeBehavior" in instruction &&
|
|
139
|
+
instruction.targetBlockTypeBehavior
|
|
140
|
+
? instruction.targetBlockTypeBehavior
|
|
141
|
+
: "text";
|
|
142
|
+
switch (targetBlockTypeBehavior) {
|
|
143
|
+
case "text":
|
|
144
|
+
return prependText(document, instruction, target);
|
|
145
|
+
case "table":
|
|
146
|
+
return prependTable(document, instruction, target);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const append = (document, instruction, target) => {
|
|
150
|
+
const targetBlockTypeBehavior = "targetBlockTypeBehavior" in instruction &&
|
|
151
|
+
instruction.targetBlockTypeBehavior
|
|
152
|
+
? instruction.targetBlockTypeBehavior
|
|
153
|
+
: "text";
|
|
154
|
+
switch (targetBlockTypeBehavior) {
|
|
155
|
+
case "text":
|
|
156
|
+
return appendText(document, instruction, target);
|
|
157
|
+
case "table":
|
|
158
|
+
return appendTable(document, instruction, target);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const getTarget = (map, instruction) => {
|
|
162
|
+
switch (instruction.targetType) {
|
|
163
|
+
case "heading":
|
|
164
|
+
return map.heading[instruction.target ? instruction.target.join("\u001f") : ""];
|
|
165
|
+
case "block":
|
|
166
|
+
return map.block[instruction.target];
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
export const applyPatch = (document, instruction) => {
|
|
170
|
+
const map = getDocumentMap(document);
|
|
171
|
+
const target = getTarget(map, instruction);
|
|
172
|
+
if (!target) {
|
|
173
|
+
throw new PatchFailed(PatchFailureReason.InvalidTarget, instruction, null);
|
|
174
|
+
}
|
|
175
|
+
if ((!("applyIfContentPreexists" in instruction) ||
|
|
176
|
+
!instruction.applyIfContentPreexists) &&
|
|
177
|
+
typeof instruction.content === "string" &&
|
|
178
|
+
document
|
|
179
|
+
.slice(target.content.start, target.content.end)
|
|
180
|
+
.includes(instruction.content.trim())) {
|
|
181
|
+
throw new PatchFailed(PatchFailureReason.ContentAlreadyPreexistsInTarget, instruction, target);
|
|
182
|
+
}
|
|
183
|
+
switch (instruction.operation) {
|
|
184
|
+
case "append":
|
|
185
|
+
return append(document, instruction, target);
|
|
186
|
+
case "prepend":
|
|
187
|
+
return prepend(document, instruction, target);
|
|
188
|
+
case "replace":
|
|
189
|
+
return replace(document, instruction, target);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { getDocumentMap } from "../map";
|
|
4
|
+
describe("map", () => {
|
|
5
|
+
const sample = fs.readFileSync(path.join(__dirname, "sample.md"), "utf-8");
|
|
6
|
+
test("heading", () => {
|
|
7
|
+
const actualHeadings = getDocumentMap(sample).heading;
|
|
8
|
+
const expectedHeadings = {
|
|
9
|
+
"": {
|
|
10
|
+
content: {
|
|
11
|
+
start: 130,
|
|
12
|
+
end: 6988,
|
|
13
|
+
},
|
|
14
|
+
marker: {
|
|
15
|
+
start: 0,
|
|
16
|
+
end: 0,
|
|
17
|
+
},
|
|
18
|
+
level: 0,
|
|
19
|
+
},
|
|
20
|
+
Overview: {
|
|
21
|
+
content: {
|
|
22
|
+
start: 142,
|
|
23
|
+
end: 430,
|
|
24
|
+
},
|
|
25
|
+
marker: {
|
|
26
|
+
start: 131,
|
|
27
|
+
end: 142,
|
|
28
|
+
},
|
|
29
|
+
level: 1,
|
|
30
|
+
},
|
|
31
|
+
Problems: {
|
|
32
|
+
content: {
|
|
33
|
+
start: 441,
|
|
34
|
+
end: 1468,
|
|
35
|
+
},
|
|
36
|
+
marker: {
|
|
37
|
+
start: 430,
|
|
38
|
+
end: 441,
|
|
39
|
+
},
|
|
40
|
+
level: 1,
|
|
41
|
+
},
|
|
42
|
+
Actions: {
|
|
43
|
+
content: {
|
|
44
|
+
start: 1478,
|
|
45
|
+
end: 3182,
|
|
46
|
+
},
|
|
47
|
+
marker: {
|
|
48
|
+
start: 1468,
|
|
49
|
+
end: 1478,
|
|
50
|
+
},
|
|
51
|
+
level: 1,
|
|
52
|
+
},
|
|
53
|
+
Headers: {
|
|
54
|
+
content: {
|
|
55
|
+
start: 3192,
|
|
56
|
+
end: 4282,
|
|
57
|
+
},
|
|
58
|
+
marker: {
|
|
59
|
+
start: 3182,
|
|
60
|
+
end: 3192,
|
|
61
|
+
},
|
|
62
|
+
level: 1,
|
|
63
|
+
},
|
|
64
|
+
"Page Targets": {
|
|
65
|
+
content: {
|
|
66
|
+
start: 4297,
|
|
67
|
+
end: 6988,
|
|
68
|
+
},
|
|
69
|
+
marker: {
|
|
70
|
+
start: 4282,
|
|
71
|
+
end: 4297,
|
|
72
|
+
},
|
|
73
|
+
level: 1,
|
|
74
|
+
},
|
|
75
|
+
"Page Targets\u001fHeading": {
|
|
76
|
+
content: {
|
|
77
|
+
start: 4309,
|
|
78
|
+
end: 5251,
|
|
79
|
+
},
|
|
80
|
+
marker: {
|
|
81
|
+
start: 4298,
|
|
82
|
+
end: 4309,
|
|
83
|
+
},
|
|
84
|
+
level: 2,
|
|
85
|
+
},
|
|
86
|
+
"Page Targets\u001fBlock": {
|
|
87
|
+
content: {
|
|
88
|
+
start: 5260,
|
|
89
|
+
end: 6122,
|
|
90
|
+
},
|
|
91
|
+
marker: {
|
|
92
|
+
start: 5251,
|
|
93
|
+
end: 5260,
|
|
94
|
+
},
|
|
95
|
+
level: 2,
|
|
96
|
+
},
|
|
97
|
+
"Page Targets\u001fBlock\u001fUse Cases": {
|
|
98
|
+
content: {
|
|
99
|
+
start: 5778,
|
|
100
|
+
end: 6122,
|
|
101
|
+
},
|
|
102
|
+
marker: {
|
|
103
|
+
start: 5764,
|
|
104
|
+
end: 5778,
|
|
105
|
+
},
|
|
106
|
+
level: 3,
|
|
107
|
+
},
|
|
108
|
+
"Page Targets\u001fFrontmatter Field": {
|
|
109
|
+
content: {
|
|
110
|
+
start: 6143,
|
|
111
|
+
end: 6690,
|
|
112
|
+
},
|
|
113
|
+
marker: {
|
|
114
|
+
start: 6122,
|
|
115
|
+
end: 6143,
|
|
116
|
+
},
|
|
117
|
+
level: 2,
|
|
118
|
+
},
|
|
119
|
+
"Page Targets\u001fFrontmatter Field\u001fUse Cases": {
|
|
120
|
+
content: {
|
|
121
|
+
start: 6510,
|
|
122
|
+
end: 6690,
|
|
123
|
+
},
|
|
124
|
+
marker: {
|
|
125
|
+
start: 6496,
|
|
126
|
+
end: 6510,
|
|
127
|
+
},
|
|
128
|
+
level: 3,
|
|
129
|
+
},
|
|
130
|
+
"Page Targets\u001fDocument Properties (Exploratory)": {
|
|
131
|
+
content: {
|
|
132
|
+
start: 6727,
|
|
133
|
+
end: 6988,
|
|
134
|
+
},
|
|
135
|
+
marker: {
|
|
136
|
+
start: 6690,
|
|
137
|
+
end: 6727,
|
|
138
|
+
},
|
|
139
|
+
level: 2,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
//console.log(JSON.stringify(actualHeadings, undefined, 4));
|
|
143
|
+
expect(actualHeadings).toEqual(expectedHeadings);
|
|
144
|
+
});
|
|
145
|
+
test("block", () => {
|
|
146
|
+
const actualBlocks = getDocumentMap(sample).block;
|
|
147
|
+
const expectedBlocks = {
|
|
148
|
+
"2c67a6": {
|
|
149
|
+
content: {
|
|
150
|
+
start: 1478,
|
|
151
|
+
end: 3172,
|
|
152
|
+
},
|
|
153
|
+
marker: {
|
|
154
|
+
start: 3173,
|
|
155
|
+
end: 3181,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
"1d6271": {
|
|
159
|
+
content: {
|
|
160
|
+
start: 3192,
|
|
161
|
+
end: 4272,
|
|
162
|
+
},
|
|
163
|
+
marker: {
|
|
164
|
+
start: 4273,
|
|
165
|
+
end: 4281,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
bfec1f: {
|
|
169
|
+
content: {
|
|
170
|
+
start: 4310,
|
|
171
|
+
end: 4606,
|
|
172
|
+
},
|
|
173
|
+
marker: {
|
|
174
|
+
start: 4607,
|
|
175
|
+
end: 4615,
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
"259a73": {
|
|
179
|
+
content: {
|
|
180
|
+
start: 6570,
|
|
181
|
+
end: 6633,
|
|
182
|
+
},
|
|
183
|
+
marker: {
|
|
184
|
+
start: 6633,
|
|
185
|
+
end: 6642,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
e6068e: {
|
|
189
|
+
content: {
|
|
190
|
+
start: 6642,
|
|
191
|
+
end: 6681,
|
|
192
|
+
},
|
|
193
|
+
marker: {
|
|
194
|
+
start: 6681,
|
|
195
|
+
end: 6690,
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
//console.log(JSON.stringify(actualBlocks, undefined, 4));
|
|
200
|
+
expect(actualBlocks).toEqual(expectedBlocks);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { applyPatch, PatchFailed } from "../patch";
|
|
4
|
+
describe("patch", () => {
|
|
5
|
+
const sample = fs.readFileSync(path.join(__dirname, "sample.md"), "utf-8");
|
|
6
|
+
describe("heading", () => {
|
|
7
|
+
test("prepend", () => {
|
|
8
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.prepend.md"), "utf-8");
|
|
9
|
+
const instruction = {
|
|
10
|
+
targetType: "heading",
|
|
11
|
+
target: ["Overview"],
|
|
12
|
+
operation: "prepend",
|
|
13
|
+
content: "Beep Boop\n",
|
|
14
|
+
};
|
|
15
|
+
const actualResult = applyPatch(sample, instruction);
|
|
16
|
+
expect(actualResult).toEqual(expected);
|
|
17
|
+
});
|
|
18
|
+
test("append", () => {
|
|
19
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.append.md"), "utf-8");
|
|
20
|
+
const instruction = {
|
|
21
|
+
targetType: "heading",
|
|
22
|
+
target: ["Overview"],
|
|
23
|
+
operation: "append",
|
|
24
|
+
content: "Beep Boop\n",
|
|
25
|
+
};
|
|
26
|
+
const actualResult = applyPatch(sample, instruction);
|
|
27
|
+
expect(actualResult).toEqual(expected);
|
|
28
|
+
});
|
|
29
|
+
test("replace", () => {
|
|
30
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.replace.md"), "utf-8");
|
|
31
|
+
const instruction = {
|
|
32
|
+
targetType: "heading",
|
|
33
|
+
target: ["Overview"],
|
|
34
|
+
operation: "replace",
|
|
35
|
+
content: "Beep Boop\n",
|
|
36
|
+
};
|
|
37
|
+
const actualResult = applyPatch(sample, instruction);
|
|
38
|
+
expect(actualResult).toEqual(expected);
|
|
39
|
+
});
|
|
40
|
+
describe("document", () => {
|
|
41
|
+
test("prepend", () => {
|
|
42
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.document.prepend.md"), "utf-8");
|
|
43
|
+
const instruction = {
|
|
44
|
+
targetType: "heading",
|
|
45
|
+
target: null,
|
|
46
|
+
operation: "prepend",
|
|
47
|
+
content: "Beep Boop\n",
|
|
48
|
+
};
|
|
49
|
+
const actualResult = applyPatch(sample, instruction);
|
|
50
|
+
expect(actualResult).toEqual(expected);
|
|
51
|
+
});
|
|
52
|
+
test("append", () => {
|
|
53
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.document.append.md"), "utf-8");
|
|
54
|
+
const instruction = {
|
|
55
|
+
targetType: "heading",
|
|
56
|
+
target: null,
|
|
57
|
+
operation: "append",
|
|
58
|
+
content: "Beep Boop\n",
|
|
59
|
+
};
|
|
60
|
+
const actualResult = applyPatch(sample, instruction);
|
|
61
|
+
expect(actualResult).toEqual(expected);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe("parameter", () => {
|
|
66
|
+
describe("trimTargetWhitespace", () => {
|
|
67
|
+
describe("heading", () => {
|
|
68
|
+
test("prepend", () => {
|
|
69
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.trimTargetWhitespace.prepend.md"), "utf-8");
|
|
70
|
+
const instruction = {
|
|
71
|
+
targetType: "heading",
|
|
72
|
+
target: ["Page Targets", "Document Properties (Exploratory)"],
|
|
73
|
+
operation: "prepend",
|
|
74
|
+
content: "Beep Boop",
|
|
75
|
+
trimTargetWhitespace: true,
|
|
76
|
+
};
|
|
77
|
+
const actualResult = applyPatch(sample, instruction);
|
|
78
|
+
expect(actualResult).toEqual(expected);
|
|
79
|
+
});
|
|
80
|
+
test("append", () => {
|
|
81
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.heading.trimTargetWhitespace.append.md"), "utf-8");
|
|
82
|
+
const instruction = {
|
|
83
|
+
targetType: "heading",
|
|
84
|
+
target: ["Problems"],
|
|
85
|
+
operation: "append",
|
|
86
|
+
content: "Beep Boop\n",
|
|
87
|
+
trimTargetWhitespace: true,
|
|
88
|
+
};
|
|
89
|
+
const actualResult = applyPatch(sample, instruction);
|
|
90
|
+
expect(actualResult).toEqual(expected);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe("applyIfContentPreexists", () => {
|
|
95
|
+
describe("disabled (default)", () => {
|
|
96
|
+
describe("heading", () => {
|
|
97
|
+
test("preexists at target", () => {
|
|
98
|
+
const instruction = {
|
|
99
|
+
targetType: "heading",
|
|
100
|
+
target: ["Page Targets"],
|
|
101
|
+
operation: "append",
|
|
102
|
+
content: "## Frontmatter Field",
|
|
103
|
+
// applyIfContentPreexists: false, # default
|
|
104
|
+
};
|
|
105
|
+
expect(() => {
|
|
106
|
+
applyPatch(sample, instruction);
|
|
107
|
+
}).toThrow(PatchFailed);
|
|
108
|
+
});
|
|
109
|
+
test("does not preexist at target", () => {
|
|
110
|
+
const instruction = {
|
|
111
|
+
targetType: "heading",
|
|
112
|
+
target: ["Headers"],
|
|
113
|
+
operation: "append",
|
|
114
|
+
content: "## Frontmatter Field",
|
|
115
|
+
// applyIfContentPreexists: false, # default
|
|
116
|
+
};
|
|
117
|
+
expect(() => {
|
|
118
|
+
applyPatch(sample, instruction);
|
|
119
|
+
}).not.toThrow(PatchFailed);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe("enabled", () => {
|
|
124
|
+
describe("heading", () => {
|
|
125
|
+
test("preexists at target", () => {
|
|
126
|
+
const instruction = {
|
|
127
|
+
targetType: "heading",
|
|
128
|
+
target: ["Page Targets"],
|
|
129
|
+
operation: "append",
|
|
130
|
+
content: "## Frontmatter Field",
|
|
131
|
+
applyIfContentPreexists: true,
|
|
132
|
+
};
|
|
133
|
+
expect(() => {
|
|
134
|
+
applyPatch(sample, instruction);
|
|
135
|
+
}).not.toThrow(PatchFailed);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("block", () => {
|
|
142
|
+
test("prepend", () => {
|
|
143
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.block.prepend.md"), "utf-8");
|
|
144
|
+
const instruction = {
|
|
145
|
+
targetType: "block",
|
|
146
|
+
target: "e6068e",
|
|
147
|
+
operation: "prepend",
|
|
148
|
+
content: "- OK\n",
|
|
149
|
+
};
|
|
150
|
+
const actualResult = applyPatch(sample, instruction);
|
|
151
|
+
expect(actualResult).toEqual(expected);
|
|
152
|
+
});
|
|
153
|
+
test("append", () => {
|
|
154
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.block.append.md"), "utf-8");
|
|
155
|
+
const instruction = {
|
|
156
|
+
targetType: "block",
|
|
157
|
+
target: "e6068e",
|
|
158
|
+
operation: "append",
|
|
159
|
+
content: "\n- OK",
|
|
160
|
+
};
|
|
161
|
+
const actualResult = applyPatch(sample, instruction);
|
|
162
|
+
expect(actualResult).toEqual(expected);
|
|
163
|
+
});
|
|
164
|
+
test("replace", () => {
|
|
165
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.block.replace.md"), "utf-8");
|
|
166
|
+
const instruction = {
|
|
167
|
+
targetType: "block",
|
|
168
|
+
target: "259a73",
|
|
169
|
+
operation: "replace",
|
|
170
|
+
content: "- OK",
|
|
171
|
+
};
|
|
172
|
+
const actualResult = applyPatch(sample, instruction);
|
|
173
|
+
expect(actualResult).toEqual(expected);
|
|
174
|
+
});
|
|
175
|
+
describe("tagetBlockTypeBehavior", () => {
|
|
176
|
+
describe("table", () => {
|
|
177
|
+
test("prepend", () => {
|
|
178
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.block.targetBlockTypeBehavior.table.prepend.md"), "utf-8");
|
|
179
|
+
const instruction = {
|
|
180
|
+
targetType: "block",
|
|
181
|
+
targetBlockTypeBehavior: "table",
|
|
182
|
+
target: "2c67a6",
|
|
183
|
+
operation: "prepend",
|
|
184
|
+
content: [
|
|
185
|
+
["`something else`", "Some other application", "✅", "✅", "✅"],
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
const actualResult = applyPatch(sample, instruction);
|
|
189
|
+
expect(actualResult).toEqual(expected);
|
|
190
|
+
});
|
|
191
|
+
test("append", () => {
|
|
192
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.block.targetBlockTypeBehavior.table.append.md"), "utf-8");
|
|
193
|
+
const instruction = {
|
|
194
|
+
targetType: "block",
|
|
195
|
+
targetBlockTypeBehavior: "table",
|
|
196
|
+
target: "2c67a6",
|
|
197
|
+
operation: "append",
|
|
198
|
+
content: [
|
|
199
|
+
["`something else`", "Some other application", "✅", "✅", "✅"],
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
const actualResult = applyPatch(sample, instruction);
|
|
203
|
+
expect(actualResult).toEqual(expected);
|
|
204
|
+
});
|
|
205
|
+
test("replace", () => {
|
|
206
|
+
const expected = fs.readFileSync(path.join(__dirname, "sample.patch.block.targetBlockTypeBehavior.table.replace.md"), "utf-8");
|
|
207
|
+
const instruction = {
|
|
208
|
+
targetType: "block",
|
|
209
|
+
targetBlockTypeBehavior: "table",
|
|
210
|
+
target: "2c67a6",
|
|
211
|
+
operation: "replace",
|
|
212
|
+
content: [
|
|
213
|
+
["`something else`", "Some other application", "✅", "✅", "✅"],
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
const actualResult = applyPatch(sample, instruction);
|
|
217
|
+
expect(actualResult).toEqual(expected);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -15,17 +15,22 @@
|
|
|
15
15
|
"typescript": "^5.5.4"
|
|
16
16
|
},
|
|
17
17
|
"name": "markdown-patch",
|
|
18
|
-
"version": "0.1.
|
|
19
|
-
"main": "index.js",
|
|
18
|
+
"version": "0.1.2",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
20
|
"scripts": {
|
|
21
|
+
"build": "npx tsc",
|
|
21
22
|
"test": "node node_modules/.bin/jest"
|
|
22
23
|
},
|
|
23
24
|
"bin": {
|
|
24
|
-
"mdpatch": "./dist/
|
|
25
|
+
"mdpatch": "./dist/cli.js"
|
|
25
26
|
},
|
|
26
27
|
"keywords": [],
|
|
27
28
|
"author": "",
|
|
28
29
|
"license": "ISC",
|
|
29
30
|
"description": "Change markdown documents by inserting or changing content relative to headings or other parts of a document's structure.",
|
|
30
|
-
"type": "module"
|
|
31
|
+
"type": "module",
|
|
32
|
+
"files": [
|
|
33
|
+
"dist/",
|
|
34
|
+
"README.md"
|
|
35
|
+
]
|
|
31
36
|
}
|
package/.tool-versions
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
nodejs 20.8.0
|
package/.vscode/launch.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Use IntelliSense to learn about possible attributes.
|
|
3
|
-
// Hover to view descriptions of existing attributes.
|
|
4
|
-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
-
"version": "0.2.0",
|
|
6
|
-
"configurations": [
|
|
7
|
-
{
|
|
8
|
-
"type": "node",
|
|
9
|
-
"request": "launch",
|
|
10
|
-
"name": "Jest All",
|
|
11
|
-
//"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/jest",
|
|
12
|
-
"args": [
|
|
13
|
-
"--runInBand"
|
|
14
|
-
],
|
|
15
|
-
"console": "integratedTerminal",
|
|
16
|
-
"internalConsoleOptions": "neverOpen",
|
|
17
|
-
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
|
18
|
-
"cwd": "${workspaceFolder}"
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|
package/document.md
DELETED