@@ -31,8 +31,6 @@ npm install jsonpath-js
3131
3232## Usage
3333
34- ### Basic Query Operations
35-
3634``` ts
3735import { JSONPathJS } from " jsonpath-js" ;
3836
@@ -56,256 +54,6 @@ const pathResult = query.paths({
5654console .log (pathResult );
5755```
5856
59- ### Node Modification Operations
60-
61- The library provides three powerful methods for modifying JSON data in-place using JSONPath queries:
62-
63- #### ` update(json, callback) ` - Callback-based Modification
64-
65- Modifies matched nodes using a callback function that receives the current value and modification context.
66-
67- ``` ts
68- const data = {
69- users: [
70- { name: " John Doe" , age: 30 , guid: " abc123" },
71- { name: " Jane Doe" , age: 25 , guid: " def456" }
72- ]
73- };
74-
75- const query = new JSONPathJS (" $.users[*]" );
76-
77- // Remove 'guid' property from all users
78- const modified = query .update (data , (value , context ) => {
79- const { guid, ... userWithoutGuid } = value ;
80- return userWithoutGuid ;
81- });
82-
83- // Transform values with access to parent and key
84- const normalized = query .update (data , (value , context ) => {
85- return {
86- ... value ,
87- name: value .name .toUpperCase (),
88- index: context .key , // Array index or object key
89- parentPath: context .parent .path
90- };
91- });
92- ```
93-
94- ** Callback Signature:**
95- ``` ts
96- type UpdateCallback <T = Json > = (
97- value : T ,
98- context : {
99- key: string | number ; // Property key or array index
100- parent: ModifiableNode ; // Parent node with modification capabilities
101- path: string ; // Full JSONPath to this node
102- root: Json ; // Reference to root document
103- }
104- ) => T | undefined ; // Return undefined to delete the node
105- ```
106-
107- #### ` parents(json) ` - Parent-Child Context Access
108-
109- Returns nodes with their parent context, enabling complex modification patterns.
110-
111- ``` ts
112- const data = {
113- document: {
114- sections: [
115- { title: " Introduction" , content: " ..." , metadata: { id: 1 } },
116- { title: " Conclusion" , content: " ..." , metadata: { id: 2 } }
117- ]
118- }
119- };
120-
121- const query = new JSONPathJS (" $.document.sections[*].metadata" );
122- const parentNodes = query .parents (data );
123-
124- parentNodes .forEach (node => {
125- // Access parent section to make contextual modifications
126- const section = node .parent .value ;
127-
128- // Modify based on parent data
129- if (section .title === " Introduction" ) {
130- node .parent .update (currentSection => ({
131- ... currentSection ,
132- metadata: { ... node .value , priority: " high" }
133- }));
134- }
135-
136- // Remove metadata entirely for conclusions
137- if (section .title === " Conclusion" ) {
138- node .delete (); // Remove this metadata node
139- }
140- });
141- ```
142-
143- ** Return Type:**
144- ``` ts
145- type ParentNode = {
146- value: Json ; // Current node value
147- path: string ; // JSONPath to this node
148- key: string | number ; // Property key or array index
149- parent: ModifiableNode ; // Parent with modification methods
150- root: Json ; // Reference to root document
151-
152- // Modification methods
153- update(callback : UpdateCallback ): void ;
154- delete(): void ;
155- replace(newValue : Json ): void ;
156- };
157- ```
158-
159- #### ` pathSegments(json) ` - Granular Path Access
160-
161- Provides detailed path information for precise navigation and modification.
162-
163- ``` ts
164- const data = {
165- config: {
166- database: {
167- connections: {
168- primary: { host: " localhost" , port: 5432 },
169- secondary: { host: " backup.db" , port: 5432 }
170- }
171- }
172- }
173- };
174-
175- const query = new JSONPathJS (" $.config.database.connections.*" );
176- const segments = query .pathSegments (data );
177-
178- segments .forEach (segment => {
179- console .log ({
180- value: segment .value ,
181- fullPath: segment .path , // "$['config']['database']['connections']['primary']"
182- segments: segment .segments , // ["config", "database", "connections", "primary"]
183- depth: segment .depth , // 4
184- isLeaf: segment .isLeaf , // true/false
185- ancestors: segment .ancestors // Path to each ancestor node
186- });
187-
188- // Modify based on path depth or segment names
189- if (segment .segments .includes (" primary" )) {
190- segment .update (conn => ({ ... conn , ssl: true }));
191- }
192- });
193- ```
194-
195- ** Return Type:**
196- ``` ts
197- type PathSegment = {
198- value: Json ; // Node value
199- path: string ; // Full JSONPath string
200- segments: string []; // Array of path segments
201- depth: number ; // Depth level (0 = root)
202- isLeaf: boolean ; // True if node has no children
203- ancestors: AncestorNode []; // Array of ancestor nodes
204-
205- // Modification methods
206- update(callback : UpdateCallback ): void ;
207- delete(): void ;
208- replace(newValue : Json ): void ;
209-
210- // Navigation methods
211- getAncestor(depth : number ): AncestorNode | undefined ;
212- getSegment(index : number ): string | undefined ;
213- };
214-
215- type AncestorNode = {
216- value: Json ;
217- path: string ;
218- segment: string ;
219- depth: number ;
220- };
221- ```
222-
223- #### Modifiable Node Interface
224-
225- All modification methods return nodes that implement the ` ModifiableNode ` interface:
226-
227- ``` ts
228- interface ModifiableNode {
229- value: Json ;
230- path: string ;
231-
232- // Core modification methods
233- update(callback : UpdateCallback ): void ;
234- replace(newValue : Json ): void ;
235- delete(): void ;
236-
237- // Type checking
238- isArray(): boolean ;
239- isObject(): boolean ;
240- isPrimitive(): boolean ;
241-
242- // Array-specific methods (when isArray() is true)
243- push(value : Json ): void ;
244- splice(start : number , deleteCount ? : number , ... items : Json []): void ;
245-
246- // Object-specific methods (when isObject() is true)
247- set(key : string , value : Json ): void ;
248- unset(key : string ): void ;
249- keys(): string [];
250- }
251- ```
252-
253- #### Advanced Usage Examples
254-
255- ** Document Transformation:**
256- ``` ts
257- const document = {
258- metadata: { version: " 1.0" , guid: " old-guid" },
259- content: {
260- sections: [
261- { id: 1 , text: " Hello" , tags: [" intro" , " temp" ] },
262- { id: 2 , text: " World" , tags: [" conclusion" , " temp" ] }
263- ]
264- }
265- };
266-
267- // Remove all temporary tags and normalize structure
268- const query = new JSONPathJS (" $..tags" );
269- query .update (document , (tags , context ) => {
270- return tags .filter (tag => tag !== " temp" );
271- });
272-
273- // Remove empty tag arrays using parent access
274- const parentQuery = new JSONPathJS (" $.content.sections[*]" );
275- parentQuery .parents (document ).forEach (node => {
276- if (node .value .tags && node .value .tags .length === 0 ) {
277- delete node .value .tags ;
278- }
279- });
280- ```
281-
282- ** Conditional Deletion:**
283- ``` ts
284- const inventory = {
285- products: [
286- { name: " Widget A" , stock: 0 , discontinued: true },
287- { name: " Widget B" , stock: 50 , discontinued: false },
288- { name: " Widget C" , stock: 0 , discontinued: false }
289- ]
290- };
291-
292- // Remove discontinued products
293- const query = new JSONPathJS (" $.products[?@.discontinued == true]" );
294- query .update (inventory , () => undefined ); // undefined = delete
295-
296- // Update low stock products using path context
297- const lowStockQuery = new JSONPathJS (" $.products[?@.stock == 0]" );
298- lowStockQuery .pathSegments (inventory ).forEach (segment => {
299- if (! segment .value .discontinued ) {
300- segment .update (product => ({
301- ... product ,
302- status: " out-of-stock" ,
303- restockDate: new Date ().toISOString ()
304- }));
305- }
306- });
307- ```
308-
30957## Contributing
31058
31159Please read the [ contributing guide] ( /docs/CONTRIBUTING.md ) .
0 commit comments