@yuneta/gobj-js 7.25.2 → 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
@@ -531,8 +531,17 @@ kw_get_dict_value(gobj, kw, path, default_value, flag)
531
531
  // the default AS GIVEN otherwise (absent key or other type), as in C:
532
532
  // kw_get_list(gobj, {x: [1, 2]}, "x", [], 0) → [1, 2] (the same array)
533
533
  // kw_get_dict(gobj, {}, "x", null, 0) → null
534
- // kw_get_bool(gobj, {x: "false"}, "x", true, 0) → true (not a boolean)
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
+ // 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,
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.
536
545
 
537
546
  kw_set_dict_value(gobj, kw, path, value)
538
547
  kw_set_subdict_value(gobj, kw, path, key, value)
@@ -3605,10 +3605,13 @@ function kw_delete(gobj, kw, path) {
3605
3605
  }
3606
3606
  /************************************************************
3607
3607
  * As the C kw_get_bool(): a boolean found is the answer, and
3608
- * anything else gives the default back -- unless KW_WILD_NUMBER
3609
- * asks to read a number (0 is false), a string ("true"/"false"
3610
- * in any case, else its integer) or null (false). Before gobj-js
3611
- * 7.25.2 the value went through Boolean(), so "false" was TRUE.
3608
+ * anything else gives the default back, LOGGED ("path MUST BE a
3609
+ * json boolean", required or not) -- unless KW_WILD_NUMBER asks
3610
+ * to read a number (0 is false), a string ("true"/"false" in any
3611
+ * case, else its integer) or null (false); a list or a dict is
3612
+ * then false, logged too. Before gobj-js 7.25.2 the value went
3613
+ * through Boolean(), so "false" was TRUE; before 7.25.3 a value
3614
+ * of the wrong type gave the default back in silence.
3612
3615
  ************************************************************/
3613
3616
  function kw_get_bool(gobj, kw, path, default_value, flag) {
3614
3617
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3636,18 +3639,47 @@ function kw_get_bool(gobj, kw, path, default_value, flag) {
3636
3639
  else if (b.toLowerCase() === "false") value = false;
3637
3640
  else value = (parseInt(b) || 0) !== 0;
3638
3641
  } else if (wild && b === null) value = false;
3639
- else {
3640
- if (required) {
3641
- log_error(`${gobj_short_name(gobj)}: path value MUST BE a boolean: ${path}`);
3642
- trace_msg(kw);
3643
- }
3642
+ else if (wild) {
3643
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
3644
+ trace_json(kw);
3645
+ return false;
3646
+ } else {
3647
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json boolean: '${path}'`);
3648
+ trace_json(kw);
3644
3649
  return Boolean(default_value);
3645
3650
  }
3646
3651
  if (extract) kw_delete(gobj, kw, path);
3647
3652
  return value;
3648
3653
  }
3649
3654
  /************************************************************
3650
- *
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.
3651
3683
  ************************************************************/
3652
3684
  function kw_get_int(gobj, kw, path, default_value, flag) {
3653
3685
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3655,6 +3687,7 @@ function kw_get_int(gobj, kw, path, default_value, flag) {
3655
3687
  const required = flag && flag & kw_flag_t.KW_REQUIRED;
3656
3688
  const create = flag && flag & kw_flag_t.KW_CREATE;
3657
3689
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3690
+ const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3658
3691
  if (v === void 0) {
3659
3692
  if (create) {
3660
3693
  let v = parseInt(default_value);
@@ -3666,18 +3699,34 @@ function kw_get_int(gobj, kw, path, default_value, flag) {
3666
3699
  }
3667
3700
  return parseInt(default_value);
3668
3701
  }
3669
- if (extract) kw_delete(gobj, kw, path);
3670
- if (!is_number(v)) {
3671
- if (required) {
3672
- log_error(`path value MUST BE a number: ${path}`);
3673
- trace_msg(kw);
3674
- }
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);
3675
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;
3676
3715
  }
3677
- return parseInt(v);
3716
+ if (extract) kw_delete(gobj, kw, path);
3717
+ return value;
3678
3718
  }
3679
3719
  /************************************************************
3680
- *
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.
3681
3730
  ************************************************************/
3682
3731
  function kw_get_real(gobj, kw, path, default_value, flag) {
3683
3732
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3685,6 +3734,7 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3685
3734
  const required = flag && flag & kw_flag_t.KW_REQUIRED;
3686
3735
  const create = flag && flag & kw_flag_t.KW_CREATE;
3687
3736
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3737
+ const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3688
3738
  if (v === void 0) {
3689
3739
  if (create) {
3690
3740
  let v = Number(default_value);
@@ -3696,15 +3746,24 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3696
3746
  }
3697
3747
  return Number(default_value);
3698
3748
  }
3699
- if (extract) kw_delete(gobj, kw, path);
3700
- if (!is_number(v)) {
3701
- if (required) {
3702
- log_error(`path value MUST BE a number: ${path}`);
3703
- trace_msg(kw);
3704
- }
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);
3705
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;
3706
3764
  }
3707
- return Number(v);
3765
+ if (extract) kw_delete(gobj, kw, path);
3766
+ return value;
3708
3767
  }
3709
3768
  /************************************************************
3710
3769
  * The default comes back AS GIVEN, as in the C kw_get_str()
@@ -3713,6 +3772,11 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3713
3772
  * TRUE: an `if(value)` on the answer took an absent key for a
3714
3773
  * present one. KW_CREATE stores a string default, and null for
3715
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.
3716
3780
  ************************************************************/
3717
3781
  function kw_get_str(gobj, kw, path, default_value, flag) {
3718
3782
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3730,7 +3794,6 @@ function kw_get_str(gobj, kw, path, default_value, flag) {
3730
3794
  }
3731
3795
  return default_value;
3732
3796
  }
3733
- if (extract) kw_delete(gobj, kw, path);
3734
3797
  if (!is_string(v)) {
3735
3798
  if (required) {
3736
3799
  log_error(`${gobj_short_name(gobj)}: path value MUST BE a string: ${path}`);
@@ -3738,6 +3801,7 @@ function kw_get_str(gobj, kw, path, default_value, flag) {
3738
3801
  }
3739
3802
  return default_value;
3740
3803
  }
3804
+ if (extract) kw_delete(gobj, kw, path);
3741
3805
  return v;
3742
3806
  }
3743
3807
  /************************************************************