@@ -15,31 +15,83 @@ export const suggestions = [
1515 {
1616 'description' : 'access a specific property' ,
1717 'value' : '.' ,
18+ 'setCarretAt' : 1 ,
1819 'scopes' : [ 'array' , 'object' ]
1920 } ,
2021 {
2122 'description' : 'search recursively for a property' ,
2223 'value' : '..' ,
24+ 'setCarretAt' : 2 ,
2325 'scopes' : [ 'array' , 'object' ]
2426 } ,
27+ {
28+ 'description' : 'filter a collection' ,
29+ 'value' : '?()' ,
30+ 'setCarretAt' : 2 ,
31+ 'scopes' : [ '[]' ]
32+ } ,
33+ {
34+ 'description' : 'filter a collection - by one of it`s item value' ,
35+ 'value' : '@.' ,
36+ 'setCarretAt' : 2 ,
37+ 'scopes' : [ '?()' , '===' ]
38+ } ,
39+ {
40+ 'value' : ' ' ,
41+ 'setCarretAt' : 1 ,
42+ 'scopes' : [ ]
43+ } ,
44+ {
45+ 'description' : 'equals' ,
46+ 'value' : '===' ,
47+ 'scopes' : [ ' ' ]
48+ } ,
49+ {
50+ 'description' : 'lesser' ,
51+ 'value' : '<' ,
52+ 'scopes' : [ ' ' ]
53+ } ,
54+ {
55+ 'description' : 'lesser or equals' ,
56+ 'value' : '<=' ,
57+ 'scopes' : [ ' ' ]
58+ } ,
59+ {
60+ 'description' : 'greater' ,
61+ 'value' : '>' ,
62+ 'scopes' : [ ' ' ]
63+ } ,
64+ {
65+ 'description' : 'greater or equals' ,
66+ 'value' : '>=' ,
67+ 'scopes' : [ ' ' ]
68+ } ,
69+ {
70+ 'description' : 'and' ,
71+ 'value' : '&&' ,
72+ 'scopes' : [ ' ' ]
73+ } ,
74+ {
75+ 'description' : 'or' ,
76+ 'value' : '||' ,
77+ 'scopes' : [ ' ' ]
78+ } ,
2579 {
2680 'value' : 'all_properties' ,
2781 'scopes' : [ '.' ]
2882 } ,
2983 {
30- 'value' : 'all_properties_recursively ' ,
31- 'scopes' : [ '. .' ]
84+ 'value' : 'all_properties_of_parent_array ' ,
85+ 'scopes' : [ '@ .' ]
3286 } ,
3387 {
34- 'description' : 'filter a collection' ,
35- 'value' : '?(@)' ,
36- 'setCarretAt' : 3 ,
37- 'scopes' : [ '[]' ]
88+ 'value' : 'all_properties_recursively' ,
89+ 'scopes' : [ '..' ]
3890 } ,
3991 {
4092 'description' : 'select an item by it\'s index relatively to the size of the collection' ,
4193 'value' : '(@.length-1)' ,
42- 'setCarretAt' : 10 ,
94+ 'setCarretAt' : 12 ,
4395 'scopes' : [ '[]' ]
4496 } ,
4597 {
@@ -67,6 +119,9 @@ export const suggestions = [
67119
68120export const getSuggestions = ( jsonPath , caretPosition , jsonToTestAgainst ) => {
69121 try {
122+ if ( caretPosition !== jsonPath . length ) {
123+ throw new Error ( 'Force to eval options according to carret positions' ) ;
124+ }
70125 const filteredJson = jp . query ( jsonToTestAgainst , jsonPath ) [ 0 ] ;
71126 if ( Array . isArray ( filteredJson ) ) {
72127 return suggestions . filter ( s => s . scopes . includes ( 'array' ) ) ;
@@ -83,38 +138,62 @@ export const getSuggestions = (jsonPath, caretPosition, jsonToTestAgainst) => {
83138 return [ ...additionalSuggestions . filter ( s => s . value . includes ( filterSuggestionJsonPath ) && s . value !== filterSuggestionJsonPath ) , ...suggestions . filter ( s => s . scopes . includes ( 'object' ) ) ] ;
84139 }
85140 } catch ( e ) {
86- const appliableScopes = suggestions . filter ( s => jsonPath . endsWith ( s . value ) ) ;
141+ const appliableScopes = suggestions . filter ( s => {
142+ if ( typeof s . setCarretAt !== undefined ) {
143+ const valueToBeBeforeCarret = s . value . substring ( 0 , s . setCarretAt ) ;
144+ const valueToBeAfterCarret = s . value . substring ( s . setCarretAt ) ;
145+ const jsonPathPartBeforeCarret = jsonPath . substring ( 0 , caretPosition ) ;
146+ const jsonPathPartAfterCarret = jsonPath . substring ( caretPosition ) ;
147+
148+ return jsonPathPartBeforeCarret . endsWith ( valueToBeBeforeCarret ) && jsonPathPartAfterCarret . startsWith ( valueToBeAfterCarret ) ;
149+ }
150+
151+ return jsonPath . endsWith ( s . value ) ;
152+ } ) ;
87153 return guessSuggestionsFromScopes ( appliableScopes , caretPosition , jsonPath , jsonToTestAgainst ) ;
88154 }
89155} ;
90156
91157const guessSuggestionsFromScopes = ( scopes , carretPosition , jsonPath , jsonToTestAgainst ) => {
92- if ( scopes . length > 0 ) {
158+ if ( ! scopes || scopes . length === 0 ) {
159+ return [ ] ;
160+ }
161+
162+ return flatten ( scopes . map ( appliableScope => {
93163 // Check if there is any conditions on carret position for appliableScope
94- const appliableScope = scopes [ scopes . length - 1 ] ;
95164 if ( appliableScope . setCarretAt ) {
96165 if ( jsonPath . length - carretPosition === appliableScope . setCarretAt ) {
97- return suggestions . filter ( s => s . scopes . includes ( appliableScope . value ) ) ;
166+ return flatten ( evalAllProperties (
167+ suggestions . filter ( s => s . scopes . includes ( appliableScope . value ) ) ,
168+ carretPosition ,
169+ jsonPath ,
170+ jsonToTestAgainst
171+ ) ) || [ ] ;
98172 } else {
99- return [ ] ;
173+ return flatten ( evalAllProperties (
174+ suggestions . filter ( s => s . scopes . includes ( appliableScope . value ) ) ,
175+ carretPosition ,
176+ jsonPath ,
177+ jsonToTestAgainst
178+ ) ) || [ ] ;
100179 }
101180 } else {
102181 return flatten ( evalAllProperties (
103182 suggestions . filter ( s => s . scopes . includes ( appliableScope . value ) ) ,
183+ carretPosition ,
104184 jsonPath ,
105185 jsonToTestAgainst
106186 ) ) ;
107187 }
108- } else {
109- return [ ] ;
110- }
188+ } ) ) ;
111189} ;
112190
113191const flatten = ( arr ) => {
114192 return [ ] . concat ( ...arr ) ;
115193} ;
116194
117- export const evalAllProperties = ( suggestions , jsonPath , jsonToTestAgainst ) => {
195+ export const evalAllProperties = ( suggestions , carretPosition , jsonPath , jsonToTestAgainst ) => {
196+ //console.log({suggestions, carretPosition, jsonPath, jsonToTestAgainst})
118197 return suggestions . map ( s => {
119198 if ( s . value === 'all_properties' ) {
120199 const jsonPathToObject = jsonPath . substring ( 0 , jsonPath . length - 1 ) ;
@@ -149,6 +228,28 @@ export const evalAllProperties = (suggestions, jsonPath, jsonToTestAgainst) => {
149228 // ignore error
150229 return [ ] ;
151230 }
231+ } else if ( s . value === 'all_properties_of_parent_array' ) {
232+ //"$.d[1].df.f[?(@.t === 'tf' && @.{cursorHere}truc === 'd' && @.defined)]"
233+ // 1. split at cursor, take first part
234+ //"$.d[1].df.f[?(@.t === 'tf' && @."
235+ const splittedJsonPathAtCursor = jsonPath . substring ( 0 , carretPosition ) ;
236+ // 2. Search for last "[" index, then split at this index, take first part
237+ //"$.d[1].df.f"
238+ const lastIndexOfOpennedArray = splittedJsonPathAtCursor . lastIndexOf ( '[' ) ;
239+ const jsonPathToParentArray = splittedJsonPathAtCursor . substring ( 0 , lastIndexOfOpennedArray ) ;
240+ // 3. We then want to evaluate all unique properties in f array at first level
241+ try {
242+ const filteredJson = jp . query ( jsonToTestAgainst , jsonPathToParentArray ) [ 0 ] ;
243+ const properties = Array . from ( new Set ( getAllPropertiesAtFirstLevel ( filteredJson ) ) ) ;
244+ return properties . map ( p => ( {
245+ value : p + ' ' ,
246+ setCarretAt : p . length - 1 ,
247+ description : 'property' ,
248+ scopes : [ 'object' ]
249+ } ) ) ;
250+ } catch ( e ) {
251+ return [ ] ;
252+ }
152253 } else {
153254 return s ;
154255 }
@@ -169,4 +270,17 @@ const getAllPropertiesRecursively = (objectOrArray) => {
169270 } else {
170271 return null ;
171272 }
273+ } ;
274+
275+ const getAllPropertiesAtFirstLevel = ( objectOrArray ) => {
276+ if ( Array . isArray ( objectOrArray ) ) {
277+ return flatten ( objectOrArray . map ( arrayEntry => {
278+ return getAllPropertiesAtFirstLevel ( arrayEntry ) ;
279+ } ) ) . filter ( p => p !== null && typeof p !== 'undefined' ) ;
280+ } else if ( typeof objectOrArray === 'object' ) {
281+ const keys = Object . keys ( objectOrArray ) ;
282+ return flatten ( keys ) . filter ( p => p !== null && typeof p !== 'undefined' ) ;
283+ } else {
284+ return null ;
285+ }
172286} ;
0 commit comments