@yuneta/gobj-js 7.13.7 → 7.16.0
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/dist/gobj-js.cjs.js +245 -6
- package/dist/gobj-js.cjs.js.map +1 -1
- package/dist/gobj-js.cjs.min.js +701 -590
- package/dist/gobj-js.cjs.min.js.map +1 -1
- package/dist/gobj-js.es.js +240 -7
- package/dist/gobj-js.es.js.map +1 -1
- package/dist/gobj-js.es.min.js +956 -840
- package/dist/gobj-js.es.min.js.map +1 -1
- package/dist/gobj-js.iife.js +245 -6
- package/dist/gobj-js.iife.js.map +1 -1
- package/dist/gobj-js.iife.min.js +720 -609
- package/dist/gobj-js.iife.min.js.map +1 -1
- package/dist/gobj-js.umd.js +245 -6
- package/dist/gobj-js.umd.js.map +1 -1
- package/dist/gobj-js.umd.min.js +720 -609
- package/dist/gobj-js.umd.min.js.map +1 -1
- package/package.json +1 -1
package/dist/gobj-js.cjs.js
CHANGED
|
@@ -2297,7 +2297,9 @@ function gobj_change_state(gobj, state_name) {
|
|
|
2297
2297
|
gobj.current_state = new_state;
|
|
2298
2298
|
let tracea = is_machine_tracing(gobj, "EV_STATE_CHANGED");
|
|
2299
2299
|
let tracea_states = __trace_gobj_states__(gobj) ? true : false;
|
|
2300
|
-
if (tracea || tracea_states)
|
|
2300
|
+
if (tracea || tracea_states) {
|
|
2301
|
+
if (__trace_machine_format__ === 1) {} else trace_machine(sprintf("🔀🔀 mach(%s%s^%s), new st(%s), prev st(%s)", !gobj.running ? "!!" : "", gobj_gclass_name(gobj), gobj_name(gobj), gobj_current_state(gobj), gobj.last_state.state_name));
|
|
2302
|
+
}
|
|
2301
2303
|
return true;
|
|
2302
2304
|
}
|
|
2303
2305
|
/***************************************************************************
|
|
@@ -2490,7 +2492,8 @@ function gobj_send_event(dst, event, kw, src) {
|
|
|
2490
2492
|
if (dst.gclass.gmt.mt_inject_event) {
|
|
2491
2493
|
__inside__--;
|
|
2492
2494
|
if (tracea) {
|
|
2493
|
-
trace_machine(sprintf("
|
|
2495
|
+
if (__trace_machine_format__ === 1) trace_machine(sprintf("🔜 %s %s%s %s", event ? event : "", !dst.running ? "!!" : "", gobj_short_name(dst), state.state_name));
|
|
2496
|
+
else trace_machine(sprintf("🔃 mach(%s%s), st: %s, ev: %s, from(%s%s)", !dst.running ? "!!" : "", gobj_short_name(dst), state.state_name, event ? event : "", src && !src.running ? "!!" : "", gobj_short_name(src)));
|
|
2494
2497
|
if (kw) {
|
|
2495
2498
|
if (tracea > 1) {
|
|
2496
2499
|
if (json_object_size(kw)) trace_json(kw);
|
|
@@ -2871,8 +2874,9 @@ function gobj_publish_event(publisher, event, kw) {
|
|
|
2871
2874
|
}
|
|
2872
2875
|
let tracea = __yuno__ && gobj_read_bool_attr(__yuno__, "trace_subscriptions");
|
|
2873
2876
|
if (tracea) {
|
|
2874
|
-
trace_machine(sprintf("🔝🔝
|
|
2875
|
-
|
|
2877
|
+
if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔝 %s %s%s %s", event ? event : "", !publisher.running ? "!!" : "", gobj_short_name(publisher), publisher.current_state.state_name));
|
|
2878
|
+
else trace_machine(sprintf("🔝🔝 mach(%s%s^%s), st: %s, ev: %s%s%s", !publisher.running ? "!!" : "", gobj_gclass_name(publisher), gobj_name(publisher), publisher.current_state.state_name, "", event ? event : "", ""));
|
|
2879
|
+
if (json_object_size(kw)) trace_json(kw);
|
|
2876
2880
|
}
|
|
2877
2881
|
if (publisher.gclass.gmt.mt_publish_event) {
|
|
2878
2882
|
let topublish = publisher.gclass.gmt.mt_publish_event(publisher, event, kw);
|
|
@@ -2919,8 +2923,9 @@ function gobj_publish_event(publisher, event, kw) {
|
|
|
2919
2923
|
if (__config__) {}
|
|
2920
2924
|
if (__global__) json_object_update(kw2publish, __global__);
|
|
2921
2925
|
if (tracea) {
|
|
2922
|
-
trace_machine(sprintf("🔝🔄
|
|
2923
|
-
|
|
2926
|
+
if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔄 %s (%s) %s%s", event ? event : "", event ? event : "", !subscriber.running ? "!!" : "", gobj_short_name(subscriber)));
|
|
2927
|
+
else trace_machine(sprintf("🔝🔄 mach(%s%s), st: %s, ev: %s, from(%s%s)", !subscriber.running ? "!!" : "", gobj_short_name(subscriber), gobj_current_state(subscriber), event ? event : "", publisher && !publisher.running ? "!!" : "", gobj_short_name(publisher)));
|
|
2928
|
+
if (json_object_size(kw2publish)) trace_json(kw2publish);
|
|
2924
2929
|
}
|
|
2925
2930
|
let ret_ = gobj_send_event(subscriber, event, kw2publish, publisher);
|
|
2926
2931
|
if (ret_ < 0 && subs_flag & subs_flag_t.__own_event__) {
|
|
@@ -5095,6 +5100,234 @@ function build_path(...segments) {
|
|
|
5095
5100
|
}
|
|
5096
5101
|
return result;
|
|
5097
5102
|
}
|
|
5103
|
+
/***************************************
|
|
5104
|
+
* Flat json (id -> value)
|
|
5105
|
+
***************************************/
|
|
5106
|
+
/************************************************************
|
|
5107
|
+
* THE FLAT FORM, AND WHY IT IS SHAPED LIKE THIS
|
|
5108
|
+
*
|
|
5109
|
+
* A json seen as a table: one row per LEAF, the id being the
|
|
5110
|
+
* PATH of the item and the value its value. Easier to store,
|
|
5111
|
+
* to compare and to diff than the nested form, and the only
|
|
5112
|
+
* one a person can read when two configurations disagree.
|
|
5113
|
+
*
|
|
5114
|
+
* {a: {b: 1}, c: [10, 20]}
|
|
5115
|
+
* -> {"a`b": 1, "c`[0]": 10, "c`[1]": 20}
|
|
5116
|
+
*
|
|
5117
|
+
* Same grammar as the C side (kwid.c), because the point is
|
|
5118
|
+
* that a flat json written by either can be read by the other:
|
|
5119
|
+
*
|
|
5120
|
+
* - segments joined by '`', the SDK's own path delimiter;
|
|
5121
|
+
* - a literal '`' in a key is DOUBLED, so no key is
|
|
5122
|
+
* forbidden -- a dict keyed by "1630" is a dict, not an
|
|
5123
|
+
* array of 1631 elements, which is what the first C
|
|
5124
|
+
* implementation answered;
|
|
5125
|
+
* - an array index is '[N]', canonical, no leading zeros;
|
|
5126
|
+
* - a dict key starting with '[' doubles it ('[[0]'), so it
|
|
5127
|
+
* can never be read as an index;
|
|
5128
|
+
* - AN EMPTY CONTAINER IS A LEAF: {} and [] hold no leaves,
|
|
5129
|
+
* and 'properties': {} is everywhere in our configs.
|
|
5130
|
+
*
|
|
5131
|
+
* flat2json() THROWS instead of guessing: an id used as leaf and
|
|
5132
|
+
* as container would depend on the order the ids are read in.
|
|
5133
|
+
************************************************************/
|
|
5134
|
+
var FLAT_MAX_DEPTH = 256;
|
|
5135
|
+
var FLAT_MAX_INDEX = 1e5;
|
|
5136
|
+
/************************************************************
|
|
5137
|
+
* Is this raw segment an array index, '[N]'?
|
|
5138
|
+
* Returns the index, or null.
|
|
5139
|
+
************************************************************/
|
|
5140
|
+
function flat_seg_index(seg) {
|
|
5141
|
+
if (typeof seg !== "string" || seg.length < 3 || seg[0] !== "[") return null;
|
|
5142
|
+
if (seg[seg.length - 1] !== "]") return null;
|
|
5143
|
+
const body = seg.slice(1, -1);
|
|
5144
|
+
if (!/^[0-9]+$/.test(body)) return null;
|
|
5145
|
+
if (body.length > 1 && body[0] === "0") return null;
|
|
5146
|
+
return parseInt(body, 10);
|
|
5147
|
+
}
|
|
5148
|
+
/************************************************************
|
|
5149
|
+
* Escape one dict key.
|
|
5150
|
+
************************************************************/
|
|
5151
|
+
function flat_escape_key(key) {
|
|
5152
|
+
const s = String(key).replace(/`/g, "``");
|
|
5153
|
+
return s[0] === "[" ? "[" + s : s;
|
|
5154
|
+
}
|
|
5155
|
+
/************************************************************
|
|
5156
|
+
* Compose a flat id from its segments.
|
|
5157
|
+
*
|
|
5158
|
+
* A STRING segment is a dict key and gets escaped; a NUMBER is
|
|
5159
|
+
* an array index and is written '[N]'. They are two types and
|
|
5160
|
+
* not two spellings: as strings, the key "[0]" and the index 0
|
|
5161
|
+
* would both be "[0]", which is the ambiguity '[N]' removes.
|
|
5162
|
+
************************************************************/
|
|
5163
|
+
function flat_key_join(segments) {
|
|
5164
|
+
if (!Array.isArray(segments) || segments.length === 0) return "";
|
|
5165
|
+
return segments.map((seg) => typeof seg === "number" ? `[${seg}]` : flat_escape_key(seg)).join("`");
|
|
5166
|
+
}
|
|
5167
|
+
/************************************************************
|
|
5168
|
+
* Split a flat id into its segments, undoing the escapes.
|
|
5169
|
+
*
|
|
5170
|
+
* An index comes back as a NUMBER and a dict key as a STRING.
|
|
5171
|
+
************************************************************/
|
|
5172
|
+
function flat_key_split(key) {
|
|
5173
|
+
if (typeof key !== "string") return null;
|
|
5174
|
+
let raw = [];
|
|
5175
|
+
let cur = "";
|
|
5176
|
+
for (let i = 0; i < key.length; i++) {
|
|
5177
|
+
if (key[i] === "`") {
|
|
5178
|
+
if (key[i + 1] === "`") {
|
|
5179
|
+
cur += "`";
|
|
5180
|
+
i++;
|
|
5181
|
+
continue;
|
|
5182
|
+
}
|
|
5183
|
+
raw.push(cur);
|
|
5184
|
+
cur = "";
|
|
5185
|
+
continue;
|
|
5186
|
+
}
|
|
5187
|
+
cur += key[i];
|
|
5188
|
+
}
|
|
5189
|
+
raw.push(cur);
|
|
5190
|
+
return raw.map((seg) => {
|
|
5191
|
+
const idx = flat_seg_index(seg);
|
|
5192
|
+
if (idx !== null) return idx;
|
|
5193
|
+
if (seg[0] === "[" && seg[1] === "[") return seg.slice(1);
|
|
5194
|
+
return seg;
|
|
5195
|
+
});
|
|
5196
|
+
}
|
|
5197
|
+
/************************************************************
|
|
5198
|
+
* Nested -> flat.
|
|
5199
|
+
************************************************************/
|
|
5200
|
+
function json2flat(jn) {
|
|
5201
|
+
const flat = {};
|
|
5202
|
+
const walk = (value, path, depth) => {
|
|
5203
|
+
if (depth > FLAT_MAX_DEPTH) throw new Error(`json2flat: deeper than ${FLAT_MAX_DEPTH}`);
|
|
5204
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
5205
|
+
const keys = Object.keys(value);
|
|
5206
|
+
if (keys.length > 0) {
|
|
5207
|
+
for (const key of keys) {
|
|
5208
|
+
const seg = flat_escape_key(key);
|
|
5209
|
+
walk(value[key], depth === 0 ? seg : path + "`" + seg, depth + 1);
|
|
5210
|
+
}
|
|
5211
|
+
return;
|
|
5212
|
+
}
|
|
5213
|
+
} else if (Array.isArray(value) && value.length > 0) {
|
|
5214
|
+
value.forEach((child, index) => {
|
|
5215
|
+
const seg = `[${index}]`;
|
|
5216
|
+
walk(child, depth === 0 ? seg : path + "`" + seg, depth + 1);
|
|
5217
|
+
});
|
|
5218
|
+
return;
|
|
5219
|
+
}
|
|
5220
|
+
if (depth === 0) return;
|
|
5221
|
+
flat[path] = value;
|
|
5222
|
+
};
|
|
5223
|
+
if (jn === void 0 || jn === null) return flat;
|
|
5224
|
+
walk(jn, "", 0);
|
|
5225
|
+
return flat;
|
|
5226
|
+
}
|
|
5227
|
+
/************************************************************
|
|
5228
|
+
* Flat -> nested. Throws on the FIRST id that does not fit:
|
|
5229
|
+
* rebuilding "most of it" is how a configuration comes back
|
|
5230
|
+
* subtly different from the one that was saved.
|
|
5231
|
+
************************************************************/
|
|
5232
|
+
function flat2json(flat) {
|
|
5233
|
+
if (flat === null || typeof flat !== "object" || Array.isArray(flat)) throw new Error("flat2json: a flat json is an object of id -> value");
|
|
5234
|
+
let root = null;
|
|
5235
|
+
for (const key of Object.keys(flat)) {
|
|
5236
|
+
const segments = flat_key_split(key);
|
|
5237
|
+
if (!segments || segments.length === 0) throw new Error(`flat2json: malformed flat id: '${key}'`);
|
|
5238
|
+
if (segments.length > FLAT_MAX_DEPTH) throw new Error(`flat2json: '${key}' deeper than ${FLAT_MAX_DEPTH}`);
|
|
5239
|
+
const first_is_index = typeof segments[0] === "number";
|
|
5240
|
+
if (root === null) root = first_is_index ? [] : {};
|
|
5241
|
+
else if (first_is_index !== Array.isArray(root)) throw new Error(`flat2json: '${key}' does not fit a ${Array.isArray(root) ? "array" : "object"} root`);
|
|
5242
|
+
let current = root;
|
|
5243
|
+
for (let i = 0; i < segments.length; i++) {
|
|
5244
|
+
const seg = segments[i];
|
|
5245
|
+
const is_index = typeof seg === "number";
|
|
5246
|
+
const is_last = i === segments.length - 1;
|
|
5247
|
+
const next_is_index = is_last ? false : typeof segments[i + 1] === "number";
|
|
5248
|
+
if (is_index && seg > FLAT_MAX_INDEX) throw new Error(`flat2json: array index ${seg} over the limit (${FLAT_MAX_INDEX}) in '${key}'`);
|
|
5249
|
+
if (is_index !== Array.isArray(current)) throw new Error(`flat2json: '${key}' uses a ${is_index ? "array index" : "key"} where the tree already has a ${Array.isArray(current) ? "array" : "object"}`);
|
|
5250
|
+
if (is_last) {
|
|
5251
|
+
if (Array.isArray(current)) {
|
|
5252
|
+
while (current.length <= seg) current.push(null);
|
|
5253
|
+
current[seg] = flat[key];
|
|
5254
|
+
} else {
|
|
5255
|
+
if (Object.prototype.hasOwnProperty.call(current, seg)) throw new Error(`flat2json: '${key}' is written twice, or once as a value and once as a container`);
|
|
5256
|
+
current[seg] = flat[key];
|
|
5257
|
+
}
|
|
5258
|
+
break;
|
|
5259
|
+
}
|
|
5260
|
+
let child;
|
|
5261
|
+
if (Array.isArray(current)) {
|
|
5262
|
+
while (current.length <= seg) current.push(null);
|
|
5263
|
+
child = current[seg];
|
|
5264
|
+
if (child === null || child === void 0) {
|
|
5265
|
+
child = next_is_index ? [] : {};
|
|
5266
|
+
current[seg] = child;
|
|
5267
|
+
}
|
|
5268
|
+
} else {
|
|
5269
|
+
child = current[seg];
|
|
5270
|
+
if (child === void 0) {
|
|
5271
|
+
child = next_is_index ? [] : {};
|
|
5272
|
+
current[seg] = child;
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
if (child === null || typeof child !== "object") throw new Error(`flat2json: '${key}' walks through a value: the same id is a leaf and a container at once`);
|
|
5276
|
+
if (next_is_index !== Array.isArray(child)) throw new Error(`flat2json: '${key}' needs a ${next_is_index ? "array" : "object"} where the tree already has a ${Array.isArray(child) ? "array" : "object"}`);
|
|
5277
|
+
current = child;
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
return root === null ? {} : root;
|
|
5281
|
+
}
|
|
5282
|
+
/************************************************************
|
|
5283
|
+
* Deep equality, for comparing two leaf values.
|
|
5284
|
+
************************************************************/
|
|
5285
|
+
function flat_value_equal(a, b) {
|
|
5286
|
+
if (a === b) return true;
|
|
5287
|
+
if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
|
|
5288
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
5289
|
+
}
|
|
5290
|
+
/************************************************************
|
|
5291
|
+
* What changed between two flat dicts:
|
|
5292
|
+
*
|
|
5293
|
+
* {added: {id: value}, removed: {id: value},
|
|
5294
|
+
* changed: {id: {from, to}}}
|
|
5295
|
+
************************************************************/
|
|
5296
|
+
function flat_diff(flat1, flat2) {
|
|
5297
|
+
const a = flat1 && typeof flat1 === "object" ? flat1 : {};
|
|
5298
|
+
const b = flat2 && typeof flat2 === "object" ? flat2 : {};
|
|
5299
|
+
const diff = {
|
|
5300
|
+
added: {},
|
|
5301
|
+
removed: {},
|
|
5302
|
+
changed: {}
|
|
5303
|
+
};
|
|
5304
|
+
for (const key of Object.keys(a)) if (!Object.prototype.hasOwnProperty.call(b, key)) diff.removed[key] = a[key];
|
|
5305
|
+
else if (!flat_value_equal(a[key], b[key])) diff.changed[key] = {
|
|
5306
|
+
from: a[key],
|
|
5307
|
+
to: b[key]
|
|
5308
|
+
};
|
|
5309
|
+
for (const key of Object.keys(b)) if (!Object.prototype.hasOwnProperty.call(a, key)) diff.added[key] = b[key];
|
|
5310
|
+
return diff;
|
|
5311
|
+
}
|
|
5312
|
+
/************************************************************
|
|
5313
|
+
* Apply that diff to a flat dict, which is MUTATED.
|
|
5314
|
+
*
|
|
5315
|
+
* On the flat form on purpose: there an id addresses one value,
|
|
5316
|
+
* so applying is setting and deleting, with nothing to walk and
|
|
5317
|
+
* nothing to guess. Nested is json2flat -> flat_apply -> flat2json.
|
|
5318
|
+
************************************************************/
|
|
5319
|
+
function flat_apply(flat, diff) {
|
|
5320
|
+
if (flat === null || typeof flat !== "object" || Array.isArray(flat)) throw new Error("flat_apply: a flat json is an object of id -> value");
|
|
5321
|
+
if (diff === null || typeof diff !== "object") throw new Error("flat_apply: a diff is the object flat_diff() answers");
|
|
5322
|
+
for (const key of Object.keys(diff.removed || {})) delete flat[key];
|
|
5323
|
+
for (const key of Object.keys(diff.added || {})) flat[key] = diff.added[key];
|
|
5324
|
+
for (const key of Object.keys(diff.changed || {})) {
|
|
5325
|
+
const change = diff.changed[key];
|
|
5326
|
+
if (!change || !Object.prototype.hasOwnProperty.call(change, "to")) throw new Error(`flat_apply: changed '${key}' without a 'to'`);
|
|
5327
|
+
flat[key] = change.to;
|
|
5328
|
+
}
|
|
5329
|
+
return flat;
|
|
5330
|
+
}
|
|
5098
5331
|
//#endregion
|
|
5099
5332
|
//#region src/dbsimple.js
|
|
5100
5333
|
/*********************************************************************************
|
|
@@ -6677,6 +6910,11 @@ exports.duplicate_objects = duplicate_objects;
|
|
|
6677
6910
|
exports.empty_string = empty_string;
|
|
6678
6911
|
exports.escapeHtml = escapeHtml;
|
|
6679
6912
|
exports.event_flag_t = event_flag_t;
|
|
6913
|
+
exports.flat2json = flat2json;
|
|
6914
|
+
exports.flat_apply = flat_apply;
|
|
6915
|
+
exports.flat_diff = flat_diff;
|
|
6916
|
+
exports.flat_key_join = flat_key_join;
|
|
6917
|
+
exports.flat_key_split = flat_key_split;
|
|
6680
6918
|
exports.gclass_add_ev_action = gclass_add_ev_action;
|
|
6681
6919
|
exports.gclass_add_event_type = gclass_add_event_type;
|
|
6682
6920
|
exports.gclass_add_state = gclass_add_state;
|
|
@@ -6804,6 +7042,7 @@ exports.jdb_get_by_idx = jdb_get_by_idx;
|
|
|
6804
7042
|
exports.jdb_get_topic = jdb_get_topic;
|
|
6805
7043
|
exports.jdb_init = jdb_init;
|
|
6806
7044
|
exports.jdb_update = jdb_update;
|
|
7045
|
+
exports.json2flat = json2flat;
|
|
6807
7046
|
exports.json_array_append = json_array_append;
|
|
6808
7047
|
exports.json_array_append_new = json_array_append_new;
|
|
6809
7048
|
exports.json_array_extend = json_array_extend;
|