Skip to content
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
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"scripts": {
"build": "tsc",
"test": "jest",
"prepare": "npm run build",
"docs": "typedoc",
"docs-serve": "http-server docs"
},
Expand Down
39 changes: 32 additions & 7 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ program
"Heading delimiter to use in place of '::'.",
"::"
)
.option(
"--replace-heading",
"Replace the heading as well as its content."
)
Comment on lines +56 to +59
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a little bit surprising to me that this would be a global option for the patch applier when that particular option is only valid for certain kinds of patch instructions; what was your intention here?

.argument("<operation>", "Operation to perform ('replace', 'append', etc.)")
.argument("<targetType>", "Target type ('heading', 'block', etc.)")
.argument(
Expand All @@ -77,13 +81,34 @@ program

const document = await fs.readFile(documentPath, "utf-8");

const instruction = {
operation,
targetType,
content,
target:
targetType !== "heading" ? target : target.split(options.delimiter),
} as PatchInstruction;
let instruction: PatchInstruction;

// Only create a ReplaceHeadingPatchInstruction when the operation and target are correct
if (operation === "replace" && targetType === "heading") {
instruction = {
operation,
targetType,
content,
target: target.split(options.delimiter),
replaceHeading: options.replaceHeading,
};
} else {
// If the user tries to use the flag incorrectly, exit with an error.
if (options.replaceHeading) {
console.error(
"The --replace-heading flag is only valid for 'replace' operations on 'heading' targets."
);
process.exit(1);
}
// Create other instruction types as before
instruction = {
operation,
targetType,
content,
target:
targetType !== "heading" ? target : target.split(options.delimiter),
} as PatchInstruction;
}
Comment on lines +87 to +111
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the answer to the above question will probably help me understand the answer to this one, but in case it doesn't: I'm finding myself wondering why we can't just read the replaceHeading value out of the incoming PatchInstruction.


const patchedDocument = applyPatch(document, instruction);
if (options.output === "-") {
Expand Down
10 changes: 9 additions & 1 deletion src/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
isList,
isString,
isStringArrayArray,
isReplaceHeadingPatchInstruction
} from "./typeGuards.js";

export enum PatchFailureReason {
Expand Down Expand Up @@ -60,8 +61,15 @@ const replaceText = (
instruction: PatchInstruction,
target: DocumentMapMarkerContentPair
): string => {
let start = target.content.start;
if (
isReplaceHeadingPatchInstruction(instruction) &&
instruction.replaceHeading
) {
start = target.marker.start;
}
return [
document.slice(0, target.content.start),
document.slice(0, start),
instruction.content,
document.slice(target.content.end),
].join("");
Expand Down
11 changes: 10 additions & 1 deletion src/typeGuards.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AppendableFrontmatterType } from "./types";
import { AppendableFrontmatterType,PatchInstruction,
ReplaceHeadingPatchInstruction, } from "./types";

export function isStringArrayArray(obj: unknown): obj is string[][] {
// Check if the object is an array
Expand Down Expand Up @@ -28,3 +29,11 @@ export function isDictionary(obj: unknown): obj is Record<string, unknown> {
export function isList(obj: unknown): obj is Array<unknown> {
return Array.isArray(obj);
}

export function isReplaceHeadingPatchInstruction(
instruction: PatchInstruction
): instruction is ReplaceHeadingPatchInstruction {
return (
instruction.targetType === "heading" && instruction.operation === "replace"
);
}
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ export interface ReplaceHeadingPatchInstruction
BaseHeadingPatchInstruction,
StringContent {
operation: "replace";
/**
* When replaceHeading is `true`, the heading will be replaced along with its content.
*
* By default, only the content under the heading is replaced.
*/
replaceHeading?: boolean;
}

/**
Expand Down