@memberjunction/react-runtime 2.92.0 → 2.94.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 (87) hide show
  1. package/.turbo/turbo-build.log +14 -16
  2. package/CHANGELOG.md +31 -0
  3. package/README.md +180 -2
  4. package/dist/compiler/babel-config.js.map +1 -1
  5. package/dist/compiler/component-compiler.d.ts.map +1 -1
  6. package/dist/compiler/component-compiler.js +206 -57
  7. package/dist/compiler/component-compiler.js.map +1 -1
  8. package/dist/compiler/index.js.map +1 -1
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +14 -5
  12. package/dist/index.js.map +1 -1
  13. package/dist/registry/component-registry-service.d.ts +37 -0
  14. package/dist/registry/component-registry-service.d.ts.map +1 -0
  15. package/dist/registry/component-registry-service.js +319 -0
  16. package/dist/registry/component-registry-service.js.map +1 -0
  17. package/dist/registry/component-registry.d.ts +4 -3
  18. package/dist/registry/component-registry.d.ts.map +1 -1
  19. package/dist/registry/component-registry.js.map +1 -1
  20. package/dist/registry/component-resolver.d.ts +12 -2
  21. package/dist/registry/component-resolver.d.ts.map +1 -1
  22. package/dist/registry/component-resolver.js +96 -12
  23. package/dist/registry/component-resolver.js.map +1 -1
  24. package/dist/registry/index.d.ts +2 -0
  25. package/dist/registry/index.d.ts.map +1 -1
  26. package/dist/registry/index.js +3 -1
  27. package/dist/registry/index.js.map +1 -1
  28. package/dist/registry/registry-provider.d.ts +54 -0
  29. package/dist/registry/registry-provider.d.ts.map +1 -0
  30. package/dist/registry/registry-provider.js +3 -0
  31. package/dist/registry/registry-provider.js.map +1 -0
  32. package/dist/runtime/component-hierarchy.d.ts.map +1 -1
  33. package/dist/runtime/component-hierarchy.js +8 -2
  34. package/dist/runtime/component-hierarchy.js.map +1 -1
  35. package/dist/runtime/error-boundary.js.map +1 -1
  36. package/dist/runtime/index.js.map +1 -1
  37. package/dist/runtime/prop-builder.d.ts +2 -2
  38. package/dist/runtime/prop-builder.d.ts.map +1 -1
  39. package/dist/runtime/prop-builder.js +32 -14
  40. package/dist/runtime/prop-builder.js.map +1 -1
  41. package/dist/runtime/react-root-manager.js.map +1 -1
  42. package/dist/runtime.umd.js +1 -1
  43. package/dist/types/dependency-types.d.ts +62 -0
  44. package/dist/types/dependency-types.d.ts.map +1 -0
  45. package/dist/types/dependency-types.js +3 -0
  46. package/dist/types/dependency-types.js.map +1 -0
  47. package/dist/types/index.d.ts +8 -10
  48. package/dist/types/index.d.ts.map +1 -1
  49. package/dist/types/index.js +1 -0
  50. package/dist/types/index.js.map +1 -1
  51. package/dist/types/library-config.js.map +1 -1
  52. package/dist/utilities/cache-manager.js.map +1 -1
  53. package/dist/utilities/component-error-analyzer.js.map +1 -1
  54. package/dist/utilities/component-styles.js.map +1 -1
  55. package/dist/utilities/core-libraries.js.map +1 -1
  56. package/dist/utilities/index.d.ts +1 -0
  57. package/dist/utilities/index.d.ts.map +1 -1
  58. package/dist/utilities/index.js +1 -0
  59. package/dist/utilities/index.js.map +1 -1
  60. package/dist/utilities/library-dependency-resolver.d.ts +19 -0
  61. package/dist/utilities/library-dependency-resolver.d.ts.map +1 -0
  62. package/dist/utilities/library-dependency-resolver.js +410 -0
  63. package/dist/utilities/library-dependency-resolver.js.map +1 -0
  64. package/dist/utilities/library-loader.d.ts +9 -0
  65. package/dist/utilities/library-loader.d.ts.map +1 -1
  66. package/dist/utilities/library-loader.js +143 -0
  67. package/dist/utilities/library-loader.js.map +1 -1
  68. package/dist/utilities/library-registry.js.map +1 -1
  69. package/dist/utilities/resource-manager.js.map +1 -1
  70. package/dist/utilities/standard-libraries.js.map +1 -1
  71. package/package.json +5 -6
  72. package/src/compiler/component-compiler.ts +227 -77
  73. package/src/index.ts +21 -5
  74. package/src/registry/component-registry-service.ts +578 -0
  75. package/src/registry/component-registry.ts +8 -7
  76. package/src/registry/component-resolver.ts +146 -16
  77. package/src/registry/index.ts +9 -0
  78. package/src/registry/registry-provider.ts +119 -0
  79. package/src/runtime/component-hierarchy.ts +13 -5
  80. package/src/runtime/prop-builder.ts +38 -18
  81. package/src/types/dependency-types.ts +110 -0
  82. package/src/types/index.ts +17 -21
  83. package/src/utilities/index.ts +1 -0
  84. package/src/utilities/library-dependency-resolver.ts +603 -0
  85. package/src/utilities/library-loader.ts +252 -0
  86. package/tsconfig.json +2 -1
  87. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,603 @@
1
+ /**
2
+ * @fileoverview Library dependency resolution utilities
3
+ * Provides dependency graph construction, cycle detection, topological sorting, and version resolution
4
+ * @module @memberjunction/react-runtime/utilities
5
+ */
6
+
7
+ import { ComponentLibraryEntity } from '@memberjunction/core-entities';
8
+ import {
9
+ DependencyGraph,
10
+ DependencyNode,
11
+ LoadOrderResult,
12
+ ParsedDependency,
13
+ ParsedVersion,
14
+ ResolvedVersion,
15
+ VersionRange,
16
+ VersionRangeType,
17
+ VersionRequirement,
18
+ DependencyResolutionOptions
19
+ } from '../types/dependency-types';
20
+
21
+ /**
22
+ * Resolves library dependencies and determines load order
23
+ */
24
+ export class LibraryDependencyResolver {
25
+ private debug: boolean = false;
26
+
27
+ constructor(options?: DependencyResolutionOptions) {
28
+ this.debug = options?.debug || false;
29
+ }
30
+
31
+ /**
32
+ * Parse dependencies from JSON string
33
+ * @param json - JSON string containing dependencies
34
+ * @returns Map of library name to version specification
35
+ */
36
+ parseDependencies(json: string | null): Map<string, string> {
37
+ const dependencies = new Map<string, string>();
38
+
39
+ if (!json || json.trim() === '') {
40
+ return dependencies;
41
+ }
42
+
43
+ try {
44
+ const parsed = JSON.parse(json);
45
+ if (typeof parsed === 'object' && parsed !== null) {
46
+ for (const [name, version] of Object.entries(parsed)) {
47
+ if (typeof version === 'string') {
48
+ dependencies.set(name, version);
49
+ }
50
+ }
51
+ }
52
+ } catch (error) {
53
+ console.error('Failed to parse dependencies JSON:', error);
54
+ }
55
+
56
+ return dependencies;
57
+ }
58
+
59
+ /**
60
+ * Build a dependency graph from a collection of libraries
61
+ * @param libraries - All available libraries
62
+ * @returns Dependency graph structure
63
+ */
64
+ buildDependencyGraph(libraries: ComponentLibraryEntity[]): DependencyGraph {
65
+ const nodes = new Map<string, DependencyNode>();
66
+ const roots = new Set<string>();
67
+
68
+ // First pass: create nodes for all libraries
69
+ for (const library of libraries) {
70
+ const dependencies = this.parseDependencies(library.Dependencies);
71
+ nodes.set(library.Name, {
72
+ library,
73
+ dependencies,
74
+ dependents: new Set()
75
+ });
76
+ // Initially assume all are roots
77
+ roots.add(library.Name);
78
+ }
79
+
80
+ // Second pass: establish dependency relationships
81
+ for (const [name, node] of nodes) {
82
+ for (const [depName, depVersion] of node.dependencies) {
83
+ const depNode = nodes.get(depName);
84
+ if (depNode) {
85
+ // This library depends on depName, so depName is not a root
86
+ roots.delete(depName);
87
+ // Add this library as a dependent of depName
88
+ depNode.dependents.add(name);
89
+ } else if (this.debug) {
90
+ console.warn(`Dependency '${depName}' not found for library '${name}'`);
91
+ }
92
+ }
93
+ }
94
+
95
+ return { nodes, roots };
96
+ }
97
+
98
+ /**
99
+ * Detect circular dependencies in the graph
100
+ * @param graph - Dependency graph
101
+ * @returns Array of cycles found
102
+ */
103
+ detectCycles(graph: DependencyGraph): string[][] {
104
+ const cycles: string[][] = [];
105
+ const visited = new Set<string>();
106
+ const recursionStack = new Set<string>();
107
+ const path: string[] = [];
108
+
109
+ const detectCyclesUtil = (nodeName: string): void => {
110
+ visited.add(nodeName);
111
+ recursionStack.add(nodeName);
112
+ path.push(nodeName);
113
+
114
+ const node = graph.nodes.get(nodeName);
115
+ if (node) {
116
+ for (const [depName] of node.dependencies) {
117
+ if (!visited.has(depName)) {
118
+ detectCyclesUtil(depName);
119
+ } else if (recursionStack.has(depName)) {
120
+ // Found a cycle
121
+ const cycleStartIndex = path.indexOf(depName);
122
+ const cycle = [...path.slice(cycleStartIndex), depName];
123
+ cycles.push(cycle);
124
+ }
125
+ }
126
+ }
127
+
128
+ path.pop();
129
+ recursionStack.delete(nodeName);
130
+ };
131
+
132
+ // Check all nodes
133
+ for (const nodeName of graph.nodes.keys()) {
134
+ if (!visited.has(nodeName)) {
135
+ detectCyclesUtil(nodeName);
136
+ }
137
+ }
138
+
139
+ return cycles;
140
+ }
141
+
142
+ /**
143
+ * Perform topological sort to determine load order
144
+ * @param graph - Dependency graph
145
+ * @returns Sorted array of libraries to load in order
146
+ */
147
+ topologicalSort(graph: DependencyGraph): ComponentLibraryEntity[] {
148
+ const result: ComponentLibraryEntity[] = [];
149
+ const visited = new Set<string>();
150
+ const tempMarked = new Set<string>();
151
+
152
+ const visit = (nodeName: string): boolean => {
153
+ if (tempMarked.has(nodeName)) {
154
+ // Cycle detected
155
+ return false;
156
+ }
157
+ if (visited.has(nodeName)) {
158
+ return true;
159
+ }
160
+
161
+ tempMarked.add(nodeName);
162
+ const node = graph.nodes.get(nodeName);
163
+
164
+ if (node) {
165
+ // Visit dependencies first
166
+ for (const [depName] of node.dependencies) {
167
+ if (graph.nodes.has(depName)) {
168
+ if (!visit(depName)) {
169
+ return false;
170
+ }
171
+ }
172
+ }
173
+ result.push(node.library);
174
+ }
175
+
176
+ tempMarked.delete(nodeName);
177
+ visited.add(nodeName);
178
+ return true;
179
+ };
180
+
181
+ // Start with all nodes
182
+ for (const nodeName of graph.nodes.keys()) {
183
+ if (!visited.has(nodeName)) {
184
+ if (!visit(nodeName)) {
185
+ console.error(`Cycle detected involving library: ${nodeName}`);
186
+ }
187
+ }
188
+ }
189
+
190
+ return result;
191
+ }
192
+
193
+ /**
194
+ * Parse a semver version string
195
+ * @param version - Version string (e.g., "1.2.3")
196
+ * @returns Parsed version object
197
+ */
198
+ private parseVersion(version: string): ParsedVersion | null {
199
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?(?:\+(.+))?$/);
200
+ if (!match) {
201
+ return null;
202
+ }
203
+
204
+ return {
205
+ major: parseInt(match[1], 10),
206
+ minor: parseInt(match[2], 10),
207
+ patch: parseInt(match[3], 10),
208
+ prerelease: match[4],
209
+ build: match[5]
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Parse a version specification into a range
215
+ * @param spec - Version specification (e.g., "^1.2.3", "~1.2.0", "1.2.3")
216
+ * @returns Parsed version range
217
+ */
218
+ private parseVersionRange(spec: string): VersionRange {
219
+ if (spec === '*' || spec === '' || spec === 'latest') {
220
+ return { type: 'any', raw: spec };
221
+ }
222
+
223
+ // Tilde range (~1.2.3)
224
+ if (spec.startsWith('~')) {
225
+ const version = this.parseVersion(spec.substring(1));
226
+ return {
227
+ type: 'tilde',
228
+ version: version || undefined,
229
+ raw: spec
230
+ };
231
+ }
232
+
233
+ // Caret range (^1.2.3)
234
+ if (spec.startsWith('^')) {
235
+ const version = this.parseVersion(spec.substring(1));
236
+ return {
237
+ type: 'caret',
238
+ version: version || undefined,
239
+ raw: spec
240
+ };
241
+ }
242
+
243
+ // Exact version
244
+ const version = this.parseVersion(spec);
245
+ if (version) {
246
+ return {
247
+ type: 'exact',
248
+ version,
249
+ raw: spec
250
+ };
251
+ }
252
+
253
+ // Default to any if we can't parse
254
+ return { type: 'any', raw: spec };
255
+ }
256
+
257
+ /**
258
+ * Check if a version satisfies a version range
259
+ * @param version - Version to check
260
+ * @param range - Version range specification
261
+ * @returns True if version satisfies range
262
+ */
263
+ private versionSatisfiesRange(version: ParsedVersion, range: VersionRange): boolean {
264
+ if (range.type === 'any') {
265
+ return true;
266
+ }
267
+
268
+ if (!range.version) {
269
+ return false;
270
+ }
271
+
272
+ const rangeVer = range.version;
273
+
274
+ switch (range.type) {
275
+ case 'exact':
276
+ return version.major === rangeVer.major &&
277
+ version.minor === rangeVer.minor &&
278
+ version.patch === rangeVer.patch;
279
+
280
+ case 'tilde': // ~1.2.3 means >=1.2.3 <1.3.0
281
+ if (version.major !== rangeVer.major) return false;
282
+ if (version.minor !== rangeVer.minor) return false;
283
+ return version.patch >= rangeVer.patch;
284
+
285
+ case 'caret': // ^1.2.3 means >=1.2.3 <2.0.0 (for 1.x.x)
286
+ if (rangeVer.major === 0) {
287
+ // ^0.x.y behaves like ~0.x.y
288
+ if (version.major !== 0) return false;
289
+ if (rangeVer.minor === 0) {
290
+ // ^0.0.x means exactly 0.0.x
291
+ return version.minor === 0 && version.patch === rangeVer.patch;
292
+ }
293
+ // ^0.x.y means >=0.x.y <0.(x+1).0
294
+ if (version.minor !== rangeVer.minor) return false;
295
+ return version.patch >= rangeVer.patch;
296
+ }
297
+ // Normal caret for major > 0
298
+ if (version.major !== rangeVer.major) return false;
299
+ if (version.minor < rangeVer.minor) return false;
300
+ if (version.minor === rangeVer.minor) {
301
+ return version.patch >= rangeVer.patch;
302
+ }
303
+ return true;
304
+
305
+ default:
306
+ return false;
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Compare two versions for sorting
312
+ * @returns -1 if a < b, 0 if a === b, 1 if a > b
313
+ */
314
+ private compareVersions(a: ParsedVersion, b: ParsedVersion): number {
315
+ if (a.major !== b.major) return a.major - b.major;
316
+ if (a.minor !== b.minor) return a.minor - b.minor;
317
+ if (a.patch !== b.patch) return a.patch - b.patch;
318
+
319
+ // Handle prerelease versions
320
+ if (!a.prerelease && b.prerelease) return 1; // a is newer
321
+ if (a.prerelease && !b.prerelease) return -1; // b is newer
322
+ if (a.prerelease && b.prerelease) {
323
+ return a.prerelease.localeCompare(b.prerelease);
324
+ }
325
+
326
+ return 0;
327
+ }
328
+
329
+ /**
330
+ * Resolve version conflicts using NPM-style resolution
331
+ * @param requirements - Array of version requirements
332
+ * @param availableLibraries - All available libraries to choose from
333
+ * @returns Resolved version information
334
+ */
335
+ resolveVersionConflicts(
336
+ requirements: VersionRequirement[],
337
+ availableLibraries: ComponentLibraryEntity[]
338
+ ): ResolvedVersion {
339
+ if (requirements.length === 0) {
340
+ throw new Error('No version requirements provided');
341
+ }
342
+
343
+ const libraryName = requirements[0].library;
344
+ const warnings: string[] = [];
345
+
346
+ // Find all available versions for this library
347
+ const availableVersions = availableLibraries
348
+ .filter(lib => lib.Name === libraryName && lib.Version)
349
+ .map(lib => ({
350
+ library: lib,
351
+ version: this.parseVersion(lib.Version!)
352
+ }))
353
+ .filter(item => item.version !== null)
354
+ .sort((a, b) => this.compareVersions(b.version!, a.version!)); // Sort descending
355
+
356
+ if (availableVersions.length === 0) {
357
+ throw new Error(`No versions available for library '${libraryName}'`);
358
+ }
359
+
360
+ // Parse all requirements
361
+ const ranges = requirements.map(req => ({
362
+ ...req,
363
+ range: this.parseVersionRange(req.versionSpec)
364
+ }));
365
+
366
+ // Find the highest version that satisfies all requirements
367
+ for (const { library, version } of availableVersions) {
368
+ let satisfiesAll = true;
369
+ const satisfiedRequirements: VersionRequirement[] = [];
370
+
371
+ for (const req of ranges) {
372
+ if (this.versionSatisfiesRange(version!, req.range)) {
373
+ satisfiedRequirements.push(req);
374
+ } else {
375
+ satisfiesAll = false;
376
+ warnings.push(
377
+ `Version ${library.Version} does not satisfy '${req.versionSpec}' required by ${req.requestedBy}`
378
+ );
379
+ break;
380
+ }
381
+ }
382
+
383
+ if (satisfiesAll) {
384
+ return {
385
+ library: libraryName,
386
+ version: library.Version!,
387
+ satisfies: requirements,
388
+ warnings: warnings.length > 0 ? warnings : undefined
389
+ };
390
+ }
391
+ }
392
+
393
+ // No version satisfies all requirements
394
+ // Return the latest version with warnings
395
+ const latest = availableVersions[0];
396
+ warnings.push(
397
+ `Could not find a version that satisfies all requirements. Using ${latest.library.Version}`
398
+ );
399
+
400
+ return {
401
+ library: libraryName,
402
+ version: latest.library.Version!,
403
+ satisfies: [],
404
+ warnings
405
+ };
406
+ }
407
+
408
+ /**
409
+ * Get the load order for a set of requested libraries
410
+ * @param requestedLibs - Library names requested
411
+ * @param allLibs - All available libraries
412
+ * @param options - Resolution options
413
+ * @returns Load order result
414
+ */
415
+ getLoadOrder(
416
+ requestedLibs: string[],
417
+ allLibs: ComponentLibraryEntity[],
418
+ options?: DependencyResolutionOptions
419
+ ): LoadOrderResult {
420
+ const errors: string[] = [];
421
+ const warnings: string[] = [];
422
+
423
+ if (this.debug || options?.debug) {
424
+ console.log('🔍 Getting load order for:', requestedLibs);
425
+ }
426
+
427
+ // Build a map for quick lookup
428
+ const libMap = new Map<string, ComponentLibraryEntity[]>();
429
+ for (const lib of allLibs) {
430
+ if (!libMap.has(lib.Name)) {
431
+ libMap.set(lib.Name, []);
432
+ }
433
+ libMap.get(lib.Name)!.push(lib);
434
+ }
435
+
436
+ // Collect all libraries needed (requested + their dependencies)
437
+ const needed = new Set<string>();
438
+ const toProcess = [...requestedLibs];
439
+ const processed = new Set<string>();
440
+ const versionRequirements = new Map<string, VersionRequirement[]>();
441
+ let depth = 0;
442
+ const maxDepth = options?.maxDepth || 10;
443
+
444
+ while (toProcess.length > 0 && depth < maxDepth) {
445
+ const current = toProcess.shift()!;
446
+ if (processed.has(current)) continue;
447
+
448
+ processed.add(current);
449
+ needed.add(current);
450
+
451
+ // Find the library
452
+ const libVersions = libMap.get(current);
453
+ if (!libVersions || libVersions.length === 0) {
454
+ errors.push(`Library '${current}' not found`);
455
+ continue;
456
+ }
457
+
458
+ // For now, use the first version found (should be resolved properly)
459
+ const lib = libVersions[0];
460
+ const deps = this.parseDependencies(lib.Dependencies);
461
+
462
+ // Process dependencies
463
+ for (const [depName, depVersion] of deps) {
464
+ needed.add(depName);
465
+
466
+ // Track version requirements
467
+ if (!versionRequirements.has(depName)) {
468
+ versionRequirements.set(depName, []);
469
+ }
470
+ versionRequirements.get(depName)!.push({
471
+ library: depName,
472
+ versionSpec: depVersion,
473
+ requestedBy: current
474
+ });
475
+
476
+ if (!processed.has(depName)) {
477
+ toProcess.push(depName);
478
+ }
479
+ }
480
+
481
+ depth++;
482
+ }
483
+
484
+ if (depth >= maxDepth) {
485
+ warnings.push(`Maximum dependency depth (${maxDepth}) reached`);
486
+ }
487
+
488
+ // Resolve version conflicts for each library
489
+ const resolvedLibraries: ComponentLibraryEntity[] = [];
490
+ for (const libName of needed) {
491
+ const requirements = versionRequirements.get(libName) || [];
492
+ const versions = libMap.get(libName) || [];
493
+
494
+ if (versions.length === 0) {
495
+ errors.push(`Library '${libName}' not found`);
496
+ continue;
497
+ }
498
+
499
+ if (requirements.length > 0) {
500
+ try {
501
+ const resolved = this.resolveVersionConflicts(requirements, versions);
502
+ const selectedLib = versions.find(lib => lib.Version === resolved.version);
503
+ if (selectedLib) {
504
+ resolvedLibraries.push(selectedLib);
505
+ if (resolved.warnings) {
506
+ warnings.push(...resolved.warnings);
507
+ }
508
+ }
509
+ } catch (error: any) {
510
+ errors.push(error.message);
511
+ // Use first available version as fallback
512
+ resolvedLibraries.push(versions[0]);
513
+ }
514
+ } else {
515
+ // No specific requirements, use the first (default) version
516
+ resolvedLibraries.push(versions[0]);
517
+ }
518
+ }
519
+
520
+ // Build dependency graph with resolved libraries
521
+ const graph = this.buildDependencyGraph(resolvedLibraries);
522
+
523
+ // Check for cycles
524
+ const cycles = this.detectCycles(graph);
525
+ if (cycles.length > 0) {
526
+ errors.push(`Circular dependencies detected: ${cycles.map(c => c.join(' -> ')).join(', ')}`);
527
+ return {
528
+ success: false,
529
+ cycles,
530
+ errors,
531
+ warnings: warnings.length > 0 ? warnings : undefined
532
+ };
533
+ }
534
+
535
+ // Perform topological sort
536
+ const sorted = this.topologicalSort(graph);
537
+
538
+ if (this.debug || options?.debug) {
539
+ console.log('✅ Load order determined:', sorted.map(lib => `${lib.Name}@${lib.Version}`));
540
+ }
541
+
542
+ return {
543
+ success: errors.length === 0,
544
+ order: sorted,
545
+ errors: errors.length > 0 ? errors : undefined,
546
+ warnings: warnings.length > 0 ? warnings : undefined
547
+ };
548
+ }
549
+
550
+ /**
551
+ * Get direct dependencies of a library
552
+ * @param library - Library to get dependencies for
553
+ * @returns Map of dependency names to version specs
554
+ */
555
+ getDirectDependencies(library: ComponentLibraryEntity): Map<string, string> {
556
+ return this.parseDependencies(library.Dependencies);
557
+ }
558
+
559
+ /**
560
+ * Get all transitive dependencies of a library
561
+ * @param libraryName - Library name to analyze
562
+ * @param allLibs - All available libraries
563
+ * @param maxDepth - Maximum depth to traverse
564
+ * @returns Set of all dependency names (including transitive)
565
+ */
566
+ getTransitiveDependencies(
567
+ libraryName: string,
568
+ allLibs: ComponentLibraryEntity[],
569
+ maxDepth: number = 10
570
+ ): Set<string> {
571
+ const dependencies = new Set<string>();
572
+ const toProcess = [libraryName];
573
+ const processed = new Set<string>();
574
+ let depth = 0;
575
+
576
+ // Build lookup map
577
+ const libMap = new Map<string, ComponentLibraryEntity>();
578
+ for (const lib of allLibs) {
579
+ libMap.set(lib.Name, lib);
580
+ }
581
+
582
+ while (toProcess.length > 0 && depth < maxDepth) {
583
+ const current = toProcess.shift()!;
584
+ if (processed.has(current)) continue;
585
+
586
+ processed.add(current);
587
+ const lib = libMap.get(current);
588
+ if (!lib) continue;
589
+
590
+ const deps = this.parseDependencies(lib.Dependencies);
591
+ for (const [depName] of deps) {
592
+ dependencies.add(depName);
593
+ if (!processed.has(depName)) {
594
+ toProcess.push(depName);
595
+ }
596
+ }
597
+
598
+ depth++;
599
+ }
600
+
601
+ return dependencies;
602
+ }
603
+ }