mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-10-12 11:01:42 +00:00
feat: add JSON output support to makepatches operator (#9940)
* feat: enhance makepatches function to support multiple suffixes and JSON output format * feat: add release notes for makepatches JSON output enhancement * doc: update makepatches operator documentation to document new json output * doc: add JSON output examples to makepatches and applypatches documentation * chore: convert space indentations to tabs * test: add tests for makepatches operator with JSON output support * chore: change space to tab indentation * test: add DiffMergePatch4 integration test for testing makepatches json output * fix: remove superfluous heading character * refactor the parsing of the makepatches suffixes Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com> * refactor: improve makepatches function for better readability and performance * chore: apply style guide by collapsing consecutive variable assignments * chore: remove extraneous tabs --------- Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
This commit is contained in:
co-authored by
Saq Imtiaz
parent
abf8ffdbca
commit
24b433211d
@@ -91,22 +91,35 @@ function diffLineWordMode(text1,text2,mode) {
|
||||
return diffs;
|
||||
}
|
||||
|
||||
exports.makepatches = function(source,operator,options) {
|
||||
var suffix = operator.suffix || "",
|
||||
result = [];
|
||||
|
||||
source(function(tiddler,title) {
|
||||
let diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmp.patchMake(title,diffs);
|
||||
exports.makepatches = function(source, operator, options) {
|
||||
const suffixes = operator.suffixes || [],
|
||||
[modeArg = [], formatArg = []] = suffixes,
|
||||
modeSuffix = modeArg[0] || operator.suffix || "",
|
||||
mode = ["lines", "words"].includes(modeSuffix) ? modeSuffix : "",
|
||||
isJson = formatArg[0] === "json",
|
||||
results = [];
|
||||
|
||||
source((tiddler, title) => {
|
||||
if (isJson) {
|
||||
const diffs = (mode === "lines" || mode === "words")
|
||||
? diffLineWordMode(title, operator.operand, mode)
|
||||
: dmp.diffMain(title, operator.operand);
|
||||
|
||||
const jsonOutput = diffs.map(([typeCode, text]) => ({
|
||||
type: typeCode === 1 ? "insert" : (typeCode === -1 ? "delete" : "equal"),
|
||||
text
|
||||
}));
|
||||
results.push(JSON.stringify(jsonOutput));
|
||||
} else {
|
||||
patches = dmp.patchMake(title,operator.operand);
|
||||
const patches = (mode === "lines" || mode === "words")
|
||||
? dmp.patchMake(title, diffLineWordMode(title, operator.operand, mode))
|
||||
: dmp.patchMake(title, operator.operand);
|
||||
|
||||
results.push(dmp.patchToText(patches));
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmp.patchToText(patches)]);
|
||||
});
|
||||
|
||||
return result;
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.applypatches = makeStringBinaryOperator(
|
||||
@@ -235,4 +248,4 @@ exports.charcode = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
return [chars.join("")];
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
title: Filters/DiffMergePatch4
|
||||
description: Tests for diff-merge-patch derived operators
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
\define text1()
|
||||
The quick brown fox
|
||||
\end
|
||||
|
||||
\define text2()
|
||||
The fast brown fox
|
||||
\end
|
||||
|
||||
<$text text={{{ [<text1>makepatches::json<text2>] }}}/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
[{"type":"equal","text":"The "},{"type":"delete","text":"quick"},{"type":"insert","text":"fast"},{"type":"equal","text":" brown fox"}]
|
||||
@@ -173,5 +173,20 @@ describe("json filter tests", function() {
|
||||
expect(wiki.filterTiddlers("[{First}format:json[ ]]")).toEqual(["{\n \"a\": \"one\",\n \"b\": \"\",\n \"c\": 1.618,\n \"d\": {\n \"e\": \"four\",\n \"f\": [\n \"five\",\n \"six\",\n true,\n false,\n null\n ]\n }\n}"]);
|
||||
});
|
||||
|
||||
it("should support the makepatches operator with json output", function() {
|
||||
expect(wiki.filterTiddlers("[[The quick brown fox]makepatches::json[The fast brown fox]]")).toEqual([
|
||||
'[{"type":"equal","text":"The "},{"type":"delete","text":"quick"},{"type":"insert","text":"fast"},{"type":"equal","text":" brown fox"}]'
|
||||
]);
|
||||
|
||||
expect(wiki.filterTiddlers("[[The quick brown fox]makepatches:words:json[The fast brown fox]]")).toEqual([
|
||||
'[{"type":"equal","text":"The "},{"type":"delete","text":"quick "},{"type":"insert","text":"fast "},{"type":"equal","text":"brown fox"}]'
|
||||
]);
|
||||
|
||||
// Safely ignores missing/invalid second suffix and returns a standard patch string instead of JSON
|
||||
expect(wiki.filterTiddlers("[[The quick brown fox]makepatches:words[The fast brown fox]]")[0]).not.toContain(
|
||||
'"type":"equal"'
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
+9
-1
@@ -1,5 +1,5 @@
|
||||
created: 20230304160331362
|
||||
modified: 20230304160332927
|
||||
modified: 20260724082228670
|
||||
tags: [[makepatches Operator]] [[applypatches Operator]] [[Operator Examples]]
|
||||
title: makepatches and applypatches Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -40,4 +40,12 @@ The `lines` mode doesn't work as well in this application:
|
||||
|
||||
It is better suited as a very fast algorithm to detect line-wise incremental changes to texts and store only the changes instead of multiple versions of the whole texts.
|
||||
|
||||
The `json` suffix outputs a structured JSON array representing the differences instead of a patch string. To use the JSON output with the default character mode, skip the first suffix with a double colon (`::`).
|
||||
|
||||
<<.operator-example 8 "[{Hamlet##Shakespeare-old}makepatches::json{Hamlet##Shakespeare-new}]">>
|
||||
|
||||
The `json` suffix can also be combined with the `words` or `lines` modes:
|
||||
|
||||
<<.operator-example 9 "[{Hamlet##Shakespeare-old}makepatches:words:json{Hamlet##Shakespeare-new}]">>
|
||||
|
||||
</div>
|
||||
@@ -1,23 +1,28 @@
|
||||
caption: makepatches
|
||||
created: 20230304122354967
|
||||
modified: 20230304122400128
|
||||
op-purpose: returns a set of patches that transform the input to a given string
|
||||
modified: 20260724081502905
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: a set of patch instructions per input title to be used by the [[applypatches Operator]] to transform the input title(s) into the string <<.place S>>, or a structured JSON array representing the differences if the `json` suffix is used
|
||||
op-parameter: a string of characters
|
||||
op-parameter-name: S
|
||||
op-output: a set of patch instructions per input title to be used by the [[applypatches Operator]] to transform the input title(s) into the string <<.place S>>
|
||||
op-suffix: `lines` to operate in line mode, `words` to operate in word mode. If omitted (default), the algorithm operates in character mode. See notes below.
|
||||
op-suffix-name: T
|
||||
op-purpose: returns a set of patches that transform the input to a given string
|
||||
op-suffix: optional suffixes specifying the diff mode and output format
|
||||
op-suffix-name: T:F
|
||||
tags: [[Filter Operators]] [[String Operators]]
|
||||
title: makepatches Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.2.6">>
|
||||
|
||||
The <<.op makepatches>> operator uses up to two suffixes:
|
||||
|
||||
* <<.place T>> (diff mode): `lines` to operate in line mode, `words` to operate in word mode. If omitted (default), the algorithm operates in character mode.
|
||||
* <<.place F>> (output format): <<.from-version "5.5.0">> `json` to output a structured JSON array of differences instead of a standard patch string. To use the JSON output with the default character mode, skip the first suffix with a double colon (e.g., `makepatches::json`).
|
||||
|
||||
The difference algorithm operates in character mode by default. This produces the most detailed diff possible. In `words` mode, each word in the input text is transformed into a meta-character, upon which the algorithm then operates. In the default character mode, the filter would find two patches between "ActionWidget" and "Action-Widgets" (the hyphen and the plural s), while in `words` mode, the whole word is found to be changed. In `lines` mode, the meta-character is formed from the whole line, delimited by newline characters, and is found to be changed independent of the number of changes within the line.
|
||||
|
||||
The different modes influence the result when the patches are applied to texts other than the original, as well as the runtime.
|
||||
|
||||
<<.tip "The calculation in `words` mode is roughly 10 times faster than the default character mode, while `lines` mode can be more than 100 times faster than the default.">>
|
||||
|
||||
<<.operator-examples "makepatches and applypatches">>
|
||||
<<.operator-examples "makepatches and applypatches">>
|
||||
@@ -0,0 +1,12 @@
|
||||
change-category: filters
|
||||
change-type: enhancement
|
||||
created: 20260724080519370
|
||||
description: The makepatches operator can now output structured JSON
|
||||
github-contributors: DesignThinkerer
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9940
|
||||
release: 5.5.0
|
||||
tags: $:/tags/ChangeNote
|
||||
title: $:/changenotes/5.5.0/#9940
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
* The [[makepatches|makepatches Operator]] operator now supports a `:json` suffix (e.g., `makepatches::json`) that outputs a structured JSON array of the differences, enabling easier and robust parsing with WikiText
|
||||
Reference in New Issue
Block a user