RFC6901 JSON Pointer implementation in OCaml using jsont

deps

+17 -1
.gitignore
··· 1 - _build 1 + # OCaml build artifacts 2 + _build/ 3 + *.install 4 + *.merlin 5 + 6 + # Third-party sources (fetch locally with opam source) 7 + third_party/ 8 + 9 + # Editor and OS files 10 + .DS_Store 11 + *.swp 12 + *~ 13 + .vscode/ 14 + .idea/ 15 + 16 + # Opam local switch 17 + _opam/
+1
.ocamlformat
··· 1 + version=0.28.1
+53
.tangled/workflows/build.yml
··· 1 + when: 2 + - event: ["push", "pull_request"] 3 + branch: ["main"] 4 + 5 + engine: nixery 6 + 7 + dependencies: 8 + nixpkgs: 9 + - shell 10 + - stdenv 11 + - findutils 12 + - binutils 13 + - libunwind 14 + - ncurses 15 + - opam 16 + - git 17 + - gawk 18 + - gnupatch 19 + - gnum4 20 + - gnumake 21 + - gnutar 22 + - gnused 23 + - gnugrep 24 + - diffutils 25 + - gzip 26 + - bzip2 27 + - gcc 28 + - ocaml 29 + - pkg-config 30 + 31 + steps: 32 + - name: opam 33 + command: | 34 + opam init --disable-sandboxing -a -y 35 + - name: repo 36 + command: | 37 + opam repo add aoah https://tangled.org/anil.recoil.org/aoah-opam-repo.git 38 + - name: switch 39 + command: | 40 + opam install . --confirm-level=unsafe-yes --deps-only 41 + - name: build 42 + command: | 43 + opam exec -- dune build -p json-pointer 44 + - name: switch-test 45 + command: | 46 + opam install . --confirm-level=unsafe-yes --deps-only --with-test 47 + - name: test 48 + command: | 49 + opam exec -- dune runtest --verbose 50 + - name: doc 51 + command: | 52 + opam install -y odoc 53 + opam exec -- dune build @doc
+15
LICENSE.md
··· 1 + ISC License 2 + 3 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org> 4 + 5 + Permission to use, copy, modify, and distribute this software for any 6 + purpose with or without fee is hereby granted, provided that the above 7 + copyright notice and this permission notice appear in all copies. 8 + 9 + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+1
dune
··· 1 + (data_only_dirs third_party)
+13 -7
dune-project
··· 1 - (lang dune 3.17) 1 + (lang dune 3.20) 2 + 2 3 (name jsont-pointer) 3 - (version 0.1.0) 4 4 5 5 (generate_opam_files true) 6 6 7 - (source (github avsm/jsont-pointer)) 8 7 (license ISC) 9 8 (authors "Anil Madhavapeddy") 10 - (maintainers "anil@recoil.org") 9 + (homepage "https://tangled.org/@anil.recoil.org/ocaml-json-pointer") 10 + (maintainers "Anil Madhavapeddy <anil@recoil.org>") 11 + (bug_reports "https://tangled.org/@anil.recoil.org/ocaml-json-pointer/issues") 12 + (maintenance_intent "(latest)") 11 13 12 14 (package 13 15 (name jsont-pointer) 14 16 (synopsis "RFC 6901 JSON Pointer implementation for jsont") 15 - (description "This library provides RFC 6901 JSON Pointer parsing, serialization, and evaluation compatible with jsont codecs. It also provides mutation operations suitable for implementing RFC 6902 JSON Patch.") 17 + (description 18 + "This library provides RFC 6901 JSON Pointer parsing, serialization, \ 19 + and evaluation compatible with jsont codecs. It also provides mutation \ 20 + operations suitable for implementing RFC 6902 JSON Patch.") 16 21 (depends 17 - (ocaml (>= 4.14.0)) 18 - (jsont (>= 0.2.0)))) 22 + ocaml 23 + (jsont (>= 0.2.0)) 24 + (odoc :with-doc)))
+6 -7
jsont-pointer.opam
··· 1 1 # This file is generated by dune, edit dune-project instead 2 2 opam-version: "2.0" 3 - version: "0.1.0" 4 3 synopsis: "RFC 6901 JSON Pointer implementation for jsont" 5 4 description: 6 5 "This library provides RFC 6901 JSON Pointer parsing, serialization, and evaluation compatible with jsont codecs. It also provides mutation operations suitable for implementing RFC 6902 JSON Patch." 7 - maintainer: ["anil@recoil.org"] 6 + maintainer: ["Anil Madhavapeddy <anil@recoil.org>"] 8 7 authors: ["Anil Madhavapeddy"] 9 8 license: "ISC" 10 - homepage: "https://github.com/avsm/jsont-pointer" 11 - bug-reports: "https://github.com/avsm/jsont-pointer/issues" 9 + homepage: "https://tangled.org/@anil.recoil.org/ocaml-json-pointer" 10 + bug-reports: "https://tangled.org/@anil.recoil.org/ocaml-json-pointer/issues" 12 11 depends: [ 13 - "dune" {>= "3.17"} 14 - "ocaml" {>= "4.14.0"} 12 + "dune" {>= "3.20"} 13 + "ocaml" 15 14 "jsont" {>= "0.2.0"} 16 15 "odoc" {with-doc} 17 16 ] ··· 29 28 "@doc" {with-doc} 30 29 ] 31 30 ] 32 - dev-repo: "git+https://github.com/avsm/jsont-pointer.git" 31 + x-maintenance-intent: ["(latest)"]
+123 -173
src/jsont_pointer.ml
··· 1 1 (*--------------------------------------------------------------------------- 2 - Copyright (c) 2024 The jsont programmers. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 5 6 6 (* Token escaping/unescaping per RFC 6901 Section 3-4 *) 7 7 module Token = struct ··· 167 167 168 168 let of_string_result s = 169 169 try Ok (of_string s) 170 - with Jsont.Error (_, _, _) as e -> 171 - Error (Jsont.Error.to_string (match e with Jsont.Error e -> e | _ -> assert false)) 170 + with Jsont.Error e -> Error (Jsont.Error.to_string e) 172 171 173 172 (* URI fragment percent-decoding *) 174 173 let hex_value c = ··· 204 203 205 204 let of_uri_fragment_result s = 206 205 try Ok (of_uri_fragment s) 207 - with Jsont.Error (_, _, _) as e -> 208 - Error (Jsont.Error.to_string (match e with Jsont.Error e -> e | _ -> assert false)) 206 + with Jsont.Error e -> Error (Jsont.Error.to_string e) 209 207 210 208 (* Serialization *) 211 209 ··· 272 270 | Segment.End, Segment.End -> 0 273 271 274 272 let equal p1 p2 = 275 - List.length p1 = List.length p2 && 276 - List.for_all2 segment_equal p1 p2 273 + List.equal segment_equal p1 p2 277 274 278 275 let compare p1 p2 = 279 - let rec loop l1 l2 = match l1, l2 with 280 - | [], [] -> 0 281 - | [], _ -> -1 282 - | _, [] -> 1 283 - | h1 :: t1, h2 :: t2 -> 284 - let c = segment_compare h1 h2 in 285 - if c <> 0 then c else loop t1 t2 286 - in 287 - loop p1 p2 276 + List.compare segment_compare p1 p2 288 277 289 278 (* Path conversion *) 290 279 ··· 384 373 (* Mutation helpers *) 385 374 386 375 let set_member name value (obj : Jsont.object') : Jsont.object' = 387 - let found = ref false in 388 - let result = List.map (fun ((n, m), v) -> 389 - if String.equal n name then begin 390 - found := true; 391 - ((n, m), value) 392 - end else 393 - ((n, m), v) 394 - ) obj in 395 - if !found then result 396 - else obj @ [((name, Jsont.Meta.none), value)] 376 + let rec loop found acc = function 377 + | [] -> 378 + if found then List.rev acc 379 + else List.rev_append acc [((name, Jsont.Meta.none), value)] 380 + | ((n, m), _) :: rest when String.equal n name -> 381 + loop true (((n, m), value) :: acc) rest 382 + | mem :: rest -> 383 + loop found (mem :: acc) rest 384 + in 385 + loop false [] obj 397 386 398 387 let remove_member name (obj : Jsont.object') : Jsont.object' = 399 388 List.filter (fun ((n, _), _) -> not (String.equal n name)) obj 400 389 401 390 let insert_at n value lst = 402 391 let rec loop i acc = function 403 - | [] when i = n -> List.rev (value :: acc) 404 - | [] -> List.rev acc (* shouldn't happen if n is valid *) 405 - | h :: t when i = n -> List.rev_append (value :: acc) (h :: t) 392 + | rest when i = n -> List.rev_append acc (value :: rest) 393 + | [] -> List.rev acc 406 394 | h :: t -> loop (i + 1) (h :: acc) t 407 395 in 408 396 loop 0 [] lst 409 397 410 398 let remove_at n lst = 411 - let rec loop i acc = function 412 - | [] -> List.rev acc 413 - | _ :: t when i = n -> List.rev_append acc t 414 - | h :: t -> loop (i + 1) (h :: acc) t 415 - in 416 - loop 0 [] lst 399 + List.filteri (fun i _ -> i <> n) lst 417 400 418 401 let replace_at n value lst = 419 402 List.mapi (fun i v -> if i = n then value else v) lst 420 403 404 + (* Common navigation for mutation operations *) 405 + 406 + let navigate_to_child token json ~on_object ~on_array ~on_other = 407 + match json with 408 + | Jsont.Object (members, meta) -> on_object members meta 409 + | Jsont.Array (elements, meta) -> 410 + (match Token.is_valid_array_index token with 411 + | Some n -> on_array elements meta n 412 + | None -> 413 + Jsont.Error.msgf (Jsont.Json.meta json) 414 + "JSON Pointer: invalid array index '%s'" token) 415 + | _ -> on_other () 416 + 417 + let error_member_not_found json token = 418 + Jsont.Error.msgf (Jsont.Json.meta json) "JSON Pointer: member '%s' not found" token 419 + 420 + let error_index_out_of_bounds json n = 421 + Jsont.Error.msgf (Jsont.Json.meta json) "JSON Pointer: index %d out of bounds" n 422 + 423 + let error_cannot_navigate json = 424 + Jsont.Error.msgf (Jsont.Json.meta json) 425 + "JSON Pointer: cannot navigate through %s" (json_sort_string json) 426 + 421 427 (* Mutation: set *) 422 428 423 429 let rec eval_set p value json = ··· 425 431 | [] -> value 426 432 | [Segment.End] -> 427 433 (match json with 428 - | Jsont.Array (elements, meta) -> 429 - Jsont.Array (elements @ [value], meta) 434 + | Jsont.Array (elements, meta) -> Jsont.Array (elements @ [value], meta) 430 435 | _ -> 431 436 Jsont.Error.msgf (Jsont.Json.meta json) 432 437 "JSON Pointer: '-' can only be used on arrays, got %s" ··· 435 440 Jsont.Error.msgf (Jsont.Json.meta json) 436 441 "JSON Pointer: '-' (end marker) refers to nonexistent array element" 437 442 | [Segment.Token token] -> 438 - (match json with 439 - | Jsont.Object (members, meta) -> 440 - if Option.is_some (get_member token members) then 441 - Jsont.Object (set_member token value members, meta) 442 - else 443 - Jsont.Error.msgf (Jsont.Json.meta json) 444 - "JSON Pointer: member '%s' not found for set" token 445 - | Jsont.Array (elements, meta) -> 446 - (match Token.is_valid_array_index token with 447 - | Some n when n >= 0 && n < List.length elements -> 443 + navigate_to_child token json 444 + ~on_object:(fun members meta -> 445 + if Option.is_some (get_member token members) then 446 + Jsont.Object (set_member token value members, meta) 447 + else 448 + Jsont.Error.msgf (Jsont.Json.meta json) 449 + "JSON Pointer: member '%s' not found for set" token) 450 + ~on_array:(fun elements meta n -> 451 + if n < List.length elements then 448 452 Jsont.Array (replace_at n value elements, meta) 449 - | Some n -> 450 - Jsont.Error.msgf (Jsont.Json.meta json) 451 - "JSON Pointer: index %d out of bounds for set" n 452 - | None -> 453 + else 453 454 Jsont.Error.msgf (Jsont.Json.meta json) 454 - "JSON Pointer: invalid array index '%s'" token) 455 - | _ -> 456 - Jsont.Error.msgf (Jsont.Json.meta json) 457 - "JSON Pointer: cannot set in %s" (json_sort_string json)) 455 + "JSON Pointer: index %d out of bounds for set" n) 456 + ~on_other:(fun () -> 457 + Jsont.Error.msgf (Jsont.Json.meta json) 458 + "JSON Pointer: cannot set in %s" (json_sort_string json)) 458 459 | Segment.Token token :: rest -> 459 - (match json with 460 - | Jsont.Object (members, meta) -> 461 - (match get_member token members with 460 + navigate_to_child token json 461 + ~on_object:(fun members meta -> 462 + match get_member token members with 462 463 | Some (_, child) -> 463 464 Jsont.Object (set_member token (eval_set rest value child) members, meta) 464 - | None -> 465 - Jsont.Error.msgf (Jsont.Json.meta json) 466 - "JSON Pointer: member '%s' not found" token) 467 - | Jsont.Array (elements, meta) -> 468 - (match Token.is_valid_array_index token with 469 - | Some n -> 470 - (match get_nth n elements with 471 - | Some child -> 472 - Jsont.Array (replace_at n (eval_set rest value child) elements, meta) 473 - | None -> 474 - Jsont.Error.msgf (Jsont.Json.meta json) 475 - "JSON Pointer: index %d out of bounds" n) 476 - | None -> 477 - Jsont.Error.msgf (Jsont.Json.meta json) 478 - "JSON Pointer: invalid array index '%s'" token) 479 - | _ -> 480 - Jsont.Error.msgf (Jsont.Json.meta json) 481 - "JSON Pointer: cannot navigate through %s" (json_sort_string json)) 465 + | None -> error_member_not_found json token) 466 + ~on_array:(fun elements meta n -> 467 + match get_nth n elements with 468 + | Some child -> 469 + Jsont.Array (replace_at n (eval_set rest value child) elements, meta) 470 + | None -> error_index_out_of_bounds json n) 471 + ~on_other:(fun () -> error_cannot_navigate json) 482 472 483 473 let set p json ~value = eval_set p value json 484 474 ··· 489 479 | [] -> value 490 480 | [Segment.End] -> 491 481 (match json with 492 - | Jsont.Array (elements, meta) -> 493 - Jsont.Array (elements @ [value], meta) 482 + | Jsont.Array (elements, meta) -> Jsont.Array (elements @ [value], meta) 494 483 | _ -> 495 484 Jsont.Error.msgf (Jsont.Json.meta json) 496 485 "JSON Pointer: '-' can only be used on arrays, got %s" ··· 499 488 Jsont.Error.msgf (Jsont.Json.meta json) 500 489 "JSON Pointer: '-' in non-final position" 501 490 | [Segment.Token token] -> 502 - (match json with 503 - | Jsont.Object (members, meta) -> 504 - (* For objects, add/replace member *) 505 - Jsont.Object (set_member token value members, meta) 506 - | Jsont.Array (elements, meta) -> 507 - (* For arrays, insert at index *) 508 - (match Token.is_valid_array_index token with 509 - | Some n -> 510 - let len = List.length elements in 511 - if n >= 0 && n <= len then 512 - Jsont.Array (insert_at n value elements, meta) 513 - else 514 - Jsont.Error.msgf (Jsont.Json.meta json) 515 - "JSON Pointer: index %d out of bounds for add (array has %d elements)" 516 - n len 517 - | None -> 491 + navigate_to_child token json 492 + ~on_object:(fun members meta -> 493 + Jsont.Object (set_member token value members, meta)) 494 + ~on_array:(fun elements meta n -> 495 + let len = List.length elements in 496 + if n <= len then 497 + Jsont.Array (insert_at n value elements, meta) 498 + else 518 499 Jsont.Error.msgf (Jsont.Json.meta json) 519 - "JSON Pointer: invalid array index '%s'" token) 520 - | _ -> 521 - Jsont.Error.msgf (Jsont.Json.meta json) 522 - "JSON Pointer: cannot add to %s" (json_sort_string json)) 500 + "JSON Pointer: index %d out of bounds for add (array has %d elements)" 501 + n len) 502 + ~on_other:(fun () -> 503 + Jsont.Error.msgf (Jsont.Json.meta json) 504 + "JSON Pointer: cannot add to %s" (json_sort_string json)) 523 505 | Segment.Token token :: rest -> 524 - (match json with 525 - | Jsont.Object (members, meta) -> 526 - (match get_member token members with 506 + navigate_to_child token json 507 + ~on_object:(fun members meta -> 508 + match get_member token members with 527 509 | Some (_, child) -> 528 510 Jsont.Object (set_member token (eval_add rest value child) members, meta) 529 - | None -> 530 - Jsont.Error.msgf (Jsont.Json.meta json) 531 - "JSON Pointer: member '%s' not found" token) 532 - | Jsont.Array (elements, meta) -> 533 - (match Token.is_valid_array_index token with 534 - | Some n -> 535 - (match get_nth n elements with 536 - | Some child -> 537 - Jsont.Array (replace_at n (eval_add rest value child) elements, meta) 538 - | None -> 539 - Jsont.Error.msgf (Jsont.Json.meta json) 540 - "JSON Pointer: index %d out of bounds" n) 541 - | None -> 542 - Jsont.Error.msgf (Jsont.Json.meta json) 543 - "JSON Pointer: invalid array index '%s'" token) 544 - | _ -> 545 - Jsont.Error.msgf (Jsont.Json.meta json) 546 - "JSON Pointer: cannot navigate through %s" (json_sort_string json)) 511 + | None -> error_member_not_found json token) 512 + ~on_array:(fun elements meta n -> 513 + match get_nth n elements with 514 + | Some child -> 515 + Jsont.Array (replace_at n (eval_add rest value child) elements, meta) 516 + | None -> error_index_out_of_bounds json n) 517 + ~on_other:(fun () -> error_cannot_navigate json) 547 518 548 519 let add p json ~value = eval_add p value json 549 520 ··· 552 523 let rec eval_remove p json = 553 524 match p with 554 525 | [] -> 555 - Jsont.Error.msgf Jsont.Meta.none 556 - "JSON Pointer: cannot remove root document" 526 + Jsont.Error.msgf Jsont.Meta.none "JSON Pointer: cannot remove root document" 557 527 | [Segment.End] -> 558 528 Jsont.Error.msgf (Jsont.Json.meta json) 559 529 "JSON Pointer: '-' refers to nonexistent element" ··· 561 531 Jsont.Error.msgf (Jsont.Json.meta json) 562 532 "JSON Pointer: '-' in non-final position" 563 533 | [Segment.Token token] -> 564 - (match json with 565 - | Jsont.Object (members, meta) -> 566 - if Option.is_some (get_member token members) then 567 - Jsont.Object (remove_member token members, meta) 568 - else 569 - Jsont.Error.msgf (Jsont.Json.meta json) 570 - "JSON Pointer: member '%s' not found for remove" token 571 - | Jsont.Array (elements, meta) -> 572 - (match Token.is_valid_array_index token with 573 - | Some n when n >= 0 && n < List.length elements -> 534 + navigate_to_child token json 535 + ~on_object:(fun members meta -> 536 + if Option.is_some (get_member token members) then 537 + Jsont.Object (remove_member token members, meta) 538 + else 539 + Jsont.Error.msgf (Jsont.Json.meta json) 540 + "JSON Pointer: member '%s' not found for remove" token) 541 + ~on_array:(fun elements meta n -> 542 + if n < List.length elements then 574 543 Jsont.Array (remove_at n elements, meta) 575 - | Some n -> 544 + else 576 545 Jsont.Error.msgf (Jsont.Json.meta json) 577 - "JSON Pointer: index %d out of bounds for remove" n 578 - | None -> 579 - Jsont.Error.msgf (Jsont.Json.meta json) 580 - "JSON Pointer: invalid array index '%s'" token) 581 - | _ -> 582 - Jsont.Error.msgf (Jsont.Json.meta json) 583 - "JSON Pointer: cannot remove from %s" (json_sort_string json)) 546 + "JSON Pointer: index %d out of bounds for remove" n) 547 + ~on_other:(fun () -> 548 + Jsont.Error.msgf (Jsont.Json.meta json) 549 + "JSON Pointer: cannot remove from %s" (json_sort_string json)) 584 550 | Segment.Token token :: rest -> 585 - (match json with 586 - | Jsont.Object (members, meta) -> 587 - (match get_member token members with 551 + navigate_to_child token json 552 + ~on_object:(fun members meta -> 553 + match get_member token members with 588 554 | Some (_, child) -> 589 555 Jsont.Object (set_member token (eval_remove rest child) members, meta) 590 - | None -> 591 - Jsont.Error.msgf (Jsont.Json.meta json) 592 - "JSON Pointer: member '%s' not found" token) 593 - | Jsont.Array (elements, meta) -> 594 - (match Token.is_valid_array_index token with 595 - | Some n -> 596 - (match get_nth n elements with 597 - | Some child -> 598 - Jsont.Array (replace_at n (eval_remove rest child) elements, meta) 599 - | None -> 600 - Jsont.Error.msgf (Jsont.Json.meta json) 601 - "JSON Pointer: index %d out of bounds" n) 602 - | None -> 603 - Jsont.Error.msgf (Jsont.Json.meta json) 604 - "JSON Pointer: invalid array index '%s'" token) 605 - | _ -> 606 - Jsont.Error.msgf (Jsont.Json.meta json) 607 - "JSON Pointer: cannot navigate through %s" (json_sort_string json)) 556 + | None -> error_member_not_found json token) 557 + ~on_array:(fun elements meta n -> 558 + match get_nth n elements with 559 + | Some child -> 560 + Jsont.Array (replace_at n (eval_remove rest child) elements, meta) 561 + | None -> error_index_out_of_bounds json n) 562 + ~on_other:(fun () -> error_cannot_navigate json) 608 563 609 564 let remove p json = eval_remove p json 610 565 ··· 617 572 618 573 (* Mutation: move *) 619 574 620 - let is_prefix_of p1 p2 = 621 - let rec loop l1 l2 = match l1, l2 with 622 - | [], _ -> true 623 - | _, [] -> false 624 - | h1 :: t1, h2 :: t2 -> 625 - segment_equal h1 h2 && loop t1 t2 626 - in 627 - loop p1 p2 575 + let rec is_prefix_of p1 p2 = 576 + match p1, p2 with 577 + | [], _ -> true 578 + | _, [] -> false 579 + | h1 :: t1, h2 :: t2 -> segment_equal h1 h2 && is_prefix_of t1 t2 628 580 629 581 let move ~from ~path json = 630 582 (* Check for cycle: path cannot be a proper prefix of from *) ··· 644 596 (* Mutation: test *) 645 597 646 598 let test p json ~expected = 647 - match find p json with 648 - | None -> false 649 - | Some value -> Jsont.Json.equal value expected 599 + Option.fold ~none:false ~some:(Jsont.Json.equal expected) (find p json) 650 600 651 601 (* Jsont codec *) 652 602
+3 -3
src/jsont_pointer.mli
··· 1 1 (*--------------------------------------------------------------------------- 2 - Copyright (c) 2024 The jsont programmers. All rights reserved. 3 - SPDX-License-Identifier: ISC 4 - ---------------------------------------------------------------------------*) 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 5 6 6 (** RFC 6901 JSON Pointer implementation for jsont. 7 7