@yuneta/gobj-js 7.25.4 → 7.25.6

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.
@@ -3035,7 +3035,7 @@
3035
3035
  *
3036
3036
  * Licence: MIT (http://www.opensource.org/licenses/mit-license)
3037
3037
  * Copyright (c) 2014,2024 Niyamaka.
3038
- * Copyright (c) 2025, ArtGins.
3038
+ * Copyright (c) 2025-2026, ArtGins.
3039
3039
  *********************************************************************************/
3040
3040
  var kw_flag_t = Object.freeze({
3041
3041
  KW_REQUIRED: 1,
@@ -3563,30 +3563,46 @@
3563
3563
  return false;
3564
3564
  }
3565
3565
  /************************************************************
3566
- *
3566
+ * The value at `path` (keys joined by a backtick), as the C
3567
+ * kw_find_path() finds it: undefined when it is not there.
3568
+ * A kw that is not a dict or a list is LOGGED ("kw must be list
3569
+ * or dict") and answers undefined, as C answers NULL; so does a
3570
+ * segment in the middle of the path whose value is a scalar. A
3571
+ * middle segment that is absent or null answers undefined, logged
3572
+ * only when `verbose`. Before gobj-js 7.25.6 a bad kw answered 0,
3573
+ * which the typed readers took for a value found (kw_get_int() and
3574
+ * kw_get_real() answered 0 instead of the default, kw_get_str() and
3575
+ * kw_get_bool() logged a second line), the log named no path and
3576
+ * called gobj_short_name() on a null gobj ("gobj bad type"), and a
3577
+ * null middle segment threw a TypeError.
3567
3578
  ************************************************************/
3568
3579
  function kw_find_path(gobj, kw, path, verbose) {
3569
3580
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
3581
+ const prefix = gobj ? `${gobj_short_name(gobj)}: ` : "";
3570
3582
  if (!(is_object(kw) || is_array(kw))) {
3571
- log_error(`${gobj_short_name(gobj)}: kw must be list or dict`);
3572
- return 0;
3583
+ log_error(`${prefix}kw must be list or dict: '${String(path)}'`);
3584
+ return;
3573
3585
  }
3574
3586
  if (!is_string(path)) {
3575
- log_error(`${gobj_short_name(gobj)}: path must be a string: ${String(path)}`);
3576
- return 0;
3587
+ log_error(`${prefix}path must be a string: ${String(path)}`);
3588
+ return;
3577
3589
  }
3578
3590
  let ss = path.split("`");
3579
- if (ss.length <= 1) return kw[path];
3580
3591
  let len = ss.length;
3581
- for (let i = 0; i < len; i++) {
3582
- let key = ss[i];
3583
- kw = kw[key];
3584
- if (kw === void 0) {
3585
- if (verbose) log_error(`${gobj_short_name(gobj)}: path not found: ${String(path)}`);
3592
+ for (let i = 0; i < len - 1; i++) {
3593
+ kw = kw[ss[i]];
3594
+ if (kw === void 0 || kw === null) {
3595
+ if (verbose) log_error(`${prefix}path not found: '${path}'`);
3596
+ return;
3597
+ }
3598
+ if (!(is_object(kw) || is_array(kw))) {
3599
+ log_error(`${prefix}kw must be list or dict: '${path}'`);
3586
3600
  return;
3587
3601
  }
3588
3602
  }
3589
- return kw;
3603
+ let value = kw[ss[len - 1]];
3604
+ if (value === void 0 && verbose) log_error(`${prefix}path not found: '${path}'`);
3605
+ return value;
3590
3606
  }
3591
3607
  /************************************************************
3592
3608
  *
@@ -3611,10 +3627,13 @@
3611
3627
  * anything else gives the default back, LOGGED ("path MUST BE a
3612
3628
  * json boolean", required or not) -- unless KW_WILD_NUMBER asks
3613
3629
  * to read a number (0 is false), a string ("true"/"false" in any
3614
- * case, else its integer) or null (false); a list or a dict is
3615
- * then false, logged too. Before gobj-js 7.25.2 the value went
3616
- * through Boolean(), so "false" was TRUE; before 7.25.3 a value
3617
- * of the wrong type gave the default back in silence.
3630
+ * case, else its decimal integer as atoi() reads it: "0x1F" is 0,
3631
+ * so false) or null (false); a list or a dict is then false,
3632
+ * logged too. Before gobj-js 7.25.2 the value went through
3633
+ * Boolean(), so "false" was TRUE; before 7.25.3 a value of the
3634
+ * wrong type gave the default back in silence; before 7.25.5 the
3635
+ * string went through parseInt() with no base, which reads hex:
3636
+ * "0x1F" was TRUE.
3618
3637
  ************************************************************/
3619
3638
  function kw_get_bool(gobj, kw, path, default_value, flag) {
3620
3639
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3624,7 +3643,7 @@
3624
3643
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3625
3644
  const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3626
3645
  if (b === void 0) {
3627
- if (create) {
3646
+ if (create && kw) {
3628
3647
  let v = Boolean(default_value);
3629
3648
  kw_set_dict_value(gobj, kw, path, v);
3630
3649
  return v;
@@ -3640,7 +3659,7 @@
3640
3659
  else if (wild && is_string(b)) {
3641
3660
  if (b.toLowerCase() === "true") value = true;
3642
3661
  else if (b.toLowerCase() === "false") value = false;
3643
- else value = (parseInt(b) || 0) !== 0;
3662
+ else value = (parseInt(b, 10) || 0) !== 0;
3644
3663
  } else if (wild && b === null) value = false;
3645
3664
  else if (wild) {
3646
3665
  log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a simple json element: '${path}'`);
@@ -3692,7 +3711,7 @@
3692
3711
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3693
3712
  const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3694
3713
  if (v === void 0) {
3695
- if (create) {
3714
+ if (create && kw) {
3696
3715
  let v = parseInt(default_value);
3697
3716
  kw_set_dict_value(gobj, kw, path, v);
3698
3717
  return v;
@@ -3739,7 +3758,7 @@
3739
3758
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3740
3759
  const wild = flag && flag & kw_flag_t.KW_WILD_NUMBER;
3741
3760
  if (v === void 0) {
3742
- if (create) {
3761
+ if (create && kw) {
3743
3762
  let v = Number(default_value);
3744
3763
  kw_set_dict_value(gobj, kw, path, v);
3745
3764
  return v;
@@ -3769,6 +3788,21 @@
3769
3788
  return value;
3770
3789
  }
3771
3790
  /************************************************************
3791
+ * TRUE when the last key of `path` is a key of its dict, whatever
3792
+ * its value: kw_find_path() answers undefined both for a key that
3793
+ * is not there and for one whose value is undefined.
3794
+ ************************************************************/
3795
+ function kw_path_holds_key(kw, path) {
3796
+ let ss = is_string(path) ? path.split("`") : [];
3797
+ let parent = kw;
3798
+ for (let i = 0; i < ss.length - 1; i++) {
3799
+ if (!(is_object(parent) || is_array(parent))) return false;
3800
+ parent = parent[ss[i]];
3801
+ }
3802
+ if (!(is_object(parent) || is_array(parent)) || ss.length === 0) return false;
3803
+ return Object.prototype.hasOwnProperty.call(parent, ss[ss.length - 1]);
3804
+ }
3805
+ /************************************************************
3772
3806
  * The default comes back AS GIVEN, as in the C kw_get_str()
3773
3807
  * (`const char *default_value`, where 0 is NULL). Turned into
3774
3808
  * a string, a default of 0 or null was "0" or "null", which is
@@ -3780,6 +3814,12 @@
3780
3814
  * C refuses to extract a string at all ("Cannot extract a
3781
3815
  * string": its answer would point into the freed json); a JS
3782
3816
  * string outlives the kw, so here it is taken out.
3817
+ * A value that is there and is not a string gives the default
3818
+ * back, LOGGED ("path MUST BE a json str", required or not), as
3819
+ * C does; a null value is the key saying "no string" and is not
3820
+ * logged, and KW_REQUIRED logs only a path that is not there at
3821
+ * all. Before gobj-js 7.25.5 a value of another type was logged
3822
+ * only with KW_REQUIRED, and then a null one too.
3783
3823
  ************************************************************/
3784
3824
  function kw_get_str(gobj, kw, path, default_value, flag) {
3785
3825
  if (gobj && !is_gobj(gobj)) log_error(`GObj bad instanceof`);
@@ -3788,19 +3828,19 @@
3788
3828
  const create = flag && flag & kw_flag_t.KW_CREATE;
3789
3829
  const extract = flag && flag & kw_flag_t.KW_EXTRACT;
3790
3830
  if (v === void 0) {
3791
- if (create) {
3831
+ if (create && kw) {
3792
3832
  kw_set_dict_value(gobj, kw, path, is_string(default_value) ? default_value : null);
3793
3833
  return default_value;
3794
- } else if (required) {
3834
+ } else if (required && !kw_path_holds_key(kw, path)) {
3795
3835
  log_error(`path not found: '${path}'`);
3796
3836
  trace_json(kw);
3797
3837
  }
3798
3838
  return default_value;
3799
3839
  }
3800
3840
  if (!is_string(v)) {
3801
- if (required) {
3802
- log_error(`${gobj_short_name(gobj)}: path value MUST BE a string: ${path}`);
3803
- trace_msg(kw);
3841
+ if (v !== null) {
3842
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json str: '${path}'`);
3843
+ trace_json(kw);
3804
3844
  }
3805
3845
  return default_value;
3806
3846
  }
@@ -3856,8 +3896,8 @@
3856
3896
  }
3857
3897
  if (!is_object(v)) {
3858
3898
  if (required) {
3859
- log_error(`${gobj_short_name(gobj)}: path value MUST BE a dict: ${path}`);
3860
- trace_msg(kw);
3899
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json dict: '${path}'`);
3900
+ trace_json(kw);
3861
3901
  }
3862
3902
  return default_value;
3863
3903
  }
@@ -3914,8 +3954,8 @@
3914
3954
  }
3915
3955
  if (!is_array(v)) {
3916
3956
  if (required) {
3917
- log_error(`${gobj_short_name(gobj)}: path value MUST BE an array: ${path}`);
3918
- trace_msg(kw);
3957
+ log_error(`${gobj ? gobj_short_name(gobj) + ": " : ""}path MUST BE a json list: '${path}'`);
3958
+ trace_json(kw);
3919
3959
  }
3920
3960
  return default_value;
3921
3961
  }