@memberjunction/react-runtime 2.94.0 → 2.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +12 -0
- package/dist/compiler/component-compiler.d.ts +1 -0
- package/dist/compiler/component-compiler.d.ts.map +1 -1
- package/dist/compiler/component-compiler.js +67 -24
- package/dist/compiler/component-compiler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/registry/component-registry-service.d.ts +2 -0
- package/dist/registry/component-registry-service.d.ts.map +1 -1
- package/dist/registry/component-registry-service.js +11 -0
- package/dist/registry/component-registry-service.js.map +1 -1
- package/dist/registry/component-registry.d.ts +2 -0
- package/dist/registry/component-registry.d.ts.map +1 -1
- package/dist/registry/component-registry.js +17 -0
- package/dist/registry/component-registry.js.map +1 -1
- package/dist/registry/component-resolver.d.ts.map +1 -1
- package/dist/registry/component-resolver.js +60 -5
- package/dist/registry/component-resolver.js.map +1 -1
- package/dist/runtime/component-hierarchy.d.ts.map +1 -1
- package/dist/runtime/component-hierarchy.js +73 -17
- package/dist/runtime/component-hierarchy.js.map +1 -1
- package/dist/runtime.umd.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/library-dependency-resolver.d.ts.map +1 -1
- package/dist/utilities/library-dependency-resolver.js +17 -8
- package/dist/utilities/library-dependency-resolver.js.map +1 -1
- package/dist/utilities/library-loader.d.ts.map +1 -1
- package/dist/utilities/library-loader.js +23 -2
- package/dist/utilities/library-loader.js.map +1 -1
- package/package.json +5 -5
- package/src/compiler/component-compiler.ts +73 -25
- package/src/index.ts +2 -1
- package/src/registry/component-registry-service.ts +21 -0
- package/src/registry/component-registry.ts +28 -0
- package/src/registry/component-resolver.ts +82 -9
- package/src/runtime/component-hierarchy.ts +97 -31
- package/src/types/index.ts +1 -1
- package/src/utilities/library-dependency-resolver.ts +21 -11
- package/src/utilities/library-loader.ts +24 -2
|
@@ -172,68 +172,115 @@ export class ComponentCompiler {
|
|
|
172
172
|
* @param dependencies - Optional child component dependencies
|
|
173
173
|
* @returns Wrapped component code
|
|
174
174
|
*/
|
|
175
|
+
// Core libraries that are passed as parameters to createComponent and should not be destructured
|
|
176
|
+
private readonly CORE_LIBRARIES = new Set(['React', 'ReactDOM']);
|
|
177
|
+
|
|
175
178
|
private wrapComponentCode(componentCode: string, componentName: string, libraries?: any[], dependencies?: Array<{ name: string }>): string {
|
|
176
179
|
// Generate library declarations if libraries are provided
|
|
180
|
+
// Skip core libraries as they're passed as parameters to createComponent
|
|
177
181
|
const libraryDeclarations = libraries && libraries.length > 0
|
|
178
182
|
? libraries
|
|
179
|
-
.filter(lib => lib.globalVariable) //
|
|
183
|
+
.filter(lib => lib.globalVariable && !this.CORE_LIBRARIES.has(lib.globalVariable)) // Skip core libraries
|
|
180
184
|
.map(lib => `const ${lib.globalVariable} = libraries['${lib.globalVariable}'];`)
|
|
181
185
|
.join('\n ')
|
|
182
186
|
: '';
|
|
183
|
-
|
|
187
|
+
const libraryLogChecks = libraries && libraries.length > 0
|
|
188
|
+
? libraries
|
|
189
|
+
.filter(lib => lib.globalVariable && !this.CORE_LIBRARIES.has(lib.globalVariable)) // Skip core libraries
|
|
190
|
+
.map(lib => `\nif (!${lib.globalVariable}) { console.error('[React-Runtime-JS] Library "${lib.globalVariable}" is not defined'); } else { console.log('[React-Runtime-JS] Library "${lib.globalVariable}" is defined'); }`)
|
|
191
|
+
.join('\n ')
|
|
192
|
+
: '';
|
|
193
|
+
|
|
184
194
|
// Generate component declarations if dependencies are provided
|
|
195
|
+
// Filter out the component being compiled to avoid naming conflicts
|
|
185
196
|
const componentDeclarations = dependencies && dependencies.length > 0
|
|
186
197
|
? dependencies
|
|
187
|
-
.
|
|
198
|
+
.filter(dep => dep.name !== componentName) // Don't destructure the component being compiled itself
|
|
199
|
+
.map(dep => `const ${dep.name} = componentsOuter['${dep.name}'];`)
|
|
200
|
+
.join('\n ')
|
|
201
|
+
: '';
|
|
202
|
+
const componentLogChecks = dependencies && dependencies.length > 0
|
|
203
|
+
? dependencies
|
|
204
|
+
.filter(dep => dep.name !== componentName) // Don't destructure the component being compiled itself
|
|
205
|
+
.map(dep => `if (!${dep.name}) { console.error('[React-Runtime-JS] Dependency "${dep.name}" is not defined'); } else { console.log('[React-Runtime-JS] Dependency "${dep.name}" is defined'); }`)
|
|
188
206
|
.join('\n ')
|
|
189
207
|
: '';
|
|
190
208
|
|
|
191
|
-
|
|
209
|
+
const wrappedCode = `
|
|
192
210
|
function createComponent(
|
|
193
211
|
React, ReactDOM,
|
|
194
212
|
useState, useEffect, useCallback, useMemo, useRef, useContext, useReducer, useLayoutEffect,
|
|
195
213
|
libraries, styles, console, components
|
|
196
214
|
) {
|
|
197
|
-
//
|
|
198
|
-
${
|
|
215
|
+
// Code for ${componentName}
|
|
216
|
+
${componentCode}
|
|
199
217
|
|
|
200
218
|
// Ensure the component exists
|
|
201
219
|
if (typeof ${componentName} === 'undefined') {
|
|
202
220
|
throw new Error('Component "${componentName}" is not defined in the provided code');
|
|
203
221
|
}
|
|
222
|
+
else {
|
|
223
|
+
console.log('[React-Runtime-JS] Component "${componentName}" is defined');
|
|
224
|
+
}
|
|
204
225
|
|
|
205
226
|
// Store the component in a variable so we don't lose it
|
|
206
227
|
const UserComponent = ${componentName};
|
|
228
|
+
|
|
229
|
+
// Check if the component is already a ComponentObject (has a .component property)
|
|
230
|
+
// If so, extract the actual React component
|
|
231
|
+
const ActualComponent = (typeof UserComponent === 'object' && UserComponent !== null && 'component' in UserComponent)
|
|
232
|
+
? UserComponent.component
|
|
233
|
+
: UserComponent;
|
|
207
234
|
|
|
208
235
|
// Debug logging to understand what we're getting
|
|
209
|
-
console.log('Component ${componentName} type:', typeof UserComponent);
|
|
236
|
+
console.log('[React-Runtime-JS]Component ${componentName} type:', typeof UserComponent);
|
|
210
237
|
if (typeof UserComponent === 'object' && UserComponent !== null) {
|
|
211
|
-
console.log('Component ${componentName} keys:', Object.keys(UserComponent));
|
|
212
|
-
console.log('Component ${componentName} has .component:', 'component' in UserComponent);
|
|
238
|
+
console.log('[React-Runtime-JS]Component ${componentName} keys:', Object.keys(UserComponent));
|
|
239
|
+
console.log('[React-Runtime-JS]Component ${componentName} has .component:', 'component' in UserComponent);
|
|
213
240
|
if ('component' in UserComponent) {
|
|
214
|
-
console.log('Component ${componentName}.component type:', typeof UserComponent.component);
|
|
241
|
+
console.log('[React-Runtime-JS]Component ${componentName}.component type:', typeof UserComponent.component);
|
|
215
242
|
}
|
|
216
243
|
}
|
|
217
244
|
|
|
218
|
-
// Check if the component is already a ComponentObject (has a .component property)
|
|
219
|
-
// If so, extract the actual React component
|
|
220
|
-
const ActualComponent = (typeof UserComponent === 'object' && UserComponent !== null && 'component' in UserComponent)
|
|
221
|
-
? UserComponent.component
|
|
222
|
-
: UserComponent;
|
|
223
|
-
|
|
224
245
|
// Validate that we have a function (React component)
|
|
225
246
|
if (typeof ActualComponent !== 'function') {
|
|
226
|
-
console.error('Invalid component type for ${componentName}:', typeof ActualComponent);
|
|
227
|
-
console.error('ActualComponent value:', ActualComponent);
|
|
228
|
-
console.error('Original UserComponent value:', UserComponent);
|
|
229
|
-
throw new Error('Component "${componentName}" must be a function (React component) or an object with a .component property that is a function. Got: ' + typeof ActualComponent);
|
|
247
|
+
console.error('[React-Runtime-JS] Invalid component type for ${componentName}:', typeof ActualComponent);
|
|
248
|
+
console.error('[React-Runtime-JS] ActualComponent value:', ActualComponent);
|
|
249
|
+
console.error('[React-Runtime-JS] Original UserComponent value:', UserComponent);
|
|
250
|
+
throw new Error('[React-Runtime-JS] Component "${componentName}" must be a function (React component) or an object with a .component property that is a function. Got: ' + typeof ActualComponent);
|
|
230
251
|
}
|
|
252
|
+
|
|
253
|
+
let componentsOuter = null, utilitiesOuter = null;
|
|
254
|
+
const DestructureWrapperUserComponent = (props) => {
|
|
255
|
+
if (!componentsOuter) {
|
|
256
|
+
componentsOuter = props?.components || components;
|
|
257
|
+
}
|
|
258
|
+
if (!utilitiesOuter) {
|
|
259
|
+
utilitiesOuter = props?.utilities;
|
|
260
|
+
}
|
|
261
|
+
console.log('Props for ${componentName}:', props);
|
|
262
|
+
console.log('components for ${componentName}:', componentsOuter);
|
|
263
|
+
console.log('styles for ${componentName}:', styles);
|
|
264
|
+
console.log('utilities for ${componentName}:', utilitiesOuter);
|
|
265
|
+
console.log('libraries for ${componentName}:', libraries);
|
|
266
|
+
${libraryDeclarations ? '// Destructure Libraries\n' + libraryDeclarations + '\n ' : ''}
|
|
267
|
+
${componentDeclarations ? '// Destructure Dependencies\n' + componentDeclarations + '\n ' : ''}
|
|
268
|
+
${libraryLogChecks}
|
|
269
|
+
${componentLogChecks}
|
|
270
|
+
|
|
271
|
+
const newProps = {
|
|
272
|
+
...props,
|
|
273
|
+
components: componentsOuter,
|
|
274
|
+
utilities: utilitiesOuter
|
|
275
|
+
}
|
|
276
|
+
return ActualComponent(newProps);
|
|
277
|
+
};
|
|
231
278
|
|
|
232
279
|
// Create a fresh method registry for each factory call
|
|
233
280
|
const methodRegistry = new Map();
|
|
234
281
|
|
|
235
282
|
// Create a wrapper component that provides RegisterMethod in callbacks
|
|
236
|
-
const ComponentWithMethodRegistry =
|
|
283
|
+
const ComponentWithMethodRegistry = (props) => {
|
|
237
284
|
// Register methods on mount
|
|
238
285
|
React.useEffect(() => {
|
|
239
286
|
// Clear previous methods
|
|
@@ -261,11 +308,11 @@ export class ComponentCompiler {
|
|
|
261
308
|
}, [props.callbacks]);
|
|
262
309
|
|
|
263
310
|
// Render the original component with enhanced callbacks
|
|
264
|
-
return React.createElement(
|
|
311
|
+
return React.createElement(DestructureWrapperUserComponent, {
|
|
265
312
|
...props,
|
|
266
313
|
callbacks: enhancedCallbacks
|
|
267
314
|
});
|
|
268
|
-
}
|
|
315
|
+
};
|
|
269
316
|
|
|
270
317
|
ComponentWithMethodRegistry.displayName = '${componentName}WithMethods';
|
|
271
318
|
|
|
@@ -273,7 +320,6 @@ export class ComponentCompiler {
|
|
|
273
320
|
return {
|
|
274
321
|
component: ComponentWithMethodRegistry,
|
|
275
322
|
|
|
276
|
-
// Legacy methods for backward compatibility
|
|
277
323
|
print: function() {
|
|
278
324
|
const printMethod = methodRegistry.get('print');
|
|
279
325
|
if (printMethod) {
|
|
@@ -326,7 +372,7 @@ export class ComponentCompiler {
|
|
|
326
372
|
if (method) {
|
|
327
373
|
return method(...args);
|
|
328
374
|
}
|
|
329
|
-
console.warn(\`Method '\${methodName}' is not registered on component ${componentName}\`);
|
|
375
|
+
console.warn(\`[React-Runtime-JS] Method '\${methodName}' is not registered on component ${componentName}\`);
|
|
330
376
|
return undefined;
|
|
331
377
|
},
|
|
332
378
|
|
|
@@ -337,6 +383,8 @@ export class ComponentCompiler {
|
|
|
337
383
|
};
|
|
338
384
|
}
|
|
339
385
|
`;
|
|
386
|
+
|
|
387
|
+
return wrappedCode;
|
|
340
388
|
}
|
|
341
389
|
|
|
342
390
|
/**
|
package/src/index.ts
CHANGED
|
@@ -561,6 +561,27 @@ export class ComponentRegistryService {
|
|
|
561
561
|
this.compiledComponentCache.clear();
|
|
562
562
|
this.componentReferences.clear();
|
|
563
563
|
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Force clear all compiled components
|
|
567
|
+
* Used for Component Studio to ensure fresh loads
|
|
568
|
+
*/
|
|
569
|
+
forceClearAll(): void {
|
|
570
|
+
this.compiledComponentCache.clear();
|
|
571
|
+
this.componentReferences.clear();
|
|
572
|
+
console.log('🧹 Component cache force cleared');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Reset the singleton instance
|
|
577
|
+
* Forces new instance creation on next access
|
|
578
|
+
*/
|
|
579
|
+
static reset(): void {
|
|
580
|
+
if (ComponentRegistryService.instance) {
|
|
581
|
+
ComponentRegistryService.instance.forceClearAll();
|
|
582
|
+
ComponentRegistryService.instance = null;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
564
585
|
|
|
565
586
|
/**
|
|
566
587
|
* Generate a cache key for a component
|
|
@@ -243,6 +243,34 @@ export class ComponentRegistry {
|
|
|
243
243
|
this.registry.clear();
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Clear all components in a specific namespace
|
|
248
|
+
* @param namespace - Namespace to clear (default: 'Global')
|
|
249
|
+
* @returns Number of components removed
|
|
250
|
+
*/
|
|
251
|
+
clearNamespace(namespace: string = 'Global'): number {
|
|
252
|
+
const toRemove: string[] = [];
|
|
253
|
+
for (const [key, entry] of this.registry) {
|
|
254
|
+
if (entry.metadata.namespace === namespace) {
|
|
255
|
+
toRemove.push(key);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
for (const key of toRemove) {
|
|
259
|
+
this.registry.delete(key);
|
|
260
|
+
}
|
|
261
|
+
return toRemove.length;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Force clear all components and reset registry
|
|
266
|
+
* Used for development/testing scenarios
|
|
267
|
+
*/
|
|
268
|
+
forceClear(): void {
|
|
269
|
+
this.stopCleanupTimer();
|
|
270
|
+
this.registry.clear();
|
|
271
|
+
console.log('🧹 Registry force cleared - all components removed');
|
|
272
|
+
}
|
|
273
|
+
|
|
246
274
|
/**
|
|
247
275
|
* Gets the current size of the registry
|
|
248
276
|
* @returns Number of registered components
|
|
@@ -68,16 +68,27 @@ export class ComponentResolver {
|
|
|
68
68
|
namespace: string = 'Global',
|
|
69
69
|
contextUser?: UserInfo
|
|
70
70
|
): Promise<ResolvedComponents> {
|
|
71
|
+
console.log(`🚀 [ComponentResolver] Starting component resolution for: ${spec.name}`);
|
|
72
|
+
console.log(`📋 [ComponentResolver] Dependencies to resolve:`, (spec.dependencies || []).map(d => ({
|
|
73
|
+
name: d.name,
|
|
74
|
+
location: d.location,
|
|
75
|
+
namespace: d.namespace
|
|
76
|
+
})));
|
|
77
|
+
|
|
71
78
|
const resolved: ResolvedComponents = {};
|
|
72
79
|
|
|
73
80
|
// Initialize component engine if we have registry service
|
|
74
81
|
if (this.registryService) {
|
|
82
|
+
console.log(`🔄 [ComponentResolver] Initializing component engine...`);
|
|
75
83
|
await this.componentEngine.Config(false, contextUser);
|
|
84
|
+
console.log(`✅ [ComponentResolver] Component engine initialized with ${this.componentEngine.Components?.length || 0} components`);
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
// Resolve the component hierarchy
|
|
79
88
|
await this.resolveComponentHierarchy(spec, resolved, namespace, new Set(), contextUser);
|
|
80
89
|
|
|
90
|
+
console.log(`📊 [ComponentResolver] Resolved components before unwrapping:`, Object.keys(resolved));
|
|
91
|
+
|
|
81
92
|
// Unwrap component wrappers before returning
|
|
82
93
|
// Components from the registry come as objects with component/print/refresh properties
|
|
83
94
|
// We need to extract just the component function for use in child components
|
|
@@ -87,17 +98,29 @@ export class ComponentResolver {
|
|
|
87
98
|
if (typeof value.component === 'function') {
|
|
88
99
|
// This is a wrapped component - extract the actual React component function
|
|
89
100
|
unwrapped[name] = value.component;
|
|
101
|
+
console.log(`✅ [ComponentResolver] Unwrapped component: ${name} (was object with .component)`);
|
|
90
102
|
} else {
|
|
91
103
|
// ComponentObject has a component property but it's not a function
|
|
92
|
-
console.error(
|
|
104
|
+
console.error(`❌ [ComponentResolver] Component ${name} has invalid component property:`, typeof value.component, value);
|
|
93
105
|
unwrapped[name] = value; // Pass through the problematic value so we can see the error
|
|
94
106
|
}
|
|
95
|
-
} else {
|
|
96
|
-
//
|
|
107
|
+
} else if (typeof value === 'function') {
|
|
108
|
+
// Already a function - use as is
|
|
97
109
|
unwrapped[name] = value;
|
|
110
|
+
console.log(`✅ [ComponentResolver] Component already a function: ${name}`);
|
|
111
|
+
} else {
|
|
112
|
+
// Something else - could be undefined or an error
|
|
113
|
+
console.warn(`⚠️ [ComponentResolver] Component ${name} is not a function or wrapped component:`, typeof value, value);
|
|
114
|
+
unwrapped[name] = value; // Pass through for debugging
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
|
|
118
|
+
console.log(`🎯 [ComponentResolver] Final resolved components:`, Object.keys(unwrapped).map(name => ({
|
|
119
|
+
name,
|
|
120
|
+
type: typeof unwrapped[name],
|
|
121
|
+
isUndefined: unwrapped[name] === undefined
|
|
122
|
+
})));
|
|
123
|
+
|
|
101
124
|
return unwrapped;
|
|
102
125
|
}
|
|
103
126
|
|
|
@@ -119,6 +142,12 @@ export class ComponentResolver {
|
|
|
119
142
|
// Create a unique identifier for this component
|
|
120
143
|
const componentId = `${spec.namespace || namespace}/${spec.name}@${spec.version || 'latest'}`;
|
|
121
144
|
|
|
145
|
+
// Check if already resolved (not just visited)
|
|
146
|
+
if (resolved[spec.name]) {
|
|
147
|
+
console.log(`⏭️ [ComponentResolver] Component already resolved: ${spec.name}`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
122
151
|
// Prevent circular dependencies
|
|
123
152
|
if (visited.has(componentId)) {
|
|
124
153
|
if (this.debug) {
|
|
@@ -128,17 +157,55 @@ export class ComponentResolver {
|
|
|
128
157
|
}
|
|
129
158
|
visited.add(componentId);
|
|
130
159
|
|
|
160
|
+
// *** CRITICAL: Process child components FIRST (depth-first, post-order) ***
|
|
161
|
+
console.log(`🔄 [ComponentResolver] Resolving dependencies for ${spec.name} BEFORE resolving itself`);
|
|
162
|
+
const children = spec.dependencies || [];
|
|
163
|
+
for (const child of children) {
|
|
164
|
+
console.log(` ↳ [ComponentResolver] Resolving dependency: ${child.name} for parent ${spec.name}`);
|
|
165
|
+
await this.resolveComponentHierarchy(child, resolved, namespace, visited, contextUser);
|
|
166
|
+
}
|
|
167
|
+
if (children.length > 0) {
|
|
168
|
+
console.log(`✅ [ComponentResolver] All ${children.length} dependencies resolved for ${spec.name}, now resolving itself`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// NOW resolve the current component (it can access its dependencies)
|
|
131
172
|
// Handle based on location
|
|
132
173
|
if (spec.location === 'registry' && this.registryService) {
|
|
133
174
|
// Registry component - need to load from database or external source
|
|
175
|
+
console.log(`🔍 [ComponentResolver] Looking for registry component: ${spec.name} in namespace: ${spec.namespace || namespace}`);
|
|
176
|
+
|
|
134
177
|
try {
|
|
135
178
|
// First, try to find the component in the metadata engine
|
|
179
|
+
const allComponents = this.componentEngine.Components || [];
|
|
180
|
+
console.log(`📊 [ComponentResolver] Total components in engine: ${allComponents.length}`);
|
|
181
|
+
|
|
182
|
+
// Log all matching names to see duplicates
|
|
183
|
+
const matchingNames = allComponents.filter((c: any) => c.Name === spec.name);
|
|
184
|
+
if (matchingNames.length > 0) {
|
|
185
|
+
console.log(`🔎 [ComponentResolver] Found ${matchingNames.length} components with name "${spec.name}":`,
|
|
186
|
+
matchingNames.map((c: any) => ({
|
|
187
|
+
ID: c.ID,
|
|
188
|
+
Name: c.Name,
|
|
189
|
+
Namespace: c.Namespace,
|
|
190
|
+
Version: c.Version,
|
|
191
|
+
Status: c.Status
|
|
192
|
+
}))
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
136
196
|
const component = this.componentEngine.Components?.find(
|
|
137
197
|
(c: any) => c.Name === spec.name &&
|
|
138
198
|
c.Namespace === (spec.namespace || namespace)
|
|
139
199
|
);
|
|
140
200
|
|
|
141
201
|
if (component) {
|
|
202
|
+
console.log(`✅ [ComponentResolver] Found component in DB:`, {
|
|
203
|
+
ID: component.ID,
|
|
204
|
+
Name: component.Name,
|
|
205
|
+
Namespace: component.Namespace,
|
|
206
|
+
Version: component.Version
|
|
207
|
+
});
|
|
208
|
+
|
|
142
209
|
// Get compiled component from registry service
|
|
143
210
|
const compiledComponent = await this.registryService.getCompiledComponent(
|
|
144
211
|
component.ID,
|
|
@@ -146,10 +213,13 @@ export class ComponentResolver {
|
|
|
146
213
|
contextUser
|
|
147
214
|
);
|
|
148
215
|
resolved[spec.name] = compiledComponent;
|
|
216
|
+
console.log(`📦 [ComponentResolver] Successfully compiled and resolved: ${spec.name}, type: ${typeof compiledComponent}`);
|
|
217
|
+
|
|
149
218
|
if (this.debug) {
|
|
150
219
|
console.log(`📦 Resolved registry component: ${spec.name} from ${componentId}`);
|
|
151
220
|
}
|
|
152
221
|
} else {
|
|
222
|
+
console.error(`❌❌❌❌❌ [ComponentResolver] Registry component NOT found in database: ${spec.name} with namespace: ${spec.namespace || namespace} ❌❌❌❌`);
|
|
153
223
|
if (this.debug) {
|
|
154
224
|
console.warn(`Registry component not found in database: ${spec.name}`);
|
|
155
225
|
}
|
|
@@ -163,34 +233,37 @@ export class ComponentResolver {
|
|
|
163
233
|
// Embedded component - get from local registry
|
|
164
234
|
// Use the component's specified namespace if it has one, otherwise use parent's namespace
|
|
165
235
|
const componentNamespace = spec.namespace || namespace;
|
|
236
|
+
console.log(`🔍 [ComponentResolver] Looking for embedded component: ${spec.name} in namespace: ${componentNamespace}`);
|
|
237
|
+
|
|
166
238
|
const component = this.registry.get(spec.name, componentNamespace);
|
|
167
239
|
if (component) {
|
|
168
240
|
resolved[spec.name] = component;
|
|
241
|
+
console.log(`✅ [ComponentResolver] Found embedded component: ${spec.name}, type: ${typeof component}`);
|
|
169
242
|
if (this.debug) {
|
|
170
243
|
console.log(`📄 Resolved embedded component: ${spec.name} from namespace ${componentNamespace}, type:`, typeof component);
|
|
171
244
|
}
|
|
172
245
|
} else {
|
|
173
246
|
// If not found with specified namespace, try the parent namespace as fallback
|
|
247
|
+
console.log(`⚠️ [ComponentResolver] Not found in namespace ${componentNamespace}, trying fallback namespace: ${namespace}`);
|
|
174
248
|
const fallbackComponent = this.registry.get(spec.name, namespace);
|
|
175
249
|
if (fallbackComponent) {
|
|
176
250
|
resolved[spec.name] = fallbackComponent;
|
|
251
|
+
console.log(`✅ [ComponentResolver] Found embedded component in fallback namespace: ${spec.name}, type: ${typeof fallbackComponent}`);
|
|
177
252
|
if (this.debug) {
|
|
178
253
|
console.log(`📄 Resolved embedded component: ${spec.name} from fallback namespace ${namespace}, type:`, typeof fallbackComponent);
|
|
179
254
|
}
|
|
180
255
|
} else {
|
|
181
256
|
// Component not found - this might cause issues later
|
|
257
|
+
console.error(`❌ [ComponentResolver] Could not resolve embedded component: ${spec.name} in namespace ${componentNamespace} or ${namespace}`);
|
|
182
258
|
console.warn(`⚠️ Could not resolve embedded component: ${spec.name} in namespace ${componentNamespace} or ${namespace}`);
|
|
183
259
|
// Store undefined explicitly so we know it failed to resolve
|
|
184
260
|
resolved[spec.name] = undefined;
|
|
185
261
|
}
|
|
186
262
|
}
|
|
187
263
|
}
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
for (const child of children) {
|
|
192
|
-
await this.resolveComponentHierarchy(child, resolved, namespace, visited, contextUser);
|
|
193
|
-
}
|
|
264
|
+
|
|
265
|
+
// Child components have already been processed at the beginning of this method
|
|
266
|
+
// No need to process them again - we're using depth-first, post-order traversal
|
|
194
267
|
}
|
|
195
268
|
|
|
196
269
|
/**
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
import {
|
|
8
8
|
CompilationResult,
|
|
9
9
|
CompileOptions,
|
|
10
|
-
RuntimeContext
|
|
10
|
+
RuntimeContext,
|
|
11
|
+
CompiledComponent
|
|
11
12
|
} from '../types';
|
|
12
13
|
import { ComponentCompiler } from '../compiler';
|
|
13
14
|
import { ComponentRegistry } from '../registry';
|
|
@@ -94,31 +95,97 @@ export class ComponentHierarchyRegistrar {
|
|
|
94
95
|
const errors: ComponentRegistrationError[] = [];
|
|
95
96
|
const warnings: string[] = [];
|
|
96
97
|
|
|
97
|
-
//
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
// PHASE 1: Compile all components first (but defer factory execution)
|
|
99
|
+
const compiledMap = new Map<string, CompiledComponent>();
|
|
100
|
+
const specMap = new Map<string, ComponentSpec>();
|
|
101
|
+
|
|
102
|
+
// Helper to compile a component without calling its factory
|
|
103
|
+
const compileOnly = async (spec: ComponentSpec): Promise<{ success: boolean; error?: ComponentRegistrationError }> => {
|
|
104
|
+
if (!spec.code) return { success: true };
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const compileOptions: CompileOptions = {
|
|
108
|
+
componentName: spec.name,
|
|
109
|
+
componentCode: spec.code,
|
|
110
|
+
styles,
|
|
111
|
+
libraries: spec.libraries,
|
|
112
|
+
dependencies: spec.dependencies,
|
|
113
|
+
allLibraries: options.allLibraries
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const result = await this.compiler.compile(compileOptions);
|
|
117
|
+
if (result.success && result.component) {
|
|
118
|
+
compiledMap.set(spec.name, result.component);
|
|
119
|
+
specMap.set(spec.name, spec);
|
|
120
|
+
return { success: true };
|
|
121
|
+
} else {
|
|
122
|
+
return {
|
|
123
|
+
success: false,
|
|
124
|
+
error: {
|
|
125
|
+
componentName: spec.name,
|
|
126
|
+
error: result.error?.message || 'Unknown compilation error',
|
|
127
|
+
phase: 'compilation'
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
error: {
|
|
135
|
+
componentName: spec.name,
|
|
136
|
+
error: error instanceof Error ? error.message : String(error),
|
|
137
|
+
phase: 'compilation'
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Compile all components in hierarchy
|
|
144
|
+
const compileQueue = [rootSpec];
|
|
145
|
+
const visited = new Set<string>();
|
|
146
|
+
|
|
147
|
+
while (compileQueue.length > 0) {
|
|
148
|
+
const spec = compileQueue.shift()!;
|
|
149
|
+
if (visited.has(spec.name)) continue;
|
|
150
|
+
visited.add(spec.name);
|
|
151
|
+
|
|
152
|
+
const result = await compileOnly(spec);
|
|
153
|
+
if (!result.success) {
|
|
154
|
+
errors.push(result.error!);
|
|
155
|
+
if (!continueOnError) {
|
|
156
|
+
return { success: false, registeredComponents, errors, warnings };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (spec.dependencies) {
|
|
161
|
+
compileQueue.push(...spec.dependencies);
|
|
109
162
|
}
|
|
110
163
|
}
|
|
111
|
-
|
|
112
|
-
//
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
164
|
+
|
|
165
|
+
// PHASE 2: Execute all factories with components available
|
|
166
|
+
for (const [name, compiled] of compiledMap) {
|
|
167
|
+
const spec = specMap.get(name)!;
|
|
168
|
+
|
|
169
|
+
// Build components object from all registered components
|
|
170
|
+
const components: Record<string, any> = {};
|
|
171
|
+
for (const [depName, depCompiled] of compiledMap) {
|
|
172
|
+
// Call factory to get ComponentObject, then extract React component
|
|
173
|
+
const depObject = depCompiled.factory(this.runtimeContext, styles);
|
|
174
|
+
components[depName] = depObject.component;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Now call factory with components available
|
|
178
|
+
const componentObject = compiled.factory(this.runtimeContext, styles, components);
|
|
179
|
+
|
|
180
|
+
// Register in registry
|
|
181
|
+
this.registry.register(
|
|
182
|
+
spec.name,
|
|
183
|
+
componentObject,
|
|
184
|
+
spec.namespace || namespace,
|
|
185
|
+
version
|
|
121
186
|
);
|
|
187
|
+
|
|
188
|
+
registeredComponents.push(spec.name);
|
|
122
189
|
}
|
|
123
190
|
|
|
124
191
|
return {
|
|
@@ -198,15 +265,14 @@ export class ComponentHierarchyRegistrar {
|
|
|
198
265
|
}
|
|
199
266
|
|
|
200
267
|
// Call the factory to create the ComponentObject
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
hasPrint: 'print' in componentObject,
|
|
208
|
-
hasRefresh: 'refresh' in componentObject
|
|
268
|
+
// IMPORTANT: We don't pass components here because child components may not be registered yet
|
|
269
|
+
// Components are resolved later when the component is actually rendered
|
|
270
|
+
console.log(`🏭 Calling factory for ${spec.name} with runtime context:`, {
|
|
271
|
+
hasReact: !!this.runtimeContext.React,
|
|
272
|
+
hasReactDOM: !!this.runtimeContext.ReactDOM,
|
|
273
|
+
libraryKeys: Object.keys(this.runtimeContext.libraries || {})
|
|
209
274
|
});
|
|
275
|
+
const componentObject = compilationResult.component!.factory(this.runtimeContext, styles);
|
|
210
276
|
|
|
211
277
|
// Register the full ComponentObject (not just the React component)
|
|
212
278
|
this.registry.register(
|
package/src/types/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { ComponentLibraryDependency, ComponentStyles, ComponentObject } from '@m
|
|
|
13
13
|
*/
|
|
14
14
|
export interface CompiledComponent {
|
|
15
15
|
/** Factory function that creates a ComponentObject when called with context */
|
|
16
|
-
factory: (context: RuntimeContext, styles?: ComponentStyles) => ComponentObject;
|
|
16
|
+
factory: (context: RuntimeContext, styles?: ComponentStyles, components?: Record<string, any>) => ComponentObject;
|
|
17
17
|
/** Unique identifier for the component */
|
|
18
18
|
id: string;
|
|
19
19
|
/** Original component name */
|