@coherent.js/core 1.0.0-beta.3 → 1.0.0-beta.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.
- package/dist/index.cjs +2531 -1308
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +2523 -1307
- package/dist/index.js.map +4 -4
- package/package.json +4 -2
- package/types/elements.d.ts +1080 -0
- package/types/index.d.ts +199 -65
package/dist/index.cjs
CHANGED
|
@@ -24,9 +24,12 @@ __export(index_exports, {
|
|
|
24
24
|
ComponentLifecycle: () => ComponentLifecycle,
|
|
25
25
|
DOMEventIntegration: () => DOMEventIntegration,
|
|
26
26
|
EventBus: () => EventBus,
|
|
27
|
+
FORBIDDEN_CHILDREN: () => FORBIDDEN_CHILDREN,
|
|
27
28
|
GlobalErrorHandler: () => GlobalErrorHandler,
|
|
29
|
+
HTMLNestingError: () => HTMLNestingError,
|
|
28
30
|
LIFECYCLE_PHASES: () => LIFECYCLE_PHASES,
|
|
29
31
|
VERSION: () => VERSION,
|
|
32
|
+
checkPeerDependencies: () => checkPeerDependencies,
|
|
30
33
|
createActionHandlers: () => createActionHandlers,
|
|
31
34
|
createAsyncErrorBoundary: () => createAsyncErrorBoundary,
|
|
32
35
|
createComponent: () => createComponent,
|
|
@@ -34,10 +37,12 @@ __export(index_exports, {
|
|
|
34
37
|
createElement: () => createElement,
|
|
35
38
|
createErrorBoundary: () => createErrorBoundary,
|
|
36
39
|
createErrorFallback: () => createErrorFallback,
|
|
40
|
+
createErrorResponse: () => createErrorResponse,
|
|
37
41
|
createEventBus: () => createEventBus,
|
|
38
42
|
createEventComponent: () => createEventComponent,
|
|
39
43
|
createEventHandlers: () => createEventHandlers,
|
|
40
44
|
createGlobalErrorHandler: () => createGlobalErrorHandler,
|
|
45
|
+
createLazyIntegration: () => createLazyIntegration,
|
|
41
46
|
createLifecycleHooks: () => createLifecycleHooks,
|
|
42
47
|
createStateManager: () => createStateManager,
|
|
43
48
|
createTextNode: () => createTextNode,
|
|
@@ -55,23 +60,32 @@ __export(index_exports, {
|
|
|
55
60
|
globalEventBus: () => globalEventBus,
|
|
56
61
|
h: () => h,
|
|
57
62
|
handleAction: () => handleAction,
|
|
63
|
+
hasChildren: () => hasChildren,
|
|
64
|
+
importPeerDependency: () => importPeerDependency,
|
|
58
65
|
initializeDOMIntegration: () => initializeDOMIntegration,
|
|
59
|
-
|
|
66
|
+
isCoherentComponent: () => isCoherentComponent,
|
|
67
|
+
isCoherentObject: () => isCoherentObject2,
|
|
60
68
|
isLazy: () => isLazy,
|
|
69
|
+
isPeerDependencyAvailable: () => isPeerDependencyAvailable,
|
|
61
70
|
lazy: () => lazy,
|
|
62
71
|
lifecycleUtils: () => componentUtils,
|
|
63
72
|
memo: () => memo2,
|
|
64
73
|
memoize: () => memoize,
|
|
74
|
+
normalizeChildren: () => normalizeChildren,
|
|
65
75
|
off: () => off,
|
|
66
76
|
on: () => on,
|
|
67
77
|
once: () => once,
|
|
68
78
|
performanceMonitor: () => performanceMonitor,
|
|
69
79
|
registerAction: () => registerAction,
|
|
70
80
|
registerComponent: () => registerComponent,
|
|
71
|
-
render: () =>
|
|
81
|
+
render: () => render2,
|
|
82
|
+
renderComponentFactory: () => renderComponentFactory,
|
|
83
|
+
renderWithMonitoring: () => renderWithMonitoring,
|
|
84
|
+
renderWithTemplate: () => renderWithTemplate,
|
|
72
85
|
shadowDOM: () => shadow_dom_exports,
|
|
73
86
|
useHooks: () => useHooks,
|
|
74
87
|
validateComponent: () => validateComponent2,
|
|
88
|
+
validateNesting: () => validateNesting,
|
|
75
89
|
withErrorBoundary: () => withErrorBoundary,
|
|
76
90
|
withEventBus: () => withEventBus,
|
|
77
91
|
withEventState: () => withEventState,
|
|
@@ -80,6 +94,7 @@ __export(index_exports, {
|
|
|
80
94
|
withStateUtils: () => withStateUtils
|
|
81
95
|
});
|
|
82
96
|
module.exports = __toCommonJS(index_exports);
|
|
97
|
+
var import_node_fs = require("node:fs");
|
|
83
98
|
|
|
84
99
|
// src/performance/monitor.js
|
|
85
100
|
function createPerformanceMonitor(options = {}) {
|
|
@@ -106,6 +121,7 @@ function createPerformanceMonitor(options = {}) {
|
|
|
106
121
|
},
|
|
107
122
|
alerts: {
|
|
108
123
|
enabled: true,
|
|
124
|
+
debounceMs: 5e3,
|
|
109
125
|
rules: []
|
|
110
126
|
},
|
|
111
127
|
resources: {
|
|
@@ -267,7 +283,7 @@ function createPerformanceMonitor(options = {}) {
|
|
|
267
283
|
const alertKey = `${rule.metric}-${rule.condition}-${rule.threshold}`;
|
|
268
284
|
const lastTriggered = alertState.triggered.get(alertKey);
|
|
269
285
|
const now = Date.now();
|
|
270
|
-
if (!lastTriggered || now - lastTriggered >
|
|
286
|
+
if (!lastTriggered || now - lastTriggered > opts.alerts.debounceMs) {
|
|
271
287
|
alertState.triggered.set(alertKey, now);
|
|
272
288
|
alertState.history.push({
|
|
273
289
|
rule,
|
|
@@ -669,738 +685,2257 @@ function validateComponent(component, path = "root") {
|
|
|
669
685
|
}
|
|
670
686
|
throw new Error(`Invalid component type at ${path}: ${typeof component}`);
|
|
671
687
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
var COMPONENT_METADATA = /* @__PURE__ */ new WeakMap();
|
|
676
|
-
var ComponentState = class {
|
|
677
|
-
constructor(initialState = {}) {
|
|
678
|
-
this.state = { ...initialState };
|
|
679
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
680
|
-
this.isUpdating = false;
|
|
688
|
+
function isCoherentObject(obj) {
|
|
689
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
690
|
+
return false;
|
|
681
691
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
* @param {string} [key] - State key to retrieve
|
|
686
|
-
* @returns {*} State value or entire state object
|
|
687
|
-
*/
|
|
688
|
-
get(key) {
|
|
689
|
-
return key ? this.state[key] : { ...this.state };
|
|
692
|
+
const keys = Object.keys(obj);
|
|
693
|
+
if (keys.length === 0) {
|
|
694
|
+
return false;
|
|
690
695
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
696
|
+
return keys.every((key) => {
|
|
697
|
+
if (key === "text") return true;
|
|
698
|
+
return /^[a-zA-Z][a-zA-Z0-9-]*$/.test(key);
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
function extractProps(coherentObj) {
|
|
702
|
+
if (!isCoherentObject(coherentObj)) {
|
|
703
|
+
return {};
|
|
704
|
+
}
|
|
705
|
+
const props = {};
|
|
706
|
+
const keys = Object.keys(coherentObj);
|
|
707
|
+
keys.forEach((tag) => {
|
|
708
|
+
const value = coherentObj[tag];
|
|
709
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
710
|
+
props[tag] = { ...value };
|
|
711
|
+
} else {
|
|
712
|
+
props[tag] = { text: value };
|
|
702
713
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
return () => this.listeners.delete(listener);
|
|
714
|
+
});
|
|
715
|
+
return props;
|
|
716
|
+
}
|
|
717
|
+
function hasChildren(component) {
|
|
718
|
+
if (Array.isArray(component)) {
|
|
719
|
+
return component.length > 0;
|
|
710
720
|
}
|
|
711
|
-
|
|
712
|
-
if (
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
}
|
|
721
|
+
if (isCoherentObject(component)) {
|
|
722
|
+
if (component.children !== void 0 && component.children !== null) {
|
|
723
|
+
return Array.isArray(component.children) ? component.children.length > 0 : true;
|
|
724
|
+
}
|
|
725
|
+
const keys = Object.keys(component);
|
|
726
|
+
return keys.some((key) => {
|
|
727
|
+
const value = component[key];
|
|
728
|
+
return value && typeof value === "object" && value.children;
|
|
720
729
|
});
|
|
721
|
-
this.isUpdating = false;
|
|
722
730
|
}
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
function normalizeChildren(children) {
|
|
734
|
+
if (children === null || children === void 0) {
|
|
735
|
+
return [];
|
|
736
|
+
}
|
|
737
|
+
if (Array.isArray(children)) {
|
|
738
|
+
return children.flat().filter((child) => child !== null && child !== void 0);
|
|
739
|
+
}
|
|
740
|
+
return [children];
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// src/rendering/base-renderer.js
|
|
744
|
+
var DEFAULT_RENDERER_CONFIG = {
|
|
745
|
+
// Core rendering options
|
|
746
|
+
maxDepth: 100,
|
|
747
|
+
enableValidation: true,
|
|
748
|
+
enableMonitoring: false,
|
|
749
|
+
validateInput: true,
|
|
750
|
+
// HTML Renderer specific options
|
|
751
|
+
enableCache: true,
|
|
752
|
+
minify: false,
|
|
753
|
+
cacheSize: 1e3,
|
|
754
|
+
cacheTTL: 3e5,
|
|
755
|
+
// 5 minutes
|
|
756
|
+
// Streaming Renderer specific options
|
|
757
|
+
chunkSize: 1024,
|
|
758
|
+
// Size of each chunk in bytes
|
|
759
|
+
bufferSize: 4096,
|
|
760
|
+
// Internal buffer size
|
|
761
|
+
enableMetrics: false,
|
|
762
|
+
// Track streaming metrics
|
|
763
|
+
yieldThreshold: 100,
|
|
764
|
+
// Yield control after N elements
|
|
765
|
+
encoding: "utf8",
|
|
766
|
+
// Output encoding
|
|
767
|
+
// DOM Renderer specific options
|
|
768
|
+
enableHydration: true,
|
|
769
|
+
// Enable hydration support
|
|
770
|
+
namespace: null,
|
|
771
|
+
// SVG namespace support
|
|
772
|
+
// Performance options
|
|
773
|
+
enablePerformanceTracking: false,
|
|
774
|
+
performanceThreshold: 10,
|
|
775
|
+
// ms threshold for slow renders
|
|
776
|
+
// Development options
|
|
777
|
+
enableDevWarnings: typeof process !== "undefined" && process.env && true,
|
|
778
|
+
enableDebugLogging: false,
|
|
779
|
+
// Error handling options
|
|
780
|
+
errorFallback: "",
|
|
781
|
+
// Fallback content on errors
|
|
782
|
+
throwOnError: true
|
|
783
|
+
// Whether to throw or return fallback
|
|
723
784
|
};
|
|
724
|
-
var
|
|
725
|
-
constructor(
|
|
726
|
-
this.
|
|
727
|
-
this.
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
this.parent = null;
|
|
732
|
-
this.rendered = null;
|
|
733
|
-
this.isMounted = false;
|
|
734
|
-
this.isDestroyed = false;
|
|
735
|
-
this.hooks = {
|
|
736
|
-
beforeCreate: definition.beforeCreate || (() => {
|
|
737
|
-
}),
|
|
738
|
-
created: definition.created || (() => {
|
|
739
|
-
}),
|
|
740
|
-
beforeMount: definition.beforeMount || (() => {
|
|
741
|
-
}),
|
|
742
|
-
mounted: definition.mounted || (() => {
|
|
743
|
-
}),
|
|
744
|
-
beforeUpdate: definition.beforeUpdate || (() => {
|
|
745
|
-
}),
|
|
746
|
-
updated: definition.updated || (() => {
|
|
747
|
-
}),
|
|
748
|
-
beforeDestroy: definition.beforeDestroy || (() => {
|
|
749
|
-
}),
|
|
750
|
-
destroyed: definition.destroyed || (() => {
|
|
751
|
-
}),
|
|
752
|
-
errorCaptured: definition.errorCaptured || (() => {
|
|
753
|
-
})
|
|
785
|
+
var BaseRenderer = class {
|
|
786
|
+
constructor(options = {}) {
|
|
787
|
+
this.config = this.validateAndMergeConfig(options);
|
|
788
|
+
this.metrics = {
|
|
789
|
+
startTime: null,
|
|
790
|
+
endTime: null,
|
|
791
|
+
elementsProcessed: 0
|
|
754
792
|
};
|
|
755
|
-
this.methods = definition.methods || {};
|
|
756
|
-
Object.keys(this.methods).forEach((methodName) => {
|
|
757
|
-
if (typeof this.methods[methodName] === "function") {
|
|
758
|
-
this[methodName] = this.methods[methodName].bind(this);
|
|
759
|
-
}
|
|
760
|
-
});
|
|
761
|
-
this.computed = definition.computed || {};
|
|
762
|
-
this.computedCache = /* @__PURE__ */ new Map();
|
|
763
|
-
this.watchers = definition.watch || {};
|
|
764
|
-
this.setupWatchers();
|
|
765
|
-
COMPONENT_METADATA.set(this, {
|
|
766
|
-
createdAt: Date.now(),
|
|
767
|
-
updateCount: 0,
|
|
768
|
-
renderCount: 0
|
|
769
|
-
});
|
|
770
|
-
this.callHook("beforeCreate");
|
|
771
|
-
this.initialize();
|
|
772
|
-
this.callHook("created");
|
|
773
793
|
}
|
|
774
794
|
/**
|
|
775
|
-
*
|
|
795
|
+
* Validate and merge configuration options
|
|
776
796
|
*/
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
797
|
+
validateAndMergeConfig(options) {
|
|
798
|
+
const config = { ...DEFAULT_RENDERER_CONFIG, ...options };
|
|
799
|
+
if (typeof config.maxDepth !== "number") {
|
|
800
|
+
throw new Error("maxDepth must be a number");
|
|
801
|
+
}
|
|
802
|
+
if (config.maxDepth <= 0) {
|
|
803
|
+
throw new Error("maxDepth must be a positive number");
|
|
804
|
+
}
|
|
805
|
+
if (typeof config.chunkSize !== "number") {
|
|
806
|
+
throw new Error("chunkSize must be a number");
|
|
807
|
+
}
|
|
808
|
+
if (config.chunkSize <= 0) {
|
|
809
|
+
throw new Error("chunkSize must be a positive number");
|
|
810
|
+
}
|
|
811
|
+
if (typeof config.yieldThreshold !== "number") {
|
|
812
|
+
throw new Error("yieldThreshold must be a number");
|
|
813
|
+
}
|
|
814
|
+
if (config.yieldThreshold <= 0) {
|
|
815
|
+
throw new Error("yieldThreshold must be a positive number");
|
|
816
|
+
}
|
|
817
|
+
if (config.enableDevWarnings) {
|
|
818
|
+
if (config.maxDepth > 1e3) {
|
|
819
|
+
console.warn("Coherent.js: maxDepth > 1000 may cause performance issues");
|
|
820
|
+
}
|
|
821
|
+
if (config.chunkSize > 16384) {
|
|
822
|
+
console.warn("Coherent.js: Large chunkSize may increase memory usage");
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
return config;
|
|
782
826
|
}
|
|
783
827
|
/**
|
|
784
|
-
*
|
|
828
|
+
* Get configuration for specific renderer type
|
|
785
829
|
*/
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
830
|
+
getRendererConfig(rendererType) {
|
|
831
|
+
const baseConfig = { ...this.config };
|
|
832
|
+
switch (rendererType) {
|
|
833
|
+
case "html":
|
|
834
|
+
return {
|
|
835
|
+
...baseConfig,
|
|
836
|
+
// HTML-specific defaults
|
|
837
|
+
enableCache: baseConfig.enableCache !== false,
|
|
838
|
+
enableMonitoring: baseConfig.enableMonitoring !== false
|
|
839
|
+
};
|
|
840
|
+
case "streaming":
|
|
841
|
+
return {
|
|
842
|
+
...baseConfig,
|
|
843
|
+
// Streaming-specific defaults
|
|
844
|
+
enableMetrics: baseConfig.enableMetrics ?? false,
|
|
845
|
+
maxDepth: baseConfig.maxDepth ?? 1e3
|
|
846
|
+
// Higher default for streaming
|
|
847
|
+
};
|
|
848
|
+
case "dom":
|
|
849
|
+
return {
|
|
850
|
+
...baseConfig,
|
|
851
|
+
// DOM-specific defaults
|
|
852
|
+
enableHydration: baseConfig.enableHydration !== false
|
|
853
|
+
};
|
|
854
|
+
default:
|
|
855
|
+
return baseConfig;
|
|
856
|
+
}
|
|
795
857
|
}
|
|
796
858
|
/**
|
|
797
|
-
*
|
|
859
|
+
* Validate component structure
|
|
798
860
|
*/
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
const value = this.computed[key].call(this);
|
|
805
|
-
this.computedCache.set(key, value);
|
|
806
|
-
}
|
|
807
|
-
return this.computedCache.get(key);
|
|
808
|
-
},
|
|
809
|
-
enumerable: true
|
|
810
|
-
});
|
|
811
|
-
});
|
|
861
|
+
validateComponent(component) {
|
|
862
|
+
if (this.config.validateInput !== false) {
|
|
863
|
+
return validateComponent(component);
|
|
864
|
+
}
|
|
865
|
+
return true;
|
|
812
866
|
}
|
|
813
867
|
/**
|
|
814
|
-
*
|
|
868
|
+
* Check if component is valid for rendering
|
|
815
869
|
*/
|
|
816
|
-
|
|
817
|
-
if (
|
|
818
|
-
|
|
819
|
-
if (
|
|
820
|
-
|
|
821
|
-
|
|
870
|
+
isValidComponent(component) {
|
|
871
|
+
if (component === null || component === void 0) return true;
|
|
872
|
+
if (typeof component === "string" || typeof component === "number") return true;
|
|
873
|
+
if (typeof component === "function") return true;
|
|
874
|
+
if (Array.isArray(component)) return component.every((child) => this.isValidComponent(child));
|
|
875
|
+
if (isCoherentObject(component)) return true;
|
|
876
|
+
return false;
|
|
822
877
|
}
|
|
823
878
|
/**
|
|
824
|
-
*
|
|
879
|
+
* Validate rendering depth to prevent stack overflow
|
|
825
880
|
*/
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
return this.hooks[hookName].call(this, ...args);
|
|
830
|
-
}
|
|
831
|
-
} catch (_error) {
|
|
832
|
-
this.handleError(_error, `${hookName} hook`);
|
|
881
|
+
validateDepth(depth) {
|
|
882
|
+
if (depth > this.config.maxDepth) {
|
|
883
|
+
throw new Error(`Maximum render depth (${this.config.maxDepth}) exceeded`);
|
|
833
884
|
}
|
|
834
885
|
}
|
|
835
886
|
/**
|
|
836
|
-
* Handle component
|
|
887
|
+
* Handle different component types with consistent logic
|
|
837
888
|
*/
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
889
|
+
processComponentType(component) {
|
|
890
|
+
if (component === null || component === void 0) {
|
|
891
|
+
return { type: "empty", value: "" };
|
|
892
|
+
}
|
|
893
|
+
if (typeof component === "string") {
|
|
894
|
+
return { type: "text", value: component };
|
|
895
|
+
}
|
|
896
|
+
if (typeof component === "number" || typeof component === "boolean") {
|
|
897
|
+
return { type: "text", value: String(component) };
|
|
898
|
+
}
|
|
899
|
+
if (typeof component === "function") {
|
|
900
|
+
return { type: "function", value: component };
|
|
901
|
+
}
|
|
902
|
+
if (Array.isArray(component)) {
|
|
903
|
+
return { type: "array", value: component };
|
|
843
904
|
}
|
|
905
|
+
if (isCoherentObject(component)) {
|
|
906
|
+
return { type: "element", value: component };
|
|
907
|
+
}
|
|
908
|
+
return { type: "unknown", value: component };
|
|
844
909
|
}
|
|
845
910
|
/**
|
|
846
|
-
*
|
|
911
|
+
* Execute function components with _error handling
|
|
847
912
|
*/
|
|
848
|
-
|
|
849
|
-
if (this.isDestroyed) {
|
|
850
|
-
console.warn(`Attempting to render destroyed component: ${this.name}`);
|
|
851
|
-
return null;
|
|
852
|
-
}
|
|
913
|
+
executeFunctionComponent(func, depth = 0) {
|
|
853
914
|
try {
|
|
854
|
-
const
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
this.rendered = this.definition.render.call(this, this.props, this.state.get());
|
|
861
|
-
} else if (typeof this.definition.template !== "undefined") {
|
|
862
|
-
this.rendered = this.processTemplate(this.definition.template, this.props, this.state.get());
|
|
915
|
+
const isContextProvider = func.length > 0 || func.isContextProvider;
|
|
916
|
+
let result;
|
|
917
|
+
if (isContextProvider) {
|
|
918
|
+
result = func((children) => {
|
|
919
|
+
return this.renderComponent(children, this.config, depth + 1);
|
|
920
|
+
});
|
|
863
921
|
} else {
|
|
864
|
-
|
|
922
|
+
result = func();
|
|
865
923
|
}
|
|
866
|
-
if (
|
|
867
|
-
|
|
924
|
+
if (typeof result === "function") {
|
|
925
|
+
return this.executeFunctionComponent(result, depth);
|
|
868
926
|
}
|
|
869
|
-
return
|
|
927
|
+
return result;
|
|
870
928
|
} catch (_error) {
|
|
871
|
-
this.
|
|
872
|
-
|
|
929
|
+
if (this.config.enableMonitoring) {
|
|
930
|
+
performanceMonitor.recordError("functionComponent", _error);
|
|
931
|
+
}
|
|
932
|
+
if (typeof process !== "undefined" && process.env && true) {
|
|
933
|
+
console.warn("Coherent.js Function Component Error:", _error.message);
|
|
934
|
+
}
|
|
935
|
+
return null;
|
|
873
936
|
}
|
|
874
937
|
}
|
|
875
938
|
/**
|
|
876
|
-
* Process
|
|
939
|
+
* Process element children consistently
|
|
877
940
|
*/
|
|
878
|
-
|
|
879
|
-
if (
|
|
880
|
-
return
|
|
881
|
-
}
|
|
882
|
-
if (typeof template === "string") {
|
|
883
|
-
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
884
|
-
return props[key] || state[key] || "";
|
|
885
|
-
});
|
|
941
|
+
processChildren(children, options, depth) {
|
|
942
|
+
if (!hasChildren({ children })) {
|
|
943
|
+
return [];
|
|
886
944
|
}
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
945
|
+
const normalizedChildren = normalizeChildren(children);
|
|
946
|
+
return normalizedChildren.map(
|
|
947
|
+
(child) => this.renderComponent(child, options, depth + 1)
|
|
948
|
+
);
|
|
890
949
|
}
|
|
891
950
|
/**
|
|
892
|
-
*
|
|
951
|
+
* Extract and process element attributes
|
|
893
952
|
*/
|
|
894
|
-
|
|
895
|
-
if (typeof
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
}
|
|
901
|
-
if (obj && typeof obj === "object") {
|
|
902
|
-
Object.keys(obj).forEach((key) => {
|
|
903
|
-
obj[key] = this.interpolateObject(obj[key], data);
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
return obj;
|
|
953
|
+
extractElementAttributes(props) {
|
|
954
|
+
if (!props || typeof props !== "object") return {};
|
|
955
|
+
const attributes = { ...props };
|
|
956
|
+
delete attributes.children;
|
|
957
|
+
delete attributes.text;
|
|
958
|
+
return attributes;
|
|
907
959
|
}
|
|
908
960
|
/**
|
|
909
|
-
*
|
|
961
|
+
* Record performance metrics
|
|
910
962
|
*/
|
|
911
|
-
|
|
912
|
-
if (this.
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
963
|
+
recordPerformance(operation, startTime, fromCache = false, metadata = {}) {
|
|
964
|
+
if (this.config.enableMonitoring) {
|
|
965
|
+
performanceMonitor.recordRender(
|
|
966
|
+
operation,
|
|
967
|
+
this.getCurrentTime() - startTime,
|
|
968
|
+
fromCache,
|
|
969
|
+
metadata
|
|
970
|
+
);
|
|
971
|
+
}
|
|
917
972
|
}
|
|
918
973
|
/**
|
|
919
|
-
*
|
|
974
|
+
* Record _error for monitoring
|
|
920
975
|
*/
|
|
921
|
-
|
|
922
|
-
if (
|
|
923
|
-
|
|
924
|
-
if (metadata) {
|
|
925
|
-
metadata.updateCount++;
|
|
976
|
+
recordError(operation, _error, metadata = {}) {
|
|
977
|
+
if (this.config.enableMonitoring) {
|
|
978
|
+
performanceMonitor.recordError(operation, _error, metadata);
|
|
926
979
|
}
|
|
927
|
-
this.callHook("beforeUpdate");
|
|
928
|
-
this.callHook("updated");
|
|
929
|
-
return this;
|
|
930
980
|
}
|
|
931
981
|
/**
|
|
932
|
-
*
|
|
982
|
+
* Get current timestamp with fallback
|
|
933
983
|
*/
|
|
934
|
-
|
|
935
|
-
if (
|
|
936
|
-
|
|
937
|
-
if (this.unsubscribeState) {
|
|
938
|
-
this.unsubscribeState();
|
|
984
|
+
getCurrentTime() {
|
|
985
|
+
if (typeof performance !== "undefined" && performance.now) {
|
|
986
|
+
return performance.now();
|
|
939
987
|
}
|
|
940
|
-
|
|
941
|
-
if (child.destroy) {
|
|
942
|
-
child.destroy();
|
|
943
|
-
}
|
|
944
|
-
});
|
|
945
|
-
this.isMounted = false;
|
|
946
|
-
this.isDestroyed = true;
|
|
947
|
-
this.children = [];
|
|
948
|
-
this.parent = null;
|
|
949
|
-
this.callHook("destroyed");
|
|
950
|
-
return this;
|
|
988
|
+
return Date.now();
|
|
951
989
|
}
|
|
952
990
|
/**
|
|
953
|
-
*
|
|
991
|
+
* Start performance timing
|
|
954
992
|
*/
|
|
955
|
-
|
|
956
|
-
|
|
993
|
+
startTiming() {
|
|
994
|
+
this.metrics.startTime = this.getCurrentTime();
|
|
957
995
|
}
|
|
958
996
|
/**
|
|
959
|
-
*
|
|
997
|
+
* End performance timing
|
|
960
998
|
*/
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
return new _Component(newDefinition);
|
|
999
|
+
endTiming() {
|
|
1000
|
+
this.metrics.endTime = this.getCurrentTime();
|
|
964
1001
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1002
|
+
/**
|
|
1003
|
+
* Get performance metrics
|
|
1004
|
+
*/
|
|
1005
|
+
getMetrics() {
|
|
1006
|
+
const duration = this.metrics.endTime ? this.metrics.endTime - this.metrics.startTime : this.getCurrentTime() - this.metrics.startTime;
|
|
1007
|
+
return {
|
|
1008
|
+
...this.metrics,
|
|
1009
|
+
duration,
|
|
1010
|
+
elementsPerSecond: this.metrics.elementsProcessed / (duration / 1e3)
|
|
971
1011
|
};
|
|
972
1012
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1013
|
+
/**
|
|
1014
|
+
* Reset metrics for new render
|
|
1015
|
+
*/
|
|
1016
|
+
resetMetrics() {
|
|
1017
|
+
this.metrics = {
|
|
1018
|
+
startTime: null,
|
|
1019
|
+
endTime: null,
|
|
1020
|
+
elementsProcessed: 0
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Abstract method - must be implemented by subclasses
|
|
1025
|
+
*/
|
|
1026
|
+
renderComponent() {
|
|
1027
|
+
throw new Error("renderComponent must be implemented by subclass");
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Abstract method - must be implemented by subclasses
|
|
1031
|
+
*/
|
|
1032
|
+
render() {
|
|
1033
|
+
throw new Error("render must be implemented by subclass");
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
var RendererUtils = {
|
|
1037
|
+
/**
|
|
1038
|
+
* Check if element is static (no functions or circular references)
|
|
1039
|
+
*/
|
|
1040
|
+
isStaticElement(element, visited = /* @__PURE__ */ new WeakSet()) {
|
|
1041
|
+
if (!element || typeof element !== "object") {
|
|
1042
|
+
return typeof element === "string" || typeof element === "number";
|
|
1043
|
+
}
|
|
1044
|
+
if (visited.has(element)) {
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
visited.add(element);
|
|
1048
|
+
for (const [_key, value] of Object.entries(element)) {
|
|
1049
|
+
if (typeof value === "function") return false;
|
|
1050
|
+
if (Array.isArray(value)) {
|
|
1051
|
+
const allStatic = value.every((child) => RendererUtils.isStaticElement(child, visited));
|
|
1052
|
+
if (!allStatic) return false;
|
|
1053
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1054
|
+
if (!RendererUtils.isStaticElement(value, visited)) return false;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return true;
|
|
1058
|
+
},
|
|
1059
|
+
/**
|
|
1060
|
+
* Check if object has functions (for caching decisions)
|
|
1061
|
+
*/
|
|
1062
|
+
hasFunctions(obj, visited = /* @__PURE__ */ new WeakSet()) {
|
|
1063
|
+
if (visited.has(obj)) return false;
|
|
1064
|
+
visited.add(obj);
|
|
1065
|
+
for (const value of Object.values(obj)) {
|
|
1066
|
+
if (typeof value === "function") return true;
|
|
1067
|
+
if (typeof value === "object" && value !== null && RendererUtils.hasFunctions(value, visited)) {
|
|
1068
|
+
return true;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
return false;
|
|
1072
|
+
},
|
|
1073
|
+
/**
|
|
1074
|
+
* Get element complexity score
|
|
1075
|
+
*/
|
|
1076
|
+
getElementComplexity(element) {
|
|
1077
|
+
if (!element || typeof element !== "object") return 1;
|
|
1078
|
+
let complexity = Object.keys(element).length;
|
|
1079
|
+
if (element.children && Array.isArray(element.children)) {
|
|
1080
|
+
complexity += element.children.reduce(
|
|
1081
|
+
(sum, child) => sum + RendererUtils.getElementComplexity(child),
|
|
1082
|
+
0
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
return complexity;
|
|
1086
|
+
},
|
|
1087
|
+
/**
|
|
1088
|
+
* Generate cache key for element
|
|
1089
|
+
*/
|
|
1090
|
+
generateCacheKey(tagName, element) {
|
|
1091
|
+
try {
|
|
1092
|
+
const keyData = {
|
|
1093
|
+
tag: tagName,
|
|
1094
|
+
props: extractProps(element),
|
|
1095
|
+
hasChildren: hasChildren(element),
|
|
1096
|
+
childrenType: Array.isArray(element.children) ? "array" : typeof element.children
|
|
1097
|
+
};
|
|
1098
|
+
return `element:${JSON.stringify(keyData)}`;
|
|
1099
|
+
} catch (_error) {
|
|
1100
|
+
if (typeof process !== "undefined" && process.env && true) {
|
|
1101
|
+
console.warn("Failed to generate cache key:", _error);
|
|
1102
|
+
}
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
/**
|
|
1107
|
+
* Check if element is cacheable
|
|
1108
|
+
*/
|
|
1109
|
+
isCacheable(element, options) {
|
|
1110
|
+
if (!options.enableCache) return false;
|
|
1111
|
+
if (RendererUtils.hasFunctions(element)) return false;
|
|
1112
|
+
if (RendererUtils.getElementComplexity(element) > 1e3) return false;
|
|
1113
|
+
const cacheKey = RendererUtils.generateCacheKey(element.tagName || "unknown", element);
|
|
1114
|
+
if (!cacheKey) return false;
|
|
1115
|
+
return true;
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// src/core/html-nesting-rules.js
|
|
1120
|
+
var FORBIDDEN_CHILDREN = {
|
|
1121
|
+
// Phrasing content only - cannot contain flow content
|
|
1122
|
+
p: /* @__PURE__ */ new Set([
|
|
1123
|
+
"address",
|
|
1124
|
+
"article",
|
|
1125
|
+
"aside",
|
|
1126
|
+
"blockquote",
|
|
1127
|
+
"div",
|
|
1128
|
+
"dl",
|
|
1129
|
+
"fieldset",
|
|
1130
|
+
"footer",
|
|
1131
|
+
"form",
|
|
1132
|
+
"h1",
|
|
1133
|
+
"h2",
|
|
1134
|
+
"h3",
|
|
1135
|
+
"h4",
|
|
1136
|
+
"h5",
|
|
1137
|
+
"h6",
|
|
1138
|
+
"header",
|
|
1139
|
+
"hr",
|
|
1140
|
+
"main",
|
|
1141
|
+
"nav",
|
|
1142
|
+
"ol",
|
|
1143
|
+
"p",
|
|
1144
|
+
"pre",
|
|
1145
|
+
"section",
|
|
1146
|
+
"table",
|
|
1147
|
+
"ul",
|
|
1148
|
+
"figure",
|
|
1149
|
+
"figcaption"
|
|
1150
|
+
]),
|
|
1151
|
+
// Interactive content restrictions
|
|
1152
|
+
a: /* @__PURE__ */ new Set(["a"]),
|
|
1153
|
+
// Links cannot nest
|
|
1154
|
+
button: /* @__PURE__ */ new Set(["button", "a", "input", "select", "textarea", "label"]),
|
|
1155
|
+
label: /* @__PURE__ */ new Set(["label"]),
|
|
1156
|
+
// Table structure restrictions
|
|
1157
|
+
thead: /* @__PURE__ */ new Set(["thead", "tbody", "tfoot", "caption", "colgroup", "tr"]),
|
|
1158
|
+
tbody: /* @__PURE__ */ new Set(["thead", "tbody", "tfoot", "caption", "colgroup"]),
|
|
1159
|
+
tfoot: /* @__PURE__ */ new Set(["thead", "tbody", "tfoot", "caption", "colgroup"]),
|
|
1160
|
+
tr: /* @__PURE__ */ new Set(["tr", "thead", "tbody", "tfoot", "table"]),
|
|
1161
|
+
td: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot", "table"]),
|
|
1162
|
+
th: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot", "table"]),
|
|
1163
|
+
// Other common restrictions
|
|
1164
|
+
select: /* @__PURE__ */ new Set(["select", "input", "textarea"]),
|
|
1165
|
+
option: /* @__PURE__ */ new Set(["option", "optgroup"])
|
|
1166
|
+
};
|
|
1167
|
+
function validateNesting(parentTag, childTag, path = "", options = {}) {
|
|
1168
|
+
if (!parentTag || !childTag) {
|
|
1169
|
+
return true;
|
|
1170
|
+
}
|
|
1171
|
+
const parent = parentTag.toLowerCase();
|
|
1172
|
+
const child = childTag.toLowerCase();
|
|
1173
|
+
const forbidden = FORBIDDEN_CHILDREN[parent];
|
|
1174
|
+
if (!forbidden || !forbidden.has(child)) {
|
|
1175
|
+
return true;
|
|
1176
|
+
}
|
|
1177
|
+
const pathSuffix = path ? ` at ${path}` : "";
|
|
1178
|
+
const message = `Invalid HTML nesting: <${child}> cannot be a child of <${parent}>${pathSuffix}. Browsers will auto-correct this, causing potential hydration mismatches.`;
|
|
1179
|
+
if (options.throwOnError) {
|
|
1180
|
+
throw new HTMLNestingError(message, { parent, child, path });
|
|
1181
|
+
}
|
|
1182
|
+
const shouldWarn = options.warn !== false && (typeof process === "undefined" || !process.env || true);
|
|
1183
|
+
if (shouldWarn) {
|
|
1184
|
+
console.warn(`[Coherent.js] ${message}`);
|
|
1185
|
+
}
|
|
1186
|
+
return false;
|
|
983
1187
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1188
|
+
var HTMLNestingError = class extends Error {
|
|
1189
|
+
constructor(message, context2 = {}) {
|
|
1190
|
+
super(message);
|
|
1191
|
+
this.name = "HTMLNestingError";
|
|
1192
|
+
this.parent = context2.parent;
|
|
1193
|
+
this.child = context2.child;
|
|
1194
|
+
this.path = context2.path;
|
|
987
1195
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1198
|
+
// src/core/html-utils.js
|
|
1199
|
+
function escapeHtml(text) {
|
|
1200
|
+
if (typeof text !== "string") return text;
|
|
1201
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
991
1202
|
}
|
|
992
|
-
function
|
|
993
|
-
|
|
1203
|
+
function isVoidElement(tagName) {
|
|
1204
|
+
if (typeof tagName !== "string") {
|
|
1205
|
+
return false;
|
|
1206
|
+
}
|
|
1207
|
+
const voidElements = /* @__PURE__ */ new Set([
|
|
1208
|
+
"area",
|
|
1209
|
+
"base",
|
|
1210
|
+
"br",
|
|
1211
|
+
"col",
|
|
1212
|
+
"embed",
|
|
1213
|
+
"hr",
|
|
1214
|
+
"img",
|
|
1215
|
+
"input",
|
|
1216
|
+
"link",
|
|
1217
|
+
"meta",
|
|
1218
|
+
"param",
|
|
1219
|
+
"source",
|
|
1220
|
+
"track",
|
|
1221
|
+
"wbr"
|
|
1222
|
+
]);
|
|
1223
|
+
return voidElements.has(tagName.toLowerCase());
|
|
994
1224
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
1225
|
+
function formatAttributes(props) {
|
|
1226
|
+
let formatted = "";
|
|
1227
|
+
for (const key in props) {
|
|
1228
|
+
if (props.hasOwnProperty(key)) {
|
|
1229
|
+
let value = props[key];
|
|
1230
|
+
const attributeName = key === "className" ? "class" : key;
|
|
1231
|
+
if (typeof value === "function") {
|
|
1232
|
+
if (attributeName.startsWith("on")) {
|
|
1233
|
+
const actionId = `__coherent_action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1234
|
+
const DEBUG = typeof process !== "undefined" && process && process.env && (process.env.COHERENT_DEBUG === "1" || true) || typeof window !== "undefined" && window && window.COHERENT_DEBUG === true;
|
|
1235
|
+
if (typeof global !== "undefined") {
|
|
1236
|
+
if (!global.__coherentActionRegistry) {
|
|
1237
|
+
global.__coherentActionRegistry = {};
|
|
1238
|
+
if (DEBUG) console.log("Initialized global action registry");
|
|
1239
|
+
}
|
|
1240
|
+
global.__coherentActionRegistry[actionId] = value;
|
|
1241
|
+
if (DEBUG) console.log(`Added action ${actionId} to global registry, total: ${Object.keys(global.__coherentActionRegistry).length}`);
|
|
1242
|
+
if (DEBUG) console.log(`Global registry keys: ${Object.keys(global.__coherentActionRegistry).join(", ")}`);
|
|
1243
|
+
if (DEBUG) {
|
|
1244
|
+
if (typeof global.__coherentActionRegistryLog === "undefined") {
|
|
1245
|
+
global.__coherentActionRegistryLog = [];
|
|
1246
|
+
}
|
|
1247
|
+
global.__coherentActionRegistryLog.push({
|
|
1248
|
+
action: "add",
|
|
1249
|
+
actionId,
|
|
1250
|
+
timestamp: Date.now(),
|
|
1251
|
+
registrySize: Object.keys(global.__coherentActionRegistry).length
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
} else if (typeof window !== "undefined") {
|
|
1255
|
+
if (!window.__coherentActionRegistry) {
|
|
1256
|
+
window.__coherentActionRegistry = {};
|
|
1257
|
+
if (DEBUG) console.log("Initialized window action registry");
|
|
1258
|
+
}
|
|
1259
|
+
window.__coherentActionRegistry[actionId] = value;
|
|
1260
|
+
if (DEBUG) console.log(`Added action ${actionId} to window registry, total: ${Object.keys(window.__coherentActionRegistry).length}`);
|
|
1261
|
+
if (DEBUG) console.log(`Window registry keys: ${Object.keys(window.__coherentActionRegistry).join(", ")}`);
|
|
1262
|
+
}
|
|
1263
|
+
const eventType = attributeName.substring(2);
|
|
1264
|
+
formatted += ` data-action="${actionId}" data-event="${eventType}"`;
|
|
1265
|
+
continue;
|
|
1266
|
+
} else {
|
|
1267
|
+
try {
|
|
1268
|
+
value = value();
|
|
1269
|
+
} catch (_error) {
|
|
1270
|
+
console.warn(`Error executing function for attribute '${key}':`, {
|
|
1271
|
+
_error: _error.message,
|
|
1272
|
+
stack: _error.stack,
|
|
1273
|
+
attributeKey: key
|
|
1274
|
+
});
|
|
1275
|
+
value = "";
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
if (value === true) {
|
|
1280
|
+
formatted += ` ${attributeName}`;
|
|
1281
|
+
} else if (value !== false && value !== null && value !== void 0) {
|
|
1282
|
+
formatted += ` ${attributeName}="${escapeHtml(String(value))}"`;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return formatted.trim();
|
|
997
1287
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
const start = performance.now();
|
|
1002
|
-
const result = originalRender.apply(this, args);
|
|
1003
|
-
const duration = performance.now() - start;
|
|
1004
|
-
performanceMonitor.recordMetric("renderTime", duration, {
|
|
1005
|
-
type: "component",
|
|
1006
|
-
name: this.name,
|
|
1007
|
-
propsSize: JSON.stringify(this.props || {}).length,
|
|
1008
|
-
hasState: Object.keys(this.state?.get() || {}).length > 0
|
|
1009
|
-
});
|
|
1010
|
-
return result;
|
|
1011
|
-
};
|
|
1288
|
+
function minifyHtml(html, options = {}) {
|
|
1289
|
+
if (!options.minify) return html;
|
|
1290
|
+
return html.replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, " ").replace(/>\s+</g, "><").trim();
|
|
1012
1291
|
}
|
|
1013
|
-
|
|
1292
|
+
|
|
1293
|
+
// src/performance/cache-manager.js
|
|
1294
|
+
function createCacheManager(options = {}) {
|
|
1014
1295
|
const {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
//
|
|
1019
|
-
|
|
1020
|
-
// Fallback value if evaluation fails
|
|
1021
|
-
onError = null,
|
|
1022
|
-
// Error handler
|
|
1023
|
-
dependencies = []
|
|
1024
|
-
// Dependencies that invalidate cache
|
|
1296
|
+
maxCacheSize = 1e3,
|
|
1297
|
+
maxMemoryMB = 100,
|
|
1298
|
+
ttlMs = 1e3 * 60 * 5,
|
|
1299
|
+
// 5 minutes
|
|
1300
|
+
enableStatistics = true
|
|
1025
1301
|
} = options;
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1302
|
+
const caches = {
|
|
1303
|
+
static: /* @__PURE__ */ new Map(),
|
|
1304
|
+
// Never-changing components
|
|
1305
|
+
component: /* @__PURE__ */ new Map(),
|
|
1306
|
+
// Component results with deps
|
|
1307
|
+
template: /* @__PURE__ */ new Map(),
|
|
1308
|
+
// Template strings
|
|
1309
|
+
data: /* @__PURE__ */ new Map()
|
|
1310
|
+
// General purpose data
|
|
1311
|
+
};
|
|
1312
|
+
let memoryUsage = 0;
|
|
1313
|
+
const stats = {
|
|
1314
|
+
hits: 0,
|
|
1315
|
+
misses: 0,
|
|
1316
|
+
hitRate: {
|
|
1317
|
+
static: 0,
|
|
1318
|
+
component: 0,
|
|
1319
|
+
template: 0,
|
|
1320
|
+
data: 0
|
|
1321
|
+
},
|
|
1322
|
+
accessCount: {
|
|
1323
|
+
static: 0,
|
|
1324
|
+
component: 0,
|
|
1325
|
+
template: 0,
|
|
1326
|
+
data: 0
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
let cleanupInterval;
|
|
1330
|
+
if (typeof setInterval === "function") {
|
|
1331
|
+
cleanupInterval = setInterval(() => cleanup(), 3e4);
|
|
1332
|
+
if (cleanupInterval.unref) {
|
|
1333
|
+
cleanupInterval.unref();
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
function generateCacheKey(component, props = {}, context2 = {}) {
|
|
1337
|
+
const componentStr = typeof component === "function" ? component.name || component.toString() : JSON.stringify(component);
|
|
1338
|
+
const propsStr = JSON.stringify(props, Object.keys(props).sort());
|
|
1339
|
+
const contextStr = JSON.stringify(context2);
|
|
1340
|
+
const hash = simpleHash(componentStr + propsStr + contextStr);
|
|
1341
|
+
return `${extractComponentName(component)}_${hash}`;
|
|
1342
|
+
}
|
|
1343
|
+
function get(key, type = "component") {
|
|
1344
|
+
const cache = caches[type] || caches.component;
|
|
1345
|
+
const entry = cache.get(key);
|
|
1346
|
+
if (!entry) {
|
|
1347
|
+
stats.misses++;
|
|
1348
|
+
if (enableStatistics) stats.accessCount[type]++;
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
if (Date.now() - entry.timestamp > ttlMs) {
|
|
1352
|
+
cache.delete(key);
|
|
1353
|
+
updateMemoryUsage(-entry.size);
|
|
1354
|
+
stats.misses++;
|
|
1355
|
+
if (enableStatistics) stats.accessCount[type]++;
|
|
1356
|
+
return null;
|
|
1357
|
+
}
|
|
1358
|
+
entry.lastAccess = Date.now();
|
|
1359
|
+
entry.accessCount++;
|
|
1360
|
+
stats.hits++;
|
|
1361
|
+
if (enableStatistics) {
|
|
1362
|
+
stats.accessCount[type]++;
|
|
1363
|
+
stats.hitRate[type] = stats.hits / (stats.hits + stats.misses) * 100;
|
|
1364
|
+
}
|
|
1365
|
+
return entry.value;
|
|
1366
|
+
}
|
|
1367
|
+
function set(key, value, type = "component", metadata = {}) {
|
|
1368
|
+
const cache = caches[type] || caches.component;
|
|
1369
|
+
const size = calculateSize(value);
|
|
1370
|
+
if (memoryUsage + size > maxMemoryMB * 1024 * 1024) {
|
|
1371
|
+
optimize(type, size);
|
|
1372
|
+
}
|
|
1373
|
+
const entry = {
|
|
1374
|
+
value,
|
|
1375
|
+
timestamp: Date.now(),
|
|
1376
|
+
lastAccess: Date.now(),
|
|
1377
|
+
size,
|
|
1378
|
+
metadata,
|
|
1379
|
+
accessCount: 0
|
|
1380
|
+
};
|
|
1381
|
+
const existing = cache.get(key);
|
|
1382
|
+
if (existing) {
|
|
1383
|
+
updateMemoryUsage(-existing.size);
|
|
1384
|
+
}
|
|
1385
|
+
cache.set(key, entry);
|
|
1386
|
+
updateMemoryUsage(size);
|
|
1387
|
+
if (cache.size > maxCacheSize) {
|
|
1388
|
+
optimize(type);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
function remove(key, type) {
|
|
1392
|
+
if (type) {
|
|
1393
|
+
const cache = caches[type];
|
|
1394
|
+
if (!cache) return false;
|
|
1395
|
+
const entry = cache.get(key);
|
|
1396
|
+
if (entry) {
|
|
1397
|
+
updateMemoryUsage(-entry.size);
|
|
1398
|
+
return cache.delete(key);
|
|
1040
1399
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
for (const [, cache] of Object.entries(caches)) {
|
|
1403
|
+
const entry = cache.get(key);
|
|
1404
|
+
if (entry) {
|
|
1405
|
+
updateMemoryUsage(-entry.size);
|
|
1406
|
+
return cache.delete(key);
|
|
1048
1407
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1408
|
+
}
|
|
1409
|
+
return false;
|
|
1410
|
+
}
|
|
1411
|
+
function clear(type) {
|
|
1412
|
+
if (type) {
|
|
1413
|
+
const cache = caches[type];
|
|
1414
|
+
if (cache) {
|
|
1415
|
+
cache.clear();
|
|
1051
1416
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1417
|
+
} else {
|
|
1418
|
+
Object.values(caches).forEach((cache) => cache.clear());
|
|
1419
|
+
}
|
|
1420
|
+
memoryUsage = 0;
|
|
1421
|
+
}
|
|
1422
|
+
function getStats() {
|
|
1423
|
+
const entries = Object.values(caches).reduce((sum, cache) => sum + cache.size, 0);
|
|
1424
|
+
return {
|
|
1425
|
+
hits: stats.hits,
|
|
1426
|
+
misses: stats.misses,
|
|
1427
|
+
size: memoryUsage,
|
|
1428
|
+
entries,
|
|
1429
|
+
hitRate: stats.hitRate,
|
|
1430
|
+
accessCount: stats.accessCount
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
function cleanup() {
|
|
1434
|
+
const now = Date.now();
|
|
1435
|
+
let freed = 0;
|
|
1436
|
+
for (const [, cache] of Object.entries(caches)) {
|
|
1437
|
+
for (const [key, entry] of cache.entries()) {
|
|
1438
|
+
if (now - entry.timestamp > ttlMs) {
|
|
1439
|
+
cache.delete(key);
|
|
1440
|
+
updateMemoryUsage(-entry.size);
|
|
1441
|
+
freed++;
|
|
1076
1442
|
}
|
|
1077
|
-
return fallback;
|
|
1078
|
-
} finally {
|
|
1079
|
-
isEvaluating = false;
|
|
1080
1443
|
}
|
|
1081
|
-
},
|
|
1082
|
-
// Force re-evaluation
|
|
1083
|
-
invalidate() {
|
|
1084
|
-
cached = false;
|
|
1085
|
-
cachedValue = null;
|
|
1086
|
-
lastDependencyHash = null;
|
|
1087
|
-
return this;
|
|
1088
|
-
},
|
|
1089
|
-
// Check if evaluated
|
|
1090
|
-
isEvaluated() {
|
|
1091
|
-
return cached;
|
|
1092
|
-
},
|
|
1093
|
-
// Get cached value without evaluation
|
|
1094
|
-
getCachedValue() {
|
|
1095
|
-
return cachedValue;
|
|
1096
|
-
},
|
|
1097
|
-
// Transform the lazy value
|
|
1098
|
-
map(transform) {
|
|
1099
|
-
return lazy((...args) => {
|
|
1100
|
-
const value = this.evaluate(...args);
|
|
1101
|
-
return transform(value);
|
|
1102
|
-
}, { ...options, cache: false });
|
|
1103
|
-
},
|
|
1104
|
-
// Chain lazy evaluations
|
|
1105
|
-
flatMap(transform) {
|
|
1106
|
-
return lazy((...args) => {
|
|
1107
|
-
const value = this.evaluate(...args);
|
|
1108
|
-
const transformed = transform(value);
|
|
1109
|
-
if (isLazy(transformed)) {
|
|
1110
|
-
return transformed.evaluate(...args);
|
|
1111
|
-
}
|
|
1112
|
-
return transformed;
|
|
1113
|
-
}, { ...options, cache: false });
|
|
1114
|
-
},
|
|
1115
|
-
// Convert to string for debugging
|
|
1116
|
-
toString() {
|
|
1117
|
-
return `[Lazy${cached ? " (cached)" : ""}]`;
|
|
1118
|
-
},
|
|
1119
|
-
// JSON serialization
|
|
1120
|
-
toJSON() {
|
|
1121
|
-
return this.evaluate();
|
|
1122
1444
|
}
|
|
1123
|
-
|
|
1124
|
-
return lazyWrapper;
|
|
1125
|
-
}
|
|
1126
|
-
function isLazy(value) {
|
|
1127
|
-
return value && typeof value === "object" && value.__isLazy === true;
|
|
1128
|
-
}
|
|
1129
|
-
function evaluateLazy(obj, ...args) {
|
|
1130
|
-
if (isLazy(obj)) {
|
|
1131
|
-
return obj.evaluate(...args);
|
|
1445
|
+
return { freed };
|
|
1132
1446
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1447
|
+
function calculateSize(value) {
|
|
1448
|
+
if (value === null || value === void 0) return 0;
|
|
1449
|
+
if (typeof value === "string") return value.length * 2;
|
|
1450
|
+
if (typeof value === "number") return 8;
|
|
1451
|
+
if (typeof value === "boolean") return 4;
|
|
1452
|
+
if (Array.isArray(value)) {
|
|
1453
|
+
return value.reduce((sum, item) => sum + calculateSize(item), 0);
|
|
1454
|
+
}
|
|
1455
|
+
if (typeof value === "object") {
|
|
1456
|
+
return Object.values(value).reduce((sum, val) => sum + calculateSize(val), 0);
|
|
1457
|
+
}
|
|
1458
|
+
return 0;
|
|
1135
1459
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1460
|
+
function updateMemoryUsage(delta) {
|
|
1461
|
+
memoryUsage = Math.max(0, memoryUsage + delta);
|
|
1462
|
+
}
|
|
1463
|
+
function optimize(type, requiredSpace = 0) {
|
|
1464
|
+
const cache = caches[type] || caches.component;
|
|
1465
|
+
const entries = Array.from(cache.entries()).sort(([, a], [, b]) => a.lastAccess - b.lastAccess);
|
|
1466
|
+
let freed = 0;
|
|
1467
|
+
for (const [key, entry] of entries) {
|
|
1468
|
+
if (freed >= requiredSpace) break;
|
|
1469
|
+
cache.delete(key);
|
|
1470
|
+
updateMemoryUsage(-entry.size);
|
|
1471
|
+
freed += entry.size;
|
|
1140
1472
|
}
|
|
1141
|
-
return
|
|
1473
|
+
return { freed };
|
|
1142
1474
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1475
|
+
function simpleHash(str) {
|
|
1476
|
+
let hash = 0;
|
|
1477
|
+
for (let i = 0; i < str.length; i++) {
|
|
1478
|
+
const char = str.charCodeAt(i);
|
|
1479
|
+
hash = (hash << 5) - hash + char;
|
|
1480
|
+
hash = hash & hash;
|
|
1149
1481
|
}
|
|
1150
|
-
return
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
const timer = setTimeout(() => {
|
|
1156
|
-
reject(new Error(`Lazy evaluation timeout after ${timeout}ms`));
|
|
1157
|
-
}, timeout);
|
|
1158
|
-
try {
|
|
1159
|
-
const result = factory(...args);
|
|
1160
|
-
if (result && typeof result.then === "function") {
|
|
1161
|
-
result.then((value) => {
|
|
1162
|
-
clearTimeout(timer);
|
|
1163
|
-
resolve(value);
|
|
1164
|
-
}).catch((_error) => {
|
|
1165
|
-
clearTimeout(timer);
|
|
1166
|
-
reject(_error);
|
|
1167
|
-
});
|
|
1168
|
-
} else {
|
|
1169
|
-
clearTimeout(timer);
|
|
1170
|
-
resolve(result);
|
|
1171
|
-
}
|
|
1172
|
-
} catch (_error) {
|
|
1173
|
-
clearTimeout(timer);
|
|
1174
|
-
reject(_error);
|
|
1482
|
+
return Math.abs(hash).toString(36);
|
|
1483
|
+
}
|
|
1484
|
+
function extractComponentName(component) {
|
|
1485
|
+
if (typeof component === "function") {
|
|
1486
|
+
return component.name || "AnonymousComponent";
|
|
1175
1487
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
strategy = "lru",
|
|
1182
|
-
// 'lru', 'ttl', 'weak', 'simple'
|
|
1183
|
-
maxSize = 100,
|
|
1184
|
-
// Maximum cache entries
|
|
1185
|
-
ttl = null,
|
|
1186
|
-
// Time to live in milliseconds
|
|
1187
|
-
// Key generation
|
|
1188
|
-
keyFn = null,
|
|
1189
|
-
// Custom key function
|
|
1190
|
-
keySerializer = JSON.stringify,
|
|
1191
|
-
// Default serialization
|
|
1192
|
-
// Comparison
|
|
1193
|
-
// eslint-disable-next-line no-unused-vars
|
|
1194
|
-
compareFn = null,
|
|
1195
|
-
// Custom equality comparison
|
|
1196
|
-
// eslint-disable-next-line no-unused-vars
|
|
1197
|
-
shallow = false,
|
|
1198
|
-
// Shallow comparison for objects
|
|
1199
|
-
// Lifecycle hooks
|
|
1200
|
-
onHit = null,
|
|
1201
|
-
// Called on cache hit
|
|
1202
|
-
onMiss = null,
|
|
1203
|
-
// Called on cache miss
|
|
1204
|
-
onEvict = null,
|
|
1205
|
-
// Called when item evicted
|
|
1206
|
-
// Performance
|
|
1207
|
-
stats = false,
|
|
1208
|
-
// Track hit/miss statistics
|
|
1209
|
-
// Development
|
|
1210
|
-
debug = false
|
|
1211
|
-
// Debug logging
|
|
1212
|
-
} = options;
|
|
1213
|
-
let cache;
|
|
1214
|
-
const stats_data = stats ? { hits: 0, misses: 0, evictions: 0 } : null;
|
|
1215
|
-
switch (strategy) {
|
|
1216
|
-
case "lru":
|
|
1217
|
-
cache = new LRUCache(maxSize, { onEvict });
|
|
1218
|
-
break;
|
|
1219
|
-
case "ttl":
|
|
1220
|
-
cache = new TTLCache(ttl, { onEvict });
|
|
1221
|
-
break;
|
|
1222
|
-
case "weak":
|
|
1223
|
-
cache = /* @__PURE__ */ new WeakMap();
|
|
1224
|
-
break;
|
|
1225
|
-
default:
|
|
1226
|
-
cache = /* @__PURE__ */ new Map();
|
|
1488
|
+
if (component && typeof component === "object") {
|
|
1489
|
+
const keys = Object.keys(component);
|
|
1490
|
+
return keys.length > 0 ? keys[0] : "ObjectComponent";
|
|
1491
|
+
}
|
|
1492
|
+
return "UnknownComponent";
|
|
1227
1493
|
}
|
|
1228
|
-
|
|
1229
|
-
if (
|
|
1230
|
-
|
|
1231
|
-
return keySerializer(args);
|
|
1232
|
-
});
|
|
1233
|
-
const memoizedFn = (...args) => {
|
|
1234
|
-
const key = generateKey(...args);
|
|
1235
|
-
if (cache.has(key)) {
|
|
1236
|
-
const cached = cache.get(key);
|
|
1237
|
-
if (cached && (!cached.expires || Date.now() < cached.expires)) {
|
|
1238
|
-
if (debug) console.log(`Memo cache hit for key: ${key}`);
|
|
1239
|
-
if (onHit) onHit(key, cached.value, args);
|
|
1240
|
-
if (stats_data) stats_data.hits++;
|
|
1241
|
-
return cached.value || cached;
|
|
1242
|
-
} else {
|
|
1243
|
-
cache.delete(key);
|
|
1244
|
-
}
|
|
1494
|
+
function destroy() {
|
|
1495
|
+
if (cleanupInterval) {
|
|
1496
|
+
clearInterval(cleanupInterval);
|
|
1245
1497
|
}
|
|
1246
|
-
|
|
1247
|
-
if (onMiss) onMiss(key, args);
|
|
1248
|
-
if (stats_data) stats_data.misses++;
|
|
1249
|
-
const result = fn(...args);
|
|
1250
|
-
const cacheEntry = ttl ? { value: result, expires: Date.now() + ttl } : result;
|
|
1251
|
-
cache.set(key, cacheEntry);
|
|
1252
|
-
return result;
|
|
1253
|
-
};
|
|
1254
|
-
memoizedFn.cache = cache;
|
|
1255
|
-
memoizedFn.clear = () => cache.clear();
|
|
1256
|
-
memoizedFn.delete = (key) => cache.delete(key);
|
|
1257
|
-
memoizedFn.has = (key) => cache.has(key);
|
|
1258
|
-
memoizedFn.size = () => cache.size;
|
|
1259
|
-
if (stats_data) {
|
|
1260
|
-
memoizedFn.stats = () => ({ ...stats_data });
|
|
1261
|
-
memoizedFn.resetStats = () => {
|
|
1262
|
-
stats_data.hits = 0;
|
|
1263
|
-
stats_data.misses = 0;
|
|
1264
|
-
stats_data.evictions = 0;
|
|
1265
|
-
};
|
|
1498
|
+
clear();
|
|
1266
1499
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1500
|
+
return {
|
|
1501
|
+
get,
|
|
1502
|
+
set,
|
|
1503
|
+
remove,
|
|
1504
|
+
clear,
|
|
1505
|
+
getStats,
|
|
1506
|
+
cleanup,
|
|
1507
|
+
destroy,
|
|
1508
|
+
generateCacheKey,
|
|
1509
|
+
get memoryUsage() {
|
|
1510
|
+
return memoryUsage;
|
|
1511
|
+
},
|
|
1512
|
+
get maxMemory() {
|
|
1513
|
+
return maxMemoryMB * 1024 * 1024;
|
|
1514
|
+
}
|
|
1271
1515
|
};
|
|
1272
|
-
return memoizedFn;
|
|
1273
1516
|
}
|
|
1274
|
-
var
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (this.cache.has(key)) {
|
|
1291
|
-
this.cache.delete(key);
|
|
1292
|
-
} else if (this.cache.size >= this.maxSize) {
|
|
1293
|
-
const firstKey = this.cache.keys().next().value;
|
|
1294
|
-
const evicted = this.cache.get(firstKey);
|
|
1295
|
-
this.cache.delete(firstKey);
|
|
1296
|
-
if (this.onEvict) {
|
|
1297
|
-
this.onEvict(firstKey, evicted);
|
|
1298
|
-
}
|
|
1517
|
+
var cacheManager = createCacheManager();
|
|
1518
|
+
|
|
1519
|
+
// src/utils/error-handler.js
|
|
1520
|
+
var CoherentError = class _CoherentError extends Error {
|
|
1521
|
+
constructor(message, options = {}) {
|
|
1522
|
+
super(message);
|
|
1523
|
+
this.name = "CoherentError";
|
|
1524
|
+
this.type = options.type || "generic";
|
|
1525
|
+
this.code = options.code || `COHERENT_${String(this.type).toUpperCase()}`;
|
|
1526
|
+
this.docsUrl = options.docsUrl || `/docs/core/errors#${this.code}`;
|
|
1527
|
+
this.component = options.component;
|
|
1528
|
+
this.context = options.context;
|
|
1529
|
+
this.suggestions = options.suggestions || [];
|
|
1530
|
+
this.timestamp = Date.now();
|
|
1531
|
+
if (Error.captureStackTrace) {
|
|
1532
|
+
Error.captureStackTrace(this, _CoherentError);
|
|
1299
1533
|
}
|
|
1300
|
-
this.cache.set(key, value);
|
|
1301
|
-
}
|
|
1302
|
-
has(key) {
|
|
1303
|
-
return this.cache.has(key);
|
|
1304
|
-
}
|
|
1305
|
-
delete(key) {
|
|
1306
|
-
return this.cache.delete(key);
|
|
1307
1534
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1535
|
+
toJSON() {
|
|
1536
|
+
return {
|
|
1537
|
+
name: this.name,
|
|
1538
|
+
message: this.message,
|
|
1539
|
+
type: this.type,
|
|
1540
|
+
code: this.code,
|
|
1541
|
+
docsUrl: this.docsUrl,
|
|
1542
|
+
component: this.component,
|
|
1543
|
+
context: this.context,
|
|
1544
|
+
suggestions: this.suggestions,
|
|
1545
|
+
timestamp: this.timestamp,
|
|
1546
|
+
stack: this.stack
|
|
1547
|
+
};
|
|
1313
1548
|
}
|
|
1314
1549
|
};
|
|
1315
|
-
var
|
|
1316
|
-
constructor(
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
this.delete(key);
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
return void 0;
|
|
1550
|
+
var ComponentValidationError = class extends CoherentError {
|
|
1551
|
+
constructor(message, component, suggestions = []) {
|
|
1552
|
+
super(message, {
|
|
1553
|
+
type: "validation",
|
|
1554
|
+
component,
|
|
1555
|
+
suggestions: [
|
|
1556
|
+
"Check component structure and syntax",
|
|
1557
|
+
"Ensure all required properties are present",
|
|
1558
|
+
"Validate prop types and values",
|
|
1559
|
+
...suggestions
|
|
1560
|
+
]
|
|
1561
|
+
});
|
|
1562
|
+
this.name = "ComponentValidationError";
|
|
1332
1563
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1564
|
+
};
|
|
1565
|
+
var RenderingError = class extends CoherentError {
|
|
1566
|
+
constructor(message, component, context2, suggestions = []) {
|
|
1567
|
+
super(message, {
|
|
1568
|
+
type: "rendering",
|
|
1569
|
+
component,
|
|
1570
|
+
context: context2,
|
|
1571
|
+
suggestions: [
|
|
1572
|
+
"Check for circular references",
|
|
1573
|
+
"Validate component depth",
|
|
1574
|
+
"Ensure all functions return valid components",
|
|
1575
|
+
...suggestions
|
|
1576
|
+
]
|
|
1577
|
+
});
|
|
1578
|
+
this.name = "RenderingError";
|
|
1579
|
+
if (context2 && context2.path) {
|
|
1580
|
+
this.renderPath = context2.path;
|
|
1336
1581
|
}
|
|
1337
|
-
const expires = Date.now() + this.ttl;
|
|
1338
|
-
this.cache.set(key, { value, expires });
|
|
1339
|
-
const timer = setTimeout(() => {
|
|
1340
|
-
this.delete(key);
|
|
1341
|
-
}, this.ttl);
|
|
1342
|
-
this.timers.set(key, timer);
|
|
1343
1582
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1583
|
+
};
|
|
1584
|
+
var PerformanceError = class extends CoherentError {
|
|
1585
|
+
constructor(message, metrics, suggestions = []) {
|
|
1586
|
+
super(message, {
|
|
1587
|
+
type: "performance",
|
|
1588
|
+
context: metrics,
|
|
1589
|
+
suggestions: [
|
|
1590
|
+
"Consider component memoization",
|
|
1591
|
+
"Reduce component complexity",
|
|
1592
|
+
"Enable caching",
|
|
1593
|
+
...suggestions
|
|
1594
|
+
]
|
|
1595
|
+
});
|
|
1596
|
+
this.name = "PerformanceError";
|
|
1350
1597
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1598
|
+
};
|
|
1599
|
+
var StateError = class extends CoherentError {
|
|
1600
|
+
constructor(message, state, suggestions = []) {
|
|
1601
|
+
super(message, {
|
|
1602
|
+
type: "state",
|
|
1603
|
+
context: state,
|
|
1604
|
+
suggestions: [
|
|
1605
|
+
"Check state mutations",
|
|
1606
|
+
"Ensure proper state initialization",
|
|
1607
|
+
"Validate state transitions",
|
|
1608
|
+
...suggestions
|
|
1609
|
+
]
|
|
1610
|
+
});
|
|
1611
|
+
this.name = "StateError";
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1614
|
+
var ErrorHandler = class {
|
|
1615
|
+
constructor(options = {}) {
|
|
1616
|
+
const isDev = typeof process !== "undefined" && process.env && true;
|
|
1617
|
+
const envForceSilent = typeof process !== "undefined" && process.env && process.env.COHERENT_SILENT === "1";
|
|
1618
|
+
const envForceDebug = typeof process !== "undefined" && process.env && process.env.COHERENT_DEBUG === "1";
|
|
1619
|
+
const defaultEnableLogging = envForceSilent ? false : envForceDebug ? true : isDev;
|
|
1620
|
+
this.options = {
|
|
1621
|
+
enableStackTrace: options.enableStackTrace !== false,
|
|
1622
|
+
enableSuggestions: options.enableSuggestions !== false,
|
|
1623
|
+
enableLogging: options.enableLogging ?? defaultEnableLogging,
|
|
1624
|
+
logLevel: options.logLevel || "_error",
|
|
1625
|
+
maxErrorHistory: options.maxErrorHistory || 100,
|
|
1626
|
+
...options
|
|
1627
|
+
};
|
|
1628
|
+
this.errorHistory = [];
|
|
1629
|
+
this.errorCounts = /* @__PURE__ */ new Map();
|
|
1630
|
+
this.suppressedErrors = /* @__PURE__ */ new Set();
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Handle and report errors with detailed context
|
|
1634
|
+
*/
|
|
1635
|
+
handle(_error, context2 = {}) {
|
|
1636
|
+
const enhancedError = this.enhanceError(_error, context2);
|
|
1637
|
+
this.addToHistory(enhancedError);
|
|
1638
|
+
if (this.options.enableLogging) {
|
|
1639
|
+
this.logError(enhancedError);
|
|
1363
1640
|
}
|
|
1364
|
-
return
|
|
1641
|
+
return enhancedError;
|
|
1365
1642
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1643
|
+
/**
|
|
1644
|
+
* Enhance existing errors with more context
|
|
1645
|
+
*/
|
|
1646
|
+
enhanceError(_error, context2 = {}) {
|
|
1647
|
+
if (_error instanceof CoherentError) {
|
|
1648
|
+
return _error;
|
|
1649
|
+
}
|
|
1650
|
+
const errorType = this.classifyError(_error, context2);
|
|
1651
|
+
switch (errorType) {
|
|
1652
|
+
case "validation":
|
|
1653
|
+
return new ComponentValidationError(
|
|
1654
|
+
_error.message,
|
|
1655
|
+
context2.component,
|
|
1656
|
+
this.generateSuggestions(_error, context2)
|
|
1657
|
+
);
|
|
1658
|
+
case "rendering":
|
|
1659
|
+
return new RenderingError(
|
|
1660
|
+
_error.message,
|
|
1661
|
+
context2.component,
|
|
1662
|
+
context2.renderContext,
|
|
1663
|
+
this.generateSuggestions(_error, context2)
|
|
1664
|
+
);
|
|
1665
|
+
case "performance":
|
|
1666
|
+
return new PerformanceError(
|
|
1667
|
+
_error.message,
|
|
1668
|
+
context2.metrics,
|
|
1669
|
+
this.generateSuggestions(_error, context2)
|
|
1670
|
+
);
|
|
1671
|
+
case "state":
|
|
1672
|
+
return new StateError(
|
|
1673
|
+
_error.message,
|
|
1674
|
+
context2.state,
|
|
1675
|
+
this.generateSuggestions(_error, context2)
|
|
1676
|
+
);
|
|
1677
|
+
default:
|
|
1678
|
+
return new CoherentError(_error.message, {
|
|
1679
|
+
type: errorType,
|
|
1680
|
+
component: context2.component,
|
|
1681
|
+
context: context2.context,
|
|
1682
|
+
suggestions: this.generateSuggestions(_error, context2)
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1370
1685
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1686
|
+
/**
|
|
1687
|
+
* Classify _error type based on message and context
|
|
1688
|
+
*/
|
|
1689
|
+
classifyError(_error, context2) {
|
|
1690
|
+
const message = _error.message.toLowerCase();
|
|
1691
|
+
if (message.includes("invalid") || message.includes("validation") || message.includes("required") || message.includes("type")) {
|
|
1692
|
+
return "validation";
|
|
1693
|
+
}
|
|
1694
|
+
if (message.includes("render") || message.includes("circular") || message.includes("depth") || message.includes("cannot render")) {
|
|
1695
|
+
return "rendering";
|
|
1696
|
+
}
|
|
1697
|
+
if (message.includes("slow") || message.includes("memory") || message.includes("performance") || message.includes("timeout")) {
|
|
1698
|
+
return "performance";
|
|
1699
|
+
}
|
|
1700
|
+
if (message.includes("state") || message.includes("mutation") || message.includes("store") || context2.state) {
|
|
1701
|
+
return "state";
|
|
1702
|
+
}
|
|
1703
|
+
if (context2.component) return "validation";
|
|
1704
|
+
if (context2.renderContext) return "rendering";
|
|
1705
|
+
if (context2.metrics) return "performance";
|
|
1706
|
+
return "generic";
|
|
1373
1707
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1708
|
+
/**
|
|
1709
|
+
* Generate helpful suggestions based on _error
|
|
1710
|
+
*/
|
|
1711
|
+
generateSuggestions(_error, context2 = {}) {
|
|
1712
|
+
const suggestions = [];
|
|
1713
|
+
const message = _error.message.toLowerCase();
|
|
1714
|
+
const patterns = [
|
|
1715
|
+
{
|
|
1716
|
+
pattern: /cannot render|render.*failed/,
|
|
1717
|
+
suggestions: [
|
|
1718
|
+
"Check if component returns a valid object structure",
|
|
1719
|
+
"Ensure all properties are properly defined",
|
|
1720
|
+
"Look for undefined variables or null references"
|
|
1721
|
+
]
|
|
1387
1722
|
},
|
|
1388
|
-
|
|
1389
|
-
|
|
1723
|
+
{
|
|
1724
|
+
pattern: /circular.*reference/,
|
|
1725
|
+
suggestions: [
|
|
1726
|
+
"Remove circular references between components",
|
|
1727
|
+
"Use lazy loading or memoization to break cycles",
|
|
1728
|
+
"Check for self-referencing components"
|
|
1729
|
+
]
|
|
1390
1730
|
},
|
|
1391
|
-
|
|
1392
|
-
|
|
1731
|
+
{
|
|
1732
|
+
pattern: /maximum.*depth/,
|
|
1733
|
+
suggestions: [
|
|
1734
|
+
"Reduce component nesting depth",
|
|
1735
|
+
"Break complex components into smaller parts",
|
|
1736
|
+
"Check for infinite recursion in component functions"
|
|
1737
|
+
]
|
|
1393
1738
|
},
|
|
1394
|
-
|
|
1395
|
-
|
|
1739
|
+
{
|
|
1740
|
+
pattern: /invalid.*component/,
|
|
1741
|
+
suggestions: [
|
|
1742
|
+
"Ensure component follows the expected object structure",
|
|
1743
|
+
"Check property names and values for typos",
|
|
1744
|
+
"Verify component is not null or undefined"
|
|
1745
|
+
]
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
pattern: /performance|slow|timeout/,
|
|
1749
|
+
suggestions: [
|
|
1750
|
+
"Enable component caching",
|
|
1751
|
+
"Use memoization for expensive operations",
|
|
1752
|
+
"Reduce component complexity",
|
|
1753
|
+
"Consider lazy loading for large components"
|
|
1754
|
+
]
|
|
1396
1755
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1756
|
+
];
|
|
1757
|
+
patterns.forEach(({ pattern, suggestions: patternSuggestions }) => {
|
|
1758
|
+
if (pattern.test(message)) {
|
|
1759
|
+
suggestions.push(...patternSuggestions);
|
|
1760
|
+
}
|
|
1761
|
+
});
|
|
1762
|
+
if (context2.component) {
|
|
1763
|
+
const componentType = typeof context2.component;
|
|
1764
|
+
if (componentType === "function") {
|
|
1765
|
+
suggestions.push("Check function component return value");
|
|
1766
|
+
} else if (componentType === "object" && context2.component === null) {
|
|
1767
|
+
suggestions.push("Component is null - ensure proper initialization");
|
|
1768
|
+
} else if (Array.isArray(context2.component)) {
|
|
1769
|
+
suggestions.push("Arrays should contain valid component objects");
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
if (suggestions.length === 0) {
|
|
1773
|
+
suggestions.push(
|
|
1774
|
+
"Enable development tools for more detailed debugging",
|
|
1775
|
+
"Check browser console for additional _error details",
|
|
1776
|
+
"Use component validation tools to identify issues"
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
return [...new Set(suggestions)];
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Add _error to history with deduplication
|
|
1783
|
+
*/
|
|
1784
|
+
addToHistory(_error) {
|
|
1785
|
+
const errorKey = `${_error.name}:${_error.message}`;
|
|
1786
|
+
this.errorCounts.set(errorKey, (this.errorCounts.get(errorKey) || 0) + 1);
|
|
1787
|
+
const historyEntry = {
|
|
1788
|
+
..._error.toJSON(),
|
|
1789
|
+
count: this.errorCounts.get(errorKey),
|
|
1790
|
+
firstSeen: this.errorHistory.find((e) => e.key === errorKey)?.firstSeen || _error.timestamp,
|
|
1791
|
+
key: errorKey
|
|
1792
|
+
};
|
|
1793
|
+
this.errorHistory = this.errorHistory.filter((e) => e.key !== errorKey);
|
|
1794
|
+
this.errorHistory.unshift(historyEntry);
|
|
1795
|
+
if (this.errorHistory.length > this.options.maxErrorHistory) {
|
|
1796
|
+
this.errorHistory = this.errorHistory.slice(0, this.options.maxErrorHistory);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Log _error with enhanced formatting
|
|
1801
|
+
*/
|
|
1802
|
+
logError(_error) {
|
|
1803
|
+
if (this.suppressedErrors.has(`${_error.name}:${_error.message}`)) {
|
|
1804
|
+
return;
|
|
1805
|
+
}
|
|
1806
|
+
const isRepeated = this.errorCounts.get(`${_error.name}:${_error.message}`) > 1;
|
|
1807
|
+
const errorGroup = `\u{1F6A8} ${_error.name}${isRepeated ? ` (\xD7${this.errorCounts.get(`${_error.name}:${_error.message}`)})` : ""}`;
|
|
1808
|
+
console.group(errorGroup);
|
|
1809
|
+
console.error(`\u274C ${_error.message}`);
|
|
1810
|
+
if (_error.code) {
|
|
1811
|
+
console.log("\u{1F3F7}\uFE0F Code:", _error.code);
|
|
1812
|
+
}
|
|
1813
|
+
if (_error.docsUrl) {
|
|
1814
|
+
console.log("\u{1F4D6} Docs:", _error.docsUrl);
|
|
1815
|
+
}
|
|
1816
|
+
if (_error.component) {
|
|
1817
|
+
console.log("\u{1F50D} Component:", this.formatComponent(_error.component));
|
|
1818
|
+
}
|
|
1819
|
+
if (_error.context) {
|
|
1820
|
+
console.log("\u{1F4CB} Context:", _error.context);
|
|
1821
|
+
}
|
|
1822
|
+
if (_error.context && typeof _error.context === "object" && _error.context.path) {
|
|
1823
|
+
console.log("\u{1F4CD} Path:", _error.context.path);
|
|
1824
|
+
}
|
|
1825
|
+
if (this.options.enableSuggestions && _error.suggestions.length > 0) {
|
|
1826
|
+
console.group("\u{1F4A1} Suggestions:");
|
|
1827
|
+
_error.suggestions.forEach((suggestion, index) => {
|
|
1828
|
+
console.log(`${index + 1}. ${suggestion}`);
|
|
1829
|
+
});
|
|
1830
|
+
console.groupEnd();
|
|
1831
|
+
}
|
|
1832
|
+
if (this.options.enableStackTrace && _error.stack) {
|
|
1833
|
+
console.log("\u{1F4DA} Stack trace:", _error.stack);
|
|
1834
|
+
}
|
|
1835
|
+
console.groupEnd();
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Format component for logging
|
|
1839
|
+
*/
|
|
1840
|
+
formatComponent(component, maxDepth = 2, currentDepth = 0) {
|
|
1841
|
+
if (currentDepth > maxDepth) {
|
|
1842
|
+
return "[...deep]";
|
|
1843
|
+
}
|
|
1844
|
+
if (typeof component === "function") {
|
|
1845
|
+
return `[Function: ${component.name || "anonymous"}]`;
|
|
1846
|
+
}
|
|
1847
|
+
if (Array.isArray(component)) {
|
|
1848
|
+
return component.slice(0, 3).map(
|
|
1849
|
+
(item) => this.formatComponent(item, maxDepth, currentDepth + 1)
|
|
1850
|
+
);
|
|
1851
|
+
}
|
|
1852
|
+
if (component && typeof component === "object") {
|
|
1853
|
+
const formatted = {};
|
|
1854
|
+
const keys = Object.keys(component).slice(0, 5);
|
|
1855
|
+
for (const key of keys) {
|
|
1856
|
+
if (key === "children" && component[key]) {
|
|
1857
|
+
formatted[key] = this.formatComponent(component[key], maxDepth, currentDepth + 1);
|
|
1858
|
+
} else {
|
|
1859
|
+
formatted[key] = component[key];
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
if (Object.keys(component).length > 5) {
|
|
1863
|
+
formatted["..."] = `(${Object.keys(component).length - 5} more)`;
|
|
1864
|
+
}
|
|
1865
|
+
return formatted;
|
|
1866
|
+
}
|
|
1867
|
+
return component;
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* Suppress specific _error types
|
|
1871
|
+
*/
|
|
1872
|
+
suppress(errorPattern) {
|
|
1873
|
+
this.suppressedErrors.add(errorPattern);
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Clear _error history
|
|
1877
|
+
*/
|
|
1878
|
+
clearHistory() {
|
|
1879
|
+
this.errorHistory = [];
|
|
1880
|
+
this.errorCounts.clear();
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Get _error statistics
|
|
1884
|
+
*/
|
|
1885
|
+
getStats() {
|
|
1886
|
+
const errorsByType = {};
|
|
1887
|
+
const errorsByTime = {};
|
|
1888
|
+
this.errorHistory.forEach((_error) => {
|
|
1889
|
+
errorsByType[_error.type] = (errorsByType[_error.type] || 0) + _error.count;
|
|
1890
|
+
const hour = new Date(_error.timestamp).toISOString().slice(0, 13);
|
|
1891
|
+
errorsByTime[hour] = (errorsByTime[hour] || 0) + _error.count;
|
|
1892
|
+
});
|
|
1893
|
+
return {
|
|
1894
|
+
totalErrors: this.errorHistory.reduce((sum, e) => sum + e.count, 0),
|
|
1895
|
+
uniqueErrors: this.errorHistory.length,
|
|
1896
|
+
errorsByType,
|
|
1897
|
+
errorsByTime,
|
|
1898
|
+
mostCommonErrors: this.getMostCommonErrors(5),
|
|
1899
|
+
recentErrors: this.errorHistory.slice(0, 10)
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Get most common errors
|
|
1904
|
+
*/
|
|
1905
|
+
getMostCommonErrors(limit = 10) {
|
|
1906
|
+
return this.errorHistory.sort((a, b) => b.count - a.count).slice(0, limit).map(({ name, message, count, type }) => ({
|
|
1907
|
+
name,
|
|
1908
|
+
message,
|
|
1909
|
+
count,
|
|
1910
|
+
type
|
|
1911
|
+
}));
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
var globalErrorHandler = new ErrorHandler();
|
|
1915
|
+
|
|
1916
|
+
// src/rendering/html-renderer.js
|
|
1917
|
+
var rendererCache = createCacheManager({
|
|
1918
|
+
maxSize: 1e3,
|
|
1919
|
+
ttlMs: 3e5
|
|
1920
|
+
// 5 minutes
|
|
1921
|
+
});
|
|
1922
|
+
function formatRenderPath(path) {
|
|
1923
|
+
if (!path || path.length === 0) return "root";
|
|
1924
|
+
let rendered = "root";
|
|
1925
|
+
for (const segment of path) {
|
|
1926
|
+
if (typeof segment !== "string" || segment.length === 0) continue;
|
|
1927
|
+
if (segment.startsWith("[")) {
|
|
1928
|
+
rendered += segment;
|
|
1929
|
+
} else {
|
|
1930
|
+
rendered += `.${segment}`;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
return rendered;
|
|
1934
|
+
}
|
|
1935
|
+
var HTMLRenderer = class extends BaseRenderer {
|
|
1936
|
+
constructor(options = {}) {
|
|
1937
|
+
super({
|
|
1938
|
+
enableCache: options.enableCache !== false,
|
|
1939
|
+
enableMonitoring: options.enableMonitoring !== false,
|
|
1940
|
+
minify: options.minify || false,
|
|
1941
|
+
streaming: options.streaming || false,
|
|
1942
|
+
maxDepth: options.maxDepth || 100,
|
|
1943
|
+
...options
|
|
1944
|
+
});
|
|
1945
|
+
if (this.config.enableCache && !this.cache) {
|
|
1946
|
+
this.cache = rendererCache;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Main render method - converts components to HTML string
|
|
1951
|
+
*
|
|
1952
|
+
* @param {Object|Array|string|Function} component - Component to render
|
|
1953
|
+
* @param {Object} [options={}] - Rendering options
|
|
1954
|
+
* @param {Object} [options.context] - Rendering context
|
|
1955
|
+
* @param {boolean} [options.enableCache] - Override cache setting
|
|
1956
|
+
* @param {number} [options.depth=0] - Current rendering depth
|
|
1957
|
+
* @returns {string} Rendered HTML string
|
|
1958
|
+
*
|
|
1959
|
+
* @example
|
|
1960
|
+
* const html = renderer.render({
|
|
1961
|
+
* div: {
|
|
1962
|
+
* className: 'container',
|
|
1963
|
+
* children: [
|
|
1964
|
+
* { h1: { text: 'Title' } },
|
|
1965
|
+
* { p: { text: 'Content' } }
|
|
1966
|
+
* ]
|
|
1967
|
+
* }
|
|
1968
|
+
* });
|
|
1969
|
+
*/
|
|
1970
|
+
render(component, options = {}) {
|
|
1971
|
+
const config = { ...this.config, ...options };
|
|
1972
|
+
this.startTiming();
|
|
1973
|
+
try {
|
|
1974
|
+
if (config.validateInput && !this.isValidComponent(component)) {
|
|
1975
|
+
throw new Error("Invalid component structure");
|
|
1976
|
+
}
|
|
1977
|
+
const renderOptions = {
|
|
1978
|
+
...config,
|
|
1979
|
+
seenObjects: /* @__PURE__ */ new WeakSet()
|
|
1980
|
+
};
|
|
1981
|
+
const html = this.renderComponent(component, renderOptions, 0, []);
|
|
1982
|
+
const finalHtml = config.minify ? minifyHtml(html, config) : html;
|
|
1983
|
+
this.endTiming();
|
|
1984
|
+
this.recordPerformance("render", this.metrics.startTime, false, {
|
|
1985
|
+
cacheEnabled: config.enableCache
|
|
1986
|
+
});
|
|
1987
|
+
return finalHtml;
|
|
1988
|
+
} catch (_error) {
|
|
1989
|
+
this.recordError("render", _error);
|
|
1990
|
+
const enhancedError = globalErrorHandler.handle(_error, {
|
|
1991
|
+
renderContext: { path: "root", renderer: "html" }
|
|
1992
|
+
});
|
|
1993
|
+
if (config.throwOnError === false) {
|
|
1994
|
+
return config.errorFallback;
|
|
1995
|
+
}
|
|
1996
|
+
throw enhancedError;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
/**
|
|
2000
|
+
* Render a single component with full optimization pipeline
|
|
2001
|
+
*/
|
|
2002
|
+
renderComponent(component, options, depth = 0, path = []) {
|
|
2003
|
+
if (component === null || component === void 0) {
|
|
2004
|
+
return "";
|
|
2005
|
+
}
|
|
2006
|
+
if (Array.isArray(component) && component.length === 0) {
|
|
2007
|
+
return "";
|
|
2008
|
+
}
|
|
2009
|
+
if (typeof component === "object" && component !== null && !Array.isArray(component)) {
|
|
2010
|
+
if (options.seenObjects && options.seenObjects.has(component)) {
|
|
2011
|
+
throw new RenderingError(
|
|
2012
|
+
"Circular reference detected in component tree",
|
|
2013
|
+
component,
|
|
2014
|
+
{ path: formatRenderPath(path) },
|
|
2015
|
+
["Remove the circular reference", "Use lazy loading to break the cycle"]
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
if (options.seenObjects) {
|
|
2019
|
+
options.seenObjects.add(component);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
this.validateDepth(depth);
|
|
2023
|
+
try {
|
|
2024
|
+
const { type, value } = this.processComponentType(component);
|
|
2025
|
+
switch (type) {
|
|
2026
|
+
case "empty":
|
|
2027
|
+
return "";
|
|
2028
|
+
case "text":
|
|
2029
|
+
return escapeHtml(value);
|
|
2030
|
+
case "function": {
|
|
2031
|
+
const result = this.executeFunctionComponent(value, depth);
|
|
2032
|
+
return this.renderComponent(result, options, depth + 1, [...path, "()"]);
|
|
2033
|
+
}
|
|
2034
|
+
case "array":
|
|
2035
|
+
if (typeof process !== "undefined" && process.env && true && value.length > 1) {
|
|
2036
|
+
const missingKeyCount = value.filter((child) => {
|
|
2037
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2038
|
+
const tagName = Object.keys(child)[0];
|
|
2039
|
+
const props = child[tagName];
|
|
2040
|
+
return props && typeof props === "object" && props.key === void 0;
|
|
2041
|
+
}
|
|
2042
|
+
return false;
|
|
2043
|
+
}).length;
|
|
2044
|
+
if (missingKeyCount > 0) {
|
|
2045
|
+
console.warn(
|
|
2046
|
+
`[Coherent.js] Array of ${value.length} elements at ${formatRenderPath(path)} has ${missingKeyCount} items missing "key" props. Keys help identify which items changed for efficient updates. Add unique key props like: { div: { key: 'unique-id', ... } }`
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
return value.map((child, index) => this.renderComponent(child, options, depth + 1, [...path, `[${index}]`])).join("");
|
|
2051
|
+
case "element": {
|
|
2052
|
+
const tagName = Object.keys(value)[0];
|
|
2053
|
+
const elementContent = value[tagName];
|
|
2054
|
+
return this.renderElement(tagName, elementContent, options, depth, [...path, tagName]);
|
|
2055
|
+
}
|
|
2056
|
+
default:
|
|
2057
|
+
this.recordError("renderComponent", new Error(`Unknown component type: ${type}`));
|
|
2058
|
+
return "";
|
|
2059
|
+
}
|
|
2060
|
+
} catch (_error) {
|
|
2061
|
+
const renderPath = formatRenderPath(path);
|
|
2062
|
+
if (_error instanceof CoherentError) {
|
|
2063
|
+
if (!_error.context || typeof _error.context !== "object") {
|
|
2064
|
+
_error.context = { path: renderPath };
|
|
2065
|
+
} else if (!_error.context.path) {
|
|
2066
|
+
_error.context = { ..._error.context, path: renderPath };
|
|
2067
|
+
}
|
|
2068
|
+
throw _error;
|
|
2069
|
+
}
|
|
2070
|
+
throw new RenderingError(_error.message, void 0, { path: renderPath, renderer: "html" });
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Render an HTML element with advanced caching and optimization
|
|
2075
|
+
*/
|
|
2076
|
+
renderElement(tagName, element, options, depth = 0, path = []) {
|
|
2077
|
+
const startTime = performance.now();
|
|
2078
|
+
if (element && typeof element === "object" && !Array.isArray(element)) {
|
|
2079
|
+
if (options.seenObjects && options.seenObjects.has(element)) {
|
|
2080
|
+
throw new RenderingError(
|
|
2081
|
+
"Circular reference detected in component tree",
|
|
2082
|
+
element,
|
|
2083
|
+
{ path: formatRenderPath(path) },
|
|
2084
|
+
["Remove the circular reference", "Use lazy loading to break the cycle"]
|
|
2085
|
+
);
|
|
2086
|
+
}
|
|
2087
|
+
if (options.seenObjects) {
|
|
2088
|
+
options.seenObjects.add(element);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
if (options.enableMonitoring && this.cache) {
|
|
2092
|
+
}
|
|
2093
|
+
if (options.enableCache && this.cache && RendererUtils.isStaticElement(element)) {
|
|
2094
|
+
try {
|
|
2095
|
+
const cacheKey = `static:${tagName}:${JSON.stringify(element)}`;
|
|
2096
|
+
const cached = this.cache.get("static", cacheKey);
|
|
2097
|
+
if (cached) {
|
|
2098
|
+
this.recordPerformance(tagName, startTime, true);
|
|
2099
|
+
return cached.value;
|
|
2100
|
+
}
|
|
2101
|
+
} catch {
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
if (typeof element === "string" || typeof element === "number" || typeof element === "boolean") {
|
|
2105
|
+
const html2 = isVoidElement(tagName) ? `<${tagName}>` : `<${tagName}>${escapeHtml(String(element))}</${tagName}>`;
|
|
2106
|
+
this.cacheIfStatic(tagName, element, html2, options);
|
|
2107
|
+
this.recordPerformance(tagName, startTime, false);
|
|
2108
|
+
return html2;
|
|
2109
|
+
}
|
|
2110
|
+
if (typeof element === "function") {
|
|
2111
|
+
const result = this.executeFunctionComponent(element, depth);
|
|
2112
|
+
return this.renderElement(tagName, result, options, depth, [...path, "()"]);
|
|
2113
|
+
}
|
|
2114
|
+
if (element && typeof element === "object") {
|
|
2115
|
+
return this.renderObjectElement(tagName, element, options, depth, path);
|
|
2116
|
+
}
|
|
2117
|
+
if (element === null || element === void 0) {
|
|
2118
|
+
const html2 = isVoidElement(tagName) ? `<${tagName}>` : `<${tagName}></${tagName}>`;
|
|
2119
|
+
this.recordPerformance(tagName, startTime, false);
|
|
2120
|
+
return html2;
|
|
2121
|
+
}
|
|
2122
|
+
const html = `<${tagName}>${escapeHtml(String(element))}</${tagName}>`;
|
|
2123
|
+
this.recordPerformance(tagName, startTime, false);
|
|
2124
|
+
return html;
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Cache element if it's static
|
|
2128
|
+
*/
|
|
2129
|
+
cacheIfStatic(tagName, element, html) {
|
|
2130
|
+
if (this.config.enableCache && this.cache && RendererUtils.isStaticElement(element)) {
|
|
2131
|
+
try {
|
|
2132
|
+
const cacheKey = `static:${tagName}:${JSON.stringify(element)}`;
|
|
2133
|
+
this.cache.set("static", cacheKey, html, {
|
|
2134
|
+
ttlMs: this.config.cacheTTL || 5 * 60 * 1e3,
|
|
2135
|
+
// 5 minutes default
|
|
2136
|
+
size: html.length
|
|
2137
|
+
// Approximate size
|
|
2138
|
+
});
|
|
2139
|
+
} catch {
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Render complex object elements with attributes and children
|
|
2145
|
+
*/
|
|
2146
|
+
renderObjectElement(tagName, element, options, depth = 0, path = []) {
|
|
2147
|
+
const startTime = performance.now();
|
|
2148
|
+
if (options.enableCache && this.cache) {
|
|
2149
|
+
const cacheKey = RendererUtils.generateCacheKey(tagName, element);
|
|
2150
|
+
if (cacheKey) {
|
|
2151
|
+
const cached = this.cache.get(cacheKey);
|
|
2152
|
+
if (cached) {
|
|
2153
|
+
this.recordPerformance(tagName, startTime, true);
|
|
2154
|
+
return cached;
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
const { children, text, key: _key, html: _rawHtml, ...attributes } = element || {};
|
|
2159
|
+
const attributeString = formatAttributes(attributes);
|
|
2160
|
+
const openingTag = attributeString ? `<${tagName} ${attributeString}>` : `<${tagName}>`;
|
|
2161
|
+
let textContent = "";
|
|
2162
|
+
if (text !== void 0) {
|
|
2163
|
+
const isScript = tagName === "script";
|
|
2164
|
+
const isStyle = tagName === "style";
|
|
2165
|
+
const isRawTag = isScript || isStyle;
|
|
2166
|
+
const raw = typeof text === "function" ? String(text()) : String(text);
|
|
2167
|
+
if (isRawTag) {
|
|
2168
|
+
const safe = raw.replace(/<\/(script)/gi, "<\\/$1").replace(/<\/(style)/gi, "<\\/$1").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
2169
|
+
textContent = safe;
|
|
2170
|
+
} else {
|
|
2171
|
+
textContent = escapeHtml(raw);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
let childrenHtml = "";
|
|
2175
|
+
if (hasChildren(element)) {
|
|
2176
|
+
const normalizedChildren = normalizeChildren(children);
|
|
2177
|
+
childrenHtml = normalizedChildren.map((child, index) => {
|
|
2178
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
2179
|
+
const childTagName = Object.keys(child)[0];
|
|
2180
|
+
if (childTagName) {
|
|
2181
|
+
validateNesting(tagName, childTagName, formatRenderPath([...path, `children[${index}]`]));
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
return this.renderComponent(child, options, depth + 1, [...path, `children[${index}]`]);
|
|
2185
|
+
}).join("");
|
|
2186
|
+
}
|
|
2187
|
+
const html = `${openingTag}${textContent}${childrenHtml}</${tagName}>`;
|
|
2188
|
+
if (options.enableCache && this.cache && RendererUtils.isCacheable(element, options)) {
|
|
2189
|
+
const cacheKey = RendererUtils.generateCacheKey(tagName, element);
|
|
2190
|
+
if (cacheKey) {
|
|
2191
|
+
this.cache.set(cacheKey, html);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
this.recordPerformance(tagName, startTime, false);
|
|
2195
|
+
return html;
|
|
2196
|
+
}
|
|
2197
|
+
};
|
|
2198
|
+
function render(component, options = {}) {
|
|
2199
|
+
const mergedOptions = {
|
|
2200
|
+
enableCache: true,
|
|
2201
|
+
enableMonitoring: false,
|
|
2202
|
+
...options
|
|
2203
|
+
};
|
|
2204
|
+
const renderer = new HTMLRenderer(mergedOptions);
|
|
2205
|
+
return renderer.render(component, mergedOptions);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
// src/components/component-system.js
|
|
2209
|
+
var COMPONENT_REGISTRY = /* @__PURE__ */ new Map();
|
|
2210
|
+
var COMPONENT_METADATA = /* @__PURE__ */ new WeakMap();
|
|
2211
|
+
var ComponentState = class {
|
|
2212
|
+
constructor(initialState = {}) {
|
|
2213
|
+
this.state = { ...initialState };
|
|
2214
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2215
|
+
this.isUpdating = false;
|
|
2216
|
+
}
|
|
2217
|
+
/**
|
|
2218
|
+
* Get state value by key or entire state
|
|
2219
|
+
*
|
|
2220
|
+
* @param {string} [key] - State key to retrieve
|
|
2221
|
+
* @returns {*} State value or entire state object
|
|
2222
|
+
*/
|
|
2223
|
+
get(key) {
|
|
2224
|
+
return key ? this.state[key] : { ...this.state };
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Update state with new values
|
|
2228
|
+
*
|
|
2229
|
+
* @param {Object} updates - State updates to apply
|
|
2230
|
+
* @returns {ComponentState} This instance for chaining
|
|
2231
|
+
*/
|
|
2232
|
+
set(updates) {
|
|
2233
|
+
if (this.isUpdating) return this;
|
|
2234
|
+
const oldState = { ...this.state };
|
|
2235
|
+
if (typeof updates === "function") {
|
|
2236
|
+
updates = updates(oldState);
|
|
2237
|
+
}
|
|
2238
|
+
this.state = { ...this.state, ...updates };
|
|
2239
|
+
this.notifyListeners(oldState, this.state);
|
|
2240
|
+
return this;
|
|
2241
|
+
}
|
|
2242
|
+
subscribe(listener) {
|
|
2243
|
+
this.listeners.add(listener);
|
|
2244
|
+
return () => this.listeners.delete(listener);
|
|
2245
|
+
}
|
|
2246
|
+
notifyListeners(oldState, newState) {
|
|
2247
|
+
if (this.listeners.size === 0) return;
|
|
2248
|
+
this.isUpdating = true;
|
|
2249
|
+
this.listeners.forEach((listener) => {
|
|
2250
|
+
try {
|
|
2251
|
+
listener(newState, oldState);
|
|
2252
|
+
} catch (_error) {
|
|
2253
|
+
console.error("State listener _error:", _error);
|
|
2254
|
+
}
|
|
2255
|
+
});
|
|
2256
|
+
this.isUpdating = false;
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
var Component = class _Component {
|
|
2260
|
+
constructor(definition = {}) {
|
|
2261
|
+
this.definition = definition;
|
|
2262
|
+
this.name = definition.name || "AnonymousComponent";
|
|
2263
|
+
this.props = {};
|
|
2264
|
+
this.state = new ComponentState(definition.state || {});
|
|
2265
|
+
this.children = [];
|
|
2266
|
+
this.parent = null;
|
|
2267
|
+
this.rendered = null;
|
|
2268
|
+
this.isMounted = false;
|
|
2269
|
+
this.isDestroyed = false;
|
|
2270
|
+
this.hooks = {
|
|
2271
|
+
beforeCreate: definition.beforeCreate || (() => {
|
|
2272
|
+
}),
|
|
2273
|
+
created: definition.created || (() => {
|
|
2274
|
+
}),
|
|
2275
|
+
beforeMount: definition.beforeMount || (() => {
|
|
2276
|
+
}),
|
|
2277
|
+
mounted: definition.mounted || (() => {
|
|
2278
|
+
}),
|
|
2279
|
+
beforeUpdate: definition.beforeUpdate || (() => {
|
|
2280
|
+
}),
|
|
2281
|
+
updated: definition.updated || (() => {
|
|
2282
|
+
}),
|
|
2283
|
+
beforeDestroy: definition.beforeDestroy || (() => {
|
|
2284
|
+
}),
|
|
2285
|
+
destroyed: definition.destroyed || (() => {
|
|
2286
|
+
}),
|
|
2287
|
+
errorCaptured: definition.errorCaptured || (() => {
|
|
2288
|
+
})
|
|
2289
|
+
};
|
|
2290
|
+
this.methods = definition.methods || {};
|
|
2291
|
+
Object.keys(this.methods).forEach((methodName) => {
|
|
2292
|
+
if (typeof this.methods[methodName] === "function") {
|
|
2293
|
+
this[methodName] = this.methods[methodName].bind(this);
|
|
2294
|
+
}
|
|
2295
|
+
});
|
|
2296
|
+
this.computed = definition.computed || {};
|
|
2297
|
+
this.computedCache = /* @__PURE__ */ new Map();
|
|
2298
|
+
this.watchers = definition.watch || {};
|
|
2299
|
+
this.setupWatchers();
|
|
2300
|
+
COMPONENT_METADATA.set(this, {
|
|
2301
|
+
createdAt: Date.now(),
|
|
2302
|
+
updateCount: 0,
|
|
2303
|
+
renderCount: 0
|
|
2304
|
+
});
|
|
2305
|
+
this.callHook("beforeCreate");
|
|
2306
|
+
this.initialize();
|
|
2307
|
+
this.callHook("created");
|
|
2308
|
+
}
|
|
2309
|
+
/**
|
|
2310
|
+
* Initialize component
|
|
2311
|
+
*/
|
|
2312
|
+
initialize() {
|
|
2313
|
+
this.unsubscribeState = this.state.subscribe((newState, oldState) => {
|
|
2314
|
+
this.onStateChange(newState, oldState);
|
|
2315
|
+
});
|
|
2316
|
+
this.initializeComputed();
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Set up watchers for reactive data
|
|
2320
|
+
*/
|
|
2321
|
+
setupWatchers() {
|
|
2322
|
+
Object.keys(this.watchers).forEach((key) => {
|
|
2323
|
+
const handler = this.watchers[key];
|
|
2324
|
+
this.state.subscribe((newState, oldState) => {
|
|
2325
|
+
if (newState[key] !== oldState[key]) {
|
|
2326
|
+
handler.call(this, newState[key], oldState[key]);
|
|
2327
|
+
}
|
|
2328
|
+
});
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Initialize computed properties
|
|
2333
|
+
*/
|
|
2334
|
+
initializeComputed() {
|
|
2335
|
+
Object.keys(this.computed).forEach((key) => {
|
|
2336
|
+
Object.defineProperty(this, key, {
|
|
2337
|
+
get: () => {
|
|
2338
|
+
if (!this.computedCache.has(key)) {
|
|
2339
|
+
const value = this.computed[key].call(this);
|
|
2340
|
+
this.computedCache.set(key, value);
|
|
2341
|
+
}
|
|
2342
|
+
return this.computedCache.get(key);
|
|
2343
|
+
},
|
|
2344
|
+
enumerable: true
|
|
2345
|
+
});
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Handle state changes
|
|
2350
|
+
*/
|
|
2351
|
+
onStateChange() {
|
|
2352
|
+
if (this.isDestroyed) return;
|
|
2353
|
+
this.computedCache.clear();
|
|
2354
|
+
if (this.isMounted) {
|
|
2355
|
+
this.update();
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Call lifecycle hook
|
|
2360
|
+
*/
|
|
2361
|
+
callHook(hookName, ...args) {
|
|
2362
|
+
try {
|
|
2363
|
+
if (this.hooks[hookName]) {
|
|
2364
|
+
return this.hooks[hookName].call(this, ...args);
|
|
2365
|
+
}
|
|
2366
|
+
} catch (_error) {
|
|
2367
|
+
this.handleError(_error, `${hookName} hook`);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
/**
|
|
2371
|
+
* Handle component errors
|
|
2372
|
+
*/
|
|
2373
|
+
handleError(_error) {
|
|
2374
|
+
console.error(`Component Error in ${this.name}:`, _error);
|
|
2375
|
+
this.callHook("errorCaptured", _error);
|
|
2376
|
+
if (this.parent && this.parent.handleError) {
|
|
2377
|
+
this.parent.handleError(_error, `${this.name} -> ${context}`);
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Render the component
|
|
2382
|
+
*/
|
|
2383
|
+
render(props = {}) {
|
|
2384
|
+
if (this.isDestroyed) {
|
|
2385
|
+
console.warn(`Attempting to render destroyed component: ${this.name}`);
|
|
2386
|
+
return null;
|
|
2387
|
+
}
|
|
2388
|
+
try {
|
|
2389
|
+
const metadata = COMPONENT_METADATA.get(this);
|
|
2390
|
+
if (metadata) {
|
|
2391
|
+
metadata.renderCount++;
|
|
2392
|
+
}
|
|
2393
|
+
this.props = { ...props };
|
|
2394
|
+
if (typeof this.definition.render === "function") {
|
|
2395
|
+
this.rendered = this.definition.render.call(this, this.props, this.state.get());
|
|
2396
|
+
} else if (typeof this.definition.template !== "undefined") {
|
|
2397
|
+
this.rendered = this.processTemplate(this.definition.template, this.props, this.state.get());
|
|
2398
|
+
} else {
|
|
2399
|
+
throw new Error(`Component ${this.name} must have either render method or template`);
|
|
2400
|
+
}
|
|
2401
|
+
if (this.rendered !== null) {
|
|
2402
|
+
validateComponent(this.rendered, this.name);
|
|
2403
|
+
}
|
|
2404
|
+
return this.rendered;
|
|
2405
|
+
} catch (_error) {
|
|
2406
|
+
this.handleError(_error);
|
|
2407
|
+
return { div: { className: "component-_error", text: `Error in ${this.name}` } };
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
/**
|
|
2411
|
+
* Process template with data
|
|
2412
|
+
*/
|
|
2413
|
+
processTemplate(template, props, state) {
|
|
2414
|
+
if (typeof template === "function") {
|
|
2415
|
+
return template.call(this, props, state);
|
|
2416
|
+
}
|
|
2417
|
+
if (typeof template === "string") {
|
|
2418
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
2419
|
+
return props[key] || state[key] || "";
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
const processed = deepClone(template);
|
|
2423
|
+
this.interpolateObject(processed, { ...props, ...state });
|
|
2424
|
+
return processed;
|
|
2425
|
+
}
|
|
2426
|
+
/**
|
|
2427
|
+
* Interpolate object with data
|
|
2428
|
+
*/
|
|
2429
|
+
interpolateObject(obj, data) {
|
|
2430
|
+
if (typeof obj === "string") {
|
|
2431
|
+
return obj.replace(/\{\{(\w+)\}\}/g, (match, key) => data[key] || "");
|
|
2432
|
+
}
|
|
2433
|
+
if (Array.isArray(obj)) {
|
|
2434
|
+
return obj.map((item) => this.interpolateObject(item, data));
|
|
2435
|
+
}
|
|
2436
|
+
if (obj && typeof obj === "object") {
|
|
2437
|
+
Object.keys(obj).forEach((key) => {
|
|
2438
|
+
obj[key] = this.interpolateObject(obj[key], data);
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
return obj;
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Mount the component
|
|
2445
|
+
*/
|
|
2446
|
+
mount() {
|
|
2447
|
+
if (this.isMounted || this.isDestroyed) return this;
|
|
2448
|
+
this.callHook("beforeMount");
|
|
2449
|
+
this.isMounted = true;
|
|
2450
|
+
this.callHook("mounted");
|
|
2451
|
+
return this;
|
|
2452
|
+
}
|
|
2453
|
+
/**
|
|
2454
|
+
* Update the component
|
|
2455
|
+
*/
|
|
2456
|
+
update() {
|
|
2457
|
+
if (!this.isMounted || this.isDestroyed) return this;
|
|
2458
|
+
const metadata = COMPONENT_METADATA.get(this);
|
|
2459
|
+
if (metadata) {
|
|
2460
|
+
metadata.updateCount++;
|
|
2461
|
+
}
|
|
2462
|
+
this.callHook("beforeUpdate");
|
|
2463
|
+
this.callHook("updated");
|
|
2464
|
+
return this;
|
|
2465
|
+
}
|
|
2466
|
+
/**
|
|
2467
|
+
* Destroy the component
|
|
2468
|
+
*/
|
|
2469
|
+
destroy() {
|
|
2470
|
+
if (this.isDestroyed) return this;
|
|
2471
|
+
this.callHook("beforeDestroy");
|
|
2472
|
+
if (this.unsubscribeState) {
|
|
2473
|
+
this.unsubscribeState();
|
|
2474
|
+
}
|
|
2475
|
+
this.children.forEach((child) => {
|
|
2476
|
+
if (child.destroy) {
|
|
2477
|
+
child.destroy();
|
|
2478
|
+
}
|
|
2479
|
+
});
|
|
2480
|
+
this.isMounted = false;
|
|
2481
|
+
this.isDestroyed = true;
|
|
2482
|
+
this.children = [];
|
|
2483
|
+
this.parent = null;
|
|
2484
|
+
this.callHook("destroyed");
|
|
2485
|
+
return this;
|
|
2486
|
+
}
|
|
2487
|
+
/**
|
|
2488
|
+
* Get component metadata
|
|
2489
|
+
*/
|
|
2490
|
+
getMetadata() {
|
|
2491
|
+
return COMPONENT_METADATA.get(this) || {};
|
|
2492
|
+
}
|
|
2493
|
+
/**
|
|
2494
|
+
* Clone component with new props/state
|
|
2495
|
+
*/
|
|
2496
|
+
clone(overrides = {}) {
|
|
2497
|
+
const newDefinition = { ...this.definition, ...overrides };
|
|
2498
|
+
return new _Component(newDefinition);
|
|
2499
|
+
}
|
|
2500
|
+
};
|
|
2501
|
+
function createComponent(definition) {
|
|
2502
|
+
if (typeof definition === "function") {
|
|
2503
|
+
definition = {
|
|
2504
|
+
name: definition.name || "FunctionalComponent",
|
|
2505
|
+
render: definition
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
return new Component(definition);
|
|
2509
|
+
}
|
|
2510
|
+
function defineComponent(definition) {
|
|
2511
|
+
const componentFactory = (props) => {
|
|
2512
|
+
const component = new Component(definition);
|
|
2513
|
+
return component.render(props);
|
|
2514
|
+
};
|
|
2515
|
+
componentFactory.componentName = definition.name || "Component";
|
|
2516
|
+
componentFactory.definition = definition;
|
|
2517
|
+
return componentFactory;
|
|
2518
|
+
}
|
|
2519
|
+
function registerComponent(name, definition) {
|
|
2520
|
+
if (COMPONENT_REGISTRY.has(name)) {
|
|
2521
|
+
console.warn(`Component ${name} is already registered. Overriding.`);
|
|
2522
|
+
}
|
|
2523
|
+
const component = typeof definition === "function" ? defineComponent({ name, render: definition }) : defineComponent(definition);
|
|
2524
|
+
COMPONENT_REGISTRY.set(name, component);
|
|
2525
|
+
return component;
|
|
2526
|
+
}
|
|
2527
|
+
function getComponent(name) {
|
|
2528
|
+
return COMPONENT_REGISTRY.get(name);
|
|
2529
|
+
}
|
|
2530
|
+
function getRegisteredComponents() {
|
|
2531
|
+
return new Map(COMPONENT_REGISTRY);
|
|
2532
|
+
}
|
|
2533
|
+
if (performanceMonitor) {
|
|
2534
|
+
const originalRender = Component.prototype.render;
|
|
2535
|
+
Component.prototype.render = function(...args) {
|
|
2536
|
+
const start = performance.now();
|
|
2537
|
+
const result = originalRender.apply(this, args);
|
|
2538
|
+
const duration = performance.now() - start;
|
|
2539
|
+
performanceMonitor.recordMetric("renderTime", duration, {
|
|
2540
|
+
type: "component",
|
|
2541
|
+
name: this.name,
|
|
2542
|
+
propsSize: JSON.stringify(this.props || {}).length,
|
|
2543
|
+
hasState: Object.keys(this.state?.get() || {}).length > 0
|
|
2544
|
+
});
|
|
2545
|
+
return result;
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
function lazy(factory, options = {}) {
|
|
2549
|
+
const {
|
|
2550
|
+
cache = true,
|
|
2551
|
+
// Cache the result after first evaluation
|
|
2552
|
+
timeout = null,
|
|
2553
|
+
// Optional timeout for evaluation
|
|
2554
|
+
fallback = null,
|
|
2555
|
+
// Fallback value if evaluation fails
|
|
2556
|
+
onError = null,
|
|
2557
|
+
// Error handler
|
|
2558
|
+
dependencies = []
|
|
2559
|
+
// Dependencies that invalidate cache
|
|
2560
|
+
} = options;
|
|
2561
|
+
let cached = false;
|
|
2562
|
+
let cachedValue = null;
|
|
2563
|
+
let isEvaluating = false;
|
|
2564
|
+
let lastDependencyHash = null;
|
|
2565
|
+
const lazyWrapper = {
|
|
2566
|
+
// Mark as lazy for identification
|
|
2567
|
+
__isLazy: true,
|
|
2568
|
+
__factory: factory,
|
|
2569
|
+
__options: options,
|
|
2570
|
+
// Evaluation method
|
|
2571
|
+
evaluate(...args) {
|
|
2572
|
+
if (isEvaluating) {
|
|
2573
|
+
console.warn("Lazy evaluation cycle detected, returning fallback");
|
|
2574
|
+
return fallback;
|
|
2575
|
+
}
|
|
2576
|
+
if (cache && dependencies.length > 0) {
|
|
2577
|
+
const currentHash = hashDependencies(dependencies);
|
|
2578
|
+
if (lastDependencyHash !== null && lastDependencyHash !== currentHash) {
|
|
2579
|
+
cached = false;
|
|
2580
|
+
cachedValue = null;
|
|
2581
|
+
}
|
|
2582
|
+
lastDependencyHash = currentHash;
|
|
2583
|
+
}
|
|
2584
|
+
if (cache && cached) {
|
|
2585
|
+
return cachedValue;
|
|
2586
|
+
}
|
|
2587
|
+
isEvaluating = true;
|
|
2588
|
+
try {
|
|
2589
|
+
let result;
|
|
2590
|
+
if (timeout) {
|
|
2591
|
+
result = evaluateWithTimeout(factory, timeout, args, fallback);
|
|
2592
|
+
} else {
|
|
2593
|
+
result = typeof factory === "function" ? factory(...args) : factory;
|
|
2594
|
+
}
|
|
2595
|
+
if (result && typeof result.then === "function") {
|
|
2596
|
+
return result.catch((_error) => {
|
|
2597
|
+
if (onError) onError(_error);
|
|
2598
|
+
return fallback;
|
|
2599
|
+
});
|
|
2600
|
+
}
|
|
2601
|
+
if (cache) {
|
|
2602
|
+
cached = true;
|
|
2603
|
+
cachedValue = result;
|
|
2604
|
+
}
|
|
2605
|
+
return result;
|
|
2606
|
+
} catch (_error) {
|
|
2607
|
+
if (onError) {
|
|
2608
|
+
onError(_error);
|
|
2609
|
+
} else {
|
|
2610
|
+
console.error("Lazy evaluation _error:", _error);
|
|
2611
|
+
}
|
|
2612
|
+
return fallback;
|
|
2613
|
+
} finally {
|
|
2614
|
+
isEvaluating = false;
|
|
2615
|
+
}
|
|
2616
|
+
},
|
|
2617
|
+
// Force re-evaluation
|
|
2618
|
+
invalidate() {
|
|
2619
|
+
cached = false;
|
|
2620
|
+
cachedValue = null;
|
|
2621
|
+
lastDependencyHash = null;
|
|
2622
|
+
return this;
|
|
2623
|
+
},
|
|
2624
|
+
// Check if evaluated
|
|
2625
|
+
isEvaluated() {
|
|
2626
|
+
return cached;
|
|
2627
|
+
},
|
|
2628
|
+
// Get cached value without evaluation
|
|
2629
|
+
getCachedValue() {
|
|
2630
|
+
return cachedValue;
|
|
2631
|
+
},
|
|
2632
|
+
// Transform the lazy value
|
|
2633
|
+
map(transform) {
|
|
2634
|
+
return lazy((...args) => {
|
|
2635
|
+
const value = this.evaluate(...args);
|
|
2636
|
+
return transform(value);
|
|
2637
|
+
}, { ...options, cache: false });
|
|
2638
|
+
},
|
|
2639
|
+
// Chain lazy evaluations
|
|
2640
|
+
flatMap(transform) {
|
|
2641
|
+
return lazy((...args) => {
|
|
2642
|
+
const value = this.evaluate(...args);
|
|
2643
|
+
const transformed = transform(value);
|
|
2644
|
+
if (isLazy(transformed)) {
|
|
2645
|
+
return transformed.evaluate(...args);
|
|
2646
|
+
}
|
|
2647
|
+
return transformed;
|
|
2648
|
+
}, { ...options, cache: false });
|
|
2649
|
+
},
|
|
2650
|
+
// Convert to string for debugging
|
|
2651
|
+
toString() {
|
|
2652
|
+
return `[Lazy${cached ? " (cached)" : ""}]`;
|
|
2653
|
+
},
|
|
2654
|
+
// JSON serialization
|
|
2655
|
+
toJSON() {
|
|
2656
|
+
return this.evaluate();
|
|
2657
|
+
}
|
|
2658
|
+
};
|
|
2659
|
+
return lazyWrapper;
|
|
2660
|
+
}
|
|
2661
|
+
function isLazy(value) {
|
|
2662
|
+
return value && typeof value === "object" && value.__isLazy === true;
|
|
2663
|
+
}
|
|
2664
|
+
function evaluateLazy(obj, ...args) {
|
|
2665
|
+
if (isLazy(obj)) {
|
|
2666
|
+
return obj.evaluate(...args);
|
|
2667
|
+
}
|
|
2668
|
+
if (Array.isArray(obj)) {
|
|
2669
|
+
return obj.map((item) => evaluateLazy(item, ...args));
|
|
2670
|
+
}
|
|
2671
|
+
if (obj && typeof obj === "object") {
|
|
2672
|
+
const result = {};
|
|
2673
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
2674
|
+
result[key] = evaluateLazy(value, ...args);
|
|
2675
|
+
}
|
|
2676
|
+
return result;
|
|
2677
|
+
}
|
|
2678
|
+
return obj;
|
|
2679
|
+
}
|
|
2680
|
+
function hashDependencies(dependencies) {
|
|
2681
|
+
return dependencies.map((dep) => {
|
|
2682
|
+
if (typeof dep === "function") {
|
|
2683
|
+
return dep.toString();
|
|
2684
|
+
}
|
|
2685
|
+
return JSON.stringify(dep);
|
|
2686
|
+
}).join("|");
|
|
2687
|
+
}
|
|
2688
|
+
function evaluateWithTimeout(factory, timeout, args, fallback) {
|
|
2689
|
+
return new Promise((resolve, reject) => {
|
|
2690
|
+
const timer = setTimeout(() => {
|
|
2691
|
+
reject(new Error(`Lazy evaluation timeout after ${timeout}ms`));
|
|
2692
|
+
}, timeout);
|
|
2693
|
+
try {
|
|
2694
|
+
const result = factory(...args);
|
|
2695
|
+
if (result && typeof result.then === "function") {
|
|
2696
|
+
result.then((value) => {
|
|
2697
|
+
clearTimeout(timer);
|
|
2698
|
+
resolve(value);
|
|
2699
|
+
}).catch((_error) => {
|
|
2700
|
+
clearTimeout(timer);
|
|
2701
|
+
reject(_error);
|
|
2702
|
+
});
|
|
2703
|
+
} else {
|
|
2704
|
+
clearTimeout(timer);
|
|
2705
|
+
resolve(result);
|
|
2706
|
+
}
|
|
2707
|
+
} catch (_error) {
|
|
2708
|
+
clearTimeout(timer);
|
|
2709
|
+
reject(_error);
|
|
2710
|
+
}
|
|
2711
|
+
}).catch(() => fallback);
|
|
2712
|
+
}
|
|
2713
|
+
function memo(fn, options = {}) {
|
|
2714
|
+
const {
|
|
2715
|
+
// Caching strategy
|
|
2716
|
+
strategy = "lru",
|
|
2717
|
+
// 'lru', 'ttl', 'weak', 'simple'
|
|
2718
|
+
maxSize = 100,
|
|
2719
|
+
// Maximum cache entries
|
|
2720
|
+
ttl = null,
|
|
2721
|
+
// Time to live in milliseconds
|
|
2722
|
+
// Key generation
|
|
2723
|
+
keyFn = null,
|
|
2724
|
+
// Custom key function
|
|
2725
|
+
keySerializer = JSON.stringify,
|
|
2726
|
+
// Default serialization
|
|
2727
|
+
// Comparison
|
|
2728
|
+
// eslint-disable-next-line no-unused-vars
|
|
2729
|
+
compareFn = null,
|
|
2730
|
+
// Custom equality comparison
|
|
2731
|
+
// eslint-disable-next-line no-unused-vars
|
|
2732
|
+
shallow = false,
|
|
2733
|
+
// Shallow comparison for objects
|
|
2734
|
+
// Lifecycle hooks
|
|
2735
|
+
onHit = null,
|
|
2736
|
+
// Called on cache hit
|
|
2737
|
+
onMiss = null,
|
|
2738
|
+
// Called on cache miss
|
|
2739
|
+
onEvict = null,
|
|
2740
|
+
// Called when item evicted
|
|
2741
|
+
// Performance
|
|
2742
|
+
stats = false,
|
|
2743
|
+
// Track hit/miss statistics
|
|
2744
|
+
// Development
|
|
2745
|
+
debug = false
|
|
2746
|
+
// Debug logging
|
|
2747
|
+
} = options;
|
|
2748
|
+
let cache;
|
|
2749
|
+
const stats_data = stats ? { hits: 0, misses: 0, evictions: 0 } : null;
|
|
2750
|
+
switch (strategy) {
|
|
2751
|
+
case "lru":
|
|
2752
|
+
cache = new LRUCache(maxSize, { onEvict });
|
|
2753
|
+
break;
|
|
2754
|
+
case "ttl":
|
|
2755
|
+
cache = new TTLCache(ttl, { onEvict });
|
|
2756
|
+
break;
|
|
2757
|
+
case "weak":
|
|
2758
|
+
cache = /* @__PURE__ */ new WeakMap();
|
|
2759
|
+
break;
|
|
2760
|
+
default:
|
|
2761
|
+
cache = /* @__PURE__ */ new Map();
|
|
2762
|
+
}
|
|
2763
|
+
const generateKey = keyFn || ((...args) => {
|
|
2764
|
+
if (args.length === 0) return "__empty__";
|
|
2765
|
+
if (args.length === 1) return keySerializer(args[0]);
|
|
2766
|
+
return keySerializer(args);
|
|
2767
|
+
});
|
|
2768
|
+
const memoizedFn = (...args) => {
|
|
2769
|
+
const key = generateKey(...args);
|
|
2770
|
+
if (cache.has(key)) {
|
|
2771
|
+
const cached = cache.get(key);
|
|
2772
|
+
if (cached && (!cached.expires || Date.now() < cached.expires)) {
|
|
2773
|
+
if (debug) console.log(`Memo cache hit for key: ${key}`);
|
|
2774
|
+
if (onHit) onHit(key, cached.value, args);
|
|
2775
|
+
if (stats_data) stats_data.hits++;
|
|
2776
|
+
return cached.value || cached;
|
|
2777
|
+
} else {
|
|
2778
|
+
cache.delete(key);
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
if (debug) console.log(`Memo cache miss for key: ${key}`);
|
|
2782
|
+
if (onMiss) onMiss(key, args);
|
|
2783
|
+
if (stats_data) stats_data.misses++;
|
|
2784
|
+
const result = fn(...args);
|
|
2785
|
+
const cacheEntry = ttl ? { value: result, expires: Date.now() + ttl } : result;
|
|
2786
|
+
cache.set(key, cacheEntry);
|
|
2787
|
+
return result;
|
|
2788
|
+
};
|
|
2789
|
+
memoizedFn.cache = cache;
|
|
2790
|
+
memoizedFn.clear = () => cache.clear();
|
|
2791
|
+
memoizedFn.delete = (key) => cache.delete(key);
|
|
2792
|
+
memoizedFn.has = (key) => cache.has(key);
|
|
2793
|
+
memoizedFn.size = () => cache.size;
|
|
2794
|
+
if (stats_data) {
|
|
2795
|
+
memoizedFn.stats = () => ({ ...stats_data });
|
|
2796
|
+
memoizedFn.resetStats = () => {
|
|
2797
|
+
stats_data.hits = 0;
|
|
2798
|
+
stats_data.misses = 0;
|
|
2799
|
+
stats_data.evictions = 0;
|
|
2800
|
+
};
|
|
2801
|
+
}
|
|
2802
|
+
memoizedFn.refresh = (...args) => {
|
|
2803
|
+
const key = generateKey(...args);
|
|
2804
|
+
cache.delete(key);
|
|
2805
|
+
return memoizedFn(...args);
|
|
2806
|
+
};
|
|
2807
|
+
return memoizedFn;
|
|
2808
|
+
}
|
|
2809
|
+
var LRUCache = class {
|
|
2810
|
+
constructor(maxSize = 100, options = {}) {
|
|
2811
|
+
this.maxSize = maxSize;
|
|
2812
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2813
|
+
this.onEvict = options.onEvict;
|
|
2814
|
+
}
|
|
2815
|
+
get(key) {
|
|
2816
|
+
if (this.cache.has(key)) {
|
|
2817
|
+
const value = this.cache.get(key);
|
|
2818
|
+
this.cache.delete(key);
|
|
2819
|
+
this.cache.set(key, value);
|
|
2820
|
+
return value;
|
|
2821
|
+
}
|
|
2822
|
+
return void 0;
|
|
2823
|
+
}
|
|
2824
|
+
set(key, value) {
|
|
2825
|
+
if (this.cache.has(key)) {
|
|
2826
|
+
this.cache.delete(key);
|
|
2827
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
2828
|
+
const firstKey = this.cache.keys().next().value;
|
|
2829
|
+
const evicted = this.cache.get(firstKey);
|
|
2830
|
+
this.cache.delete(firstKey);
|
|
2831
|
+
if (this.onEvict) {
|
|
2832
|
+
this.onEvict(firstKey, evicted);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
this.cache.set(key, value);
|
|
2836
|
+
}
|
|
2837
|
+
has(key) {
|
|
2838
|
+
return this.cache.has(key);
|
|
2839
|
+
}
|
|
2840
|
+
delete(key) {
|
|
2841
|
+
return this.cache.delete(key);
|
|
2842
|
+
}
|
|
2843
|
+
clear() {
|
|
2844
|
+
this.cache.clear();
|
|
2845
|
+
}
|
|
2846
|
+
get size() {
|
|
2847
|
+
return this.cache.size;
|
|
2848
|
+
}
|
|
2849
|
+
};
|
|
2850
|
+
var TTLCache = class {
|
|
2851
|
+
constructor(ttl, options = {}) {
|
|
2852
|
+
this.ttl = ttl;
|
|
2853
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2854
|
+
this.timers = /* @__PURE__ */ new Map();
|
|
2855
|
+
this.onEvict = options.onEvict;
|
|
2856
|
+
}
|
|
2857
|
+
get(key) {
|
|
2858
|
+
if (this.cache.has(key)) {
|
|
2859
|
+
const entry = this.cache.get(key);
|
|
2860
|
+
if (Date.now() < entry.expires) {
|
|
2861
|
+
return entry.value;
|
|
2862
|
+
} else {
|
|
2863
|
+
this.delete(key);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
return void 0;
|
|
2867
|
+
}
|
|
2868
|
+
set(key, value) {
|
|
2869
|
+
if (this.timers.has(key)) {
|
|
2870
|
+
clearTimeout(this.timers.get(key));
|
|
2871
|
+
}
|
|
2872
|
+
const expires = Date.now() + this.ttl;
|
|
2873
|
+
this.cache.set(key, { value, expires });
|
|
2874
|
+
const timer = setTimeout(() => {
|
|
2875
|
+
this.delete(key);
|
|
2876
|
+
}, this.ttl);
|
|
2877
|
+
this.timers.set(key, timer);
|
|
2878
|
+
}
|
|
2879
|
+
has(key) {
|
|
2880
|
+
if (this.cache.has(key)) {
|
|
2881
|
+
const entry = this.cache.get(key);
|
|
2882
|
+
return Date.now() < entry.expires;
|
|
2883
|
+
}
|
|
2884
|
+
return false;
|
|
2885
|
+
}
|
|
2886
|
+
delete(key) {
|
|
2887
|
+
const had = this.cache.has(key);
|
|
2888
|
+
if (had) {
|
|
2889
|
+
const entry = this.cache.get(key);
|
|
2890
|
+
this.cache.delete(key);
|
|
2891
|
+
if (this.timers.has(key)) {
|
|
2892
|
+
clearTimeout(this.timers.get(key));
|
|
2893
|
+
this.timers.delete(key);
|
|
2894
|
+
}
|
|
2895
|
+
if (this.onEvict) {
|
|
2896
|
+
this.onEvict(key, entry.value);
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
return had;
|
|
2900
|
+
}
|
|
2901
|
+
clear() {
|
|
2902
|
+
this.timers.forEach((timer) => clearTimeout(timer));
|
|
2903
|
+
this.timers.clear();
|
|
2904
|
+
this.cache.clear();
|
|
2905
|
+
}
|
|
2906
|
+
get size() {
|
|
2907
|
+
return this.cache.size;
|
|
2908
|
+
}
|
|
2909
|
+
};
|
|
2910
|
+
function withState(initialState = {}, options = {}) {
|
|
2911
|
+
const {
|
|
2912
|
+
// State options
|
|
2913
|
+
persistent = false,
|
|
2914
|
+
// Persist state across component unmounts
|
|
2915
|
+
storageKey = null,
|
|
2916
|
+
// Key for persistent storage
|
|
2917
|
+
storage = typeof window !== "undefined" && typeof window.localStorage !== "undefined" ? window.localStorage : {
|
|
2918
|
+
// Fallback storage for Node.js environments
|
|
2919
|
+
_data: /* @__PURE__ */ new Map(),
|
|
2920
|
+
setItem(key, value) {
|
|
2921
|
+
this._data.set(key, value);
|
|
2922
|
+
},
|
|
2923
|
+
getItem(key) {
|
|
2924
|
+
return this._data.get(key) || null;
|
|
2925
|
+
},
|
|
2926
|
+
removeItem(key) {
|
|
2927
|
+
this._data.delete(key);
|
|
2928
|
+
},
|
|
2929
|
+
clear() {
|
|
2930
|
+
this._data.clear();
|
|
2931
|
+
}
|
|
2932
|
+
},
|
|
2933
|
+
// Storage mechanism
|
|
2934
|
+
// State transformation
|
|
2935
|
+
stateTransform = null,
|
|
2936
|
+
// Transform state before injection
|
|
2937
|
+
propName = "state",
|
|
2938
|
+
// Prop name for state injection
|
|
1404
2939
|
actionsName = "actions",
|
|
1405
2940
|
// Prop name for action injection
|
|
1406
2941
|
// Reducers and actions
|
|
@@ -1514,6 +3049,8 @@ function withState(initialState = {}, options = {}) {
|
|
|
1514
3049
|
...props,
|
|
1515
3050
|
[propName]: transformedState,
|
|
1516
3051
|
[actionsName]: boundActions,
|
|
3052
|
+
setState: stateUtils.setState,
|
|
3053
|
+
getState: stateUtils.getState,
|
|
1517
3054
|
stateUtils
|
|
1518
3055
|
};
|
|
1519
3056
|
if (debug) {
|
|
@@ -1618,631 +3155,254 @@ function createStateContainer(initialState, options) {
|
|
|
1618
3155
|
unsubscribe(listener) {
|
|
1619
3156
|
return listeners.delete(listener);
|
|
1620
3157
|
},
|
|
1621
|
-
batch(batchFn) {
|
|
1622
|
-
const originalListeners = listeners;
|
|
1623
|
-
listeners = /* @__PURE__ */ new Set();
|
|
1624
|
-
try {
|
|
1625
|
-
batchFn();
|
|
1626
|
-
} finally {
|
|
1627
|
-
listeners = originalListeners;
|
|
1628
|
-
listeners.forEach((listener) => listener(state));
|
|
1629
|
-
}
|
|
1630
|
-
},
|
|
1631
|
-
destroy() {
|
|
1632
|
-
listeners.clear();
|
|
1633
|
-
if (persistent && storageKey) {
|
|
1634
|
-
try {
|
|
1635
|
-
storage.removeItem(storageKey);
|
|
1636
|
-
} catch (_error) {
|
|
1637
|
-
if (debug) console.warn("Failed to remove persisted state:", _error);
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
};
|
|
1642
|
-
return container;
|
|
1643
|
-
}
|
|
1644
|
-
function createBoundActions(actions, stateContainer, options) {
|
|
1645
|
-
const { props, context: context2, supportAsync, debug } = options;
|
|
1646
|
-
const boundActions = {};
|
|
1647
|
-
Object.entries(actions).forEach(([actionName, actionCreator]) => {
|
|
1648
|
-
boundActions[actionName] = (...args) => {
|
|
1649
|
-
try {
|
|
1650
|
-
const result = actionCreator(
|
|
1651
|
-
stateContainer.getState(),
|
|
1652
|
-
stateContainer.setState.bind(stateContainer),
|
|
1653
|
-
{ props, context: context2, args }
|
|
1654
|
-
);
|
|
1655
|
-
if (supportAsync && result && typeof result.then === "function") {
|
|
1656
|
-
return result.catch((_error) => {
|
|
1657
|
-
if (debug) console.error(`Async action ${actionName} failed:`, _error);
|
|
1658
|
-
throw _error;
|
|
1659
|
-
});
|
|
1660
|
-
}
|
|
1661
|
-
return result;
|
|
1662
|
-
} catch (_error) {
|
|
1663
|
-
if (debug) console.error(`Action ${actionName} failed:`, _error);
|
|
1664
|
-
throw _error;
|
|
1665
|
-
}
|
|
1666
|
-
};
|
|
1667
|
-
});
|
|
1668
|
-
return boundActions;
|
|
1669
|
-
}
|
|
1670
|
-
var withStateUtils = {
|
|
1671
|
-
/**
|
|
1672
|
-
* Simple local state
|
|
1673
|
-
*/
|
|
1674
|
-
local: (initialState) => withState(initialState),
|
|
1675
|
-
/**
|
|
1676
|
-
* Persistent state with localStorage
|
|
1677
|
-
*/
|
|
1678
|
-
persistent: (initialState, key) => withState(initialState, {
|
|
1679
|
-
persistent: true,
|
|
1680
|
-
storageKey: key
|
|
1681
|
-
}),
|
|
1682
|
-
/**
|
|
1683
|
-
* State with reducer pattern
|
|
1684
|
-
*/
|
|
1685
|
-
reducer: (initialState, reducer, actions = {}) => withState(initialState, {
|
|
1686
|
-
reducer,
|
|
1687
|
-
actions
|
|
1688
|
-
}),
|
|
1689
|
-
/**
|
|
1690
|
-
* Async state management
|
|
1691
|
-
*/
|
|
1692
|
-
async: (initialState, asyncActions = {}) => withState(initialState, {
|
|
1693
|
-
supportAsync: true,
|
|
1694
|
-
actions: asyncActions
|
|
1695
|
-
}),
|
|
1696
|
-
/**
|
|
1697
|
-
* State with validation
|
|
1698
|
-
*/
|
|
1699
|
-
validated: (initialState, validator) => withState(initialState, {
|
|
1700
|
-
validator,
|
|
1701
|
-
debug: true
|
|
1702
|
-
}),
|
|
1703
|
-
/**
|
|
1704
|
-
* Shared state across components
|
|
1705
|
-
*/
|
|
1706
|
-
shared: (initialState, sharedKey) => {
|
|
1707
|
-
const sharedStates = withStateUtils._shared || (withStateUtils._shared = /* @__PURE__ */ new Map());
|
|
1708
|
-
if (!sharedStates.has(sharedKey)) {
|
|
1709
|
-
sharedStates.set(sharedKey, createStateContainer(initialState, {}));
|
|
1710
|
-
}
|
|
1711
|
-
return (WrappedComponent) => {
|
|
1712
|
-
const sharedContainer = sharedStates.get(sharedKey);
|
|
1713
|
-
function SharedStateComponent(props, globalState, context2) {
|
|
1714
|
-
const currentState = sharedContainer.getState();
|
|
1715
|
-
const enhancedProps = {
|
|
1716
|
-
...props,
|
|
1717
|
-
state: currentState,
|
|
1718
|
-
setState: sharedContainer.setState.bind(sharedContainer),
|
|
1719
|
-
subscribe: sharedContainer.subscribe.bind(sharedContainer)
|
|
1720
|
-
};
|
|
1721
|
-
return typeof WrappedComponent === "function" ? WrappedComponent(enhancedProps, globalState, context2) : WrappedComponent;
|
|
1722
|
-
}
|
|
1723
|
-
SharedStateComponent.displayName = `withSharedState(${getComponentName(WrappedComponent)})`;
|
|
1724
|
-
return SharedStateComponent;
|
|
1725
|
-
};
|
|
1726
|
-
},
|
|
1727
|
-
/**
|
|
1728
|
-
* State with form utilities
|
|
1729
|
-
*/
|
|
1730
|
-
form: (initialFormState) => withState(initialFormState, {
|
|
1731
|
-
actions: {
|
|
1732
|
-
updateField: (state, setState, { args: [field, value] }) => {
|
|
1733
|
-
setState({ [field]: value });
|
|
1734
|
-
},
|
|
1735
|
-
updateMultiple: (state, setState, { args: [updates] }) => {
|
|
1736
|
-
setState(updates);
|
|
1737
|
-
},
|
|
1738
|
-
resetForm: (state, setState) => {
|
|
1739
|
-
setState(initialFormState);
|
|
1740
|
-
},
|
|
1741
|
-
validateForm: (state, setState, { args: [validator] }) => {
|
|
1742
|
-
const errors = validator(state);
|
|
1743
|
-
setState({ _errors: errors });
|
|
1744
|
-
return Object.keys(errors).length === 0;
|
|
3158
|
+
batch(batchFn) {
|
|
3159
|
+
const originalListeners = listeners;
|
|
3160
|
+
listeners = /* @__PURE__ */ new Set();
|
|
3161
|
+
try {
|
|
3162
|
+
batchFn();
|
|
3163
|
+
} finally {
|
|
3164
|
+
listeners = originalListeners;
|
|
3165
|
+
listeners.forEach((listener) => listener(state));
|
|
1745
3166
|
}
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
*/
|
|
1751
|
-
withLoading: async (initialState) => withState({
|
|
1752
|
-
...initialState,
|
|
1753
|
-
_loading: false,
|
|
1754
|
-
_error: null
|
|
1755
|
-
}, {
|
|
1756
|
-
supportAsync: true,
|
|
1757
|
-
actions: {
|
|
1758
|
-
setLoading: (state, setState, { args: [loading] }) => {
|
|
1759
|
-
setState({ _loading: loading });
|
|
1760
|
-
},
|
|
1761
|
-
setError: (state, setState, { args: [_error] }) => {
|
|
1762
|
-
setState({ _error, _loading: false });
|
|
1763
|
-
},
|
|
1764
|
-
clearError: (state, setState) => {
|
|
1765
|
-
setState({ _error: null });
|
|
1766
|
-
},
|
|
1767
|
-
asyncAction: async (state, setState, { args: [asyncFn] }) => {
|
|
1768
|
-
setState({ _loading: true, _error: null });
|
|
3167
|
+
},
|
|
3168
|
+
destroy() {
|
|
3169
|
+
listeners.clear();
|
|
3170
|
+
if (persistent && storageKey) {
|
|
1769
3171
|
try {
|
|
1770
|
-
|
|
1771
|
-
setState({ _loading: false });
|
|
1772
|
-
return result;
|
|
3172
|
+
storage.removeItem(storageKey);
|
|
1773
3173
|
} catch (_error) {
|
|
1774
|
-
|
|
1775
|
-
throw _error;
|
|
3174
|
+
if (debug) console.warn("Failed to remove persisted state:", _error);
|
|
1776
3175
|
}
|
|
1777
3176
|
}
|
|
1778
3177
|
}
|
|
1779
|
-
}),
|
|
1780
|
-
/**
|
|
1781
|
-
* State with undo/redo functionality
|
|
1782
|
-
*/
|
|
1783
|
-
withHistory: (initialState, maxHistory = 10) => {
|
|
1784
|
-
const historyState = {
|
|
1785
|
-
present: initialState,
|
|
1786
|
-
past: [],
|
|
1787
|
-
future: []
|
|
1788
|
-
};
|
|
1789
|
-
return withState(historyState, {
|
|
1790
|
-
actions: {
|
|
1791
|
-
undo: (state, setState) => {
|
|
1792
|
-
if (state.past.length === 0) return;
|
|
1793
|
-
const previous = state.past[state.past.length - 1];
|
|
1794
|
-
const newPast = state.past.slice(0, state.past.length - 1);
|
|
1795
|
-
setState({
|
|
1796
|
-
past: newPast,
|
|
1797
|
-
present: previous,
|
|
1798
|
-
future: [state.present, ...state.future]
|
|
1799
|
-
});
|
|
1800
|
-
},
|
|
1801
|
-
redo: (state, setState) => {
|
|
1802
|
-
if (state.future.length === 0) return;
|
|
1803
|
-
const next = state.future[0];
|
|
1804
|
-
const newFuture = state.future.slice(1);
|
|
1805
|
-
setState({
|
|
1806
|
-
past: [...state.past, state.present],
|
|
1807
|
-
present: next,
|
|
1808
|
-
future: newFuture
|
|
1809
|
-
});
|
|
1810
|
-
},
|
|
1811
|
-
updatePresent: (state, setState, { args: [newPresent] }) => {
|
|
1812
|
-
setState({
|
|
1813
|
-
past: [...state.past, state.present].slice(-maxHistory),
|
|
1814
|
-
present: newPresent,
|
|
1815
|
-
future: []
|
|
1816
|
-
});
|
|
1817
|
-
},
|
|
1818
|
-
canUndo: (state) => state.past.length > 0,
|
|
1819
|
-
canRedo: (state) => state.future.length > 0
|
|
1820
|
-
}
|
|
1821
|
-
});
|
|
1822
|
-
},
|
|
1823
|
-
/**
|
|
1824
|
-
* Computed state properties
|
|
1825
|
-
*/
|
|
1826
|
-
computed: (initialState, computedProps) => withState(initialState, {
|
|
1827
|
-
stateTransform: (state) => {
|
|
1828
|
-
const computed = {};
|
|
1829
|
-
Object.entries(computedProps).forEach(([key, computeFn]) => {
|
|
1830
|
-
computed[key] = computeFn(state);
|
|
1831
|
-
});
|
|
1832
|
-
return { ...state, ...computed };
|
|
1833
|
-
},
|
|
1834
|
-
memoizeState: true
|
|
1835
|
-
})
|
|
1836
|
-
};
|
|
1837
|
-
function createStateManager(config) {
|
|
1838
|
-
const {
|
|
1839
|
-
initialState = {},
|
|
1840
|
-
reducers = {},
|
|
1841
|
-
actions = {},
|
|
1842
|
-
middleware = [],
|
|
1843
|
-
plugins = []
|
|
1844
|
-
} = config;
|
|
1845
|
-
const rootReducer = (state, action) => {
|
|
1846
|
-
let nextState = state;
|
|
1847
|
-
Object.entries(reducers).forEach(([key, reducer]) => {
|
|
1848
|
-
nextState = {
|
|
1849
|
-
...nextState,
|
|
1850
|
-
[key]: reducer(nextState[key], action)
|
|
1851
|
-
};
|
|
1852
|
-
});
|
|
1853
|
-
return nextState;
|
|
1854
3178
|
};
|
|
1855
|
-
|
|
1856
|
-
(acc, plugin) => plugin(acc),
|
|
1857
|
-
{ initialState, reducer: rootReducer, actions, middleware }
|
|
1858
|
-
);
|
|
1859
|
-
return withState(enhancedConfig.initialState, {
|
|
1860
|
-
reducer: enhancedConfig.reducer,
|
|
1861
|
-
actions: enhancedConfig.actions,
|
|
1862
|
-
middleware: enhancedConfig.middleware
|
|
1863
|
-
});
|
|
1864
|
-
}
|
|
1865
|
-
function getComponentName(component) {
|
|
1866
|
-
if (!component) return "Component";
|
|
1867
|
-
return component.displayName || component.name || component.constructor?.name || "Component";
|
|
3179
|
+
return container;
|
|
1868
3180
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
};
|
|
1897
|
-
var ComponentValidationError = class extends CoherentError {
|
|
1898
|
-
constructor(message, component, suggestions = []) {
|
|
1899
|
-
super(message, {
|
|
1900
|
-
type: "validation",
|
|
1901
|
-
component,
|
|
1902
|
-
suggestions: [
|
|
1903
|
-
"Check component structure and syntax",
|
|
1904
|
-
"Ensure all required properties are present",
|
|
1905
|
-
"Validate prop types and values",
|
|
1906
|
-
...suggestions
|
|
1907
|
-
]
|
|
1908
|
-
});
|
|
1909
|
-
this.name = "ComponentValidationError";
|
|
1910
|
-
}
|
|
1911
|
-
};
|
|
1912
|
-
var RenderingError = class extends CoherentError {
|
|
1913
|
-
constructor(message, component, context2, suggestions = []) {
|
|
1914
|
-
super(message, {
|
|
1915
|
-
type: "rendering",
|
|
1916
|
-
component,
|
|
1917
|
-
context: context2,
|
|
1918
|
-
suggestions: [
|
|
1919
|
-
"Check for circular references",
|
|
1920
|
-
"Validate component depth",
|
|
1921
|
-
"Ensure all functions return valid components",
|
|
1922
|
-
...suggestions
|
|
1923
|
-
]
|
|
1924
|
-
});
|
|
1925
|
-
this.name = "RenderingError";
|
|
1926
|
-
}
|
|
1927
|
-
};
|
|
1928
|
-
var PerformanceError = class extends CoherentError {
|
|
1929
|
-
constructor(message, metrics, suggestions = []) {
|
|
1930
|
-
super(message, {
|
|
1931
|
-
type: "performance",
|
|
1932
|
-
context: metrics,
|
|
1933
|
-
suggestions: [
|
|
1934
|
-
"Consider component memoization",
|
|
1935
|
-
"Reduce component complexity",
|
|
1936
|
-
"Enable caching",
|
|
1937
|
-
...suggestions
|
|
1938
|
-
]
|
|
1939
|
-
});
|
|
1940
|
-
this.name = "PerformanceError";
|
|
1941
|
-
}
|
|
1942
|
-
};
|
|
1943
|
-
var StateError = class extends CoherentError {
|
|
1944
|
-
constructor(message, state, suggestions = []) {
|
|
1945
|
-
super(message, {
|
|
1946
|
-
type: "state",
|
|
1947
|
-
context: state,
|
|
1948
|
-
suggestions: [
|
|
1949
|
-
"Check state mutations",
|
|
1950
|
-
"Ensure proper state initialization",
|
|
1951
|
-
"Validate state transitions",
|
|
1952
|
-
...suggestions
|
|
1953
|
-
]
|
|
1954
|
-
});
|
|
1955
|
-
this.name = "StateError";
|
|
1956
|
-
}
|
|
1957
|
-
};
|
|
1958
|
-
var ErrorHandler = class {
|
|
1959
|
-
constructor(options = {}) {
|
|
1960
|
-
this.options = {
|
|
1961
|
-
enableStackTrace: options.enableStackTrace !== false,
|
|
1962
|
-
enableSuggestions: options.enableSuggestions !== false,
|
|
1963
|
-
enableLogging: options.enableLogging !== false,
|
|
1964
|
-
logLevel: options.logLevel || "_error",
|
|
1965
|
-
maxErrorHistory: options.maxErrorHistory || 100,
|
|
1966
|
-
...options
|
|
1967
|
-
};
|
|
1968
|
-
this.errorHistory = [];
|
|
1969
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
1970
|
-
this.suppressedErrors = /* @__PURE__ */ new Set();
|
|
1971
|
-
}
|
|
1972
|
-
/**
|
|
1973
|
-
* Handle and report errors with detailed context
|
|
1974
|
-
*/
|
|
1975
|
-
handle(_error, context2 = {}) {
|
|
1976
|
-
const enhancedError = this.enhanceError(_error, context2);
|
|
1977
|
-
this.addToHistory(enhancedError);
|
|
1978
|
-
if (this.options.enableLogging) {
|
|
1979
|
-
this.logError(enhancedError);
|
|
1980
|
-
}
|
|
1981
|
-
return enhancedError;
|
|
1982
|
-
}
|
|
3181
|
+
function createBoundActions(actions, stateContainer, options) {
|
|
3182
|
+
const { props, context: context2, supportAsync, debug } = options;
|
|
3183
|
+
const boundActions = {};
|
|
3184
|
+
Object.entries(actions).forEach(([actionName, actionCreator]) => {
|
|
3185
|
+
boundActions[actionName] = (...args) => {
|
|
3186
|
+
try {
|
|
3187
|
+
const result = actionCreator(
|
|
3188
|
+
stateContainer.getState(),
|
|
3189
|
+
stateContainer.setState.bind(stateContainer),
|
|
3190
|
+
{ props, context: context2, args }
|
|
3191
|
+
);
|
|
3192
|
+
if (supportAsync && result && typeof result.then === "function") {
|
|
3193
|
+
return result.catch((_error) => {
|
|
3194
|
+
if (debug) console.error(`Async action ${actionName} failed:`, _error);
|
|
3195
|
+
throw _error;
|
|
3196
|
+
});
|
|
3197
|
+
}
|
|
3198
|
+
return result;
|
|
3199
|
+
} catch (_error) {
|
|
3200
|
+
if (debug) console.error(`Action ${actionName} failed:`, _error);
|
|
3201
|
+
throw _error;
|
|
3202
|
+
}
|
|
3203
|
+
};
|
|
3204
|
+
});
|
|
3205
|
+
return boundActions;
|
|
3206
|
+
}
|
|
3207
|
+
var withStateUtils = {
|
|
1983
3208
|
/**
|
|
1984
|
-
*
|
|
3209
|
+
* Simple local state
|
|
1985
3210
|
*/
|
|
1986
|
-
|
|
1987
|
-
if (_error instanceof CoherentError) {
|
|
1988
|
-
return _error;
|
|
1989
|
-
}
|
|
1990
|
-
const errorType = this.classifyError(_error, context2);
|
|
1991
|
-
switch (errorType) {
|
|
1992
|
-
case "validation":
|
|
1993
|
-
return new ComponentValidationError(
|
|
1994
|
-
_error.message,
|
|
1995
|
-
context2.component,
|
|
1996
|
-
this.generateSuggestions(_error, context2)
|
|
1997
|
-
);
|
|
1998
|
-
case "rendering":
|
|
1999
|
-
return new RenderingError(
|
|
2000
|
-
_error.message,
|
|
2001
|
-
context2.component,
|
|
2002
|
-
context2.renderContext,
|
|
2003
|
-
this.generateSuggestions(_error, context2)
|
|
2004
|
-
);
|
|
2005
|
-
case "performance":
|
|
2006
|
-
return new PerformanceError(
|
|
2007
|
-
_error.message,
|
|
2008
|
-
context2.metrics,
|
|
2009
|
-
this.generateSuggestions(_error, context2)
|
|
2010
|
-
);
|
|
2011
|
-
case "state":
|
|
2012
|
-
return new StateError(
|
|
2013
|
-
_error.message,
|
|
2014
|
-
context2.state,
|
|
2015
|
-
this.generateSuggestions(_error, context2)
|
|
2016
|
-
);
|
|
2017
|
-
default:
|
|
2018
|
-
return new CoherentError(_error.message, {
|
|
2019
|
-
type: errorType,
|
|
2020
|
-
component: context2.component,
|
|
2021
|
-
context: context2.context,
|
|
2022
|
-
suggestions: this.generateSuggestions(_error, context2)
|
|
2023
|
-
});
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
3211
|
+
local: (initialState) => withState(initialState),
|
|
2026
3212
|
/**
|
|
2027
|
-
*
|
|
3213
|
+
* Persistent state with localStorage
|
|
2028
3214
|
*/
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
}
|
|
2034
|
-
if (message.includes("render") || message.includes("circular") || message.includes("depth") || message.includes("cannot render")) {
|
|
2035
|
-
return "rendering";
|
|
2036
|
-
}
|
|
2037
|
-
if (message.includes("slow") || message.includes("memory") || message.includes("performance") || message.includes("timeout")) {
|
|
2038
|
-
return "performance";
|
|
2039
|
-
}
|
|
2040
|
-
if (message.includes("state") || message.includes("mutation") || message.includes("store") || context2.state) {
|
|
2041
|
-
return "state";
|
|
2042
|
-
}
|
|
2043
|
-
if (context2.component) return "validation";
|
|
2044
|
-
if (context2.renderContext) return "rendering";
|
|
2045
|
-
if (context2.metrics) return "performance";
|
|
2046
|
-
return "generic";
|
|
2047
|
-
}
|
|
3215
|
+
persistent: (initialState, key) => withState(initialState, {
|
|
3216
|
+
persistent: true,
|
|
3217
|
+
storageKey: key
|
|
3218
|
+
}),
|
|
2048
3219
|
/**
|
|
2049
|
-
*
|
|
3220
|
+
* State with reducer pattern
|
|
2050
3221
|
*/
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
{
|
|
2056
|
-
pattern: /cannot render|render.*failed/,
|
|
2057
|
-
suggestions: [
|
|
2058
|
-
"Check if component returns a valid object structure",
|
|
2059
|
-
"Ensure all properties are properly defined",
|
|
2060
|
-
"Look for undefined variables or null references"
|
|
2061
|
-
]
|
|
2062
|
-
},
|
|
2063
|
-
{
|
|
2064
|
-
pattern: /circular.*reference/,
|
|
2065
|
-
suggestions: [
|
|
2066
|
-
"Remove circular references between components",
|
|
2067
|
-
"Use lazy loading or memoization to break cycles",
|
|
2068
|
-
"Check for self-referencing components"
|
|
2069
|
-
]
|
|
2070
|
-
},
|
|
2071
|
-
{
|
|
2072
|
-
pattern: /maximum.*depth/,
|
|
2073
|
-
suggestions: [
|
|
2074
|
-
"Reduce component nesting depth",
|
|
2075
|
-
"Break complex components into smaller parts",
|
|
2076
|
-
"Check for infinite recursion in component functions"
|
|
2077
|
-
]
|
|
2078
|
-
},
|
|
2079
|
-
{
|
|
2080
|
-
pattern: /invalid.*component/,
|
|
2081
|
-
suggestions: [
|
|
2082
|
-
"Ensure component follows the expected object structure",
|
|
2083
|
-
"Check property names and values for typos",
|
|
2084
|
-
"Verify component is not null or undefined"
|
|
2085
|
-
]
|
|
2086
|
-
},
|
|
2087
|
-
{
|
|
2088
|
-
pattern: /performance|slow|timeout/,
|
|
2089
|
-
suggestions: [
|
|
2090
|
-
"Enable component caching",
|
|
2091
|
-
"Use memoization for expensive operations",
|
|
2092
|
-
"Reduce component complexity",
|
|
2093
|
-
"Consider lazy loading for large components"
|
|
2094
|
-
]
|
|
2095
|
-
}
|
|
2096
|
-
];
|
|
2097
|
-
patterns.forEach(({ pattern, suggestions: patternSuggestions }) => {
|
|
2098
|
-
if (pattern.test(message)) {
|
|
2099
|
-
suggestions.push(...patternSuggestions);
|
|
2100
|
-
}
|
|
2101
|
-
});
|
|
2102
|
-
if (context2.component) {
|
|
2103
|
-
const componentType = typeof context2.component;
|
|
2104
|
-
if (componentType === "function") {
|
|
2105
|
-
suggestions.push("Check function component return value");
|
|
2106
|
-
} else if (componentType === "object" && context2.component === null) {
|
|
2107
|
-
suggestions.push("Component is null - ensure proper initialization");
|
|
2108
|
-
} else if (Array.isArray(context2.component)) {
|
|
2109
|
-
suggestions.push("Arrays should contain valid component objects");
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
if (suggestions.length === 0) {
|
|
2113
|
-
suggestions.push(
|
|
2114
|
-
"Enable development tools for more detailed debugging",
|
|
2115
|
-
"Check browser console for additional _error details",
|
|
2116
|
-
"Use component validation tools to identify issues"
|
|
2117
|
-
);
|
|
2118
|
-
}
|
|
2119
|
-
return [...new Set(suggestions)];
|
|
2120
|
-
}
|
|
3222
|
+
reducer: (initialState, reducer, actions = {}) => withState(initialState, {
|
|
3223
|
+
reducer,
|
|
3224
|
+
actions
|
|
3225
|
+
}),
|
|
2121
3226
|
/**
|
|
2122
|
-
*
|
|
3227
|
+
* Async state management
|
|
2123
3228
|
*/
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
..._error.toJSON(),
|
|
2129
|
-
count: this.errorCounts.get(errorKey),
|
|
2130
|
-
firstSeen: this.errorHistory.find((e) => e.key === errorKey)?.firstSeen || _error.timestamp,
|
|
2131
|
-
key: errorKey
|
|
2132
|
-
};
|
|
2133
|
-
this.errorHistory = this.errorHistory.filter((e) => e.key !== errorKey);
|
|
2134
|
-
this.errorHistory.unshift(historyEntry);
|
|
2135
|
-
if (this.errorHistory.length > this.options.maxErrorHistory) {
|
|
2136
|
-
this.errorHistory = this.errorHistory.slice(0, this.options.maxErrorHistory);
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
3229
|
+
async: (initialState, asyncActions = {}) => withState(initialState, {
|
|
3230
|
+
supportAsync: true,
|
|
3231
|
+
actions: asyncActions
|
|
3232
|
+
}),
|
|
2139
3233
|
/**
|
|
2140
|
-
*
|
|
3234
|
+
* State with validation
|
|
2141
3235
|
*/
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
const isRepeated = this.errorCounts.get(`${_error.name}:${_error.message}`) > 1;
|
|
2147
|
-
const errorGroup = `\u{1F6A8} ${_error.name}${isRepeated ? ` (\xD7${this.errorCounts.get(`${_error.name}:${_error.message}`)})` : ""}`;
|
|
2148
|
-
console.group(errorGroup);
|
|
2149
|
-
console.error(`\u274C ${_error.message}`);
|
|
2150
|
-
if (_error.component) {
|
|
2151
|
-
console.log("\u{1F50D} Component:", this.formatComponent(_error.component));
|
|
2152
|
-
}
|
|
2153
|
-
if (_error.context) {
|
|
2154
|
-
console.log("\u{1F4CB} Context:", _error.context);
|
|
2155
|
-
}
|
|
2156
|
-
if (this.options.enableSuggestions && _error.suggestions.length > 0) {
|
|
2157
|
-
console.group("\u{1F4A1} Suggestions:");
|
|
2158
|
-
_error.suggestions.forEach((suggestion, index) => {
|
|
2159
|
-
console.log(`${index + 1}. ${suggestion}`);
|
|
2160
|
-
});
|
|
2161
|
-
console.groupEnd();
|
|
2162
|
-
}
|
|
2163
|
-
if (this.options.enableStackTrace && _error.stack) {
|
|
2164
|
-
console.log("\u{1F4DA} Stack trace:", _error.stack);
|
|
2165
|
-
}
|
|
2166
|
-
console.groupEnd();
|
|
2167
|
-
}
|
|
3236
|
+
validated: (initialState, validator) => withState(initialState, {
|
|
3237
|
+
validator,
|
|
3238
|
+
debug: true
|
|
3239
|
+
}),
|
|
2168
3240
|
/**
|
|
2169
|
-
*
|
|
3241
|
+
* Shared state across components
|
|
2170
3242
|
*/
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
if (typeof component === "function") {
|
|
2176
|
-
return `[Function: ${component.name || "anonymous"}]`;
|
|
2177
|
-
}
|
|
2178
|
-
if (Array.isArray(component)) {
|
|
2179
|
-
return component.slice(0, 3).map(
|
|
2180
|
-
(item) => this.formatComponent(item, maxDepth, currentDepth + 1)
|
|
2181
|
-
);
|
|
3243
|
+
shared: (initialState, sharedKey) => {
|
|
3244
|
+
const sharedStates = withStateUtils._shared || (withStateUtils._shared = /* @__PURE__ */ new Map());
|
|
3245
|
+
if (!sharedStates.has(sharedKey)) {
|
|
3246
|
+
sharedStates.set(sharedKey, createStateContainer(initialState, {}));
|
|
2182
3247
|
}
|
|
2183
|
-
|
|
2184
|
-
const
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
formatted["..."] = `(${Object.keys(component).length - 5} more)`;
|
|
3248
|
+
return (WrappedComponent) => {
|
|
3249
|
+
const sharedContainer = sharedStates.get(sharedKey);
|
|
3250
|
+
function SharedStateComponent(props, globalState, context2) {
|
|
3251
|
+
const currentState = sharedContainer.getState();
|
|
3252
|
+
const enhancedProps = {
|
|
3253
|
+
...props,
|
|
3254
|
+
state: currentState,
|
|
3255
|
+
setState: sharedContainer.setState.bind(sharedContainer),
|
|
3256
|
+
subscribe: sharedContainer.subscribe.bind(sharedContainer)
|
|
3257
|
+
};
|
|
3258
|
+
return typeof WrappedComponent === "function" ? WrappedComponent(enhancedProps, globalState, context2) : WrappedComponent;
|
|
2195
3259
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
}
|
|
3260
|
+
SharedStateComponent.displayName = `withSharedState(${getComponentName(WrappedComponent)})`;
|
|
3261
|
+
return SharedStateComponent;
|
|
3262
|
+
};
|
|
3263
|
+
},
|
|
2200
3264
|
/**
|
|
2201
|
-
*
|
|
3265
|
+
* State with form utilities
|
|
2202
3266
|
*/
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
3267
|
+
form: (initialFormState) => withState(initialFormState, {
|
|
3268
|
+
actions: {
|
|
3269
|
+
updateField: (state, setState, { args: [field, value] }) => {
|
|
3270
|
+
setState({ [field]: value });
|
|
3271
|
+
},
|
|
3272
|
+
updateMultiple: (state, setState, { args: [updates] }) => {
|
|
3273
|
+
setState(updates);
|
|
3274
|
+
},
|
|
3275
|
+
resetForm: (state, setState) => {
|
|
3276
|
+
setState(initialFormState);
|
|
3277
|
+
},
|
|
3278
|
+
validateForm: (state, setState, { args: [validator] }) => {
|
|
3279
|
+
const errors = validator(state);
|
|
3280
|
+
setState({ _errors: errors });
|
|
3281
|
+
return Object.keys(errors).length === 0;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
}),
|
|
2206
3285
|
/**
|
|
2207
|
-
*
|
|
3286
|
+
* State with loading/_error handling
|
|
2208
3287
|
*/
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
3288
|
+
withLoading: async (initialState) => withState({
|
|
3289
|
+
...initialState,
|
|
3290
|
+
_loading: false,
|
|
3291
|
+
_error: null
|
|
3292
|
+
}, {
|
|
3293
|
+
supportAsync: true,
|
|
3294
|
+
actions: {
|
|
3295
|
+
setLoading: (state, setState, { args: [loading] }) => {
|
|
3296
|
+
setState({ _loading: loading });
|
|
3297
|
+
},
|
|
3298
|
+
setError: (state, setState, { args: [_error] }) => {
|
|
3299
|
+
setState({ _error, _loading: false });
|
|
3300
|
+
},
|
|
3301
|
+
clearError: (state, setState) => {
|
|
3302
|
+
setState({ _error: null });
|
|
3303
|
+
},
|
|
3304
|
+
asyncAction: async (state, setState, { args: [asyncFn] }) => {
|
|
3305
|
+
setState({ _loading: true, _error: null });
|
|
3306
|
+
try {
|
|
3307
|
+
const result = await asyncFn(state);
|
|
3308
|
+
setState({ _loading: false });
|
|
3309
|
+
return result;
|
|
3310
|
+
} catch (_error) {
|
|
3311
|
+
setState({ _loading: false, _error });
|
|
3312
|
+
throw _error;
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
}),
|
|
2213
3317
|
/**
|
|
2214
|
-
*
|
|
3318
|
+
* State with undo/redo functionality
|
|
2215
3319
|
*/
|
|
2216
|
-
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
const hour = new Date(_error.timestamp).toISOString().slice(0, 13);
|
|
2222
|
-
errorsByTime[hour] = (errorsByTime[hour] || 0) + _error.count;
|
|
2223
|
-
});
|
|
2224
|
-
return {
|
|
2225
|
-
totalErrors: this.errorHistory.reduce((sum, e) => sum + e.count, 0),
|
|
2226
|
-
uniqueErrors: this.errorHistory.length,
|
|
2227
|
-
errorsByType,
|
|
2228
|
-
errorsByTime,
|
|
2229
|
-
mostCommonErrors: this.getMostCommonErrors(5),
|
|
2230
|
-
recentErrors: this.errorHistory.slice(0, 10)
|
|
3320
|
+
withHistory: (initialState, maxHistory = 10) => {
|
|
3321
|
+
const historyState = {
|
|
3322
|
+
present: initialState,
|
|
3323
|
+
past: [],
|
|
3324
|
+
future: []
|
|
2231
3325
|
};
|
|
2232
|
-
|
|
3326
|
+
return withState(historyState, {
|
|
3327
|
+
actions: {
|
|
3328
|
+
undo: (state, setState) => {
|
|
3329
|
+
if (state.past.length === 0) return;
|
|
3330
|
+
const previous = state.past[state.past.length - 1];
|
|
3331
|
+
const newPast = state.past.slice(0, state.past.length - 1);
|
|
3332
|
+
setState({
|
|
3333
|
+
past: newPast,
|
|
3334
|
+
present: previous,
|
|
3335
|
+
future: [state.present, ...state.future]
|
|
3336
|
+
});
|
|
3337
|
+
},
|
|
3338
|
+
redo: (state, setState) => {
|
|
3339
|
+
if (state.future.length === 0) return;
|
|
3340
|
+
const next = state.future[0];
|
|
3341
|
+
const newFuture = state.future.slice(1);
|
|
3342
|
+
setState({
|
|
3343
|
+
past: [...state.past, state.present],
|
|
3344
|
+
present: next,
|
|
3345
|
+
future: newFuture
|
|
3346
|
+
});
|
|
3347
|
+
},
|
|
3348
|
+
updatePresent: (state, setState, { args: [newPresent] }) => {
|
|
3349
|
+
setState({
|
|
3350
|
+
past: [...state.past, state.present].slice(-maxHistory),
|
|
3351
|
+
present: newPresent,
|
|
3352
|
+
future: []
|
|
3353
|
+
});
|
|
3354
|
+
},
|
|
3355
|
+
canUndo: (state) => state.past.length > 0,
|
|
3356
|
+
canRedo: (state) => state.future.length > 0
|
|
3357
|
+
}
|
|
3358
|
+
});
|
|
3359
|
+
},
|
|
2233
3360
|
/**
|
|
2234
|
-
*
|
|
3361
|
+
* Computed state properties
|
|
2235
3362
|
*/
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
3363
|
+
computed: (initialState, computedProps) => withState(initialState, {
|
|
3364
|
+
stateTransform: (state) => {
|
|
3365
|
+
const computed = {};
|
|
3366
|
+
Object.entries(computedProps).forEach(([key, computeFn]) => {
|
|
3367
|
+
computed[key] = computeFn(state);
|
|
3368
|
+
});
|
|
3369
|
+
return { ...state, ...computed };
|
|
3370
|
+
},
|
|
3371
|
+
memoizeState: true
|
|
3372
|
+
})
|
|
2244
3373
|
};
|
|
2245
|
-
|
|
3374
|
+
function createStateManager(config) {
|
|
3375
|
+
const {
|
|
3376
|
+
initialState = {},
|
|
3377
|
+
reducers = {},
|
|
3378
|
+
actions = {},
|
|
3379
|
+
middleware = [],
|
|
3380
|
+
plugins = []
|
|
3381
|
+
} = config;
|
|
3382
|
+
const rootReducer = (state, action) => {
|
|
3383
|
+
let nextState = state;
|
|
3384
|
+
Object.entries(reducers).forEach(([key, reducer]) => {
|
|
3385
|
+
nextState = {
|
|
3386
|
+
...nextState,
|
|
3387
|
+
[key]: reducer(nextState[key], action)
|
|
3388
|
+
};
|
|
3389
|
+
});
|
|
3390
|
+
return nextState;
|
|
3391
|
+
};
|
|
3392
|
+
const enhancedConfig = plugins.reduce(
|
|
3393
|
+
(acc, plugin) => plugin(acc),
|
|
3394
|
+
{ initialState, reducer: rootReducer, actions, middleware }
|
|
3395
|
+
);
|
|
3396
|
+
return withState(enhancedConfig.initialState, {
|
|
3397
|
+
reducer: enhancedConfig.reducer,
|
|
3398
|
+
actions: enhancedConfig.actions,
|
|
3399
|
+
middleware: enhancedConfig.middleware
|
|
3400
|
+
});
|
|
3401
|
+
}
|
|
3402
|
+
function getComponentName(component) {
|
|
3403
|
+
if (!component) return "Component";
|
|
3404
|
+
return component.displayName || component.name || component.constructor?.name || "Component";
|
|
3405
|
+
}
|
|
2246
3406
|
|
|
2247
3407
|
// src/components/lifecycle.js
|
|
2248
3408
|
var LIFECYCLE_PHASES = {
|
|
@@ -3484,6 +4644,117 @@ function createGlobalErrorHandler(options = {}) {
|
|
|
3484
4644
|
return new GlobalErrorHandler(options);
|
|
3485
4645
|
}
|
|
3486
4646
|
|
|
4647
|
+
// src/utils/render-utils.js
|
|
4648
|
+
function renderWithMonitoring(component, options = {}) {
|
|
4649
|
+
const {
|
|
4650
|
+
enablePerformanceMonitoring = false
|
|
4651
|
+
} = options;
|
|
4652
|
+
let html;
|
|
4653
|
+
if (enablePerformanceMonitoring) {
|
|
4654
|
+
const renderId = performanceMonitor.startRender();
|
|
4655
|
+
html = render(component);
|
|
4656
|
+
performanceMonitor.endRender(renderId);
|
|
4657
|
+
} else {
|
|
4658
|
+
html = render(component);
|
|
4659
|
+
}
|
|
4660
|
+
return html;
|
|
4661
|
+
}
|
|
4662
|
+
function renderWithTemplate(component, options = {}) {
|
|
4663
|
+
const {
|
|
4664
|
+
template = "<!DOCTYPE html>\n{{content}}"
|
|
4665
|
+
} = options;
|
|
4666
|
+
const html = renderWithMonitoring(component, options);
|
|
4667
|
+
return template.replace("{{content}}", html);
|
|
4668
|
+
}
|
|
4669
|
+
async function renderComponentFactory(componentFactory, factoryArgs, options = {}) {
|
|
4670
|
+
const component = await Promise.resolve(
|
|
4671
|
+
componentFactory(...factoryArgs)
|
|
4672
|
+
);
|
|
4673
|
+
if (!component) {
|
|
4674
|
+
throw new Error("Component factory returned null/undefined");
|
|
4675
|
+
}
|
|
4676
|
+
return renderWithTemplate(component, options);
|
|
4677
|
+
}
|
|
4678
|
+
function isCoherentComponent(obj) {
|
|
4679
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
4680
|
+
return false;
|
|
4681
|
+
}
|
|
4682
|
+
const keys = Object.keys(obj);
|
|
4683
|
+
return keys.length === 1;
|
|
4684
|
+
}
|
|
4685
|
+
function createErrorResponse(error, context2 = "rendering") {
|
|
4686
|
+
return {
|
|
4687
|
+
error: "Internal Server Error",
|
|
4688
|
+
message: error.message,
|
|
4689
|
+
context: context2,
|
|
4690
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4691
|
+
};
|
|
4692
|
+
}
|
|
4693
|
+
|
|
4694
|
+
// src/utils/dependency-utils.js
|
|
4695
|
+
function isPeerDependencyAvailable(packageName) {
|
|
4696
|
+
try {
|
|
4697
|
+
if (typeof require !== "undefined" && require.resolve) {
|
|
4698
|
+
require.resolve(packageName);
|
|
4699
|
+
return true;
|
|
4700
|
+
}
|
|
4701
|
+
return false;
|
|
4702
|
+
} catch {
|
|
4703
|
+
return false;
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4706
|
+
async function importPeerDependency(packageName, integrationName) {
|
|
4707
|
+
try {
|
|
4708
|
+
return await import(packageName);
|
|
4709
|
+
} catch {
|
|
4710
|
+
throw new Error(
|
|
4711
|
+
`${integrationName} integration requires the '${packageName}' package to be installed.
|
|
4712
|
+
Please install it with: npm install ${packageName}
|
|
4713
|
+
Or with pnpm: pnpm add ${packageName}
|
|
4714
|
+
Or with yarn: yarn add ${packageName}`
|
|
4715
|
+
);
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
function createLazyIntegration(packageName, integrationName, createIntegration) {
|
|
4719
|
+
let cachedIntegration = null;
|
|
4720
|
+
let importPromise = null;
|
|
4721
|
+
return async function(...args) {
|
|
4722
|
+
if (cachedIntegration) {
|
|
4723
|
+
return cachedIntegration(...args);
|
|
4724
|
+
}
|
|
4725
|
+
if (!importPromise) {
|
|
4726
|
+
importPromise = importPeerDependency(packageName, integrationName).then((module2) => {
|
|
4727
|
+
cachedIntegration = createIntegration(module2);
|
|
4728
|
+
return cachedIntegration;
|
|
4729
|
+
});
|
|
4730
|
+
}
|
|
4731
|
+
const integration = await importPromise;
|
|
4732
|
+
return integration(...args);
|
|
4733
|
+
};
|
|
4734
|
+
}
|
|
4735
|
+
function checkPeerDependencies(dependencies) {
|
|
4736
|
+
const results = {};
|
|
4737
|
+
const missing = [];
|
|
4738
|
+
for (const { package: packageName, integration } of dependencies) {
|
|
4739
|
+
const available = isPeerDependencyAvailable(packageName);
|
|
4740
|
+
results[packageName] = available;
|
|
4741
|
+
if (!available) {
|
|
4742
|
+
missing.push({ package: packageName, integration });
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4745
|
+
if (missing.length > 0) {
|
|
4746
|
+
const installCommands = missing.map(({ package: pkg }) => pkg).join(" ");
|
|
4747
|
+
const integrationsList = missing.map(({ integration }) => integration).join(", ");
|
|
4748
|
+
console.warn(
|
|
4749
|
+
`Optional dependencies missing for ${integrationsList} integration(s).
|
|
4750
|
+
To use these integrations, install: npm install ${installCommands}
|
|
4751
|
+
Or with pnpm: pnpm add ${installCommands}
|
|
4752
|
+
Or with yarn: yarn add ${installCommands}`
|
|
4753
|
+
);
|
|
4754
|
+
}
|
|
4755
|
+
return results;
|
|
4756
|
+
}
|
|
4757
|
+
|
|
3487
4758
|
// src/shadow-dom.js
|
|
3488
4759
|
var shadow_dom_exports = {};
|
|
3489
4760
|
__export(shadow_dom_exports, {
|
|
@@ -4950,6 +6221,7 @@ var eventSystem2 = {
|
|
|
4950
6221
|
var events_default = eventSystem2;
|
|
4951
6222
|
|
|
4952
6223
|
// src/index.js
|
|
6224
|
+
var import_meta = {};
|
|
4953
6225
|
var scopeCounter = { value: 0 };
|
|
4954
6226
|
function generateScopeId() {
|
|
4955
6227
|
return `coh-${scopeCounter.value++}`;
|
|
@@ -4993,7 +6265,7 @@ function applyScopeToElement(element, scopeId) {
|
|
|
4993
6265
|
}
|
|
4994
6266
|
return element;
|
|
4995
6267
|
}
|
|
4996
|
-
function
|
|
6268
|
+
function escapeHtml2(text) {
|
|
4997
6269
|
if (typeof text !== "string") return text;
|
|
4998
6270
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4999
6271
|
}
|
|
@@ -5003,83 +6275,11 @@ function dangerouslySetInnerContent(content) {
|
|
|
5003
6275
|
__trusted: true
|
|
5004
6276
|
};
|
|
5005
6277
|
}
|
|
5006
|
-
function
|
|
5007
|
-
|
|
5008
|
-
}
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
"area",
|
|
5012
|
-
"base",
|
|
5013
|
-
"br",
|
|
5014
|
-
"col",
|
|
5015
|
-
"embed",
|
|
5016
|
-
"hr",
|
|
5017
|
-
"img",
|
|
5018
|
-
"input",
|
|
5019
|
-
"link",
|
|
5020
|
-
"meta",
|
|
5021
|
-
"param",
|
|
5022
|
-
"source",
|
|
5023
|
-
"track",
|
|
5024
|
-
"wbr"
|
|
5025
|
-
]);
|
|
5026
|
-
return voidElements.has(tagName.toLowerCase());
|
|
5027
|
-
}
|
|
5028
|
-
function formatAttributes(attrs) {
|
|
5029
|
-
if (!attrs || typeof attrs !== "object") return "";
|
|
5030
|
-
return Object.entries(attrs).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => {
|
|
5031
|
-
if (typeof value === "function") {
|
|
5032
|
-
value = value();
|
|
5033
|
-
}
|
|
5034
|
-
const attrName = key === "className" ? "class" : key;
|
|
5035
|
-
if (value === true) return attrName;
|
|
5036
|
-
return `${attrName}="${escapeHtml(String(value))}"`;
|
|
5037
|
-
}).join(" ");
|
|
5038
|
-
}
|
|
5039
|
-
function renderRaw(obj) {
|
|
5040
|
-
if (obj === null || obj === void 0) return "";
|
|
5041
|
-
if (typeof obj === "string" || typeof obj === "number") return escapeHtml(String(obj));
|
|
5042
|
-
if (Array.isArray(obj)) return obj.map(renderRaw).join("");
|
|
5043
|
-
if (typeof obj === "function") {
|
|
5044
|
-
const result = obj(renderRaw);
|
|
5045
|
-
return renderRaw(result);
|
|
5046
|
-
}
|
|
5047
|
-
if (typeof obj !== "object") return escapeHtml(String(obj));
|
|
5048
|
-
if (obj.text !== void 0) {
|
|
5049
|
-
return escapeHtml(String(obj.text));
|
|
5050
|
-
}
|
|
5051
|
-
for (const [tagName, props] of Object.entries(obj)) {
|
|
5052
|
-
if (typeof props === "object" && props !== null) {
|
|
5053
|
-
const { children, text, ...attributes } = props;
|
|
5054
|
-
const attrsStr = formatAttributes(attributes);
|
|
5055
|
-
const openTag = attrsStr ? `<${tagName} ${attrsStr}>` : `<${tagName}>`;
|
|
5056
|
-
if (isVoidElement(tagName)) {
|
|
5057
|
-
return openTag.replace(">", " />");
|
|
5058
|
-
}
|
|
5059
|
-
let content = "";
|
|
5060
|
-
if (text !== void 0) {
|
|
5061
|
-
if (isTrustedContent(text)) {
|
|
5062
|
-
content = text.__html;
|
|
5063
|
-
} else {
|
|
5064
|
-
content = escapeHtml(String(text));
|
|
5065
|
-
}
|
|
5066
|
-
} else if (children) {
|
|
5067
|
-
content = renderRaw(children);
|
|
5068
|
-
}
|
|
5069
|
-
return `${openTag}${content}</${tagName}>`;
|
|
5070
|
-
} else if (typeof props === "string") {
|
|
5071
|
-
const content = isTrustedContent(props) ? props.__html : escapeHtml(props);
|
|
5072
|
-
return isVoidElement(tagName) ? `<${tagName} />` : `<${tagName}>${content}</${tagName}>`;
|
|
5073
|
-
}
|
|
5074
|
-
}
|
|
5075
|
-
return "";
|
|
5076
|
-
}
|
|
5077
|
-
function render(obj, options = {}) {
|
|
5078
|
-
const { scoped = false } = options;
|
|
5079
|
-
if (scoped) {
|
|
5080
|
-
return renderScopedComponent(obj);
|
|
5081
|
-
}
|
|
5082
|
-
return renderRaw(obj);
|
|
6278
|
+
function render2(obj, options = {}) {
|
|
6279
|
+
const scoped = options.scoped ?? options.encapsulate ?? false;
|
|
6280
|
+
const { scoped: _scoped, encapsulate: _encapsulate, ...rendererOptions } = options;
|
|
6281
|
+
const component = scoped ? renderScopedComponent(obj) : obj;
|
|
6282
|
+
return render(component, rendererOptions);
|
|
5083
6283
|
}
|
|
5084
6284
|
function renderScopedComponent(component) {
|
|
5085
6285
|
const scopeId = generateScopeId();
|
|
@@ -5111,7 +6311,7 @@ function renderScopedComponent(component) {
|
|
|
5111
6311
|
}
|
|
5112
6312
|
const processedComponent = processScopedElement(component);
|
|
5113
6313
|
const scopedComponent = applyScopeToElement(processedComponent, scopeId);
|
|
5114
|
-
return
|
|
6314
|
+
return scopedComponent;
|
|
5115
6315
|
}
|
|
5116
6316
|
var memoCache = /* @__PURE__ */ new Map();
|
|
5117
6317
|
function memo2(component, keyGenerator) {
|
|
@@ -5135,7 +6335,7 @@ function validateComponent2(obj) {
|
|
|
5135
6335
|
}
|
|
5136
6336
|
return true;
|
|
5137
6337
|
}
|
|
5138
|
-
function
|
|
6338
|
+
function isCoherentObject2(obj) {
|
|
5139
6339
|
return obj && typeof obj === "object" && !Array.isArray(obj);
|
|
5140
6340
|
}
|
|
5141
6341
|
function deepClone2(obj) {
|
|
@@ -5148,10 +6348,13 @@ function deepClone2(obj) {
|
|
|
5148
6348
|
}
|
|
5149
6349
|
return cloned;
|
|
5150
6350
|
}
|
|
5151
|
-
var
|
|
6351
|
+
var _corePackageJson = JSON.parse(
|
|
6352
|
+
(0, import_node_fs.readFileSync)(new URL("../package.json", import_meta.url), "utf-8")
|
|
6353
|
+
);
|
|
6354
|
+
var VERSION = _corePackageJson.version;
|
|
5152
6355
|
var coherent = {
|
|
5153
6356
|
// Core rendering
|
|
5154
|
-
render,
|
|
6357
|
+
render: render2,
|
|
5155
6358
|
// Shadow DOM (client-side only)
|
|
5156
6359
|
shadowDOM: shadow_dom_exports,
|
|
5157
6360
|
// Component system
|
|
@@ -5203,9 +6406,9 @@ var coherent = {
|
|
|
5203
6406
|
withEventState,
|
|
5204
6407
|
// Utilities
|
|
5205
6408
|
validateComponent: validateComponent2,
|
|
5206
|
-
isCoherentObject,
|
|
6409
|
+
isCoherentObject: isCoherentObject2,
|
|
5207
6410
|
deepClone: deepClone2,
|
|
5208
|
-
escapeHtml,
|
|
6411
|
+
escapeHtml: escapeHtml2,
|
|
5209
6412
|
performanceMonitor,
|
|
5210
6413
|
VERSION
|
|
5211
6414
|
};
|
|
@@ -5216,9 +6419,12 @@ var index_default = coherent;
|
|
|
5216
6419
|
ComponentLifecycle,
|
|
5217
6420
|
DOMEventIntegration,
|
|
5218
6421
|
EventBus,
|
|
6422
|
+
FORBIDDEN_CHILDREN,
|
|
5219
6423
|
GlobalErrorHandler,
|
|
6424
|
+
HTMLNestingError,
|
|
5220
6425
|
LIFECYCLE_PHASES,
|
|
5221
6426
|
VERSION,
|
|
6427
|
+
checkPeerDependencies,
|
|
5222
6428
|
createActionHandlers,
|
|
5223
6429
|
createAsyncErrorBoundary,
|
|
5224
6430
|
createComponent,
|
|
@@ -5226,10 +6432,12 @@ var index_default = coherent;
|
|
|
5226
6432
|
createElement,
|
|
5227
6433
|
createErrorBoundary,
|
|
5228
6434
|
createErrorFallback,
|
|
6435
|
+
createErrorResponse,
|
|
5229
6436
|
createEventBus,
|
|
5230
6437
|
createEventComponent,
|
|
5231
6438
|
createEventHandlers,
|
|
5232
6439
|
createGlobalErrorHandler,
|
|
6440
|
+
createLazyIntegration,
|
|
5233
6441
|
createLifecycleHooks,
|
|
5234
6442
|
createStateManager,
|
|
5235
6443
|
createTextNode,
|
|
@@ -5246,13 +6454,18 @@ var index_default = coherent;
|
|
|
5246
6454
|
globalEventBus,
|
|
5247
6455
|
h,
|
|
5248
6456
|
handleAction,
|
|
6457
|
+
hasChildren,
|
|
6458
|
+
importPeerDependency,
|
|
5249
6459
|
initializeDOMIntegration,
|
|
6460
|
+
isCoherentComponent,
|
|
5250
6461
|
isCoherentObject,
|
|
5251
6462
|
isLazy,
|
|
6463
|
+
isPeerDependencyAvailable,
|
|
5252
6464
|
lazy,
|
|
5253
6465
|
lifecycleUtils,
|
|
5254
6466
|
memo,
|
|
5255
6467
|
memoize,
|
|
6468
|
+
normalizeChildren,
|
|
5256
6469
|
off,
|
|
5257
6470
|
on,
|
|
5258
6471
|
once,
|
|
@@ -5260,9 +6473,13 @@ var index_default = coherent;
|
|
|
5260
6473
|
registerAction,
|
|
5261
6474
|
registerComponent,
|
|
5262
6475
|
render,
|
|
6476
|
+
renderComponentFactory,
|
|
6477
|
+
renderWithMonitoring,
|
|
6478
|
+
renderWithTemplate,
|
|
5263
6479
|
shadowDOM,
|
|
5264
6480
|
useHooks,
|
|
5265
6481
|
validateComponent,
|
|
6482
|
+
validateNesting,
|
|
5266
6483
|
withErrorBoundary,
|
|
5267
6484
|
withEventBus,
|
|
5268
6485
|
withEventState,
|
|
@@ -5270,11 +6487,17 @@ var index_default = coherent;
|
|
|
5270
6487
|
withState,
|
|
5271
6488
|
withStateUtils
|
|
5272
6489
|
});
|
|
6490
|
+
/**
|
|
6491
|
+
* Advanced caching system with memory management and smart invalidation for Coherent.js
|
|
6492
|
+
*
|
|
6493
|
+
* @module @coherent/performance/cache-manager
|
|
6494
|
+
* @license MIT
|
|
6495
|
+
*/
|
|
5273
6496
|
/**
|
|
5274
6497
|
* Coherent.js - Object-Based Rendering Framework
|
|
5275
6498
|
* A pure JavaScript framework for server-side rendering using natural object syntax
|
|
5276
6499
|
*
|
|
5277
|
-
* @version
|
|
6500
|
+
* @version 1.0.0-beta.6
|
|
5278
6501
|
* @author Coherent Framework Team
|
|
5279
6502
|
* @license MIT
|
|
5280
6503
|
*/
|