@memberjunction/react-runtime 2.99.0 → 2.100.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 +15 -20
- package/CHANGELOG.md +14 -0
- package/README.md +171 -1
- package/dist/compiler/component-compiler.d.ts.map +1 -1
- package/dist/compiler/component-compiler.js +10 -1
- package/dist/compiler/component-compiler.js.map +1 -1
- package/dist/component-manager/component-manager.d.ts +39 -0
- package/dist/component-manager/component-manager.d.ts.map +1 -0
- package/dist/component-manager/component-manager.js +474 -0
- package/dist/component-manager/component-manager.js.map +1 -0
- package/dist/component-manager/index.d.ts +3 -0
- package/dist/component-manager/index.d.ts.map +1 -0
- package/dist/component-manager/index.js +6 -0
- package/dist/component-manager/index.js.map +1 -0
- package/dist/component-manager/types.d.ts +62 -0
- package/dist/component-manager/types.d.ts.map +1 -0
- package/dist/component-manager/types.js +3 -0
- package/dist/component-manager/types.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/registry/component-registry-service.d.ts +16 -1
- package/dist/registry/component-registry-service.d.ts.map +1 -1
- package/dist/registry/component-registry-service.js +212 -10
- package/dist/registry/component-registry-service.js.map +1 -1
- package/dist/registry/component-registry.d.ts +1 -1
- package/dist/registry/component-registry.d.ts.map +1 -1
- 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 +122 -52
- package/dist/registry/component-resolver.js.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js.map +1 -1
- package/dist/runtime/component-hierarchy.d.ts +4 -0
- package/dist/runtime/component-hierarchy.d.ts.map +1 -1
- package/dist/runtime/component-hierarchy.js +127 -12
- package/dist/runtime/component-hierarchy.js.map +1 -1
- package/dist/runtime.umd.js +535 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/library-loader.d.ts +3 -0
- package/dist/utilities/library-loader.d.ts.map +1 -1
- package/dist/utilities/library-loader.js +85 -17
- package/dist/utilities/library-loader.js.map +1 -1
- package/examples/component-registry-integration.ts +191 -0
- package/package.json +6 -5
- package/src/compiler/component-compiler.ts +14 -1
- package/src/component-manager/component-manager.ts +736 -0
- package/src/component-manager/index.ts +13 -0
- package/src/component-manager/types.ts +204 -0
- package/src/index.ts +27 -1
- package/src/registry/component-registry-service.ts +315 -18
- package/src/registry/component-registry.ts +1 -1
- package/src/registry/component-resolver.ts +159 -67
- package/src/registry/index.ts +1 -1
- package/src/runtime/component-hierarchy.ts +124 -13
- package/src/types/index.ts +2 -0
- package/src/utilities/library-loader.ts +133 -22
|
@@ -68,9 +68,16 @@ export class ComponentResolver {
|
|
|
68
68
|
namespace: string = 'Global',
|
|
69
69
|
contextUser?: UserInfo
|
|
70
70
|
): Promise<ResolvedComponents> {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
console.log(`🚀 [ComponentResolver] Starting component resolution for: ${spec.name}`);
|
|
72
|
+
console.log(`📋 [ComponentResolver] Root component spec:`, {
|
|
73
|
+
name: spec.name,
|
|
74
|
+
location: spec.location,
|
|
75
|
+
registry: spec.registry,
|
|
76
|
+
namespace: spec.namespace,
|
|
77
|
+
hasCode: !!spec.code,
|
|
78
|
+
hasDependencies: !!(spec.dependencies && spec.dependencies.length > 0)
|
|
79
|
+
});
|
|
80
|
+
|
|
74
81
|
if (this.debug) {
|
|
75
82
|
console.log(`📋 [ComponentResolver] Dependencies to resolve:`, (spec.dependencies || []).map(d => ({
|
|
76
83
|
name: d.name,
|
|
@@ -93,7 +100,15 @@ export class ComponentResolver {
|
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
// Resolve the component hierarchy
|
|
103
|
+
console.log(`🔄 [ComponentResolver] About to call resolveComponentHierarchy for root: ${spec.name}`);
|
|
96
104
|
await this.resolveComponentHierarchy(spec, resolved, namespace, new Set(), contextUser);
|
|
105
|
+
console.log(`✅ [ComponentResolver] Returned from resolveComponentHierarchy`);
|
|
106
|
+
console.log(`🔍 [ComponentResolver] Looking for root component '${spec.name}' in resolved:`, !!resolved[spec.name]);
|
|
107
|
+
|
|
108
|
+
if (!resolved[spec.name]) {
|
|
109
|
+
console.error(`❌ [ComponentResolver] Root component '${spec.name}' was NOT added to resolved map!`);
|
|
110
|
+
console.log(`📦 [ComponentResolver] What IS in resolved map:`, Object.keys(resolved));
|
|
111
|
+
}
|
|
97
112
|
|
|
98
113
|
if (this.debug) {
|
|
99
114
|
console.log(`📊 [ComponentResolver] Resolved components before unwrapping:`, Object.keys(resolved));
|
|
@@ -196,62 +211,96 @@ export class ComponentResolver {
|
|
|
196
211
|
// Registry component - need to load from database or external source
|
|
197
212
|
if (this.debug) {
|
|
198
213
|
console.log(`🔍 [ComponentResolver] Looking for registry component: ${spec.name} in namespace: ${spec.namespace || namespace}`);
|
|
214
|
+
if (spec.registry) {
|
|
215
|
+
console.log(` 📍 [ComponentResolver] External registry specified: ${spec.registry}`);
|
|
216
|
+
} else {
|
|
217
|
+
console.log(` 📍 [ComponentResolver] Local registry (no registry field specified)`);
|
|
218
|
+
}
|
|
199
219
|
}
|
|
200
220
|
|
|
201
221
|
try {
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Log all matching names to see duplicates
|
|
209
|
-
const matchingNames = allComponents.filter((c: any) => c.Name === spec.name);
|
|
210
|
-
if (matchingNames.length > 0 && this.debug) {
|
|
211
|
-
console.log(`🔎 [ComponentResolver] Found ${matchingNames.length} components with name "${spec.name}":`,
|
|
212
|
-
matchingNames.map((c: any) => ({
|
|
213
|
-
ID: c.ID,
|
|
214
|
-
Name: c.Name,
|
|
215
|
-
Namespace: c.Namespace,
|
|
216
|
-
Version: c.Version,
|
|
217
|
-
Status: c.Status
|
|
218
|
-
}))
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const component = this.componentEngine.Components?.find(
|
|
223
|
-
(c: any) => c.Name === spec.name &&
|
|
224
|
-
c.Namespace === (spec.namespace || namespace)
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
if (component) {
|
|
222
|
+
// If spec.registry is populated, this is an external registry component
|
|
223
|
+
// If spec.registry is blank/undefined, this is a local registry component
|
|
224
|
+
if (spec.registry) {
|
|
225
|
+
// EXTERNAL REGISTRY: Need to fetch from external registry via GraphQL
|
|
228
226
|
if (this.debug) {
|
|
229
|
-
console.log(
|
|
230
|
-
ID: component.ID,
|
|
231
|
-
Name: component.Name,
|
|
232
|
-
Namespace: component.Namespace,
|
|
233
|
-
Version: component.Version
|
|
234
|
-
});
|
|
227
|
+
console.log(`🌐 [ComponentResolver] Fetching from external registry: ${spec.registry}`);
|
|
235
228
|
}
|
|
236
229
|
|
|
237
|
-
// Get compiled component from registry service
|
|
238
|
-
const compiledComponent = await this.registryService.
|
|
239
|
-
|
|
230
|
+
// Get compiled component from registry service (which will handle the external fetch)
|
|
231
|
+
const compiledComponent = await this.registryService.getCompiledComponentFromRegistry(
|
|
232
|
+
spec.registry, // Registry name
|
|
233
|
+
spec.namespace || namespace,
|
|
234
|
+
spec.name,
|
|
235
|
+
spec.version || 'latest',
|
|
240
236
|
this.resolverInstanceId,
|
|
241
237
|
contextUser
|
|
242
238
|
);
|
|
243
|
-
|
|
239
|
+
|
|
240
|
+
if (compiledComponent) {
|
|
241
|
+
resolved[spec.name] = compiledComponent;
|
|
242
|
+
if (this.debug) {
|
|
243
|
+
console.log(`✅ [ComponentResolver] Successfully fetched and compiled from external registry: ${spec.name}`);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
console.error(`❌ [ComponentResolver] Failed to fetch from external registry: ${spec.name} from ${spec.registry}`);
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
// LOCAL REGISTRY: Get from local database
|
|
244
250
|
if (this.debug) {
|
|
245
|
-
console.log(
|
|
251
|
+
console.log(`💾 [ComponentResolver] Looking for locally registered component`);
|
|
246
252
|
}
|
|
247
253
|
|
|
254
|
+
// First, try to find the component in the metadata engine
|
|
255
|
+
const allComponents = this.componentEngine.Components || [];
|
|
248
256
|
if (this.debug) {
|
|
249
|
-
console.log(
|
|
257
|
+
console.log(`📊 [ComponentResolver] Total components in engine: ${allComponents.length}`);
|
|
250
258
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
|
|
260
|
+
// Log all matching names to see duplicates
|
|
261
|
+
const matchingNames = allComponents.filter((c: any) => c.Name === spec.name);
|
|
262
|
+
if (matchingNames.length > 0 && this.debug) {
|
|
263
|
+
console.log(`🔎 [ComponentResolver] Found ${matchingNames.length} components with name "${spec.name}":`,
|
|
264
|
+
matchingNames.map((c: any) => ({
|
|
265
|
+
ID: c.ID,
|
|
266
|
+
Name: c.Name,
|
|
267
|
+
Namespace: c.Namespace,
|
|
268
|
+
Version: c.Version,
|
|
269
|
+
Status: c.Status
|
|
270
|
+
}))
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const component = this.componentEngine.Components?.find(
|
|
275
|
+
(c: any) => c.Name === spec.name &&
|
|
276
|
+
c.Namespace === (spec.namespace || namespace)
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
if (component) {
|
|
280
|
+
if (this.debug) {
|
|
281
|
+
console.log(`✅ [ComponentResolver] Found component in local DB:`, {
|
|
282
|
+
ID: component.ID,
|
|
283
|
+
Name: component.Name,
|
|
284
|
+
Namespace: component.Namespace,
|
|
285
|
+
Version: component.Version
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Get compiled component from registry service (local compilation)
|
|
290
|
+
const compiledComponent = await this.registryService.getCompiledComponent(
|
|
291
|
+
component.ID,
|
|
292
|
+
this.resolverInstanceId,
|
|
293
|
+
contextUser
|
|
294
|
+
);
|
|
295
|
+
resolved[spec.name] = compiledComponent;
|
|
296
|
+
if (this.debug) {
|
|
297
|
+
console.log(`📦 [ComponentResolver] Successfully compiled and resolved local component: ${spec.name}, type: ${typeof compiledComponent}`);
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
console.error(`❌ [ComponentResolver] Local registry component NOT found in database: ${spec.name} with namespace: ${spec.namespace || namespace}`);
|
|
301
|
+
if (this.debug) {
|
|
302
|
+
console.warn(`Local registry component not found in database: ${spec.name}`);
|
|
303
|
+
}
|
|
255
304
|
}
|
|
256
305
|
}
|
|
257
306
|
} catch (error) {
|
|
@@ -260,44 +309,87 @@ export class ComponentResolver {
|
|
|
260
309
|
}
|
|
261
310
|
}
|
|
262
311
|
} else {
|
|
263
|
-
// Embedded component
|
|
312
|
+
// Embedded/Local component
|
|
264
313
|
// Use the component's specified namespace if it has one, otherwise use parent's namespace
|
|
265
314
|
const componentNamespace = spec.namespace || namespace;
|
|
266
|
-
if (this.debug) {
|
|
267
|
-
console.log(`🔍 [ComponentResolver] Looking for embedded component: ${spec.name} in namespace: ${componentNamespace}`);
|
|
268
|
-
}
|
|
269
315
|
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
resolved[spec.name] = component;
|
|
316
|
+
// First check if component has inline code that needs compilation
|
|
317
|
+
if (spec.code && this.compiler) {
|
|
273
318
|
if (this.debug) {
|
|
274
|
-
console.log(
|
|
319
|
+
console.log(`🔨 [ComponentResolver] Component ${spec.name} has inline code, compiling...`);
|
|
275
320
|
}
|
|
276
|
-
|
|
277
|
-
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
// Compile the component with its code
|
|
324
|
+
const compilationResult = await this.compiler.compile({
|
|
325
|
+
componentName: spec.name,
|
|
326
|
+
componentCode: spec.code,
|
|
327
|
+
libraries: spec.libraries,
|
|
328
|
+
dependencies: spec.dependencies,
|
|
329
|
+
allLibraries: [] // TODO: Get from ComponentMetadataEngine if needed
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
if (compilationResult.success && compilationResult.component) {
|
|
333
|
+
// Get the component object from the factory (only if we have runtimeContext)
|
|
334
|
+
if (!this.runtimeContext) {
|
|
335
|
+
console.error(`❌ [ComponentResolver] Cannot compile without runtime context`);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const componentObject = compilationResult.component.factory(this.runtimeContext);
|
|
339
|
+
|
|
340
|
+
// Register it in the local registry for future use
|
|
341
|
+
this.registry.register(spec.name, componentObject, componentNamespace, spec.version || 'latest');
|
|
342
|
+
|
|
343
|
+
// Add to resolved
|
|
344
|
+
resolved[spec.name] = componentObject;
|
|
345
|
+
|
|
346
|
+
if (this.debug) {
|
|
347
|
+
console.log(`✅ [ComponentResolver] Successfully compiled and registered inline component: ${spec.name}`);
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
console.error(`❌ [ComponentResolver] Failed to compile inline component ${spec.name}:`, compilationResult.error);
|
|
351
|
+
}
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error(`❌ [ComponentResolver] Error compiling inline component ${spec.name}:`, error);
|
|
278
354
|
}
|
|
279
355
|
} else {
|
|
280
|
-
//
|
|
356
|
+
// No inline code, try to get from local registry
|
|
281
357
|
if (this.debug) {
|
|
282
|
-
console.log(
|
|
358
|
+
console.log(`🔍 [ComponentResolver] Looking for embedded component: ${spec.name} in namespace: ${componentNamespace}`);
|
|
283
359
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
360
|
+
|
|
361
|
+
const component = this.registry.get(spec.name, componentNamespace);
|
|
362
|
+
if (component) {
|
|
363
|
+
resolved[spec.name] = component;
|
|
287
364
|
if (this.debug) {
|
|
288
|
-
console.log(`✅ [ComponentResolver] Found embedded component
|
|
365
|
+
console.log(`✅ [ComponentResolver] Found embedded component: ${spec.name}, type: ${typeof component}`);
|
|
289
366
|
}
|
|
290
367
|
if (this.debug) {
|
|
291
|
-
console.log(`📄 Resolved embedded component: ${spec.name} from
|
|
368
|
+
console.log(`📄 Resolved embedded component: ${spec.name} from namespace ${componentNamespace}, type:`, typeof component);
|
|
292
369
|
}
|
|
293
370
|
} else {
|
|
294
|
-
//
|
|
295
|
-
console.error(`❌ [ComponentResolver] Could not resolve embedded component: ${spec.name} in namespace ${componentNamespace} or ${namespace}`);
|
|
371
|
+
// If not found with specified namespace, try the parent namespace as fallback
|
|
296
372
|
if (this.debug) {
|
|
297
|
-
console.
|
|
373
|
+
console.log(`⚠️ [ComponentResolver] Not found in namespace ${componentNamespace}, trying fallback namespace: ${namespace}`);
|
|
374
|
+
}
|
|
375
|
+
const fallbackComponent = this.registry.get(spec.name, namespace);
|
|
376
|
+
if (fallbackComponent) {
|
|
377
|
+
resolved[spec.name] = fallbackComponent;
|
|
378
|
+
if (this.debug) {
|
|
379
|
+
console.log(`✅ [ComponentResolver] Found embedded component in fallback namespace: ${spec.name}, type: ${typeof fallbackComponent}`);
|
|
380
|
+
}
|
|
381
|
+
if (this.debug) {
|
|
382
|
+
console.log(`📄 Resolved embedded component: ${spec.name} from fallback namespace ${namespace}, type:`, typeof fallbackComponent);
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
// Component not found - this might cause issues later
|
|
386
|
+
console.error(`❌ [ComponentResolver] Could not resolve embedded component: ${spec.name} in namespace ${componentNamespace} or ${namespace}`);
|
|
387
|
+
if (this.debug) {
|
|
388
|
+
console.warn(`⚠️ Could not resolve embedded component: ${spec.name} in namespace ${componentNamespace} or ${namespace}`);
|
|
389
|
+
}
|
|
390
|
+
// Store undefined explicitly so we know it failed to resolve
|
|
391
|
+
resolved[spec.name] = undefined;
|
|
298
392
|
}
|
|
299
|
-
// Store undefined explicitly so we know it failed to resolve
|
|
300
|
-
resolved[spec.name] = undefined;
|
|
301
393
|
}
|
|
302
394
|
}
|
|
303
395
|
}
|
package/src/registry/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
export { ComponentRegistry } from './component-registry';
|
|
7
7
|
export { ComponentResolver, ResolvedComponents } from './component-resolver';
|
|
8
|
-
export { ComponentRegistryService } from './component-registry-service';
|
|
8
|
+
export { ComponentRegistryService, IComponentRegistryClient } from './component-registry-service';
|
|
9
9
|
export {
|
|
10
10
|
RegistryProvider,
|
|
11
11
|
RegistryComponentMetadata,
|
|
@@ -14,7 +14,7 @@ import { ComponentCompiler } from '../compiler';
|
|
|
14
14
|
import { ComponentRegistry } from '../registry';
|
|
15
15
|
|
|
16
16
|
import { ComponentSpec, ComponentStyles } from '@memberjunction/interactive-component-types';
|
|
17
|
-
import { UserInfo } from '@memberjunction/core';
|
|
17
|
+
import { UserInfo, Metadata } from '@memberjunction/core';
|
|
18
18
|
import { ComponentLibraryEntity } from '@memberjunction/core-entities';
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -25,6 +25,8 @@ export interface HierarchyRegistrationResult {
|
|
|
25
25
|
registeredComponents: string[];
|
|
26
26
|
errors: ComponentRegistrationError[];
|
|
27
27
|
warnings: string[];
|
|
28
|
+
/** The fully resolved component specification with all dependencies and libraries */
|
|
29
|
+
resolvedSpec?: ComponentSpec;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -55,6 +57,8 @@ export interface HierarchyRegistrationOptions {
|
|
|
55
57
|
*/
|
|
56
58
|
allLibraries: ComponentLibraryEntity[];
|
|
57
59
|
debug?: boolean;
|
|
60
|
+
/** Optional user context for fetching from external registries */
|
|
61
|
+
contextUser?: UserInfo;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
/**
|
|
@@ -66,6 +70,44 @@ export class ComponentHierarchyRegistrar {
|
|
|
66
70
|
private registry: ComponentRegistry,
|
|
67
71
|
private runtimeContext: RuntimeContext
|
|
68
72
|
) {}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Fetches a component specification from an external registry
|
|
76
|
+
*/
|
|
77
|
+
private async fetchExternalComponent(
|
|
78
|
+
spec: ComponentSpec,
|
|
79
|
+
contextUser?: UserInfo
|
|
80
|
+
): Promise<ComponentSpec | null> {
|
|
81
|
+
try {
|
|
82
|
+
const provider = Metadata?.Provider;
|
|
83
|
+
if (!provider || !(provider as any).ExecuteGQL) {
|
|
84
|
+
console.warn('⚠️ [ComponentHierarchyRegistrar] No GraphQL provider available for external registry fetch');
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Dynamically import the GraphQL client to avoid circular dependencies
|
|
89
|
+
const { GraphQLComponentRegistryClient } = await import('@memberjunction/graphql-dataprovider');
|
|
90
|
+
const graphQLClient = new GraphQLComponentRegistryClient(provider as any);
|
|
91
|
+
|
|
92
|
+
const fullSpec = await graphQLClient.GetRegistryComponent({
|
|
93
|
+
registryName: spec.registry!,
|
|
94
|
+
namespace: spec.namespace || 'Global',
|
|
95
|
+
name: spec.name,
|
|
96
|
+
version: spec.version || 'latest'
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (fullSpec && fullSpec.code) {
|
|
100
|
+
console.log(`✅ [ComponentHierarchyRegistrar] Fetched external component ${spec.name} with code (${fullSpec.code.length} chars)`);
|
|
101
|
+
return fullSpec;
|
|
102
|
+
} else {
|
|
103
|
+
console.warn(`⚠️ [ComponentHierarchyRegistrar] Failed to fetch external component ${spec.name} or no code`);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error(`❌ [ComponentHierarchyRegistrar] Error fetching external component ${spec.name}:`, error);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
69
111
|
|
|
70
112
|
/**
|
|
71
113
|
* Registers a complete component hierarchy from a root specification
|
|
@@ -77,6 +119,12 @@ export class ComponentHierarchyRegistrar {
|
|
|
77
119
|
rootSpec: ComponentSpec,
|
|
78
120
|
options: HierarchyRegistrationOptions
|
|
79
121
|
): Promise<HierarchyRegistrationResult> {
|
|
122
|
+
// If this is an external registry component without code, fetch it first
|
|
123
|
+
let resolvedRootSpec = rootSpec;
|
|
124
|
+
if (rootSpec.location === 'registry' && rootSpec.registry && !rootSpec.code) {
|
|
125
|
+
console.log(`🌐 [ComponentHierarchyRegistrar] Fetching external registry component: ${rootSpec.registry}/${rootSpec.name}`);
|
|
126
|
+
resolvedRootSpec = await this.fetchExternalComponent(rootSpec, options.contextUser) || rootSpec;
|
|
127
|
+
}
|
|
80
128
|
const {
|
|
81
129
|
styles,
|
|
82
130
|
namespace = 'Global',
|
|
@@ -86,10 +134,10 @@ export class ComponentHierarchyRegistrar {
|
|
|
86
134
|
} = options;
|
|
87
135
|
|
|
88
136
|
console.log('🌳 ComponentHierarchyRegistrar.registerHierarchy:', {
|
|
89
|
-
rootComponent:
|
|
90
|
-
hasLibraries: !!(
|
|
91
|
-
libraryCount:
|
|
92
|
-
libraries:
|
|
137
|
+
rootComponent: resolvedRootSpec.name,
|
|
138
|
+
hasLibraries: !!(resolvedRootSpec.libraries && resolvedRootSpec.libraries.length > 0),
|
|
139
|
+
libraryCount: resolvedRootSpec.libraries?.length || 0,
|
|
140
|
+
libraries: resolvedRootSpec.libraries?.map(l => l.name)
|
|
93
141
|
});
|
|
94
142
|
|
|
95
143
|
const registeredComponents: string[] = [];
|
|
@@ -99,17 +147,26 @@ export class ComponentHierarchyRegistrar {
|
|
|
99
147
|
// PHASE 1: Compile all components first (but defer factory execution)
|
|
100
148
|
const compiledMap = new Map<string, CompiledComponent>();
|
|
101
149
|
const specMap = new Map<string, ComponentSpec>();
|
|
150
|
+
const allLoadedLibraries = new Map<string, any>(); // Track all loaded libraries
|
|
102
151
|
|
|
103
152
|
// Helper to compile a component without calling its factory
|
|
104
153
|
const compileOnly = async (spec: ComponentSpec): Promise<{ success: boolean; error?: ComponentRegistrationError }> => {
|
|
105
154
|
if (!spec.code) return { success: true };
|
|
106
155
|
|
|
107
156
|
try {
|
|
157
|
+
// Filter out invalid library entries before compilation
|
|
158
|
+
const validLibraries = spec.libraries?.filter(lib => {
|
|
159
|
+
if (!lib || typeof lib !== 'object') return false;
|
|
160
|
+
if (!lib.name || lib.name === 'unknown' || lib.name === 'null' || lib.name === 'undefined') return false;
|
|
161
|
+
if (!lib.globalVariable || lib.globalVariable === 'undefined' || lib.globalVariable === 'null') return false;
|
|
162
|
+
return true;
|
|
163
|
+
});
|
|
164
|
+
|
|
108
165
|
const compileOptions: CompileOptions = {
|
|
109
166
|
componentName: spec.name,
|
|
110
167
|
componentCode: spec.code,
|
|
111
168
|
styles,
|
|
112
|
-
libraries:
|
|
169
|
+
libraries: validLibraries,
|
|
113
170
|
dependencies: spec.dependencies,
|
|
114
171
|
allLibraries: options.allLibraries
|
|
115
172
|
};
|
|
@@ -118,6 +175,17 @@ export class ComponentHierarchyRegistrar {
|
|
|
118
175
|
if (result.success && result.component) {
|
|
119
176
|
compiledMap.set(spec.name, result.component);
|
|
120
177
|
specMap.set(spec.name, spec);
|
|
178
|
+
|
|
179
|
+
// Extract and accumulate loaded libraries from the compilation
|
|
180
|
+
if (result.loadedLibraries) {
|
|
181
|
+
result.loadedLibraries.forEach((value, key) => {
|
|
182
|
+
if (!allLoadedLibraries.has(key)) {
|
|
183
|
+
allLoadedLibraries.set(key, value);
|
|
184
|
+
console.log(`📚 [registerHierarchy] Added library ${key} to accumulated libraries`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
121
189
|
return { success: true };
|
|
122
190
|
} else {
|
|
123
191
|
return {
|
|
@@ -142,19 +210,30 @@ export class ComponentHierarchyRegistrar {
|
|
|
142
210
|
};
|
|
143
211
|
|
|
144
212
|
// Compile all components in hierarchy
|
|
145
|
-
const compileQueue = [
|
|
213
|
+
const compileQueue = [resolvedRootSpec];
|
|
146
214
|
const visited = new Set<string>();
|
|
147
215
|
|
|
148
216
|
while (compileQueue.length > 0) {
|
|
149
|
-
|
|
217
|
+
let spec = compileQueue.shift()!;
|
|
150
218
|
if (visited.has(spec.name)) continue;
|
|
151
219
|
visited.add(spec.name);
|
|
152
220
|
|
|
221
|
+
// If this is an external registry component without code, fetch it first
|
|
222
|
+
if (spec.location === 'registry' && spec.registry && !spec.code) {
|
|
223
|
+
const fetched = await this.fetchExternalComponent(spec, options.contextUser);
|
|
224
|
+
if (fetched) {
|
|
225
|
+
spec = fetched;
|
|
226
|
+
} else {
|
|
227
|
+
console.warn(`⚠️ [ComponentHierarchyRegistrar] Could not fetch external component ${spec.name}, skipping`);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
153
232
|
const result = await compileOnly(spec);
|
|
154
233
|
if (!result.success) {
|
|
155
234
|
errors.push(result.error!);
|
|
156
235
|
if (!continueOnError) {
|
|
157
|
-
return { success: false, registeredComponents, errors, warnings };
|
|
236
|
+
return { success: false, registeredComponents, errors, warnings, resolvedSpec: resolvedRootSpec };
|
|
158
237
|
}
|
|
159
238
|
}
|
|
160
239
|
|
|
@@ -163,6 +242,17 @@ export class ComponentHierarchyRegistrar {
|
|
|
163
242
|
}
|
|
164
243
|
}
|
|
165
244
|
|
|
245
|
+
// Add all accumulated libraries to runtime context
|
|
246
|
+
if (allLoadedLibraries.size > 0) {
|
|
247
|
+
if (!this.runtimeContext.libraries) {
|
|
248
|
+
this.runtimeContext.libraries = {};
|
|
249
|
+
}
|
|
250
|
+
allLoadedLibraries.forEach((value, key) => {
|
|
251
|
+
this.runtimeContext.libraries![key] = value;
|
|
252
|
+
console.log(`✅ [registerHierarchy] Added ${key} to runtime context libraries`);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
166
256
|
// PHASE 2: Execute all factories with components available
|
|
167
257
|
for (const [name, compiled] of compiledMap) {
|
|
168
258
|
const spec = specMap.get(name)!;
|
|
@@ -193,7 +283,8 @@ export class ComponentHierarchyRegistrar {
|
|
|
193
283
|
success: errors.length === 0,
|
|
194
284
|
registeredComponents,
|
|
195
285
|
errors,
|
|
196
|
-
warnings
|
|
286
|
+
warnings,
|
|
287
|
+
resolvedSpec: resolvedRootSpec
|
|
197
288
|
};
|
|
198
289
|
}
|
|
199
290
|
|
|
@@ -237,19 +328,28 @@ export class ComponentHierarchyRegistrar {
|
|
|
237
328
|
};
|
|
238
329
|
}
|
|
239
330
|
|
|
331
|
+
// Filter out invalid library entries before compilation
|
|
332
|
+
const validLibraries = spec.libraries?.filter(lib => {
|
|
333
|
+
if (!lib || typeof lib !== 'object') return false;
|
|
334
|
+
if (!lib.name || lib.name === 'unknown' || lib.name === 'null' || lib.name === 'undefined') return false;
|
|
335
|
+
if (!lib.globalVariable || lib.globalVariable === 'undefined' || lib.globalVariable === 'null') return false;
|
|
336
|
+
return true;
|
|
337
|
+
});
|
|
338
|
+
|
|
240
339
|
// Compile the component
|
|
241
340
|
const compileOptions: CompileOptions = {
|
|
242
341
|
componentName: spec.name,
|
|
243
342
|
componentCode: spec.code,
|
|
244
343
|
styles,
|
|
245
|
-
libraries:
|
|
344
|
+
libraries: validLibraries, // Pass along filtered library dependencies
|
|
246
345
|
dependencies: spec.dependencies, // Pass along child component dependencies
|
|
247
346
|
allLibraries: options.allLibraries
|
|
248
347
|
};
|
|
249
348
|
|
|
250
349
|
console.log(`🔧 Compiling component ${spec.name} with libraries:`, {
|
|
251
|
-
|
|
252
|
-
|
|
350
|
+
originalCount: spec.libraries?.length || 0,
|
|
351
|
+
filteredCount: validLibraries?.length || 0,
|
|
352
|
+
validLibraries: validLibraries?.map(l => ({ name: l.name, globalVariable: l.globalVariable }))
|
|
253
353
|
});
|
|
254
354
|
|
|
255
355
|
const compilationResult = await this.compiler.compile(compileOptions);
|
|
@@ -265,6 +365,17 @@ export class ComponentHierarchyRegistrar {
|
|
|
265
365
|
};
|
|
266
366
|
}
|
|
267
367
|
|
|
368
|
+
// Add loaded libraries to runtime context
|
|
369
|
+
if (compilationResult.loadedLibraries && compilationResult.loadedLibraries.size > 0) {
|
|
370
|
+
if (!this.runtimeContext.libraries) {
|
|
371
|
+
this.runtimeContext.libraries = {};
|
|
372
|
+
}
|
|
373
|
+
compilationResult.loadedLibraries.forEach((value, key) => {
|
|
374
|
+
this.runtimeContext.libraries![key] = value;
|
|
375
|
+
console.log(`✅ [registerSingleComponent] Added ${key} to runtime context libraries`);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
268
379
|
// Call the factory to create the ComponentObject
|
|
269
380
|
// IMPORTANT: We don't pass components here because child components may not be registered yet
|
|
270
381
|
// Components are resolved later when the component is actually rendered
|
package/src/types/index.ts
CHANGED