onelaraveljs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +87 -0
  2. package/docs/integration_analysis.md +116 -0
  3. package/docs/onejs_analysis.md +108 -0
  4. package/docs/optimization_implementation_group2.md +458 -0
  5. package/docs/optimization_plan.md +130 -0
  6. package/index.js +16 -0
  7. package/package.json +13 -0
  8. package/src/app.js +61 -0
  9. package/src/core/API.js +72 -0
  10. package/src/core/ChildrenRegistry.js +410 -0
  11. package/src/core/DOMBatcher.js +207 -0
  12. package/src/core/ErrorBoundary.js +226 -0
  13. package/src/core/EventDelegator.js +416 -0
  14. package/src/core/Helper.js +817 -0
  15. package/src/core/LoopContext.js +97 -0
  16. package/src/core/OneDOM.js +246 -0
  17. package/src/core/OneMarkup.js +444 -0
  18. package/src/core/Router.js +996 -0
  19. package/src/core/SEOConfig.js +321 -0
  20. package/src/core/SectionEngine.js +75 -0
  21. package/src/core/TemplateEngine.js +83 -0
  22. package/src/core/View.js +273 -0
  23. package/src/core/ViewConfig.js +229 -0
  24. package/src/core/ViewController.js +1410 -0
  25. package/src/core/ViewControllerOptimized.js +164 -0
  26. package/src/core/ViewIdentifier.js +361 -0
  27. package/src/core/ViewLoader.js +272 -0
  28. package/src/core/ViewManager.js +1962 -0
  29. package/src/core/ViewState.js +761 -0
  30. package/src/core/ViewSystem.js +301 -0
  31. package/src/core/ViewTemplate.js +4 -0
  32. package/src/core/helpers/BindingHelper.js +239 -0
  33. package/src/core/helpers/ConfigHelper.js +37 -0
  34. package/src/core/helpers/EventHelper.js +172 -0
  35. package/src/core/helpers/LifecycleHelper.js +17 -0
  36. package/src/core/helpers/ReactiveHelper.js +169 -0
  37. package/src/core/helpers/RenderHelper.js +15 -0
  38. package/src/core/helpers/ResourceHelper.js +89 -0
  39. package/src/core/helpers/TemplateHelper.js +11 -0
  40. package/src/core/managers/BindingManager.js +671 -0
  41. package/src/core/managers/ConfigurationManager.js +136 -0
  42. package/src/core/managers/EventManager.js +309 -0
  43. package/src/core/managers/LifecycleManager.js +356 -0
  44. package/src/core/managers/ReactiveManager.js +334 -0
  45. package/src/core/managers/RenderEngine.js +292 -0
  46. package/src/core/managers/ResourceManager.js +441 -0
  47. package/src/core/managers/ViewHierarchyManager.js +258 -0
  48. package/src/core/managers/ViewTemplateManager.js +127 -0
  49. package/src/core/reactive/ReactiveComponent.js +592 -0
  50. package/src/core/services/EventService.js +418 -0
  51. package/src/core/services/HttpService.js +106 -0
  52. package/src/core/services/LoggerService.js +57 -0
  53. package/src/core/services/StateService.js +512 -0
  54. package/src/core/services/StorageService.js +856 -0
  55. package/src/core/services/StoreService.js +258 -0
  56. package/src/core/services/TemplateDetectorService.js +361 -0
  57. package/src/core/services/Test.js +18 -0
  58. package/src/helpers/devWarnings.js +205 -0
  59. package/src/helpers/performance.js +226 -0
  60. package/src/helpers/utils.js +287 -0
  61. package/src/init.js +343 -0
  62. package/src/plugins/auto-plugin.js +34 -0
  63. package/src/services/Test.js +18 -0
  64. package/src/types/index.js +193 -0
  65. package/src/utils/date-helper.js +51 -0
  66. package/src/utils/helpers.js +39 -0
  67. package/src/utils/validation.js +32 -0
@@ -0,0 +1,164 @@
1
+ import { ViewState } from './ViewState.js';
2
+
3
+ // Import Helpers
4
+ import EventHelper from './helpers/EventHelper.js';
5
+ import ReactiveHelper from './helpers/ReactiveHelper.js';
6
+ import BindingHelper from './helpers/BindingHelper.js';
7
+ import ResourceHelper from './helpers/ResourceHelper.js';
8
+ import RenderHelper from './helpers/RenderHelper.js';
9
+ import LifecycleHelper from './helpers/LifecycleHelper.js';
10
+ import ConfigHelper from './helpers/ConfigHelper.js';
11
+ import TemplateHelper from './helpers/TemplateHelper.js';
12
+ import { ViewHierarchyManager } from './managers/ViewHierarchyManager.js';
13
+ import { ChildrenRegistry } from './managers/ChildrenRegistry.js';
14
+
15
+ /**
16
+ * ViewControllerOptimized (New Architecture)
17
+ * Fully stateless logic delegating to Static Helpers
18
+ */
19
+ export class ViewControllerOptimized {
20
+ constructor(path, view, app) {
21
+ this.path = path;
22
+ this.view = view;
23
+ this.App = app;
24
+
25
+ // --- Core Properties ---
26
+ this.id = view.id || null;
27
+ this.states = new ViewState(this);
28
+ this.config = {};
29
+ this.data = {};
30
+
31
+ // --- State Management (Internal) ---
32
+ this.initializeInternalState();
33
+
34
+ // --- Legacy Manager Bridges (Optional: Keep only if strictly needed for Hierarchy/Children) ---
35
+ // Hierarchy and ChildrenRegistry are complex logic-heavy stateful managers.
36
+ // For now, we keep them as objects or migrate later.
37
+ this._hierarchyManager = new ViewHierarchyManager(this);
38
+ this._childrenRegistry = new ChildrenRegistry(this);
39
+
40
+ // --- Flags ---
41
+ this.isMounted = false;
42
+ this.isDestroyed = false;
43
+ this.isReady = false;
44
+ this.isRendered = false;
45
+ this.eventListenerStatus = false;
46
+ }
47
+
48
+ initializeInternalState() {
49
+ this._internal = {
50
+ events: {
51
+ unsubscribers: new Map()
52
+ },
53
+ reactive: {
54
+ components: new Map(),
55
+ config: [],
56
+ index: 0,
57
+ scanIndex: 0,
58
+ ids: [],
59
+ prerenderIDs: [],
60
+ renderIDs: [],
61
+ followingIDs: [],
62
+ followingRenderIDs: [],
63
+ followingPrerenderIDs: [],
64
+ parentWatch: null
65
+ },
66
+ binding: {
67
+ listeners: [],
68
+ isStarted: false,
69
+ elementFlags: new WeakMap(),
70
+ elementMap: new WeakMap(),
71
+ attrConfigs: [],
72
+ attrListeners: [],
73
+ attrIndex: 0,
74
+ classConfigs: [],
75
+ classListeners: [],
76
+ isClassReady: false
77
+ },
78
+ resources: {
79
+ insertedKeys: new Set()
80
+ }
81
+ };
82
+ }
83
+
84
+ // --- Public API Bridges to Helpers ---
85
+
86
+ /**
87
+ * Setup the view controller with configuration
88
+ * This is called by View.js after instantiation
89
+ */
90
+ setup(path, config) {
91
+ if (this.isInitlized) {
92
+ return this;
93
+ }
94
+
95
+ // Set config and path
96
+ this.path = path;
97
+ this.config = config || {};
98
+
99
+ // Parse basic config properties
100
+ if (config) {
101
+ this.id = config.viewId || this.id;
102
+ this.data = config.data || {};
103
+ // ... map other flat config properties if needed ...
104
+ }
105
+
106
+ // Initialize Internal State via ConfigHelper
107
+ // This will define properties (props, methods, getters) on the controller itself
108
+ ConfigHelper.processDefinedProperties(this, config);
109
+
110
+ // Execute Initialization Lifecycle
111
+ this.initialize();
112
+
113
+ return this;
114
+ }
115
+
116
+ initialize() {
117
+ if (this.isInitlized) return;
118
+ this.isInitlized = true;
119
+
120
+ LifecycleHelper.callHook(this, 'beforeCreate');
121
+
122
+ // Commit initial data from constructor to state
123
+ // We need to implement commitConstructorData in ConfigHelper or here
124
+ // Assuming ConfigHelper handles it for now based on previous context
125
+ // ConfigHelper.commitConstructorData(this);
126
+
127
+ LifecycleHelper.callHook(this, 'created');
128
+
129
+ LifecycleHelper.callHook(this, 'beforeInit');
130
+ if (typeof this.init === 'function') {
131
+ this.init();
132
+ }
133
+ LifecycleHelper.callHook(this, 'init');
134
+ LifecycleHelper.callHook(this, 'afterInit');
135
+ }
136
+
137
+ __reactive(id, keys, renderFn) {
138
+ return ReactiveHelper.renderOutputComponent(this, keys, renderFn);
139
+ }
140
+
141
+ // ... replicate other necessary methods ...
142
+
143
+ mounted() {
144
+ LifecycleHelper.callHook(this, 'beforeMount');
145
+ // ... logic ...
146
+ EventHelper.startEventListener(this);
147
+ BindingHelper.startBindingEventListener(this);
148
+ // ... logic ...
149
+ this.isMounted = true;
150
+ LifecycleHelper.callHook(this, 'mounted');
151
+ }
152
+
153
+ destroy() {
154
+ EventHelper.stopEventListener(this);
155
+ BindingHelper.destroy(this);
156
+ ReactiveHelper.destroy(this);
157
+ ResourceHelper.removeResources(this);
158
+
159
+ if (this._childrenRegistry) this._childrenRegistry.clear();
160
+
161
+ this._internal = null;
162
+ this.isDestroyed = true;
163
+ }
164
+ }
@@ -0,0 +1,361 @@
1
+ /**
2
+ * View Identifier System
3
+ * Handles view identification and DOM mapping for server-rendered content
4
+ */
5
+
6
+ export class ViewIdentifier {
7
+ constructor() {
8
+ this.viewElements = new Map();
9
+ this.viewHierarchy = new Map();
10
+ this.currentView = null;
11
+ this.debugMode = false;
12
+ }
13
+
14
+ /**
15
+ * Initialize view identification system
16
+ */
17
+ init() {
18
+ this.scanViewElements();
19
+ this.buildViewHierarchy();
20
+ this.setupViewTracking();
21
+
22
+ if (this.debugMode) {
23
+ this.enableDebugMode();
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Scan all elements with view identification attributes
29
+ */
30
+ scanViewElements() {
31
+ const elements = document.querySelectorAll('[data-spa-view]');
32
+
33
+ elements.forEach(element => {
34
+ const viewInfo = this.extractViewInfo(element);
35
+ if (viewInfo) {
36
+ this.viewElements.set(viewInfo.id, {
37
+ element,
38
+ info: viewInfo,
39
+ children: [],
40
+ parent: null
41
+ });
42
+ }
43
+ });
44
+
45
+ console.log(`🔍 Found ${this.viewElements.size} view elements`);
46
+ }
47
+
48
+ /**
49
+ * Extract view information from element
50
+ */
51
+ extractViewInfo(element) {
52
+ const viewId = element.getAttribute('data-spa-view-id');
53
+ const viewName = element.getAttribute('data-spa-view-name');
54
+ const viewPath = element.getAttribute('data-spa-view-path');
55
+ const viewType = element.getAttribute('data-spa-view-type');
56
+ const viewScope = element.getAttribute('data-spa-view');
57
+
58
+ if (!viewId) return null;
59
+
60
+ return {
61
+ id: viewId,
62
+ name: viewName || 'unknown',
63
+ path: viewPath || 'unknown',
64
+ type: viewType || 'view',
65
+ scope: viewScope || 'unknown',
66
+ element
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Build view hierarchy based on DOM structure
72
+ */
73
+ buildViewHierarchy() {
74
+ this.viewElements.forEach((viewData, viewId) => {
75
+ const element = viewData.element;
76
+
77
+ // Find parent view
78
+ let parent = element.parentElement;
79
+ while (parent && parent !== document.body) {
80
+ const parentViewId = parent.getAttribute('data-spa-view-id');
81
+ if (parentViewId && this.viewElements.has(parentViewId)) {
82
+ viewData.parent = parentViewId;
83
+ this.viewElements.get(parentViewId).children.push(viewId);
84
+ break;
85
+ }
86
+ parent = parent.parentElement;
87
+ }
88
+ });
89
+
90
+ console.log('🏗️ View hierarchy built');
91
+ }
92
+
93
+ /**
94
+ * Setup view tracking and event listeners
95
+ */
96
+ setupViewTracking() {
97
+ // Track view changes
98
+ this.viewElements.forEach((viewData, viewId) => {
99
+ this.setupViewEventListeners(viewData);
100
+ });
101
+
102
+ // Track DOM changes for dynamic content
103
+ this.setupMutationObserver();
104
+ }
105
+
106
+ /**
107
+ * Setup event listeners for a view
108
+ */
109
+ setupViewEventListeners(viewData) {
110
+ const { element, info } = viewData;
111
+
112
+ // Add view lifecycle events
113
+ element.addEventListener('spa:view:enter', () => {
114
+ this.onViewEnter(info);
115
+ });
116
+
117
+ element.addEventListener('spa:view:leave', () => {
118
+ this.onViewLeave(info);
119
+ });
120
+
121
+ // Add click tracking for debugging
122
+ if (this.debugMode) {
123
+ element.addEventListener('click', (e) => {
124
+ console.log(`🖱️ Click on view: ${info.name} (${info.id})`, e.target);
125
+ });
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Setup mutation observer for dynamic content
131
+ */
132
+ setupMutationObserver() {
133
+ const observer = new MutationObserver((mutations) => {
134
+ mutations.forEach((mutation) => {
135
+ if (mutation.type === 'childList') {
136
+ mutation.addedNodes.forEach((node) => {
137
+ if (node.nodeType === Node.ELEMENT_NODE) {
138
+ const viewId = node.getAttribute('data-spa-view-id');
139
+ if (viewId && !this.viewElements.has(viewId)) {
140
+ // New view element added
141
+ this.scanViewElements();
142
+ this.buildViewHierarchy();
143
+ }
144
+ }
145
+ });
146
+ }
147
+ });
148
+ });
149
+
150
+ observer.observe(document.body, {
151
+ childList: true,
152
+ subtree: true
153
+ });
154
+ }
155
+
156
+ /**
157
+ * Get view by ID
158
+ */
159
+ getView(viewId) {
160
+ return this.viewElements.get(viewId);
161
+ }
162
+
163
+ /**
164
+ * Get all views by type
165
+ */
166
+ getViewsByType(type) {
167
+ const views = [];
168
+ this.viewElements.forEach((viewData, viewId) => {
169
+ if (viewData.info.type === type) {
170
+ views.push(viewData);
171
+ }
172
+ });
173
+ return views;
174
+ }
175
+
176
+ /**
177
+ * Get current active view
178
+ */
179
+ getCurrentView() {
180
+ return this.currentView;
181
+ }
182
+
183
+ /**
184
+ * Set current active view
185
+ */
186
+ setCurrentView(viewId) {
187
+ const viewData = this.viewElements.get(viewId);
188
+ if (viewData) {
189
+ this.currentView = viewData;
190
+ this.emitViewChange(viewData);
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Get view hierarchy for a specific view
196
+ */
197
+ getViewHierarchy(viewId) {
198
+ const hierarchy = [];
199
+ let current = viewId;
200
+
201
+ while (current) {
202
+ const viewData = this.viewElements.get(current);
203
+ if (viewData) {
204
+ hierarchy.unshift(viewData);
205
+ current = viewData.parent;
206
+ } else {
207
+ break;
208
+ }
209
+ }
210
+
211
+ return hierarchy;
212
+ }
213
+
214
+ /**
215
+ * Find view containing a specific element
216
+ */
217
+ findViewContainingElement(element) {
218
+ let current = element;
219
+
220
+ while (current && current !== document.body) {
221
+ const viewId = current.getAttribute('data-spa-view-id');
222
+ if (viewId && this.viewElements.has(viewId)) {
223
+ return this.viewElements.get(viewId);
224
+ }
225
+ current = current.parentElement;
226
+ }
227
+
228
+ return null;
229
+ }
230
+
231
+ /**
232
+ * View lifecycle events
233
+ */
234
+ onViewEnter(viewInfo) {
235
+ console.log(`🚀 View entered: ${viewInfo.name} (${viewInfo.id})`);
236
+ this.setCurrentView(viewInfo.id);
237
+ }
238
+
239
+ onViewLeave(viewInfo) {
240
+ console.log(`👋 View left: ${viewInfo.name} (${viewInfo.id})`);
241
+ }
242
+
243
+ /**
244
+ * Emit view change event
245
+ */
246
+ emitViewChange(viewData) {
247
+ const event = new CustomEvent('spa:view:changed', {
248
+ detail: {
249
+ view: viewData,
250
+ timestamp: Date.now()
251
+ }
252
+ });
253
+ document.dispatchEvent(event);
254
+ }
255
+
256
+ /**
257
+ * Enable debug mode
258
+ */
259
+ enableDebugMode() {
260
+ this.debugMode = true;
261
+ document.body.classList.add('debug-view-boundaries');
262
+
263
+ // Add debug styles
264
+ const style = document.createElement('style');
265
+ style.textContent = `
266
+ .debug-view-boundaries [data-spa-view] {
267
+ border: 2px dashed #007cba !important;
268
+ margin: 2px !important;
269
+ position: relative !important;
270
+ }
271
+
272
+ .debug-view-boundaries [data-spa-view]::before {
273
+ content: attr(data-spa-view-name) " (" attr(data-spa-view-id) ")" !important;
274
+ position: absolute !important;
275
+ top: -20px !important;
276
+ left: 0 !important;
277
+ font-size: 10px !important;
278
+ color: white !important;
279
+ background: #007cba !important;
280
+ padding: 2px 6px !important;
281
+ border-radius: 3px !important;
282
+ opacity: 1 !important;
283
+ z-index: 1000 !important;
284
+ }
285
+ `;
286
+ document.head.appendChild(style);
287
+ }
288
+
289
+ /**
290
+ * Disable debug mode
291
+ */
292
+ disableDebugMode() {
293
+ this.debugMode = false;
294
+ document.body.classList.remove('debug-view-boundaries');
295
+ }
296
+
297
+ /**
298
+ * Get debug information
299
+ */
300
+ getDebugInfo() {
301
+ return {
302
+ totalViews: this.viewElements.size,
303
+ currentView: this.currentView?.info,
304
+ viewTypes: this.getViewTypeStats(),
305
+ hierarchy: this.getViewHierarchyStats()
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Get view type statistics
311
+ */
312
+ getViewTypeStats() {
313
+ const stats = {};
314
+ this.viewElements.forEach((viewData) => {
315
+ const type = viewData.info.type;
316
+ stats[type] = (stats[type] || 0) + 1;
317
+ });
318
+ return stats;
319
+ }
320
+
321
+ /**
322
+ * Get view hierarchy statistics
323
+ */
324
+ getViewHierarchyStats() {
325
+ const stats = {
326
+ rootViews: 0,
327
+ nestedViews: 0,
328
+ maxDepth: 0
329
+ };
330
+
331
+ this.viewElements.forEach((viewData) => {
332
+ if (!viewData.parent) {
333
+ stats.rootViews++;
334
+ } else {
335
+ stats.nestedViews++;
336
+ }
337
+
338
+ const depth = this.getViewHierarchy(viewData.info.id).length;
339
+ stats.maxDepth = Math.max(stats.maxDepth, depth);
340
+ });
341
+
342
+ return stats;
343
+ }
344
+
345
+ /**
346
+ * Export view data for debugging
347
+ */
348
+ exportViewData() {
349
+ const data = {};
350
+ this.viewElements.forEach((viewData, viewId) => {
351
+ data[viewId] = {
352
+ info: viewData.info,
353
+ hasParent: !!viewData.parent,
354
+ childrenCount: viewData.children.length,
355
+ elementTag: viewData.element.tagName,
356
+ elementClasses: viewData.element.className
357
+ };
358
+ });
359
+ return data;
360
+ }
361
+ }