mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-26 03:27:18 +00:00
Allow negative indexes in json operators (#7849)
* Add unit tests for negative indexes in json ops * Allow negative indexes in JSON operators Negative indexes will be treated as counting from the end, so -1 means last item of the array, -2 means next-to-last item, and so on. * Add documentation for negative indexes
This commit is contained in:
parent
bf8b3cff03
commit
ab72cc7b09
@ -213,6 +213,18 @@ function getDataItemType(data,indexes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getItemAtIndex(item,index) {
|
||||||
|
if($tw.utils.hop(item,index)) {
|
||||||
|
return item[index];
|
||||||
|
} else if($tw.utils.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
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
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
|
||||||
*/
|
*/
|
||||||
@ -225,7 +237,7 @@ function getDataItem(data,indexes) {
|
|||||||
for(var i=0; i<indexes.length; i++) {
|
for(var i=0; i<indexes.length; i++) {
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||||
item = item[indexes[i]];
|
item = getItemAtIndex(item,indexes[i]);
|
||||||
} else {
|
} else {
|
||||||
item = undefined;
|
item = undefined;
|
||||||
}
|
}
|
||||||
@ -249,16 +261,18 @@ function setDataItem(data,indexes,value) {
|
|||||||
// Traverse the JSON data structure using the index chain
|
// Traverse the JSON data structure using the index chain
|
||||||
var current = data;
|
var current = data;
|
||||||
for(var i = 0; i < indexes.length - 1; i++) {
|
for(var i = 0; i < indexes.length - 1; i++) {
|
||||||
var index = indexes[i];
|
current = getItemAtIndex(current,indexes[i]);
|
||||||
if($tw.utils.hop(current,index)) {
|
if(current === undefined) {
|
||||||
current = current[index];
|
|
||||||
} else {
|
|
||||||
// Return the original JSON data structure if any of the index strings are invalid
|
// Return the original JSON data structure if any of the index strings are invalid
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add the value to the end of the index chain
|
// Add the value to the end of the index chain
|
||||||
var lastIndex = indexes[indexes.length - 1];
|
var lastIndex = indexes[indexes.length - 1];
|
||||||
|
if($tw.utils.isArray(current)) {
|
||||||
|
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||||
|
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||||
|
}
|
||||||
current[lastIndex] = value;
|
current[lastIndex] = value;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,11 @@ describe("json filter tests", function() {
|
|||||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[2]]")).toEqual(["true"]);
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[2]]")).toEqual(["true"]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[3]]")).toEqual(["false"]);
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[3]]")).toEqual(["false"]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[4]]")).toEqual(["null"]);
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[4]]")).toEqual(["null"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[-5]]")).toEqual(["five"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[-4]]")).toEqual(["six"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[-3]]")).toEqual(["true"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[-2]]")).toEqual(["false"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[-1]]")).toEqual(["null"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should support the jsonextract operator", function() {
|
it("should support the jsonextract operator", function() {
|
||||||
@ -70,6 +75,11 @@ describe("json filter tests", function() {
|
|||||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[2]]")).toEqual(["true"]);
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[2]]")).toEqual(["true"]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[3]]")).toEqual(["false"]);
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[3]]")).toEqual(["false"]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[4]]")).toEqual(["null"]);
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[4]]")).toEqual(["null"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[-5]]")).toEqual(['"five"']);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[-4]]")).toEqual(['"six"']);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[-3]]")).toEqual(["true"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[-2]]")).toEqual(["false"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[-1]]")).toEqual(["null"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should support the jsonindexes operator", function() {
|
it("should support the jsonindexes operator", function() {
|
||||||
@ -85,6 +95,11 @@ describe("json filter tests", function() {
|
|||||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[2]]")).toEqual([]);
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[2]]")).toEqual([]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[3]]")).toEqual([]);
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[3]]")).toEqual([]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[4]]")).toEqual([]);
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[4]]")).toEqual([]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[-5]]")).toEqual([]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[-4]]")).toEqual([]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[-3]]")).toEqual([]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[-2]]")).toEqual([]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[-1]]")).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should support the jsontype operator", function() {
|
it("should support the jsontype operator", function() {
|
||||||
@ -101,6 +116,11 @@ describe("json filter tests", function() {
|
|||||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[2]]")).toEqual(["boolean"]);
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[2]]")).toEqual(["boolean"]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[3]]")).toEqual(["boolean"]);
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[3]]")).toEqual(["boolean"]);
|
||||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[4]]")).toEqual(["null"]);
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[4]]")).toEqual(["null"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[-5]]")).toEqual(["string"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[-4]]")).toEqual(["string"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[-3]]")).toEqual(["boolean"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[-2]]")).toEqual(["boolean"]);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[-1]]")).toEqual(["null"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should support the jsonset operator", function() {
|
it("should support the jsonset operator", function() {
|
||||||
@ -115,6 +135,7 @@ describe("json filter tests", function() {
|
|||||||
expect(wiki.filterTiddlers("[{First}jsonset:null[id]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":null}']);
|
expect(wiki.filterTiddlers("[{First}jsonset:null[id]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":null}']);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonset:array[d],[f],[5]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null,[]]}}']);
|
expect(wiki.filterTiddlers("[{First}jsonset:array[d],[f],[5]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null,[]]}}']);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonset:object[d],[f],[5]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null,{}]}}']);
|
expect(wiki.filterTiddlers("[{First}jsonset:object[d],[f],[5]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null,{}]}}']);
|
||||||
|
expect(wiki.filterTiddlers("[{First}jsonset:number[d],[f],[-1],[42]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,42]}}']);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonset[missing],[id],[Antelope]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
expect(wiki.filterTiddlers("[{First}jsonset[missing],[id],[Antelope]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonset:json[\"Antelope\"]]")).toEqual(['"Antelope"']);
|
expect(wiki.filterTiddlers("[{First}jsonset:json[\"Antelope\"]]")).toEqual(['"Antelope"']);
|
||||||
expect(wiki.filterTiddlers("[{First}jsonset:json[id],[{\"a\":313}]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":{"a":313}}']);
|
expect(wiki.filterTiddlers("[{First}jsonset:json[id],[{\"a\":313}]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":{"a":313}}']);
|
||||||
|
@ -53,6 +53,14 @@ The <<.op jsonextract>> operator uses multiple operands to specify the indexes o
|
|||||||
[<jsondata>jsonextract[d],[g]] --> {"x":"max","y":"may","z":"maize"}
|
[<jsondata>jsonextract[d],[g]] --> {"x":"max","y":"may","z":"maize"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<<.from-version "5.3.2">> 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
[<jsondata>jsonextract[d],[f],[-1]] --> null
|
||||||
|
[<jsondata>jsonextract[d],[f],[-2]] --> false
|
||||||
|
[<jsondata>jsonextract[d],[f],[-4]] --> "six"
|
||||||
|
```
|
||||||
|
|
||||||
Indexes can be dynamically composed from variables and transclusions:
|
Indexes can be dynamically composed from variables and transclusions:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -51,6 +51,14 @@ The <<.op jsonget>> operator uses multiple operands to specify the indexes of th
|
|||||||
[<jsondata>jsonget[d],[f],[0]] --> "five"
|
[<jsondata>jsonget[d],[f],[0]] --> "five"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<<.from-version "5.3.2">> 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
[<jsondata>jsonget[d],[f],[-1]] --> null
|
||||||
|
[<jsondata>jsonget[d],[f],[-2]] --> false
|
||||||
|
[<jsondata>jsonget[d],[f],[-4]] --> "six"
|
||||||
|
```
|
||||||
|
|
||||||
Indexes can be dynamically composed from variables and transclusions:
|
Indexes can be dynamically composed from variables and transclusions:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -51,6 +51,14 @@ The <<.op jsonset>> operator uses multiple operands to specify the indexes of th
|
|||||||
[<jsondata>jsonset[d],[f],[Panther]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": "Panther","g": {"x": "max","y": "may","z": "maize"}}"}
|
[<jsondata>jsonset[d],[f],[Panther]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": "Panther","g": {"x": "max","y": "may","z": "maize"}}"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```
|
||||||
|
[<jsondata>jsonset[d],[f],[-1],[Elephant]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five","six",true,false,"Elephant"],"g": {"x": "max","y": "may","z": "maize"}}"}
|
||||||
|
[<jsondata>jsonset[d],[f],[-2],[Elephant]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five","six",true,"Elephant",null],"g": {"x": "max","y": "may","z": "maize"}}"}
|
||||||
|
[<jsondata>jsonset[d],[f],[-4],[Elephant]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five","Elephant",true,false,null],"g": {"x": "max","y": "may","z": "maize"}}"}
|
||||||
|
```
|
||||||
|
|
||||||
Indexes can be dynamically composed from variables and transclusions:
|
Indexes can be dynamically composed from variables and transclusions:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -61,6 +61,14 @@ The <<.op jsontype>> operator uses multiple operands to specify the indexes of t
|
|||||||
[<jsondata>jsontype[d],[f],[2]] --> "boolean"
|
[<jsondata>jsontype[d],[f],[2]] --> "boolean"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<<.from-version "5.3.2">> 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
[<jsondata>jsontype[d],[f],[-1]] --> "null"
|
||||||
|
[<jsondata>jsontype[d],[f],[-2]] --> "boolean"
|
||||||
|
[<jsondata>jsontype[d],[f],[-4]] --> "string"
|
||||||
|
```
|
||||||
|
|
||||||
Indexes can be dynamically composed from variables and transclusions:
|
Indexes can be dynamically composed from variables and transclusions:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user