@yuneta/gobj-js 7.25.3 → 7.25.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -534,7 +534,14 @@ kw_get_dict_value(gobj, kw, path, default_value, flag)
534
534
  // kw_get_bool(gobj, {x: "false"}, "x", true, 0) → true (not a boolean: logged)
535
535
  // kw_get_bool(gobj, {x: "false"}, "x", true, KW_WILD_NUMBER) → false
536
536
  // kw_get_bool() logs a value that is not a boolean even without
537
- // KW_REQUIRED ("path MUST BE a json boolean"), as the C reader does.
537
+ // KW_REQUIRED ("path MUST BE a json boolean"), as the C reader does,
538
+ // and so do kw_get_int() / kw_get_real() for a value that is not a
539
+ // number ("path MUST BE a json integer" / "... a json real"):
540
+ // kw_get_int(gobj, {x: 3.9}, "x", 0, 0) → 3 (truncated, as C)
541
+ // kw_get_int(gobj, {x: "12"}, "x", 5, 0) → 5 (not a number: logged)
542
+ // kw_get_int(gobj, {x: "0x1F"}, "x", 5, KW_WILD_NUMBER) → 31 (strtoll base 0)
543
+ // KW_EXTRACT takes out only a value the reader answers with: a value
544
+ // of another type stays in the kw.
538
545
 
539
546
  kw_set_dict_value(gobj, kw, path, value)
540
547
  kw_set_subdict_value(gobj, kw, path, key, value)
@@ -3652,7 +3652,34 @@ function kw_get_bool(gobj, kw, path, default_value, flag) {
3652
3652
  return value;
3653
3653
  }
3654
3654
  /************************************************************
3655
- *
3655
+ * The integer at the start of a string, as C's strtoll(s, 0, 0)
3656
+ * reads it: leading spaces, a sign, then "0x" for hex, "0" for
3657
+ * octal, else decimal, up to the first character that is not a
3658
+ * digit of that base. 0 when there is no digit.
3659
+ ************************************************************/
3660
+ function strtoll_base0(s) {
3661
+ const m = /^\s*([+-]?)(0[xX][0-9a-fA-F]+|0[0-7]*|[1-9][0-9]*)/.exec(s);
3662
+ if (!m) return 0;
3663
+ let digits = m[2];
3664
+ let value;
3665
+ if (digits.length > 1 && (digits[1] === "x" || digits[1] === "X")) value = parseInt(digits.substring(2), 16);
3666
+ else if (digits[0] === "0") value = parseInt(digits, 8);
3667
+ else value = parseInt(digits, 10);
3668
+ return m[1] === "-" ? -value : value;
3669
+ }
3670
+ /************************************************************
3671
+ * As the C kw_get_int(): a number found is the answer,
3672
+ * truncated toward zero as C casts a real, and anything else
3673
+ * gives the default back (as an integer), LOGGED ("path MUST BE
3674
+ * a json integer", required or not) -- unless KW_WILD_NUMBER
3675
+ * asks to read a boolean (1/0), a string (as strtoll() with base
3676
+ * 0: "0x1F" is 31, "017" is 15, "12abc" is 12, "abc" is 0) or
3677
+ * null (0); a list or a dict is then 0, logged too. KW_EXTRACT
3678
+ * takes out only a value the reader answers with.
3679
+ * Before gobj-js 7.25.4 KW_EXTRACT deleted the value before its
3680
+ * type was looked at, a value of another type was logged only
3681
+ * with KW_REQUIRED, KW_WILD_NUMBER was ignored, and a number went
3682
+ * through parseInt(), which reads it as a string: 1e-7 gave 1.
3656
3683
  ************************************************************/
3657
3684
  function kw_get_int(gobj, kw, path, default_value, flag) {
3658
3685
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3660,6 +3687,7 @@ function kw_get_int(gobj, kw, path, default_value, flag) {
3660
3687
  const required = flag && flag & kw_flag_t.KW_REQUIRED;
3661
3688
  const create = flag && flag & kw_flag_t.KW_CREATE;
3662
3689
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3690
+ const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3663
3691
  if (v === void 0) {
3664
3692
  if (create) {
3665
3693
  let v = parseInt(default_value);
@@ -3671,18 +3699,34 @@ function kw_get_int(gobj, kw, path, default_value, flag) {
3671
3699
  }
3672
3700
  return parseInt(default_value);
3673
3701
  }
3674
- if (extract) kw_delete(gobj, kw, path);
3675
- if (!is_number(v)) {
3676
- if (required) {
3677
- log_error(`path value MUST BE a number: ${path}`);
3678
- trace_msg(kw);
3679
- }
3702
+ let value;
3703
+ if (is_number(v)) value = Math.trunc(v);
3704
+ else if (!wild) {
3705
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json integer: '${path}'`);
3706
+ trace_json(kw);
3680
3707
  return parseInt(default_value);
3708
+ } else if (is_boolean(v)) value = v ? 1 : 0;
3709
+ else if (is_string(v)) value = strtoll_base0(v);
3710
+ else if (v === null) value = 0;
3711
+ else {
3712
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
3713
+ trace_json(kw);
3714
+ return 0;
3681
3715
  }
3682
- return parseInt(v);
3716
+ if (extract) kw_delete(gobj, kw, path);
3717
+ return value;
3683
3718
  }
3684
3719
  /************************************************************
3685
- *
3720
+ * As the C kw_get_real(): a number found is the answer, and
3721
+ * anything else gives the default back (as a number), LOGGED
3722
+ * ("path MUST BE a json real", required or not) -- unless
3723
+ * KW_WILD_NUMBER asks to read a boolean (1/0), a string (as
3724
+ * parseFloat() reads it, 0 when it does not start with a number)
3725
+ * or null (0); a list or a dict is then 0, logged too.
3726
+ * KW_EXTRACT takes out only a value the reader answers with.
3727
+ * Before gobj-js 7.25.4 KW_EXTRACT deleted the value before its
3728
+ * type was looked at, a value of another type was logged only
3729
+ * with KW_REQUIRED, and KW_WILD_NUMBER was ignored.
3686
3730
  ************************************************************/
3687
3731
  function kw_get_real(gobj, kw, path, default_value, flag) {
3688
3732
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3690,6 +3734,7 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3690
3734
  const required = flag && flag & kw_flag_t.KW_REQUIRED;
3691
3735
  const create = flag && flag & kw_flag_t.KW_CREATE;
3692
3736
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3737
+ const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3693
3738
  if (v === void 0) {
3694
3739
  if (create) {
3695
3740
  let v = Number(default_value);
@@ -3701,15 +3746,24 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3701
3746
  }
3702
3747
  return Number(default_value);
3703
3748
  }
3704
- if (extract) kw_delete(gobj, kw, path);
3705
- if (!is_number(v)) {
3706
- if (required) {
3707
- log_error(`path value MUST BE a number: ${path}`);
3708
- trace_msg(kw);
3709
- }
3749
+ let value;
3750
+ if (is_number(v)) value = v;
3751
+ else if (!wild) {
3752
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json real: '${path}'`);
3753
+ trace_json(kw);
3710
3754
  return Number(default_value);
3755
+ } else if (is_boolean(v)) value = v ? 1 : 0;
3756
+ else if (is_string(v)) {
3757
+ value = parseFloat(v);
3758
+ if (Number.isNaN(value)) value = 0;
3759
+ } else if (v === null) value = 0;
3760
+ else {
3761
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
3762
+ trace_json(kw);
3763
+ return 0;
3711
3764
  }
3712
- return Number(v);
3765
+ if (extract) kw_delete(gobj, kw, path);
3766
+ return value;
3713
3767
  }
3714
3768
  /************************************************************
3715
3769
  * The default comes back AS GIVEN, as in the C kw_get_str()
@@ -3718,6 +3772,11 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3718
3772
  * TRUE: an `if(value)` on the answer took an absent key for a
3719
3773
  * present one. KW_CREATE stores a string default, and null for
3720
3774
  * any other, as C stores json_null() for a NULL default.
3775
+ * KW_EXTRACT takes out only a string (before gobj-js 7.25.4 it
3776
+ * deleted any value, and a value that was not a string was lost).
3777
+ * C refuses to extract a string at all ("Cannot extract a
3778
+ * string": its answer would point into the freed json); a JS
3779
+ * string outlives the kw, so here it is taken out.
3721
3780
  ************************************************************/
3722
3781
  function kw_get_str(gobj, kw, path, default_value, flag) {
3723
3782
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3735,7 +3794,6 @@ function kw_get_str(gobj, kw, path, default_value, flag) {
3735
3794
  }
3736
3795
  return default_value;
3737
3796
  }
3738
- if (extract) kw_delete(gobj, kw, path);
3739
3797
  if (!is_string(v)) {
3740
3798
  if (required) {
3741
3799
  log_error(`${gobj_short_name(gobj)}: path value MUST BE a string: ${path}`);
@@ -3743,6 +3801,7 @@ function kw_get_str(gobj, kw, path, default_value, flag) {
3743
3801
  }
3744
3802
  return default_value;
3745
3803
  }
3804
+ if (extract) kw_delete(gobj, kw, path);
3746
3805
  return v;
3747
3806
  }
3748
3807
  /************************************************************