@yuneta/gobj-js 7.25.4 → 7.25.5

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
@@ -540,6 +540,14 @@ kw_get_dict_value(gobj, kw, path, default_value, flag)
540
540
  // kw_get_int(gobj, {x: 3.9}, "x", 0, 0) → 3 (truncated, as C)
541
541
  // kw_get_int(gobj, {x: "12"}, "x", 5, 0) → 5 (not a number: logged)
542
542
  // kw_get_int(gobj, {x: "0x1F"}, "x", 5, KW_WILD_NUMBER) → 31 (strtoll base 0)
543
+ // kw_get_bool(gobj, {x: "0x1F"}, "x", true, KW_WILD_NUMBER) → false (atoi: decimal)
544
+ // kw_get_str() logs as C too: a value that is there and is not a
545
+ // string, required or not ("path MUST BE a json str"), never a null
546
+ // value, and with KW_REQUIRED a path that is not there:
547
+ // kw_get_str(gobj, {x: 5}, "x", "d", 0) → "d" (logged)
548
+ // kw_get_str(gobj, {x: null}, "x", "d", KW_REQUIRED) → "d" (not logged)
549
+ // kw_get_dict() / kw_get_list() log a value of another type only with
550
+ // KW_REQUIRED ("path MUST BE a json dict" / "... a json list"), as C.
543
551
  // KW_EXTRACT takes out only a value the reader answers with: a value
544
552
  // of another type stays in the kw.
545
553
 
@@ -3032,7 +3032,7 @@ function gobj_stats(gobj, stats, kw, src) {
3032
3032
  *
3033
3033
  * Licence: MIT (http://www.opensource.org/licenses/mit-license)
3034
3034
  * Copyright (c) 2014,2024 Niyamaka.
3035
- * Copyright (c) 2025, ArtGins.
3035
+ * Copyright (c) 2025-2026, ArtGins.
3036
3036
  *********************************************************************************/
3037
3037
  var kw_flag_t = Object.freeze({
3038
3038
  KW_REQUIRED: 1,
@@ -3608,10 +3608,13 @@ function kw_delete(gobj, kw, path) {
3608
3608
  * anything else gives the default back, LOGGED ("path MUST BE a
3609
3609
  * json boolean", required or not) -- unless KW_WILD_NUMBER asks
3610
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.
3611
+ * case, else its decimal integer as atoi() reads it: "0x1F" is 0,
3612
+ * so false) or null (false); a list or a dict is then false,
3613
+ * logged too. Before gobj-js 7.25.2 the value went through
3614
+ * Boolean(), so "false" was TRUE; before 7.25.3 a value of the
3615
+ * wrong type gave the default back in silence; before 7.25.5 the
3616
+ * string went through parseInt() with no base, which reads hex:
3617
+ * "0x1F" was TRUE.
3615
3618
  ************************************************************/
3616
3619
  function kw_get_bool(gobj, kw, path, default_value, flag) {
3617
3620
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3637,7 +3640,7 @@ function kw_get_bool(gobj, kw, path, default_value, flag) {
3637
3640
  else if (wild && is_string(b)) {
3638
3641
  if (b.toLowerCase() === "true") value = true;
3639
3642
  else if (b.toLowerCase() === "false") value = false;
3640
- else value = (parseInt(b) || 0) !== 0;
3643
+ else value = (parseInt(b, 10) || 0) !== 0;
3641
3644
  } else if (wild && b === null) value = false;
3642
3645
  else if (wild) {
3643
3646
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
@@ -3766,6 +3769,21 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3766
3769
  return value;
3767
3770
  }
3768
3771
  /************************************************************
3772
+ * TRUE when the last key of `path` is a key of its dict, whatever
3773
+ * its value: kw_find_path() answers undefined both for a key that
3774
+ * is not there and for one whose value is undefined.
3775
+ ************************************************************/
3776
+ function kw_path_holds_key(kw, path) {
3777
+ let ss = is_string(path) ? path.split("`") : [];
3778
+ let parent = kw;
3779
+ for (let i = 0; i < ss.length - 1; i++) {
3780
+ if (!(is_object(parent) || is_array(parent))) return false;
3781
+ parent = parent[ss[i]];
3782
+ }
3783
+ if (!(is_object(parent) || is_array(parent)) || ss.length === 0) return false;
3784
+ return Object.prototype.hasOwnProperty.call(parent, ss[ss.length - 1]);
3785
+ }
3786
+ /************************************************************
3769
3787
  * The default comes back AS GIVEN, as in the C kw_get_str()
3770
3788
  * (`const char *default_value`, where 0 is NULL). Turned into
3771
3789
  * a string, a default of 0 or null was "0" or "null", which is
@@ -3777,6 +3795,12 @@ function kw_get_real(gobj, kw, path, default_value, flag) {
3777
3795
  * C refuses to extract a string at all ("Cannot extract a
3778
3796
  * string": its answer would point into the freed json); a JS
3779
3797
  * string outlives the kw, so here it is taken out.
3798
+ * A value that is there and is not a string gives the default
3799
+ * back, LOGGED ("path MUST BE a json str", required or not), as
3800
+ * C does; a null value is the key saying "no string" and is not
3801
+ * logged, and KW_REQUIRED logs only a path that is not there at
3802
+ * all. Before gobj-js 7.25.5 a value of another type was logged
3803
+ * only with KW_REQUIRED, and then a null one too.
3780
3804
  ************************************************************/
3781
3805
  function kw_get_str(gobj, kw, path, default_value, flag) {
3782
3806
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3788,16 +3812,16 @@ function kw_get_str(gobj, kw, path, default_value, flag) {
3788
3812
  if (create) {
3789
3813
  kw_set_dict_value(gobj, kw, path, is_string(default_value) ? default_value : null);
3790
3814
  return default_value;
3791
- } else if (required) {
3815
+ } else if (required && !kw_path_holds_key(kw, path)) {
3792
3816
  log_error(`path not found: '${path}'`);
3793
3817
  trace_json(kw);
3794
3818
  }
3795
3819
  return default_value;
3796
3820
  }
3797
3821
  if (!is_string(v)) {
3798
- if (required) {
3799
- log_error(`${gobj_short_name(gobj)}: path value MUST BE a string: ${path}`);
3800
- trace_msg(kw);
3822
+ if (v !== null) {
3823
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json str: '${path}'`);
3824
+ trace_json(kw);
3801
3825
  }
3802
3826
  return default_value;
3803
3827
  }
@@ -3853,8 +3877,8 @@ function kw_get_dict(gobj, kw, path, default_value, flag) {
3853
3877
  }
3854
3878
  if (!is_object(v)) {
3855
3879
  if (required) {
3856
- log_error(`${gobj_short_name(gobj)}: path value MUST BE a dict: ${path}`);
3857
- trace_msg(kw);
3880
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json dict: '${path}'`);
3881
+ trace_json(kw);
3858
3882
  }
3859
3883
  return default_value;
3860
3884
  }
@@ -3911,8 +3935,8 @@ function kw_get_list(gobj, kw, path, default_value, flag) {
3911
3935
  }
3912
3936
  if (!is_array(v)) {
3913
3937
  if (required) {
3914
- log_error(`${gobj_short_name(gobj)}: path value MUST BE an array: ${path}`);
3915
- trace_msg(kw);
3938
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json list: '${path}'`);
3939
+ trace_json(kw);
3916
3940
  }
3917
3941
  return default_value;
3918
3942
  }