mirror of
https://github.com/Jermolene/TiddlyWiki5.git
synced 2025-12-05 18:20:38 -08:00
Compare commits
5 commits
e339f112a4
...
30e9b4f3b7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30e9b4f3b7 | ||
|
|
c6556d5207 | ||
|
|
a8da7e0207 | ||
|
|
d5762b1fbb | ||
|
|
2b0739f06e |
14 changed files with 293 additions and 23 deletions
2
.github/workflows/pr-check-build-size.yml
vendored
2
.github/workflows/pr-check-build-size.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
steps:
|
||||
- name: build-size-check
|
||||
id: get_sizes
|
||||
uses: TiddlyWiki/cerebrus@v5
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
|
|
|||
2
.github/workflows/pr-comment-build-size.yml
vendored
2
.github/workflows/pr-comment-build-size.yml
vendored
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Build and check size
|
||||
uses: TiddlyWiki/cerebrus@v5
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ inputs.pr_number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
|
|
|||
8
.github/workflows/pr-validation.yml
vendored
8
.github/workflows/pr-validation.yml
vendored
|
|
@ -15,22 +15,22 @@ jobs:
|
|||
steps:
|
||||
# Step 1: Validate PR paths
|
||||
- name: Validate PR Paths
|
||||
uses: TiddlyWiki/cerebrus@v5
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.base_ref }}
|
||||
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: rules
|
||||
continue-on-error: true
|
||||
|
||||
# Step 2: Validate change notes
|
||||
- name: Validate Change Notes
|
||||
uses: TiddlyWiki/cerebrus@v5
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.base_ref }}
|
||||
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: changenotes
|
||||
continue-on-error: false
|
||||
|
|
|
|||
|
|
@ -113,6 +113,22 @@ exports["jsonset"] = function(source,operator,options) {
|
|||
return results;
|
||||
};
|
||||
|
||||
exports["jsondelete"] = function(source,operator,options) {
|
||||
var indexes = operator.operands,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
// If parsing failed (data equals original title and is a string), return unchanged
|
||||
if(data === title && typeof data === "string") {
|
||||
results.push(title);
|
||||
} else if(data) {
|
||||
data = deleteDataItem(data,indexes);
|
||||
results.push(JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
|
|
@ -144,7 +160,7 @@ function convertDataItemValueToStrings(item) {
|
|||
return ["null"]
|
||||
} else if(typeof item === "object") {
|
||||
var results = [],i,t;
|
||||
if($tw.utils.isArray(item)) {
|
||||
if(Array.isArray(item)) {
|
||||
// Return all the items in arrays recursively
|
||||
for(i=0; i<item.length; i++) {
|
||||
t = convertDataItemValueToStrings(item[i])
|
||||
|
|
@ -178,7 +194,7 @@ function convertDataItemKeysToStrings(item) {
|
|||
return [];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
if(Array.isArray(item)) {
|
||||
for(var i=0; i<item.length; i++) {
|
||||
results.push(i.toString());
|
||||
}
|
||||
|
|
@ -201,7 +217,7 @@ function getDataItemType(data,indexes) {
|
|||
return item;
|
||||
} else if(item === null) {
|
||||
return "null";
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
} else if(Array.isArray(item)) {
|
||||
return "array";
|
||||
} else if(typeof item === "object") {
|
||||
return "object";
|
||||
|
|
@ -213,7 +229,7 @@ function getDataItemType(data,indexes) {
|
|||
function getItemAtIndex(item,index) {
|
||||
if($tw.utils.hop(item,index)) {
|
||||
return item[index];
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
} else if(Array.isArray(item)) {
|
||||
index = $tw.utils.parseInt(index);
|
||||
if(index < 0) { index = index + item.length };
|
||||
return item[index]; // Will be undefined if index was out-of-bounds
|
||||
|
|
@ -223,15 +239,16 @@ function getItemAtIndex(item,index) {
|
|||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
Traverse the index chain and return the item at the specified depth.
|
||||
Returns the item at the end of the traversal, or undefined if traversal fails.
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
function traverseIndexChain(data,indexes,stopBeforeLast) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Get the item
|
||||
var item = data;
|
||||
for(var i=0; i<indexes.length; i++) {
|
||||
var stopIndex = stopBeforeLast ? indexes.length - 1 : indexes.length;
|
||||
for(var i = 0; i < stopIndex; i++) {
|
||||
if(item !== undefined) {
|
||||
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||
item = getItemAtIndex(item,indexes[i]);
|
||||
|
|
@ -243,6 +260,13 @@ function getDataItem(data,indexes) {
|
|||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
return traverseIndexChain(data,indexes,false);
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
||||
*/
|
||||
|
|
@ -255,18 +279,15 @@ function setDataItem(data,indexes,value) {
|
|||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return value;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain
|
||||
var current = data;
|
||||
for(var i = 0; i < indexes.length - 1; i++) {
|
||||
current = getItemAtIndex(current,indexes[i]);
|
||||
if(current === undefined) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain up to the parent
|
||||
var current = traverseIndexChain(data,indexes,true);
|
||||
if(current === undefined) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Add the value to the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if($tw.utils.isArray(current)) {
|
||||
if(Array.isArray(current)) {
|
||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||
}
|
||||
|
|
@ -276,3 +297,32 @@ function setDataItem(data,indexes,value) {
|
|||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the data structure with the item at the end of the index chain deleted. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then the JSON data structure is returned unmodified.
|
||||
*/
|
||||
function deleteDataItem(data,indexes) {
|
||||
// Check for the root item - don't delete the root
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain up to the parent
|
||||
var current = traverseIndexChain(data,indexes,true);
|
||||
if(current === undefined || current === null) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Delete the item at the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if(Array.isArray(current) && current !== null) {
|
||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||
// Check if index is valid before splicing
|
||||
if(lastIndex >= 0 && lastIndex < current.length) {
|
||||
current.splice(lastIndex,1);
|
||||
}
|
||||
} else if(typeof current === "object" && current !== null) {
|
||||
delete current[lastIndex];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,33 @@ describe("json filter tests", function() {
|
|||
expect(wiki.filterTiddlers("[{First}jsonset:json[notjson]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
});
|
||||
|
||||
it("should support the jsondelete operator", function() {
|
||||
// Delete top-level object property
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[a]]")).toEqual(['{"b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[b]]")).toEqual(['{"a":"one","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[c]]")).toEqual(['{"a":"one","b":"","d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
// Delete nested object property
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[e]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"f":["five","six",true,false,null]}}']);
|
||||
// Delete array element
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[0]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["six",true,false,null]}}']);
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[1]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five",true,false,null]}}']);
|
||||
// Delete using negative array index
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[-1]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false]}}']);
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[-2]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,null]}}']);
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[-5]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["six",true,false,null]}}']);
|
||||
// Delete from array
|
||||
expect(wiki.filterTiddlers("[{Second}jsondelete[0]]")).toEqual(['["deux","trois",["quatre","cinq"]]']);
|
||||
expect(wiki.filterTiddlers("[{Second}jsondelete[1]]")).toEqual(['["une","trois",["quatre","cinq"]]']);
|
||||
expect(wiki.filterTiddlers("[{Second}jsondelete[-1]]")).toEqual(['["une","deux","trois"]']);
|
||||
// Attempting to delete non-existent property should return unchanged
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[missing-property]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[d],[missing]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
// Attempting to delete root should return unchanged
|
||||
expect(wiki.filterTiddlers("[{First}jsondelete[]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||
// Non-JSON input should return unchanged
|
||||
expect(wiki.filterTiddlers("[{Third}jsondelete[a]]")).toEqual(["This is not JSON"]);
|
||||
});
|
||||
|
||||
it("should support the format:json operator", function() {
|
||||
expect(wiki.filterTiddlers("[{First}format:json[]]")).toEqual(["{\"a\":\"one\",\"b\":\"\",\"c\":1.618,\"d\":{\"e\":\"four\",\"f\":[\"five\",\"six\",true,false,null]}}"]);
|
||||
expect(wiki.filterTiddlers("[{First}format:json[4]]")).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}"]);
|
||||
|
|
|
|||
59
editions/tw5.com/tiddlers/filters/examples/jsondelete.tid
Normal file
59
editions/tw5.com/tiddlers/filters/examples/jsondelete.tid
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
created: 20250115120000000
|
||||
modified: 20250115120000000
|
||||
tags: [[Operator Examples]] [[jsondelete Operator]]
|
||||
title: jsondelete Operator (Examples)
|
||||
|
||||
<$let object-a="""{
|
||||
"a": "one",
|
||||
"b": "",
|
||||
"c": "three",
|
||||
"d": {
|
||||
"e": "four",
|
||||
"f": [
|
||||
"five",
|
||||
"six",
|
||||
true,
|
||||
false,
|
||||
null
|
||||
],
|
||||
"g": {
|
||||
"x": "max",
|
||||
"y": "may",
|
||||
"z": "maize"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
object-b="""{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}"""
|
||||
array-a="""["une","deux","trois",["quatre","cinq"]]""">
|
||||
|
||||
The examples below assume the following JSON object is contained in the variable `object-a`:
|
||||
|
||||
<pre><<object-a>></pre>
|
||||
|
||||
<<.operator-example 1 "[<object-a>jsondelete[a]]" "Delete a top-level object property">>
|
||||
<<.operator-example 2 "[<object-a>jsondelete[d],[e]]" "Delete a nested object property">>
|
||||
<<.operator-example 3 "[<object-a>jsondelete[d],[f],[0]]" "Delete the first element from an array">>
|
||||
<<.operator-example 4 "[<object-a>jsondelete[d],[f],[-1]]" "Delete the last element from an array using negative index">>
|
||||
<<.operator-example 5 "[<object-a>jsondelete[d],[f],[-2]]" "Delete the second-to-last element from an array using negative index">>
|
||||
<<.operator-example 6 "[<object-a>jsondelete[d],[g],[x]]" "Delete a deeply nested object property">>
|
||||
<<.operator-example 7 "[<object-a>jsondelete[]]" "If no parameters are specified, the JSON object is returned unchanged">>
|
||||
<<.operator-example 8 "[<object-a>jsondelete[missing]]" "If the property does not exist, the JSON object is returned unchanged">>
|
||||
|
||||
The examples below assume the following JSON object is contained in the variable `object-b`:
|
||||
|
||||
<pre><<object-b>></pre>
|
||||
|
||||
<<.operator-example 9 "[<object-b>jsondelete[b]]" "Delete an empty string property">>
|
||||
<<.operator-example 10 "[<object-b>jsondelete[d],[f],[1]]" "Delete a middle element from an array">>
|
||||
|
||||
The examples below assume the following JSON array is contained in the variable `array-a`:
|
||||
|
||||
<pre><<array-a>></pre>
|
||||
|
||||
<<.operator-example 11 "[<array-a>jsondelete[0]]" "Delete the first element from a top-level array">>
|
||||
<<.operator-example 12 "[<array-a>jsondelete[-1]]" "Delete the last element from a top-level array using negative index">>
|
||||
<<.operator-example 13 "[<array-a>jsondelete[3],[0]]" "Delete an element from a nested array">>
|
||||
|
||||
<<.operator-example 14 "[<object-a>] [<object-b>] :and[jsondelete[a]]" "If the input consists of multiple JSON objects with matching properties, the property is deleted from all of them">>
|
||||
|
||||
54
editions/tw5.com/tiddlers/filters/jsondelete.tid
Normal file
54
editions/tw5.com/tiddlers/filters/jsondelete.tid
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
caption: jsondelete
|
||||
created: 20250115120000000
|
||||
modified: 20250115120000000
|
||||
op-input: a selection of JSON objects
|
||||
op-output: the JSON objects with the specified property deleted
|
||||
op-parameter: one or more indexes of the property to delete
|
||||
op-purpose: delete a property from JSON objects
|
||||
tags: [[Filter Operators]] [[JSON Operators]]
|
||||
title: jsondelete Operator
|
||||
|
||||
<<.from-version "5.4.0">> The <<.op jsondelete>> operator is used to delete a property from JSON strings. See [[JSON in TiddlyWiki]] for background. See also the following related operators:
|
||||
|
||||
* <<.olink jsonset>> to set values within JSON objects
|
||||
* <<.olink jsonget>> to retrieve the values of a property in JSON data
|
||||
* <<.olink jsontype>> to retrieve the type of a JSON value
|
||||
* <<.olink jsonindexes>> to retrieve the names of the fields of a JSON object, or the indexes of a JSON array
|
||||
* <<.olink jsonextract>> to retrieve a JSON value as a string of JSON
|
||||
|
||||
Properties within a JSON object are identified by a sequence of indexes. In the following example, the value at `[a]` is `one`, and the value at `[d][f][0]` is `five`.
|
||||
|
||||
```
|
||||
{
|
||||
"a": "one",
|
||||
"b": "",
|
||||
"c": "three",
|
||||
"d": {
|
||||
"e": "four",
|
||||
"f": [
|
||||
"five",
|
||||
"six",
|
||||
true,
|
||||
false,
|
||||
null
|
||||
],
|
||||
"g": {
|
||||
"x": "max",
|
||||
"y": "may",
|
||||
"z": "maize"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The <<.op jsondelete>> operator uses multiple parameters to specify the indexes of the property to delete. For object properties, the property is removed using JavaScript's `delete` operator. For array elements, the element is removed using `splice`, which shifts remaining elements.
|
||||
|
||||
Negative indexes into an array are counted from the end, so -1 means the last item, -2 the next-to-last item, and so on.
|
||||
|
||||
Indexes can be dynamically composed from variables and transclusions, e.g. `[<jsondata>jsondelete<variable>,{!!field},[0]]`.
|
||||
|
||||
If the specified property does not exist, the JSON object is returned unchanged. If you attempt to delete the root object itself (by providing no indexes or a blank index), the JSON object is returned unchanged.
|
||||
|
||||
If the input consists of multiple JSON objects, the property is deleted from all of them.
|
||||
|
||||
<<.operator-examples "jsondelete">>
|
||||
|
|
@ -6,3 +6,13 @@ change-type: enhancement
|
|||
change-category: developer
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9103
|
||||
github-contributors: Arlen22
|
||||
|
||||
This adds support for async functions to commands and startups.
|
||||
|
||||
In both `synchronous: true` and `synchronous: false` mode, if you return a promise (manually or by using the async keyword), it will wait for the promise to resolve, and then proceed using the resolved value as the return value of the function.
|
||||
|
||||
Importantly, in `synchronous: false` mode, returning a promise will not change the callback behavior. So you can safely use an async function and still call the callback to continue execution.
|
||||
|
||||
Previously, in `synchronous: true` mode, returning a promise would have just logged the promise to console and halted execution. Now the promise will be awaited, and if the value is truthy, it will be logged to console and halt execution. If the promise resolves to a falsy value, execution will continue. This is the main breaking change, but since logging an opaque promise to console is the most useless of all error messages, this is unlikely to seriously break anything in practice. Throwing anything, truthy or not, will still stop execution (in `synchronous: true` mode).
|
||||
|
||||
This also does not add any error handling code. Rejected promises should still be logged to console as unhandled rejections just as uncaught exceptions are currently.
|
||||
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9135.tid
Normal file
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9135.tid
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
title: $:/changenotes/5.4.0/#9135
|
||||
description: Update ESLint target to ES2017
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: developer
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9135
|
||||
github-contributors: Arlen22
|
||||
|
||||
Updates the eslint config to check for syntax newer than ES2017. This uses a plugin to check for newer syntax, for better error messages, and may need to be updated regularly along with eslint to catch the latest features.
|
||||
13
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9305.tid
Normal file
13
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9305.tid
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
title: $:/changenotes/5.4.0/#9305
|
||||
description: Let tiddler modules overwrite shadow modules with the same exports but different names
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: bugfix
|
||||
change-category: internal
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9305
|
||||
github-contributors: yaisog
|
||||
|
||||
Tiddlers were previously processed before shadows during module registration. The shadow modules registration algorithm only checked for a matching title to prevent overwriting, but a differently named tiddler with the same exports would be overwritten by a shadow. This change swaps the order of $tw.wiki.defineTiddlerModules() and $tw.wiki.defineShadowModules() in boot.js, so that tiddlers are processed after shadows and can therefore override them.
|
||||
|
||||
Each group (tiddlers or shadows) is sorted alphabetically, so plugin shadows would previously correctly overwrite core shadows (assuming their name starts with $:/plugins/), which remains unchanged. This change only affects module tiddlers that have the same export as a shadow, but a different name.
|
||||
|
||||
18
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9337.tid
Normal file
18
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9337.tid
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
title: $:/changenotes/5.4.0/#9337
|
||||
description: Modify output of some math operators for empty inputs
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: bugfix
|
||||
change-category: filters
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9337
|
||||
github-contributors: yaisog
|
||||
|
||||
The following math operators are changed to output an empty list when the input list is empty:
|
||||
|
||||
* sum[]
|
||||
* product[]
|
||||
* maxall[]
|
||||
* minall[]
|
||||
* average[]
|
||||
* variance[]
|
||||
* standard-deviation[]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
title$:/changenotes/5.4.0/#9337/compatibility-break/math-filters
|
||||
changenote: $:/changenotes/5.4.0/#9337
|
||||
created - 20251112152513384
|
||||
modified - 20251112152513384
|
||||
tags: $:/tags/ImpactNote
|
||||
description: filter output with empty input changes for some math filter operators
|
||||
impact-type: compatibility-break
|
||||
|
||||
These math operators will now output an empty list when the input list is empty:
|
||||
|
||||
* sum[] - previously returned 0
|
||||
* product[] - previously returned 1
|
||||
* maxall[] - previously returned -Infinity
|
||||
* minall[] - previously returned Infinity
|
||||
* average[] - previously returned NaN
|
||||
* variance[] - previously returned NaN
|
||||
* standard-deviation[] - previously returned NaN
|
||||
11
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9371.tid
Normal file
11
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9371.tid
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
title: $:/changenotes/5.4.0/#9371
|
||||
description: Added jsondelete operator for deleting properties from JSON objects
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: feature
|
||||
change-category: filters
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9390
|
||||
github-contributors: SmartDever02
|
||||
|
||||
Added the <<.op jsondelete>> operator for deleting properties from JSON strings. The operator uses the same code path as <<.op jsonset>> to locate the correct part of the object, ensuring consistency between setting and deleting operations. It supports deleting both object properties and array elements, with support for negative array indexes counted from the end.
|
||||
|
||||
|
|
@ -11,6 +11,7 @@ categories/hackability/caption: Hackability
|
|||
categories/nodejs/caption: Node.js
|
||||
categories/performance/caption: Performance
|
||||
categories/developer/caption: Developer
|
||||
categories/filters/caption: Filters
|
||||
change-types/bugfix/caption: Bugfix
|
||||
change-types/bugfix/colour: #ffe246
|
||||
change-types/feature/caption: Feature
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue