@ugo-studio/jspp 0.1.2 → 0.1.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.
Files changed (72) hide show
  1. package/README.md +5 -3
  2. package/dist/analysis/scope.js +38 -15
  3. package/dist/analysis/typeAnalyzer.js +257 -23
  4. package/dist/ast/types.js +6 -0
  5. package/dist/cli.js +3 -4
  6. package/dist/core/codegen/class-handlers.js +127 -0
  7. package/dist/core/codegen/control-flow-handlers.js +464 -0
  8. package/dist/core/codegen/declaration-handlers.js +31 -14
  9. package/dist/core/codegen/expression-handlers.js +432 -116
  10. package/dist/core/codegen/function-handlers.js +110 -13
  11. package/dist/core/codegen/helpers.js +76 -8
  12. package/dist/core/codegen/index.js +18 -5
  13. package/dist/core/codegen/literal-handlers.js +3 -0
  14. package/dist/core/codegen/statement-handlers.js +152 -186
  15. package/dist/core/codegen/visitor.js +35 -3
  16. package/package.json +3 -3
  17. package/src/prelude/any_value.hpp +658 -734
  18. package/src/prelude/any_value_access.hpp +103 -0
  19. package/src/prelude/any_value_defines.hpp +151 -0
  20. package/src/prelude/any_value_helpers.hpp +246 -0
  21. package/src/prelude/exception.hpp +31 -0
  22. package/src/prelude/exception_helpers.hpp +49 -0
  23. package/src/prelude/index.hpp +35 -12
  24. package/src/prelude/library/console.hpp +20 -20
  25. package/src/prelude/library/error.hpp +111 -0
  26. package/src/prelude/library/global.hpp +15 -4
  27. package/src/prelude/library/performance.hpp +25 -0
  28. package/src/prelude/library/promise.hpp +121 -0
  29. package/src/prelude/library/symbol.hpp +60 -4
  30. package/src/prelude/library/timer.hpp +92 -0
  31. package/src/prelude/scheduler.hpp +145 -0
  32. package/src/prelude/types.hpp +33 -6
  33. package/src/prelude/utils/access.hpp +174 -0
  34. package/src/prelude/utils/log_any_value/array.hpp +245 -0
  35. package/src/prelude/utils/log_any_value/config.hpp +32 -0
  36. package/src/prelude/utils/log_any_value/function.hpp +37 -0
  37. package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
  38. package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
  39. package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
  40. package/src/prelude/utils/log_any_value/object.hpp +119 -0
  41. package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
  42. package/src/prelude/{operators.hpp → utils/operators.hpp} +31 -12
  43. package/src/prelude/utils/well_known_symbols.hpp +13 -0
  44. package/src/prelude/values/array.hpp +5 -2
  45. package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
  46. package/src/prelude/values/function.hpp +76 -19
  47. package/src/prelude/values/{operators → helpers}/array.hpp +30 -14
  48. package/src/prelude/values/helpers/function.hpp +125 -0
  49. package/src/prelude/values/helpers/iterator.hpp +107 -0
  50. package/src/prelude/values/helpers/object.hpp +64 -0
  51. package/src/prelude/values/helpers/promise.hpp +181 -0
  52. package/src/prelude/values/helpers/string.hpp +50 -0
  53. package/src/prelude/values/helpers/symbol.hpp +23 -0
  54. package/src/prelude/values/iterator.hpp +96 -0
  55. package/src/prelude/values/object.hpp +8 -3
  56. package/src/prelude/values/promise.hpp +73 -0
  57. package/src/prelude/values/prototypes/array.hpp +23 -16
  58. package/src/prelude/values/prototypes/function.hpp +26 -0
  59. package/src/prelude/values/prototypes/iterator.hpp +58 -0
  60. package/src/prelude/values/prototypes/object.hpp +26 -0
  61. package/src/prelude/values/prototypes/promise.hpp +124 -0
  62. package/src/prelude/values/prototypes/string.hpp +366 -357
  63. package/src/prelude/values/prototypes/symbol.hpp +41 -0
  64. package/src/prelude/values/string.hpp +25 -0
  65. package/src/prelude/values/symbol.hpp +102 -0
  66. package/src/prelude/access.hpp +0 -86
  67. package/src/prelude/error.hpp +0 -31
  68. package/src/prelude/error_helpers.hpp +0 -59
  69. package/src/prelude/log_string.hpp +0 -403
  70. package/src/prelude/values/operators/function.hpp +0 -34
  71. package/src/prelude/values/operators/object.hpp +0 -34
  72. package/src/prelude/well_known_symbols.hpp +0 -10
@@ -0,0 +1,145 @@
1
+ #pragma once
2
+ #include <deque>
3
+ #include <functional>
4
+ #include <chrono>
5
+ #include <queue>
6
+ #include <unordered_set>
7
+ #include <vector>
8
+ #include <thread>
9
+ #include <iostream>
10
+
11
+ namespace jspp {
12
+ class Scheduler {
13
+ public:
14
+ using Task = std::function<void()>;
15
+ using TimePoint = std::chrono::steady_clock::time_point;
16
+
17
+ struct Timer {
18
+ size_t id;
19
+ TimePoint next_run;
20
+ std::chrono::milliseconds interval; // 0 if not repeating
21
+ Task task;
22
+
23
+ // Min-heap priority queue (smallest time at top)
24
+ bool operator>(const Timer& other) const {
25
+ return next_run > other.next_run;
26
+ }
27
+ };
28
+
29
+ static Scheduler& instance() {
30
+ static Scheduler s;
31
+ return s;
32
+ }
33
+
34
+ void enqueue(Task task) {
35
+ tasks.push_back(std::move(task));
36
+ }
37
+
38
+ size_t set_timeout(Task task, size_t delay_ms) {
39
+ return schedule_timer(std::move(task), delay_ms, false);
40
+ }
41
+
42
+ size_t set_interval(Task task, size_t delay_ms) {
43
+ return schedule_timer(std::move(task), delay_ms, true);
44
+ }
45
+
46
+ void clear_timer(size_t id) {
47
+ cancelled_timers.insert(id);
48
+ }
49
+
50
+ void run() {
51
+ while (true) {
52
+ bool has_work = false;
53
+
54
+ // 1. Process all immediate tasks (microtask/task queue)
55
+ while (!tasks.empty()) {
56
+ Task task = tasks.front();
57
+ tasks.pop_front();
58
+ task();
59
+ has_work = true;
60
+ }
61
+
62
+ // 2. Process timers
63
+ auto now = std::chrono::steady_clock::now();
64
+ while (!timers.empty()) {
65
+ // Peek top
66
+ const auto& top = timers.top();
67
+
68
+ // Cleanup cancelled timers lazily
69
+ if (cancelled_timers.count(top.id)) {
70
+ cancelled_timers.erase(top.id);
71
+ timers.pop();
72
+ continue;
73
+ }
74
+
75
+ if (top.next_run <= now) {
76
+ // Timer is ready
77
+ Timer t = top;
78
+ timers.pop();
79
+
80
+ // Execute task
81
+ t.task();
82
+ has_work = true;
83
+
84
+ // Reschedule if interval and not cancelled during execution
85
+ if (t.interval.count() > 0 && cancelled_timers.find(t.id) == cancelled_timers.end()) {
86
+ // Drift-safe(ish) scheduling: run next interval relative to now
87
+ // Note: JS allows drift.
88
+ t.next_run = std::chrono::steady_clock::now() + t.interval;
89
+ timers.push(t);
90
+ }
91
+ } else {
92
+ break; // Next timer is in the future
93
+ }
94
+ }
95
+
96
+ // 3. Exit or Wait
97
+ if (!has_work) {
98
+ if (tasks.empty() && timers.empty()) {
99
+ break; // No pending work, exit event loop
100
+ }
101
+
102
+ if (!timers.empty()) {
103
+ auto next_time = timers.top().next_run;
104
+ std::this_thread::sleep_until(next_time);
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ bool has_tasks() const {
111
+ return !tasks.empty() || !timers.empty();
112
+ }
113
+
114
+ private:
115
+ std::deque<Task> tasks;
116
+ std::priority_queue<Timer, std::vector<Timer>, std::greater<Timer>> timers;
117
+ std::unordered_set<size_t> cancelled_timers;
118
+ size_t next_timer_id = 1;
119
+ const size_t MAX_TIMER_ID = 2147483647; // 2^31 - 1
120
+
121
+ size_t schedule_timer(Task task, size_t delay_ms, bool repeat) {
122
+ size_t id = next_timer_id++;
123
+ if (next_timer_id > MAX_TIMER_ID) {
124
+ next_timer_id = 1;
125
+ }
126
+
127
+ // If we wrap around, ensure we don't accidentally treat this new ID as cancelled
128
+ // (in case an old timer with this ID is still lingering in the 'cancelled' set)
129
+ if (cancelled_timers.count(id)) {
130
+ cancelled_timers.erase(id);
131
+ }
132
+
133
+ auto now = std::chrono::steady_clock::now();
134
+
135
+ Timer t;
136
+ t.id = id;
137
+ t.next_run = now + std::chrono::milliseconds(delay_ms);
138
+ t.interval = repeat ? std::chrono::milliseconds(delay_ms) : std::chrono::milliseconds(0);
139
+ t.task = std::move(task);
140
+
141
+ timers.push(t);
142
+ return id;
143
+ }
144
+ };
145
+ }
@@ -6,6 +6,7 @@
6
6
  #include <variant>
7
7
  #include <functional>
8
8
  #include <memory>
9
+ #include <map>
9
10
  #include <unordered_map>
10
11
  #include <algorithm>
11
12
  #include <cctype>
@@ -17,34 +18,60 @@
17
18
  // JSPP standard library
18
19
  namespace jspp
19
20
  {
20
- // Forward declarations
21
+ // Js value forward declarations
21
22
  struct JsUndefined; // cannot set property
22
23
  struct JsNull; // cannot set property
23
24
  struct JsUninitialized; // cannot set property
25
+ struct JsString; // can set property
24
26
  struct JsObject; // can set property
25
27
  struct JsArray; // can set property
26
28
  struct JsFunction; // can set property
29
+ struct JsPromise; // can set property
30
+ struct JsSymbol; // can set property (but usually doesn't have own props)
31
+
32
+ template <typename T>
33
+ class JsIterator; // can set property
27
34
 
28
35
  // Object property configuration forward declarations
29
36
  struct DataDescriptor;
30
37
  struct AccessorDescriptor;
31
38
 
39
+ // Custom runtime exception
40
+ struct Exception;
41
+
32
42
  // Dynamic AnyValue
33
43
  class AnyValue;
34
44
 
35
- // Custom runtime exception
36
- struct RuntimeError;
37
-
38
45
  // Arithemetic operators
39
46
  inline AnyValue pow(const AnyValue &lhs, const AnyValue &rhs);
40
47
 
41
48
  // AnyValue prototypes
49
+ namespace ObjectPrototypes
50
+ {
51
+ inline std::optional<AnyValue> get(const std::string &key, JsObject *self);
52
+ }
42
53
  namespace StringPrototypes
43
54
  {
44
- inline std::optional<AnyValue> get(const std::string &key, const std::unique_ptr<std::string> &self);
55
+ inline std::optional<AnyValue> get(const std::string &key, JsString *self);
45
56
  }
46
57
  namespace ArrayPrototypes
47
58
  {
48
59
  inline std::optional<AnyValue> get(const std::string &key, JsArray *self);
49
60
  }
50
- }
61
+ namespace FunctionPrototypes
62
+ {
63
+ inline std::optional<AnyValue> get(const std::string &key, JsFunction *self);
64
+ }
65
+ namespace PromisePrototypes
66
+ {
67
+ inline std::optional<AnyValue> get(const std::string &key, JsPromise *self);
68
+ }
69
+ namespace IteratorPrototypes
70
+ {
71
+ inline std::optional<AnyValue> get(const std::string &key, JsIterator<AnyValue> *self);
72
+ }
73
+ namespace SymbolPrototypes
74
+ {
75
+ inline std::optional<AnyValue> get(const std::string &key, JsSymbol *self);
76
+ }
77
+ }
@@ -0,0 +1,174 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "well_known_symbols.hpp"
5
+ #include "values/function.hpp"
6
+ #include "values/symbol.hpp"
7
+ #include "exception.hpp"
8
+ #include "any_value.hpp"
9
+ #include <ranges>
10
+
11
+ namespace jspp
12
+ {
13
+ namespace Access
14
+ {
15
+ // Helper function to check for TDZ and deref heap-allocated variables
16
+ inline const AnyValue &deref_ptr(const std::shared_ptr<AnyValue> &var, const std::string &name)
17
+ {
18
+ if ((*var).is_uninitialized()) [[unlikely]]
19
+ {
20
+ Exception::throw_uninitialized_reference(name);
21
+ }
22
+ return *var;
23
+ }
24
+ inline AnyValue &deref_ptr(std::shared_ptr<AnyValue> &var, const std::string &name)
25
+ {
26
+ if ((*var).is_uninitialized()) [[unlikely]]
27
+ {
28
+ Exception::throw_uninitialized_reference(name);
29
+ }
30
+ return *var;
31
+ }
32
+ inline const AnyValue &deref_ptr(const std::unique_ptr<AnyValue> &var, const std::string &name)
33
+ {
34
+ if ((*var).is_uninitialized()) [[unlikely]]
35
+ {
36
+ Exception::throw_uninitialized_reference(name);
37
+ }
38
+ return *var;
39
+ }
40
+ inline AnyValue &deref_ptr(std::unique_ptr<AnyValue> &var, const std::string &name)
41
+ {
42
+ if ((*var).is_uninitialized()) [[unlikely]]
43
+ {
44
+ Exception::throw_uninitialized_reference(name);
45
+ }
46
+ return *var;
47
+ }
48
+
49
+ // Helper function to check for TDZ on stack-allocated variables
50
+ inline const AnyValue &deref_stack(const AnyValue &var, const std::string &name)
51
+ {
52
+ if (var.is_uninitialized()) [[unlikely]]
53
+ {
54
+ Exception::throw_uninitialized_reference(name);
55
+ }
56
+ return var;
57
+ }
58
+ inline AnyValue &deref_stack(AnyValue &var, const std::string &name)
59
+ {
60
+ if (var.is_uninitialized()) [[unlikely]]
61
+ {
62
+ Exception::throw_uninitialized_reference(name);
63
+ }
64
+ return var;
65
+ }
66
+
67
+ inline AnyValue typeof(const AnyValue &val)
68
+ {
69
+ switch (val.get_type())
70
+ {
71
+ case JsType::Undefined:
72
+ return AnyValue::make_string("undefined");
73
+ case JsType::Null:
74
+ return AnyValue::make_string("object");
75
+ case JsType::Boolean:
76
+ return AnyValue::make_string("boolean");
77
+ case JsType::Number:
78
+ return AnyValue::make_string("number");
79
+ case JsType::String:
80
+ return AnyValue::make_string("string");
81
+ case JsType::Symbol:
82
+ return AnyValue::make_string("symbol");
83
+ case JsType::Function:
84
+ return AnyValue::make_string("function");
85
+ case JsType::Object:
86
+ case JsType::Array:
87
+ case JsType::Iterator:
88
+ return AnyValue::make_string("object");
89
+ default:
90
+ return AnyValue::make_string("undefined");
91
+ }
92
+ }
93
+ inline AnyValue typeof() // for undeclared variables
94
+ {
95
+ return AnyValue::make_string("undefined");
96
+ }
97
+
98
+ // Helper function to get enumerable own property keys/values of an object
99
+ inline std::vector<std::string> get_object_keys(const AnyValue &obj)
100
+ {
101
+ std::vector<std::string> keys;
102
+
103
+ if (obj.is_object())
104
+ {
105
+ auto ptr = obj.as_object();
106
+ for (const auto &pair : ptr->props)
107
+ {
108
+ if (!JsSymbol::is_internal_key(pair.first))
109
+ keys.push_back(pair.first);
110
+ }
111
+ }
112
+ if (obj.is_function())
113
+ {
114
+ auto ptr = obj.as_function();
115
+ for (const auto &pair : ptr->props)
116
+ {
117
+ if (!JsSymbol::is_internal_key(pair.first))
118
+ {
119
+ if (!pair.second.is_data_descriptor() && !pair.second.is_accessor_descriptor())
120
+ keys.push_back(pair.first);
121
+ else if ((pair.second.is_data_descriptor() && pair.second.as_data_descriptor()->enumerable) ||
122
+ (pair.second.is_accessor_descriptor() && pair.second.as_accessor_descriptor()->enumerable))
123
+ keys.push_back(pair.first);
124
+ }
125
+ }
126
+ }
127
+ if (obj.is_array())
128
+ {
129
+ auto len = obj.as_array()->length;
130
+ for (auto i = 0; i < len; ++i)
131
+ {
132
+ keys.push_back(std::to_string(i));
133
+ }
134
+ }
135
+ if (obj.is_string())
136
+ {
137
+ auto len = obj.as_string()->value.length();
138
+ for (auto i = 0; i < len; ++i)
139
+ {
140
+ keys.push_back(std::to_string(i));
141
+ }
142
+ }
143
+
144
+ return keys;
145
+ }
146
+ inline AnyValue get_object_value_iterator(const AnyValue &obj, const std::string &name)
147
+ {
148
+ if (obj.is_iterator())
149
+ {
150
+ return obj;
151
+ }
152
+
153
+ auto gen_fn = obj.get_own_property(WellKnownSymbols::iterator->key);
154
+ if (gen_fn.is_function())
155
+ {
156
+ auto iter = gen_fn.as_function()->call(gen_fn, {});
157
+ if (iter.is_iterator())
158
+ {
159
+ return iter;
160
+ }
161
+ if (iter.is_object())
162
+ {
163
+ auto next_fn = iter.get_own_property("next");
164
+ if (next_fn.is_function())
165
+ {
166
+ return iter;
167
+ }
168
+ }
169
+ }
170
+
171
+ throw jspp::Exception::make_exception(name + " is not iterable", "TypeError");
172
+ }
173
+ }
174
+ }
@@ -0,0 +1,245 @@
1
+ #pragma once
2
+ #include "types.hpp"
3
+ #include "any_value.hpp"
4
+ #include "utils/log_any_value/config.hpp"
5
+ #include "utils/log_any_value/helpers.hpp"
6
+ #include "utils/log_any_value/fwd.hpp"
7
+ #include <string>
8
+ #include <sstream>
9
+ #include <unordered_set>
10
+ #include <algorithm>
11
+ #include <optional>
12
+
13
+ namespace jspp
14
+ {
15
+ namespace LogAnyValue
16
+ {
17
+ inline std::string format_array(const AnyValue &val, std::unordered_set<const void *> &visited, int depth)
18
+ {
19
+ auto arr = val.as_array();
20
+ size_t item_count = static_cast<size_t>(arr->length);
21
+ size_t prop_count = arr->props.size();
22
+
23
+ // // If custom toString exists on the object, prefer it
24
+ // auto itToString = arr->props.find("toString");
25
+ // if (depth > 0 && itToString != arr->props.end() && itToString->second.is_function())
26
+ // {
27
+ // try
28
+ // {
29
+ // auto result = itToString->second.as_function()->call(itToString->second, {});
30
+ // return to_log_string(result, visited, depth);
31
+ // }
32
+ // catch (...)
33
+ // {
34
+ // // ignore and fallback to manual formatting
35
+ // }
36
+ // }
37
+
38
+ std::string indent(depth * 2, ' ');
39
+ std::string next_indent((depth + 1) * 2, ' ');
40
+ std::stringstream ss;
41
+
42
+ // Horizontal layout for small and simple arrays
43
+ bool use_horizontal_layout = item_count <= HORIZONTAL_ARRAY_MAX_ITEMS;
44
+ if (use_horizontal_layout)
45
+ {
46
+ for (size_t i = 0; i < item_count; ++i)
47
+ {
48
+ std::optional<AnyValue> itemVal;
49
+ if (i < arr->dense.size())
50
+ {
51
+ itemVal = arr->dense[i];
52
+ }
53
+ else
54
+ {
55
+ auto it = arr->sparse.find(static_cast<uint32_t>(i));
56
+ if (it != arr->sparse.end())
57
+ {
58
+ itemVal = it->second;
59
+ }
60
+ }
61
+ if (itemVal.has_value() && !is_simple_value(itemVal.value()))
62
+ {
63
+ use_horizontal_layout = false;
64
+ break;
65
+ }
66
+ }
67
+ }
68
+
69
+ if (use_horizontal_layout)
70
+ {
71
+ ss << "[ ";
72
+ size_t empty_count = 0;
73
+ bool needs_comma = false;
74
+
75
+ for (size_t i = 0; i < item_count; ++i)
76
+ {
77
+ std::optional<AnyValue> itemVal;
78
+ if (i < arr->dense.size())
79
+ {
80
+ itemVal = arr->dense[i];
81
+ }
82
+ else
83
+ {
84
+ auto it = arr->sparse.find(static_cast<uint32_t>(i));
85
+ if (it != arr->sparse.end())
86
+ {
87
+ itemVal = it->second;
88
+ }
89
+ }
90
+
91
+ if (itemVal.has_value())
92
+ {
93
+ if (empty_count > 0)
94
+ {
95
+ if (needs_comma)
96
+ ss << Color::BRIGHT_BLACK << ", " << Color::RESET;
97
+ ss << Color::BRIGHT_BLACK << empty_count << " x empty item" << (empty_count > 1 ? "s" : "") << Color::RESET;
98
+ needs_comma = true;
99
+ empty_count = 0;
100
+ }
101
+ if (needs_comma)
102
+ ss << Color::BRIGHT_BLACK << ", " << Color::RESET;
103
+ ss << to_log_string(itemVal.value(), visited, depth + 1);
104
+ needs_comma = true;
105
+ }
106
+ else
107
+ {
108
+ empty_count++;
109
+ }
110
+ }
111
+
112
+ if (empty_count > 0)
113
+ {
114
+ if (needs_comma)
115
+ ss << Color::BRIGHT_BLACK << ", " << Color::RESET;
116
+ ss << Color::BRIGHT_BLACK << empty_count << " x empty item" << (empty_count > 1 ? "s" : "") << Color::RESET;
117
+ }
118
+
119
+ // Print properties
120
+ if (prop_count > 0)
121
+ {
122
+ ss << Color::BRIGHT_BLACK << ", " << Color::RESET;
123
+
124
+ size_t current_prop = 0;
125
+ for (const auto &pair : arr->props)
126
+ {
127
+ if (!is_enumerable_property(pair.second))
128
+ continue;
129
+
130
+ if (is_valid_js_identifier(pair.first))
131
+ {
132
+ ss << pair.first;
133
+ }
134
+ else
135
+ {
136
+ ss << "\"" << pair.first << "\"";
137
+ }
138
+ ss << ": " << to_log_string(pair.second, visited, depth + 1);
139
+ if (++current_prop < prop_count)
140
+ ss << Color::BRIGHT_BLACK << ", " << Color::RESET;
141
+ }
142
+ }
143
+
144
+ ss << " ]";
145
+ return ss.str();
146
+ }
147
+
148
+ // Bun-like multi-line layout
149
+ ss << "[\n";
150
+
151
+ const size_t items_to_show = std::min(item_count, MAX_ARRAY_ITEMS);
152
+ size_t empty_count = 0;
153
+ bool first_item_printed = false;
154
+
155
+ for (size_t i = 0; i < items_to_show; ++i)
156
+ {
157
+ std::optional<AnyValue> itemVal;
158
+ if (i < arr->dense.size())
159
+ {
160
+ itemVal = arr->dense[i];
161
+ }
162
+ else
163
+ {
164
+ auto it = arr->sparse.find(static_cast<uint32_t>(i));
165
+ if (it != arr->sparse.end())
166
+ {
167
+ itemVal = it->second;
168
+ }
169
+ }
170
+
171
+ if (itemVal.has_value())
172
+ {
173
+ if (empty_count > 0)
174
+ {
175
+ if (first_item_printed)
176
+ ss << Color::BRIGHT_BLACK << ",\n"
177
+ << Color::RESET;
178
+ ss << next_indent << Color::BRIGHT_BLACK << empty_count << " x empty item" << (empty_count > 1 ? "s" : "") << Color::RESET;
179
+ first_item_printed = true;
180
+ empty_count = 0;
181
+ }
182
+ if (first_item_printed)
183
+ ss << Color::BRIGHT_BLACK << ",\n"
184
+ << Color::RESET;
185
+ ss << next_indent << to_log_string(itemVal.value(), visited, depth + 1);
186
+ first_item_printed = true;
187
+ }
188
+ else
189
+ {
190
+ empty_count++;
191
+ }
192
+ }
193
+
194
+ if (empty_count > 0)
195
+ {
196
+ if (first_item_printed)
197
+ ss << Color::BRIGHT_BLACK << ",\n"
198
+ << Color::RESET;
199
+ ss << next_indent << Color::BRIGHT_BLACK << empty_count << " x empty item" << (empty_count > 1 ? "s" : "") << Color::RESET;
200
+ first_item_printed = true;
201
+ }
202
+
203
+ if (item_count > items_to_show)
204
+ {
205
+ if (first_item_printed)
206
+ ss << Color::BRIGHT_BLACK << ",\n"
207
+ << Color::RESET;
208
+ ss << next_indent << Color::BRIGHT_BLACK << "... " << (item_count - items_to_show) << " more items" << Color::RESET;
209
+ }
210
+ // Print properties
211
+ else if (prop_count > 0)
212
+ {
213
+ if (first_item_printed)
214
+ ss << Color::BRIGHT_BLACK << ",\n"
215
+ << Color::RESET;
216
+
217
+ size_t current_prop = 0;
218
+ for (const auto &pair : arr->props)
219
+ {
220
+ if (current_prop >= MAX_OBJECT_PROPS)
221
+ break;
222
+ if (!is_enumerable_property(pair.second))
223
+ continue;
224
+
225
+ ss << next_indent;
226
+ if (is_valid_js_identifier(pair.first))
227
+ {
228
+ ss << pair.first;
229
+ }
230
+ else
231
+ {
232
+ ss << "\"" << pair.first << "\"";
233
+ }
234
+ ss << ": " << to_log_string(pair.second, visited, depth + 1);
235
+ if (++current_prop < prop_count)
236
+ ss << Color::BRIGHT_BLACK << ",\n"
237
+ << Color::RESET;
238
+ }
239
+ }
240
+ ss << "\n";
241
+ ss << indent << "]";
242
+ return ss.str();
243
+ }
244
+ }
245
+ }
@@ -0,0 +1,32 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+
5
+ namespace jspp
6
+ {
7
+ namespace LogAnyValue
8
+ {
9
+ // --- Configuration for Logging Verbosity ---
10
+ const int MAX_DEPTH = 5;
11
+ const size_t MAX_STRING_LENGTH = 100;
12
+ const size_t MAX_ARRAY_ITEMS = 50;
13
+ const size_t MAX_OBJECT_PROPS = 30;
14
+
15
+ // --- Configuration for Horizontal Layout ---
16
+ const size_t HORIZONTAL_ARRAY_MAX_ITEMS = 10;
17
+ const size_t HORIZONTAL_OBJECT_MAX_PROPS = 5;
18
+
19
+ // ANSI Color Codes for terminal output
20
+ namespace Color
21
+ {
22
+ const std::string RESET = "\033[0m";
23
+ const std::string RED = "\033[31m";
24
+ const std::string GREEN = "\033[32m";
25
+ const std::string YELLOW = "\033[33m";
26
+ const std::string BLUE = "\033[94m";
27
+ const std::string CYAN = "\033[36m";
28
+ const std::string MAGENTA = "\033[35m";
29
+ const std::string BRIGHT_BLACK = "\033[90m"; // Grey
30
+ }
31
+ }
32
+ }