@jsenv/navi 0.10.1 → 0.11.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/jsenv_navi.js +13858 -23295
- package/dist/jsenv_navi.js.map +1281 -0
- package/package.json +5 -7
- package/index.js +0 -122
- package/src/action_private_properties.js +0 -11
- package/src/action_proxy_test.html +0 -353
- package/src/action_run_states.js +0 -5
- package/src/actions.js +0 -1401
- package/src/browser_integration/browser_integration.js +0 -216
- package/src/browser_integration/document_back_and_forward.js +0 -17
- package/src/browser_integration/document_loading_signal.js +0 -100
- package/src/browser_integration/document_state_signal.js +0 -9
- package/src/browser_integration/document_url_signal.js +0 -9
- package/src/browser_integration/use_is_visited.js +0 -19
- package/src/browser_integration/via_history.js +0 -232
- package/src/browser_integration/via_navigation.js +0 -168
- package/src/components/action_execution/form_context.js +0 -5
- package/src/components/action_execution/render_actionable_component.jsx +0 -29
- package/src/components/action_execution/use_action.js +0 -99
- package/src/components/action_execution/use_execute_action.js +0 -177
- package/src/components/action_execution/use_run_on_mount.js +0 -9
- package/src/components/action_renderer.jsx +0 -125
- package/src/components/callout/callout.js +0 -990
- package/src/components/callout/callout_demo.html +0 -201
- package/src/components/callout/test_dynamic_positioning.html +0 -161
- package/src/components/callout/test_html_document_iframe.html +0 -182
- package/src/components/demos/0_button_demo.html +0 -707
- package/src/components/demos/10_column_reordering_debug.html +0 -277
- package/src/components/demos/11_table_selection_debug.html +0 -432
- package/src/components/demos/1_checkbox_demo.html +0 -754
- package/src/components/demos/2_input_textual_demo.html +0 -286
- package/src/components/demos/3_radio_demo.html +0 -874
- package/src/components/demos/4_select_demo.html +0 -100
- package/src/components/demos/5_list_scrollable_demo.html +0 -153
- package/src/components/demos/6_tablist_demo.html +0 -77
- package/src/components/demos/7_table_selection_demo.html +0 -176
- package/src/components/demos/8_table_fixed_headers_demo.html +0 -584
- package/src/components/demos/9_table_column_drag_demo.html +0 -325
- package/src/components/demos/action/0_button_demo.html +0 -204
- package/src/components/demos/action/10_shortcuts_demo.html +0 -189
- package/src/components/demos/action/11_nested_shortcuts_demo.xhtml +0 -401
- package/src/components/demos/action/1_input_text_demo.html +0 -876
- package/src/components/demos/action/2_form_multiple.html +0 -303
- package/src/components/demos/action/3_details_demo.html +0 -203
- package/src/components/demos/action/4_input_checkbox_demo.html +0 -731
- package/src/components/demos/action/5_input_checkbox_state_demo.html +0 -270
- package/src/components/demos/action/6_checkbox_list_demo.html +0 -341
- package/src/components/demos/action/7_radio_list_demo.html +0 -357
- package/src/components/demos/action/8_editable_demo.html +0 -431
- package/src/components/demos/action/9_link_demo.html +0 -194
- package/src/components/demos/demo.md +0 -0
- package/src/components/demos/route/basic/basic.html +0 -14
- package/src/components/demos/route/basic/basic_route_demo.jsx +0 -224
- package/src/components/demos/route/multi/multi.html +0 -14
- package/src/components/demos/route/multi/multi_route_demo.jsx +0 -277
- package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +0 -695
- package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +0 -429
- package/src/components/demos/ui_transition/2_height_transition_test.html +0 -295
- package/src/components/details/details.jsx +0 -245
- package/src/components/details/summary_marker.jsx +0 -141
- package/src/components/edition/editable.jsx +0 -186
- package/src/components/error_boundary_context.js +0 -9
- package/src/components/field/README.md +0 -247
- package/src/components/field/button.jsx +0 -429
- package/src/components/field/checkbox_list.jsx +0 -185
- package/src/components/field/collect_form_element_values.js +0 -82
- package/src/components/field/custom_field.js +0 -106
- package/src/components/field/form.jsx +0 -209
- package/src/components/field/input.jsx +0 -16
- package/src/components/field/input_checkbox.jsx +0 -434
- package/src/components/field/input_radio.jsx +0 -432
- package/src/components/field/input_textual.jsx +0 -389
- package/src/components/field/label.jsx +0 -46
- package/src/components/field/radio_list.jsx +0 -183
- package/src/components/field/select.jsx +0 -256
- package/src/components/field/use_action_events.js +0 -132
- package/src/components/field/use_form_events.js +0 -59
- package/src/components/field/use_ui_state_controller.js +0 -506
- package/src/components/item_tracker/README.md +0 -461
- package/src/components/item_tracker/use_isolated_item_tracker.jsx +0 -209
- package/src/components/item_tracker/use_isolated_item_tracker_demo.html +0 -148
- package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +0 -460
- package/src/components/item_tracker/use_item_tracker.jsx +0 -143
- package/src/components/item_tracker/use_item_tracker_demo.html +0 -207
- package/src/components/item_tracker/use_item_tracker_demo.jsx +0 -216
- package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +0 -87
- package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +0 -61
- package/src/components/keyboard_shortcuts/keyboard_key_meta.js +0 -17
- package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +0 -371
- package/src/components/keyboard_shortcuts/os.js +0 -9
- package/src/components/layout/demos/demo_flex.html +0 -638
- package/src/components/layout/demos/demo_layout_style_buttons.html +0 -351
- package/src/components/layout/demos/demo_layout_style_input.html +0 -226
- package/src/components/layout/demos/demo_layout_style_text.html +0 -514
- package/src/components/layout/flex.jsx +0 -109
- package/src/components/layout/layout_context.jsx +0 -3
- package/src/components/layout/spacing.jsx +0 -20
- package/src/components/layout/use_layout_style.js +0 -249
- package/src/components/link/link.jsx +0 -267
- package/src/components/link/link_with_icon.jsx +0 -52
- package/src/components/loader/loader_background.jsx +0 -372
- package/src/components/loader/loading_spinner.jsx +0 -68
- package/src/components/loader/network_speed.js +0 -83
- package/src/components/loader/rectangle_loading.jsx +0 -244
- package/src/components/props_composition/demos/demo_with_props_style.html +0 -81
- package/src/components/props_composition/with_props_class_name.js +0 -37
- package/src/components/props_composition/with_props_style.js +0 -26
- package/src/components/route.jsx +0 -19
- package/src/components/selection/selection.jsx +0 -1583
- package/src/components/svg/font_sized_svg.jsx +0 -59
- package/src/components/svg/icon_and_text.jsx +0 -21
- package/src/components/svg/svg_mask_overlay.jsx +0 -105
- package/src/components/table/drag/table_drag.jsx +0 -506
- package/src/components/table/resize/table_resize.jsx +0 -650
- package/src/components/table/resize/table_size.js +0 -43
- package/src/components/table/selection/table_selection.js +0 -106
- package/src/components/table/selection/table_selection.jsx +0 -203
- package/src/components/table/sticky/sticky_group.js +0 -354
- package/src/components/table/sticky/table_sticky.js +0 -25
- package/src/components/table/sticky/table_sticky.jsx +0 -501
- package/src/components/table/table.jsx +0 -721
- package/src/components/table/table_css.js +0 -211
- package/src/components/table/table_ui.jsx +0 -49
- package/src/components/table/use_cells_and_columns.js +0 -90
- package/src/components/table/use_object_array_to_cells.js +0 -46
- package/src/components/table/z_indexes.js +0 -23
- package/src/components/tablist/tablist.jsx +0 -99
- package/src/components/text/demos/demo_text_and_icon.html +0 -421
- package/src/components/text/overflow.jsx +0 -15
- package/src/components/text/text.jsx +0 -83
- package/src/components/text/text_and_count.jsx +0 -28
- package/src/components/ui_transition.jsx +0 -128
- package/src/components/use_auto_focus.js +0 -94
- package/src/components/use_batch_during_render.js +0 -33
- package/src/components/use_debounce_true.js +0 -31
- package/src/components/use_dependencies_diff.js +0 -35
- package/src/components/use_focus_group.js +0 -20
- package/src/components/use_initial_value.js +0 -78
- package/src/components/use_is_visited.js +0 -19
- package/src/components/use_ref_array.js +0 -38
- package/src/components/use_signal_sync.js +0 -50
- package/src/components/use_stable_callback.js +0 -68
- package/src/components/use_state_array.js +0 -47
- package/src/docs/actions.md +0 -250
- package/src/docs/demos/resource/action_status.jsx +0 -42
- package/src/docs/demos/resource/demo.md +0 -1
- package/src/docs/demos/resource/resource_demo_0.html +0 -84
- package/src/docs/demos/resource/resource_demo_10_post_gc.html +0 -364
- package/src/docs/demos/resource/resource_demo_11_describe_many.html +0 -362
- package/src/docs/demos/resource/resource_demo_2.html +0 -173
- package/src/docs/demos/resource/resource_demo_3_filtered_users.html +0 -415
- package/src/docs/demos/resource/resource_demo_4_details.html +0 -284
- package/src/docs/demos/resource/resource_demo_5_renderer_lazy.html +0 -115
- package/src/docs/demos/resource/resource_demo_6_gc.html +0 -217
- package/src/docs/demos/resource/resource_demo_7_child_gc.html +0 -240
- package/src/docs/demos/resource/resource_demo_8_proxy_gc.html +0 -319
- package/src/docs/demos/resource/resource_demo_9_describe_one.html +0 -472
- package/src/docs/demos/resource/tata.jsx +0 -3
- package/src/docs/demos/resource/toto.jsx +0 -3
- package/src/docs/demos/user_nav/user_nav.html +0 -12
- package/src/docs/demos/user_nav/user_nav.jsx +0 -330
- package/src/docs/resource_dependencies.md +0 -103
- package/src/docs/resource_with_params.md +0 -80
- package/src/navi_css_vars.js +0 -14
- package/src/notes.md +0 -34
- package/src/route/route.js +0 -596
- package/src/route/route.xtest.html +0 -228
- package/src/store/array_signal_store.js +0 -537
- package/src/store/local_storage_signal.js +0 -17
- package/src/store/resource_graph.js +0 -1304
- package/src/store/tests/resource_graph_autoreload_demo.html +0 -12
- package/src/store/tests/resource_graph_autoreload_demo.jsx +0 -964
- package/src/store/tests/resource_graph_dependencies.test_manual.js +0 -95
- package/src/store/value_in_local_storage.js +0 -187
- package/src/symbol_object_signal.js +0 -1
- package/src/use_action_data.js +0 -10
- package/src/use_action_status.js +0 -47
- package/src/utils/add_many_event_listeners.js +0 -15
- package/src/utils/array_add_remove.js +0 -61
- package/src/utils/array_signal.js +0 -15
- package/src/utils/compare_two_js_values.js +0 -172
- package/src/utils/execute_with_cleanup.js +0 -21
- package/src/utils/get_caller_info.js +0 -85
- package/src/utils/is_signal.js +0 -20
- package/src/utils/js_value_weak_map.js +0 -162
- package/src/utils/js_value_weak_map_demo.html +0 -690
- package/src/utils/merge_two_js_values.js +0 -53
- package/src/utils/stringify_for_display.js +0 -131
- package/src/utils/weak_effect.js +0 -48
- package/src/validation/constraints/confirm_constraint.js +0 -14
- package/src/validation/constraints/create_unique_value_constraint.js +0 -27
- package/src/validation/constraints/native_constraints.js +0 -338
- package/src/validation/constraints/readonly_constraint.js +0 -41
- package/src/validation/constraints/same_as_constraint.js +0 -42
- package/src/validation/constraints/single_space_constraint.js +0 -13
- package/src/validation/custom_constraint_validation.js +0 -793
- package/src/validation/custom_message.js +0 -18
- package/src/validation/demos/browser_style.png +0 -0
- package/src/validation/demos/demo_same_as_constraint.html +0 -259
- package/src/validation/demos/form_validation_demo.html +0 -142
- package/src/validation/demos/form_validation_demo_preact.html +0 -87
- package/src/validation/demos/form_validation_native_popover_demo.html +0 -168
- package/src/validation/demos/form_validation_vs_native_demo.html +0 -172
- package/src/validation/hooks/use_constraints.js +0 -23
- package/src/validation/hooks/use_custom_validation_ref.js +0 -73
- package/src/validation/hooks/use_validation_message.js +0 -19
- package/src/validation/input_change_effect.js +0 -106
|
@@ -1,690 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>JS Value WeakMap Test</title>
|
|
7
|
-
<style>
|
|
8
|
-
body {
|
|
9
|
-
font-family: Arial, sans-serif;
|
|
10
|
-
max-width: 800px;
|
|
11
|
-
margin: 0 auto;
|
|
12
|
-
padding: 20px;
|
|
13
|
-
}
|
|
14
|
-
.test-section {
|
|
15
|
-
margin: 20px 0;
|
|
16
|
-
padding: 15px;
|
|
17
|
-
border: 1px solid #ddd;
|
|
18
|
-
border-radius: 5px;
|
|
19
|
-
}
|
|
20
|
-
button {
|
|
21
|
-
margin: 5px;
|
|
22
|
-
padding: 8px 16px;
|
|
23
|
-
cursor: pointer;
|
|
24
|
-
}
|
|
25
|
-
.log {
|
|
26
|
-
background: #f5f5f5;
|
|
27
|
-
padding: 10px;
|
|
28
|
-
margin: 10px 0;
|
|
29
|
-
border-radius: 3px;
|
|
30
|
-
font-family: monospace;
|
|
31
|
-
white-space: pre-wrap;
|
|
32
|
-
max-height: 300px;
|
|
33
|
-
overflow-y: auto;
|
|
34
|
-
}
|
|
35
|
-
.status {
|
|
36
|
-
padding: 5px;
|
|
37
|
-
margin: 5px 0;
|
|
38
|
-
border-radius: 3px;
|
|
39
|
-
}
|
|
40
|
-
.success {
|
|
41
|
-
background: #d4edda;
|
|
42
|
-
color: #155724;
|
|
43
|
-
}
|
|
44
|
-
.error {
|
|
45
|
-
background: #f8d7da;
|
|
46
|
-
color: #721c24;
|
|
47
|
-
}
|
|
48
|
-
.info {
|
|
49
|
-
background: #d1ecf1;
|
|
50
|
-
color: #0c5460;
|
|
51
|
-
}
|
|
52
|
-
.warning {
|
|
53
|
-
background: #fff3cd;
|
|
54
|
-
color: #856404;
|
|
55
|
-
}
|
|
56
|
-
</style>
|
|
57
|
-
</head>
|
|
58
|
-
<body>
|
|
59
|
-
<h1>JS Value WeakMap Test</h1>
|
|
60
|
-
|
|
61
|
-
<div class="test-section">
|
|
62
|
-
<h3>Ephemeron Pattern (Mutual Retention)</h3>
|
|
63
|
-
<button onclick="testMutualRetention()">Test Mutual Retention</button>
|
|
64
|
-
<button onclick="forceGC()">Force GC</button>
|
|
65
|
-
<button onclick="checkAliveness()">Check Aliveness</button>
|
|
66
|
-
<button onclick="testEphemeronGC()">Test Ephemeron GC</button>
|
|
67
|
-
<div id="retention-log" class="log"></div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<div class="test-section">
|
|
71
|
-
<h3>Memory Management</h3>
|
|
72
|
-
<button onclick="createManyEntries()">Create Many Entries</button>
|
|
73
|
-
<button onclick="clearReferences()">Clear References</button>
|
|
74
|
-
<button onclick="testCleanup()">Test Cleanup</button>
|
|
75
|
-
<div id="memory-log" class="log"></div>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<div class="test-section">
|
|
79
|
-
<h3>Basic Operations</h3>
|
|
80
|
-
<button onclick="testBasicOperations()">Test Basic Set/Get</button>
|
|
81
|
-
<button onclick="testDeepEquality()">Test Deep Equality</button>
|
|
82
|
-
<div id="basic-log" class="log"></div>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<script type="module">
|
|
86
|
-
import { createJsValueWeakMap } from "./js_value_weak_map.js";
|
|
87
|
-
|
|
88
|
-
// Global test state
|
|
89
|
-
let cache = createJsValueWeakMap();
|
|
90
|
-
let testKey1;
|
|
91
|
-
let testValue1;
|
|
92
|
-
let testKey2;
|
|
93
|
-
let testValue2;
|
|
94
|
-
let keyWeakRef;
|
|
95
|
-
let valueWeakRef;
|
|
96
|
-
|
|
97
|
-
function log(elementId, message, type = "info") {
|
|
98
|
-
const element = document.getElementById(elementId);
|
|
99
|
-
const timestamp = new Date().toLocaleTimeString();
|
|
100
|
-
const statusClass =
|
|
101
|
-
{
|
|
102
|
-
error: "error",
|
|
103
|
-
success: "success",
|
|
104
|
-
warning: "warning",
|
|
105
|
-
info: "info",
|
|
106
|
-
}[type] || "info";
|
|
107
|
-
element.innerHTML += `<div class="status ${statusClass}">[${timestamp}] ${message}</div>`;
|
|
108
|
-
element.scrollTop = element.scrollHeight;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const forceGCWithPressure = async () => {
|
|
112
|
-
if (window.gc) {
|
|
113
|
-
window.gc();
|
|
114
|
-
return "✓ Forced GC (native)";
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Fallback: create memory pressure
|
|
118
|
-
const arrays = [];
|
|
119
|
-
for (let i = 0; i < 100; i++) {
|
|
120
|
-
arrays.push(new Array(100000).fill(Math.random()));
|
|
121
|
-
}
|
|
122
|
-
arrays.length = 0;
|
|
123
|
-
|
|
124
|
-
// Wait for GC
|
|
125
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
126
|
-
return "✓ Forced GC (memory pressure)";
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
window.testEphemeronGC = async () => {
|
|
130
|
-
const logId = "retention-log";
|
|
131
|
-
|
|
132
|
-
log(logId, "", "info");
|
|
133
|
-
log(logId, "🗑️ TESTING EPHEMERON GARBAGE COLLECTION", "warning");
|
|
134
|
-
log(logId, "📝 What we do: Clear all references and test GC", "info");
|
|
135
|
-
log(
|
|
136
|
-
logId,
|
|
137
|
-
"📝 Expected: Both key and value should be garbage collected",
|
|
138
|
-
"info",
|
|
139
|
-
);
|
|
140
|
-
log(logId, "", "info");
|
|
141
|
-
|
|
142
|
-
// Clear all references
|
|
143
|
-
testKey1 = null;
|
|
144
|
-
testValue1 = null;
|
|
145
|
-
|
|
146
|
-
const message = await forceGCWithPressure();
|
|
147
|
-
log(logId, message, "success");
|
|
148
|
-
|
|
149
|
-
// Wait a bit then check results
|
|
150
|
-
setTimeout(() => {
|
|
151
|
-
log(logId, "🔍 CHECKING GC RESULTS:", "warning");
|
|
152
|
-
|
|
153
|
-
const keyAlive = keyWeakRef?.deref() !== undefined;
|
|
154
|
-
const valueAlive = valueWeakRef?.deref() !== undefined;
|
|
155
|
-
|
|
156
|
-
log(
|
|
157
|
-
logId,
|
|
158
|
-
`Key alive via WeakRef: ${keyAlive ? "YES" : "NO"}`,
|
|
159
|
-
!keyAlive ? "success" : "error",
|
|
160
|
-
);
|
|
161
|
-
log(
|
|
162
|
-
logId,
|
|
163
|
-
`Value alive via WeakRef: ${valueAlive ? "YES" : "NO"}`,
|
|
164
|
-
!valueAlive ? "success" : "error",
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
if (!keyAlive && !valueAlive) {
|
|
168
|
-
log(
|
|
169
|
-
logId,
|
|
170
|
-
"✅ SUCCESS: Key and value could be GC'ed, as expected",
|
|
171
|
-
"success",
|
|
172
|
-
);
|
|
173
|
-
} else {
|
|
174
|
-
log(
|
|
175
|
-
logId,
|
|
176
|
-
"❌ FAILURE: Objects still alive despite no references",
|
|
177
|
-
"error",
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
}, 100);
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
window.testMutualRetention = () => {
|
|
184
|
-
const logId = "retention-log";
|
|
185
|
-
document.getElementById(logId).innerHTML = "";
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
log(logId, "🎯 STARTING MUTUAL RETENTION TEST", "warning");
|
|
189
|
-
log(
|
|
190
|
-
logId,
|
|
191
|
-
"📝 What we do: Create key-value pair with WeakRef monitoring",
|
|
192
|
-
"info",
|
|
193
|
-
);
|
|
194
|
-
log(
|
|
195
|
-
logId,
|
|
196
|
-
"📝 Expected: Both key and value should be findable in cache",
|
|
197
|
-
"info",
|
|
198
|
-
);
|
|
199
|
-
log(logId, "", "info");
|
|
200
|
-
|
|
201
|
-
testKey1 = { id: "mutual-test-1" };
|
|
202
|
-
testValue1 = { data: "should-stay-alive-1" };
|
|
203
|
-
keyWeakRef = new WeakRef(testKey1);
|
|
204
|
-
valueWeakRef = new WeakRef(testValue1);
|
|
205
|
-
|
|
206
|
-
cache.set(testKey1, testValue1);
|
|
207
|
-
|
|
208
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
209
|
-
const keyExists = cache.get(testKey1) !== undefined;
|
|
210
|
-
const valueMatches = cache.get(testKey1) === testValue1;
|
|
211
|
-
const keyAlive = keyWeakRef.deref() !== undefined;
|
|
212
|
-
const valueAlive = valueWeakRef.deref() !== undefined;
|
|
213
|
-
|
|
214
|
-
log(
|
|
215
|
-
logId,
|
|
216
|
-
`Key exists in cache: ${keyExists}`,
|
|
217
|
-
keyExists ? "success" : "error",
|
|
218
|
-
);
|
|
219
|
-
log(
|
|
220
|
-
logId,
|
|
221
|
-
`Value matches in cache: ${valueMatches}`,
|
|
222
|
-
valueMatches ? "success" : "error",
|
|
223
|
-
);
|
|
224
|
-
log(
|
|
225
|
-
logId,
|
|
226
|
-
`Key alive via WeakRef: ${keyAlive}`,
|
|
227
|
-
keyAlive ? "success" : "error",
|
|
228
|
-
);
|
|
229
|
-
log(
|
|
230
|
-
logId,
|
|
231
|
-
`Value alive via WeakRef: ${valueAlive}`,
|
|
232
|
-
valueAlive ? "success" : "error",
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
if (keyExists && valueMatches && keyAlive && valueAlive) {
|
|
236
|
-
log(logId, "✅ SUCCESS: Initial state correct", "success");
|
|
237
|
-
} else {
|
|
238
|
-
log(logId, "❌ FAILURE: Initial state incorrect", "error");
|
|
239
|
-
}
|
|
240
|
-
} catch (error) {
|
|
241
|
-
log(logId, `Error: ${error.message}`, "error");
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
window.forceGC = async () => {
|
|
246
|
-
const logId = "retention-log";
|
|
247
|
-
log(logId, "🧹 FORCING GARBAGE COLLECTION", "warning");
|
|
248
|
-
log(
|
|
249
|
-
logId,
|
|
250
|
-
"📝 What we do: Force GC and check if ephemeron survives",
|
|
251
|
-
"info",
|
|
252
|
-
);
|
|
253
|
-
log(
|
|
254
|
-
logId,
|
|
255
|
-
"📝 Expected: If value referenced, both key+value stay alive",
|
|
256
|
-
"info",
|
|
257
|
-
);
|
|
258
|
-
log(logId, "", "info");
|
|
259
|
-
|
|
260
|
-
const message = await forceGCWithPressure();
|
|
261
|
-
log(logId, message, "success");
|
|
262
|
-
|
|
263
|
-
setTimeout(() => {
|
|
264
|
-
window.checkAliveness();
|
|
265
|
-
}, 100);
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
// Remove the duplicate checkAliveness function and keep only this one:
|
|
269
|
-
window.checkAliveness = () => {
|
|
270
|
-
const logId = "retention-log";
|
|
271
|
-
|
|
272
|
-
if (testKey1) {
|
|
273
|
-
log(logId, "🗑️ CLEARING KEY REFERENCE", "warning");
|
|
274
|
-
log(
|
|
275
|
-
logId,
|
|
276
|
-
"📝 What we do: Clear local key ref, keep value ref",
|
|
277
|
-
"info",
|
|
278
|
-
);
|
|
279
|
-
log(
|
|
280
|
-
logId,
|
|
281
|
-
"📝 Expected: Value should keep key alive (ephemeron)",
|
|
282
|
-
"info",
|
|
283
|
-
);
|
|
284
|
-
testKey1 = null;
|
|
285
|
-
} else {
|
|
286
|
-
log(logId, "🔍 CHECKING CURRENT STATE", "warning");
|
|
287
|
-
log(
|
|
288
|
-
logId,
|
|
289
|
-
"📝 What we check: Current aliveness after previous operations",
|
|
290
|
-
"info",
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
log(logId, "", "info");
|
|
294
|
-
|
|
295
|
-
if (testValue1) {
|
|
296
|
-
log(
|
|
297
|
-
logId,
|
|
298
|
-
"📝 Expected: Key alive via ephemeron, value alive via reference",
|
|
299
|
-
"info",
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
const testKeyClone = { id: "mutual-test-1" };
|
|
303
|
-
const foundValue = cache.get(testKeyClone);
|
|
304
|
-
const entryFound = foundValue === testValue1;
|
|
305
|
-
const keyAlive = keyWeakRef?.deref() !== undefined;
|
|
306
|
-
const valueAlive = valueWeakRef?.deref() !== undefined;
|
|
307
|
-
|
|
308
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
309
|
-
log(
|
|
310
|
-
logId,
|
|
311
|
-
`Cache lookup with equivalent key: ${entryFound ? "FOUND" : "NOT FOUND"}`,
|
|
312
|
-
entryFound ? "success" : "error",
|
|
313
|
-
);
|
|
314
|
-
log(logId, `Value reference still alive: YES`, "success");
|
|
315
|
-
log(
|
|
316
|
-
logId,
|
|
317
|
-
`Key alive via WeakRef: ${keyAlive ? "YES" : "NO"}`,
|
|
318
|
-
keyAlive ? "success" : "error",
|
|
319
|
-
);
|
|
320
|
-
log(
|
|
321
|
-
logId,
|
|
322
|
-
`Value alive via WeakRef: ${valueAlive ? "YES" : "NO"}`,
|
|
323
|
-
valueAlive ? "success" : "error",
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
if (entryFound && keyAlive && valueAlive) {
|
|
327
|
-
log(logId, "✅ EPHEMERON WORKING: Value kept key alive", "success");
|
|
328
|
-
} else {
|
|
329
|
-
log(
|
|
330
|
-
logId,
|
|
331
|
-
"❌ EPHEMERON FAILED: Entry lost despite value reference",
|
|
332
|
-
"error",
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
} else {
|
|
336
|
-
log(
|
|
337
|
-
logId,
|
|
338
|
-
"📝 Expected: Both key and value should be garbage collected",
|
|
339
|
-
"info",
|
|
340
|
-
);
|
|
341
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
342
|
-
|
|
343
|
-
const keyAlive = keyWeakRef?.deref() !== undefined;
|
|
344
|
-
const valueAlive = valueWeakRef?.deref() !== undefined;
|
|
345
|
-
|
|
346
|
-
log(
|
|
347
|
-
logId,
|
|
348
|
-
`Key alive via WeakRef: ${keyAlive ? "YES" : "NO"}`,
|
|
349
|
-
!keyAlive ? "success" : "error",
|
|
350
|
-
);
|
|
351
|
-
log(
|
|
352
|
-
logId,
|
|
353
|
-
`Value alive via WeakRef: ${valueAlive ? "YES" : "NO"}`,
|
|
354
|
-
!valueAlive ? "success" : "error",
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
if (!keyAlive && !valueAlive) {
|
|
358
|
-
log(
|
|
359
|
-
logId,
|
|
360
|
-
"✅ SUCCESS: Key and value could be GC'ed, as expected",
|
|
361
|
-
"success",
|
|
362
|
-
);
|
|
363
|
-
} else {
|
|
364
|
-
log(
|
|
365
|
-
logId,
|
|
366
|
-
"❌ FAILURE: Objects still alive despite no references",
|
|
367
|
-
"error",
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
window.createManyEntries = () => {
|
|
374
|
-
const logId = "memory-log";
|
|
375
|
-
document.getElementById(logId).innerHTML = "";
|
|
376
|
-
|
|
377
|
-
log(logId, "🏗️ CREATING MANY CACHE ENTRIES", "warning");
|
|
378
|
-
log(
|
|
379
|
-
logId,
|
|
380
|
-
"📝 What we do: Create 100 entries, keep refs to first 5",
|
|
381
|
-
"info",
|
|
382
|
-
);
|
|
383
|
-
log(
|
|
384
|
-
logId,
|
|
385
|
-
"📝 Expected: All entries created, stats show 100 pairs",
|
|
386
|
-
"info",
|
|
387
|
-
);
|
|
388
|
-
log(logId, "", "info");
|
|
389
|
-
|
|
390
|
-
try {
|
|
391
|
-
const count = 100;
|
|
392
|
-
const keys = [];
|
|
393
|
-
const values = [];
|
|
394
|
-
|
|
395
|
-
for (let i = 0; i < count; i++) {
|
|
396
|
-
const key = { id: i, data: `key-${i}` };
|
|
397
|
-
const value = { id: i, result: `value-${i}` };
|
|
398
|
-
cache.set(key, value);
|
|
399
|
-
|
|
400
|
-
if (i < 5) {
|
|
401
|
-
keys.push(key);
|
|
402
|
-
values.push(value);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
window.testReferences = { keys, values };
|
|
407
|
-
|
|
408
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
409
|
-
const stats = cache.getStats();
|
|
410
|
-
log(logId, `Created entries: ${count}`, "info");
|
|
411
|
-
log(logId, `Kept references to: 5 entries`, "info");
|
|
412
|
-
log(
|
|
413
|
-
logId,
|
|
414
|
-
`Cache stats: ${stats.ephemeronPairs.total} total pairs`,
|
|
415
|
-
stats.ephemeronPairs.total >= count ? "success" : "error",
|
|
416
|
-
);
|
|
417
|
-
log(logId, `✅ SUCCESS: Entries created`, "success");
|
|
418
|
-
} catch (error) {
|
|
419
|
-
log(logId, `❌ ERROR: ${error.message}`, "error");
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
window.clearReferences = async () => {
|
|
424
|
-
const logId = "memory-log";
|
|
425
|
-
|
|
426
|
-
const initialStats = cache.getStats();
|
|
427
|
-
|
|
428
|
-
// Check if already cleared
|
|
429
|
-
if (
|
|
430
|
-
initialStats.ephemeronPairs.total <= 1 &&
|
|
431
|
-
!window.testReferences &&
|
|
432
|
-
!testKey2 &&
|
|
433
|
-
!testValue2
|
|
434
|
-
) {
|
|
435
|
-
log(logId, "✅ ALREADY CLEAN", "success");
|
|
436
|
-
log(logId, "📝 All test references already cleared and GC'd", "info");
|
|
437
|
-
log(
|
|
438
|
-
logId,
|
|
439
|
-
`Current state: ${initialStats.ephemeronPairs.total} pairs remaining (ephemeron test only)`,
|
|
440
|
-
"info",
|
|
441
|
-
);
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
log(logId, "🗑️ CLEARING ALL REFERENCES", "warning");
|
|
446
|
-
log(
|
|
447
|
-
logId,
|
|
448
|
-
"📝 What we do: Clear all test references (except ephemeron test)",
|
|
449
|
-
"info",
|
|
450
|
-
);
|
|
451
|
-
log(
|
|
452
|
-
logId,
|
|
453
|
-
"📝 Expected: Unreferenced entries should be GC eligible",
|
|
454
|
-
"info",
|
|
455
|
-
);
|
|
456
|
-
log(logId, "", "info");
|
|
457
|
-
|
|
458
|
-
try {
|
|
459
|
-
const beforeStats = cache.getStats();
|
|
460
|
-
|
|
461
|
-
if (window.testReferences) {
|
|
462
|
-
window.testReferences.keys.length = 0;
|
|
463
|
-
window.testReferences.values.length = 0;
|
|
464
|
-
window.testReferences = null;
|
|
465
|
-
}
|
|
466
|
-
// Don't clear testValue1 - that's for ephemeron test
|
|
467
|
-
testKey2 = null;
|
|
468
|
-
testValue2 = null;
|
|
469
|
-
|
|
470
|
-
await forceGCWithPressure();
|
|
471
|
-
|
|
472
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
473
|
-
const afterStats = cache.getStats();
|
|
474
|
-
log(
|
|
475
|
-
logId,
|
|
476
|
-
`Before clearing: ${beforeStats.ephemeronPairs.total} pairs`,
|
|
477
|
-
"info",
|
|
478
|
-
);
|
|
479
|
-
log(
|
|
480
|
-
logId,
|
|
481
|
-
`After GC: ${afterStats.ephemeronPairs.total} pairs`,
|
|
482
|
-
"info",
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
const wasGCed =
|
|
486
|
-
afterStats.ephemeronPairs.total < beforeStats.ephemeronPairs.total;
|
|
487
|
-
log(
|
|
488
|
-
logId,
|
|
489
|
-
`Entries garbage collected: ${wasGCed ? "YES" : "NO"}`,
|
|
490
|
-
wasGCed ? "success" : "warning",
|
|
491
|
-
);
|
|
492
|
-
|
|
493
|
-
if (wasGCed) {
|
|
494
|
-
log(
|
|
495
|
-
logId,
|
|
496
|
-
`✅ SUCCESS: ${beforeStats.ephemeronPairs.total - afterStats.ephemeronPairs.total} entries GC'd`,
|
|
497
|
-
"success",
|
|
498
|
-
);
|
|
499
|
-
} else {
|
|
500
|
-
log(
|
|
501
|
-
logId,
|
|
502
|
-
"⚠️ No GC detected (ephemeron test entry still alive)",
|
|
503
|
-
"warning",
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
} catch (error) {
|
|
507
|
-
log(logId, `❌ ERROR: ${error.message}`, "error");
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
|
|
511
|
-
window.testCleanup = async () => {
|
|
512
|
-
const logId = "memory-log";
|
|
513
|
-
|
|
514
|
-
log(logId, "🧹 TESTING CLEANUP MECHANISM", "warning");
|
|
515
|
-
log(
|
|
516
|
-
logId,
|
|
517
|
-
"📝 What we do: Force GC then iterate cache to trigger cleanup",
|
|
518
|
-
"info",
|
|
519
|
-
);
|
|
520
|
-
log(
|
|
521
|
-
logId,
|
|
522
|
-
"📝 Expected: Dead pairs removed from internal structures",
|
|
523
|
-
"info",
|
|
524
|
-
);
|
|
525
|
-
log(logId, "", "info");
|
|
526
|
-
|
|
527
|
-
try {
|
|
528
|
-
const beforeStats = cache.getStats();
|
|
529
|
-
await forceGCWithPressure();
|
|
530
|
-
|
|
531
|
-
let iteratedCount = 0;
|
|
532
|
-
// eslint-disable-next-line no-unused-vars
|
|
533
|
-
for (const [key, value] of cache) {
|
|
534
|
-
iteratedCount++;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
538
|
-
const afterStats = cache.getStats();
|
|
539
|
-
log(
|
|
540
|
-
logId,
|
|
541
|
-
`Before cleanup: ${beforeStats.ephemeronPairs.total} total, ${beforeStats.ephemeronPairs.alive} alive`,
|
|
542
|
-
"info",
|
|
543
|
-
);
|
|
544
|
-
log(
|
|
545
|
-
logId,
|
|
546
|
-
`After cleanup: ${afterStats.ephemeronPairs.total} total, ${afterStats.ephemeronPairs.alive} alive`,
|
|
547
|
-
"info",
|
|
548
|
-
);
|
|
549
|
-
log(logId, `Iterated entries: ${iteratedCount}`, "info");
|
|
550
|
-
|
|
551
|
-
const cleaned =
|
|
552
|
-
beforeStats.ephemeronPairs.total - afterStats.ephemeronPairs.total;
|
|
553
|
-
if (cleaned > 0) {
|
|
554
|
-
log(
|
|
555
|
-
logId,
|
|
556
|
-
`✅ SUCCESS: Cleanup removed ${cleaned} dead entries`,
|
|
557
|
-
"success",
|
|
558
|
-
);
|
|
559
|
-
} else {
|
|
560
|
-
log(logId, "ℹ️ No cleanup needed (no dead entries)", "info");
|
|
561
|
-
}
|
|
562
|
-
} catch (error) {
|
|
563
|
-
log(logId, `❌ ERROR: ${error.message}`, "error");
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
window.testBasicOperations = () => {
|
|
568
|
-
const logId = "basic-log";
|
|
569
|
-
document.getElementById(logId).innerHTML = "";
|
|
570
|
-
|
|
571
|
-
log(logId, "🔧 TESTING BASIC SET/GET OPERATIONS", "warning");
|
|
572
|
-
log(
|
|
573
|
-
logId,
|
|
574
|
-
"📝 What we do: Set object key-value, then get it back",
|
|
575
|
-
"info",
|
|
576
|
-
);
|
|
577
|
-
log(logId, "📝 Expected: Key exists, value matches exactly", "info");
|
|
578
|
-
log(logId, "", "info");
|
|
579
|
-
|
|
580
|
-
try {
|
|
581
|
-
testKey2 = { id: 1, name: "test" };
|
|
582
|
-
testValue2 = { data: "value1" };
|
|
583
|
-
|
|
584
|
-
cache.set(testKey2, testValue2);
|
|
585
|
-
const retrieved = cache.get(testKey2);
|
|
586
|
-
const keyExists = cache.get(testKey2) !== undefined;
|
|
587
|
-
|
|
588
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
589
|
-
log(
|
|
590
|
-
logId,
|
|
591
|
-
`Key exists in cache: ${keyExists}`,
|
|
592
|
-
keyExists ? "success" : "error",
|
|
593
|
-
);
|
|
594
|
-
log(
|
|
595
|
-
logId,
|
|
596
|
-
`Retrieved value matches: ${retrieved === testValue2}`,
|
|
597
|
-
retrieved === testValue2 ? "success" : "error",
|
|
598
|
-
);
|
|
599
|
-
|
|
600
|
-
// Test primitive keys
|
|
601
|
-
log(logId, "", "info");
|
|
602
|
-
log(logId, "📝 Testing primitive keys (string)", "info");
|
|
603
|
-
log(logId, "📝 Expected: Works but uses permanent memory", "info");
|
|
604
|
-
|
|
605
|
-
cache.set("primitive", "primitiveValue");
|
|
606
|
-
const primitiveValue = cache.get("primitive");
|
|
607
|
-
const primitiveExists = cache.get("primitive") !== undefined;
|
|
608
|
-
|
|
609
|
-
log(
|
|
610
|
-
logId,
|
|
611
|
-
`Primitive key exists: ${primitiveExists}`,
|
|
612
|
-
primitiveExists ? "success" : "error",
|
|
613
|
-
);
|
|
614
|
-
log(
|
|
615
|
-
logId,
|
|
616
|
-
`Primitive value matches: ${primitiveValue === "primitiveValue"}`,
|
|
617
|
-
primitiveValue === "primitiveValue" ? "success" : "error",
|
|
618
|
-
);
|
|
619
|
-
log(logId, "⚠️ Primitive keys never garbage collected", "warning");
|
|
620
|
-
} catch (error) {
|
|
621
|
-
log(logId, `❌ ERROR: ${error.message}`, "error");
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
window.testDeepEquality = () => {
|
|
626
|
-
const logId = "basic-log";
|
|
627
|
-
|
|
628
|
-
log(logId, "", "info");
|
|
629
|
-
log(logId, "🔍 TESTING DEEP EQUALITY", "warning");
|
|
630
|
-
log(
|
|
631
|
-
logId,
|
|
632
|
-
"📝 What we do: Set with key1, get with key2 (same content, different objects)",
|
|
633
|
-
"info",
|
|
634
|
-
);
|
|
635
|
-
log(logId, "📝 Expected: key2 should find value set by key1", "info");
|
|
636
|
-
log(logId, "", "info");
|
|
637
|
-
|
|
638
|
-
try {
|
|
639
|
-
const key1 = { id: 1, nested: { prop: "value" } };
|
|
640
|
-
const key2 = { id: 1, nested: { prop: "value" } };
|
|
641
|
-
const value = { result: "found" };
|
|
642
|
-
|
|
643
|
-
cache.set(key1, value);
|
|
644
|
-
const key1Exists = cache.get(key1) !== undefined;
|
|
645
|
-
const key2Exists = cache.get(key2) !== undefined;
|
|
646
|
-
const retrieved = cache.get(key2);
|
|
647
|
-
|
|
648
|
-
log(logId, "🔍 ACTUAL RESULTS:", "warning");
|
|
649
|
-
log(
|
|
650
|
-
logId,
|
|
651
|
-
`Original key1 exists: ${key1Exists}`,
|
|
652
|
-
key1Exists ? "success" : "error",
|
|
653
|
-
);
|
|
654
|
-
log(
|
|
655
|
-
logId,
|
|
656
|
-
`Equivalent key2 exists: ${key2Exists}`,
|
|
657
|
-
key2Exists ? "success" : "error",
|
|
658
|
-
);
|
|
659
|
-
log(
|
|
660
|
-
logId,
|
|
661
|
-
`Retrieved same value: ${retrieved === value}`,
|
|
662
|
-
retrieved === value ? "success" : "error",
|
|
663
|
-
);
|
|
664
|
-
|
|
665
|
-
if (key2Exists && retrieved === value) {
|
|
666
|
-
log(logId, "✅ SUCCESS: Deep equality working", "success");
|
|
667
|
-
} else {
|
|
668
|
-
log(logId, "❌ FAILURE: Deep equality not working", "error");
|
|
669
|
-
}
|
|
670
|
-
} catch (error) {
|
|
671
|
-
log(logId, `❌ ERROR: ${error.message}`, "error");
|
|
672
|
-
}
|
|
673
|
-
};
|
|
674
|
-
|
|
675
|
-
// Initial setup
|
|
676
|
-
log(
|
|
677
|
-
"retention-log",
|
|
678
|
-
"🎯 Ready to test ephemeron pattern - mutual retention",
|
|
679
|
-
"info",
|
|
680
|
-
);
|
|
681
|
-
log(
|
|
682
|
-
"retention-log",
|
|
683
|
-
"📖 Ephemeron: As long as either key OR value is alive, BOTH stay alive",
|
|
684
|
-
"info",
|
|
685
|
-
);
|
|
686
|
-
log("memory-log", "🧠 Ready to test memory management", "info");
|
|
687
|
-
log("basic-log", "⚙️ Ready to test basic operations", "info");
|
|
688
|
-
</script>
|
|
689
|
-
</body>
|
|
690
|
-
</html>
|