@brainwav/diagram 1.0.7 → 1.1.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 (91) hide show
  1. package/.diagram/contracts/machine-command-coverage.json +73 -0
  2. package/.diagram/migration/finalization-policy.json +20 -0
  3. package/LICENSE +202 -21
  4. package/README.md +132 -339
  5. package/package.json +46 -13
  6. package/scripts/refresh-diagram-context.sh +274 -182
  7. package/src/analyzers/default-analyzer.js +11 -0
  8. package/src/analyzers/index.js +34 -0
  9. package/src/artifacts/agent-context.js +105 -0
  10. package/src/artifacts/artifact-budget.js +224 -0
  11. package/src/artifacts/brief.js +153 -0
  12. package/src/artifacts/evidence-manifest.js +206 -0
  13. package/src/artifacts/evidence-summary.js +29 -0
  14. package/src/commands/analyze.js +125 -0
  15. package/src/commands/changed.js +185 -0
  16. package/src/commands/context.js +110 -0
  17. package/src/commands/diff.js +142 -0
  18. package/src/commands/doctor.js +335 -0
  19. package/src/commands/explain.js +273 -0
  20. package/src/commands/generate-all.js +170 -0
  21. package/src/commands/generate-animated.js +50 -0
  22. package/src/commands/generate-video.js +65 -0
  23. package/src/commands/generate.js +522 -0
  24. package/src/commands/init.js +123 -0
  25. package/src/commands/output.js +76 -0
  26. package/src/commands/scan.js +624 -0
  27. package/src/commands/shared.js +396 -0
  28. package/src/commands/validate.js +328 -0
  29. package/src/commands/video-shared.js +105 -0
  30. package/src/commands/workflow-pr.js +26 -0
  31. package/src/confidence/pipeline.js +186 -0
  32. package/src/config/diagramrc.js +79 -0
  33. package/src/context/build-context-pack.js +291 -0
  34. package/src/context/normalize-diagram-manifest.js +282 -0
  35. package/src/core/analysis-generation-analyze-components.js +102 -0
  36. package/src/core/analysis-generation-analyze-dependencies.js +33 -0
  37. package/src/core/analysis-generation-analyze-files.js +48 -0
  38. package/src/core/analysis-generation-analyze-options.js +73 -0
  39. package/src/core/analysis-generation-analyze.js +63 -0
  40. package/src/core/analysis-generation-constants.js +53 -0
  41. package/src/core/analysis-generation-diagrams-core-architecture.js +105 -0
  42. package/src/core/analysis-generation-diagrams-core-dependency.js +68 -0
  43. package/src/core/analysis-generation-diagrams-core-sequence.js +142 -0
  44. package/src/core/analysis-generation-diagrams-core-shapes.js +104 -0
  45. package/src/core/analysis-generation-diagrams-core.js +12 -0
  46. package/src/core/analysis-generation-diagrams-empty.js +68 -0
  47. package/src/core/analysis-generation-diagrams-erd.js +59 -0
  48. package/src/core/analysis-generation-diagrams-limit.js +27 -0
  49. package/src/core/analysis-generation-diagrams-role-ai-agent.js +103 -0
  50. package/src/core/analysis-generation-diagrams-role-ai-context.js +186 -0
  51. package/src/core/analysis-generation-diagrams-role-ai.js +11 -0
  52. package/src/core/analysis-generation-diagrams-role-data.js +182 -0
  53. package/src/core/analysis-generation-diagrams-role-helpers.js +129 -0
  54. package/src/core/analysis-generation-diagrams-role-security.js +129 -0
  55. package/src/core/analysis-generation-diagrams-role.js +25 -0
  56. package/src/core/analysis-generation-diagrams.js +182 -0
  57. package/src/core/analysis-generation-role-tags-constants.js +55 -0
  58. package/src/core/analysis-generation-role-tags-imports.js +32 -0
  59. package/src/core/analysis-generation-role-tags-infer.js +49 -0
  60. package/src/core/analysis-generation-role-tags-match.js +19 -0
  61. package/src/core/analysis-generation-role-tags.js +7 -0
  62. package/src/core/analysis-generation-utils-core.js +308 -0
  63. package/src/core/analysis-generation-utils-graph.js +321 -0
  64. package/src/core/analysis-generation-utils-resolution.js +76 -0
  65. package/src/core/analysis-generation-utils.js +9 -0
  66. package/src/core/analysis-generation.js +44 -0
  67. package/src/diagram.js +180 -1760
  68. package/src/formatters/console.js +198 -0
  69. package/src/formatters/index.js +41 -0
  70. package/src/formatters/json.js +113 -0
  71. package/src/formatters/junit.js +123 -0
  72. package/src/graph.js +159 -0
  73. package/src/incremental/cache.js +210 -0
  74. package/src/ir/architecture-ir.js +48 -0
  75. package/src/migration/evidence.js +262 -0
  76. package/src/migration/finalization-policy.js +35 -0
  77. package/src/renderers/report-html.js +265 -0
  78. package/src/rules/factory.js +108 -0
  79. package/src/rules/types/base.js +54 -0
  80. package/src/rules/types/import-rule.js +286 -0
  81. package/src/rules.js +380 -0
  82. package/src/schema/erd-confidence.js +56 -0
  83. package/src/schema/erd-extractor.js +504 -0
  84. package/src/schema/erd-model.js +176 -0
  85. package/src/schema/rules-schema.js +170 -0
  86. package/src/utils/suggestions.js +67 -0
  87. package/src/video.js +4 -5
  88. package/src/workflow/git-helpers.js +576 -0
  89. package/src/workflow/pr-command.js +694 -0
  90. package/src/workflow/pr-impact.js +848 -0
  91. package/src/workflow/sort-utils.js +16 -0
@@ -0,0 +1,321 @@
1
+ const { sanitize } = require('./analysis-generation-utils-core');
2
+
3
+ /**
4
+ * Determine whether a component declares the given role tag.
5
+ * @param {Object} component - Component object which may contain a `roleTags` array.
6
+ * @param {string} role - Role tag to check for presence.
7
+ * @returns {boolean} `true` if `component.roleTags` is an array and includes `role`, `false` otherwise.
8
+ */
9
+ function hasRole(component, role) {
10
+ return (Array.isArray(component.roleTags) && component.roleTags.includes(role));
11
+ }
12
+
13
+ /**
14
+ * Filter a list of components to those that have the specified role.
15
+ * @param {Array} components - Array of component objects.
16
+ * @param {string} role - Role name to match against each component's `roleTags`.
17
+ * @returns {Array} Array of components that include the specified role.
18
+ */
19
+ function componentsByRole(components, role) {
20
+ if (!Array.isArray(components)) return [];
21
+ return components.filter((component) => hasRole(component, role));
22
+ }
23
+
24
+ /**
25
+ * Return a deduplicated array of truthy components preserving their original order.
26
+ *
27
+ * If `components` is not an array the function returns an empty array. Falsy values
28
+ * (e.g. null, undefined, false, 0, '') are removed before deduplication.
29
+ *
30
+ * @param {Array} components - Array of component items to filter and deduplicate.
31
+ * @returns {Array} An array of unique, truthy components in their original order.
32
+ */
33
+ function uniqueComponents(components) {
34
+ if (!Array.isArray(components)) return [];
35
+ return [...new Set(components.filter(Boolean))];
36
+ }
37
+
38
+ /**
39
+ * Merge components that match an ordered list of role specifications.
40
+ *
41
+ * For each entry in `roleSpecs` (a role string or an object `{ role, limit }`) the function
42
+ * collects components whose `roleTags` include the specified role, appending matches in
43
+ * spec order. If a spec provides an integer `limit` ≥ 0, only the first `limit` matches
44
+ * for that spec are taken. The final result is deduplicated, preserving the first occurrence
45
+ * of each component.
46
+ *
47
+ * @param {Array<object>} components - Array of component objects to search.
48
+ * @param {Array<string|{role: string, limit?: number}>} roleSpecs - Ordered list of role specifications.
49
+ * @returns {Array<object>} An array of unique components that match the given role specifications, in merged order.
50
+ */
51
+ function mergeRoleComponents(components, roleSpecs) {
52
+ if (!Array.isArray(components) || !Array.isArray(roleSpecs)) return [];
53
+
54
+ const merged = [];
55
+ for (const spec of roleSpecs) {
56
+ const role = (typeof spec === 'string') ? spec : spec?.role;
57
+ if (!role) continue;
58
+
59
+ const matches = componentsByRole(components, role);
60
+ if (typeof spec === 'object' && Number.isInteger(spec.limit) && spec.limit >= 0) {
61
+ merged.push(...matches.slice(0, spec.limit));
62
+ } else {
63
+ merged.push(...matches);
64
+ }
65
+ }
66
+
67
+ return uniqueComponents(merged);
68
+ }
69
+
70
+ /**
71
+ * Produce a map from component objects to unique, sanitized node identifiers.
72
+ *
73
+ * The base identifier is derived from sanitize(component.name || component.originalName || 'node').
74
+ * If a base identifier is already used, a numeric suffix `_1`, `_2`, … is appended to produce a unique identifier.
75
+ *
76
+ * @param {Array<object>} components - Array of component objects to name.
77
+ * @returns {Map<object,string>} Map that associates each input component object with its unique sanitized name.
78
+ */
79
+ function mapSafeNames(components) {
80
+ const map = new Map();
81
+ const used = new Set();
82
+
83
+ for (const component of components) {
84
+ const rawName = sanitize(component.name || component.originalName || 'node');
85
+ if (!used.has(rawName)) {
86
+ map.set(component, rawName);
87
+ used.add(rawName);
88
+ continue;
89
+ }
90
+
91
+ let i = 1;
92
+ let candidate = `${rawName}_${i}`;
93
+ while (used.has(candidate)) {
94
+ i += 1;
95
+ candidate = `${rawName}_${i}`;
96
+ }
97
+ map.set(component, candidate);
98
+ used.add(candidate);
99
+ }
100
+
101
+ return map;
102
+ }
103
+
104
+ /**
105
+ * Build an index that maps component names to their component objects.
106
+ *
107
+ * @param {Array} components - Array of component objects; non-arrays produce an empty Map. Components without a truthy `name` are ignored.
108
+ * @returns {Map<string, Object>} Map whose keys are `component.name` and values are the corresponding component. Later components with the same name overwrite earlier entries.
109
+ */
110
+ function byNameIndex(components) {
111
+ const map = new Map();
112
+ if (!Array.isArray(components)) return map;
113
+ for (const component of components) {
114
+ if (component && component.name) {
115
+ map.set(component.name, component);
116
+ }
117
+ }
118
+ return map;
119
+ }
120
+
121
+ /**
122
+ * Builds a reverse index from dependency name to components that depend on it.
123
+ *
124
+ * @param {Array<Object>} components - Array of component objects; each component should have a string `name` and an optional `dependencies` array of dependency names.
125
+ * @returns {Map<string, Array<Object>>} A Map where each key is a dependency name and the value is an array of components that include that dependency. Returns an empty Map if `components` is not an array.
126
+ */
127
+ function buildReverseDependencyIndex(components) {
128
+ const map = new Map();
129
+ if (!Array.isArray(components)) return map;
130
+
131
+ for (const component of components) {
132
+ if (!component || typeof component.name !== 'string') continue;
133
+ const deps = Array.isArray(component.dependencies) ? component.dependencies : [];
134
+ for (const depName of deps) {
135
+ if (!map.has(depName)) map.set(depName, []);
136
+ map.get(depName).push(component);
137
+ }
138
+ }
139
+
140
+ return map;
141
+ }
142
+
143
+ /**
144
+ * Selects a connected subgraph of components by expanding from seed components.
145
+ *
146
+ * Performs a breadth-style expansion from each seed over both forward `dependencies` and reverse dependency links, collecting components whose `name` is a string. Expansion stops when `maxDepth` layers have been traversed or when `maxNodes` components have been selected. Inputs that are not arrays or an empty `seedComponents` result in an empty array.
147
+ *
148
+ * @param {Array<Object>} components - Array of available components (each may have `name` and `dependencies`).
149
+ * @param {Array<Object>} seedComponents - Array of seed components to start the expansion; seeds must have a truthy `name` to be included.
150
+ * @param {number} [maxDepth=2] - Maximum number of expansion layers to traverse from the seeds.
151
+ * @param {number} [maxNodes=35] - Maximum number of components to include; expansion stops once this limit is reached.
152
+ * @returns {Array<Object>} Array of selected components (including seeds) in the order they were discovered.
153
+ */
154
+ function collectConnectedComponents(components, seedComponents, maxDepth = 2, maxNodes = 35) {
155
+ if (!Array.isArray(components)) return [];
156
+ if (!Array.isArray(seedComponents) || seedComponents.length === 0) return [];
157
+
158
+ const byName = byNameIndex(components);
159
+ const reverseDependencies = buildReverseDependencyIndex(components);
160
+ const selected = new Map();
161
+ const queue = [];
162
+ const addSelected = (candidate) => {
163
+ if (!candidate || typeof candidate.name !== 'string') return false;
164
+ if (selected.has(candidate.name)) return false;
165
+ if (selected.size >= maxNodes) return false;
166
+ selected.set(candidate.name, candidate);
167
+ return true;
168
+ };
169
+
170
+ for (const seed of seedComponents) {
171
+ if (addSelected(seed)) {
172
+ queue.push(seed);
173
+ }
174
+ if (selected.size >= maxNodes) break;
175
+ }
176
+
177
+ let depth = 0;
178
+ let levelStart = 0;
179
+ const visited = new Set();
180
+ while (levelStart < queue.length && depth < maxDepth) {
181
+ const levelEnd = queue.length;
182
+ for (let i = levelStart; i < levelEnd; i++) {
183
+ const current = queue[i];
184
+ if (!current || typeof current.name !== 'string') continue;
185
+ const depthKey = `${current.name}:${depth}`;
186
+ if (visited.has(depthKey)) continue;
187
+ visited.add(depthKey);
188
+
189
+ const next = [];
190
+ for (const depName of current.dependencies || []) {
191
+ if (selected.size >= maxNodes) break;
192
+ const dependency = byName.get(depName);
193
+ if (addSelected(dependency)) {
194
+ next.push(dependency);
195
+ }
196
+ }
197
+
198
+ const reverse = reverseDependencies.get(current.name) || [];
199
+ for (const candidate of reverse) {
200
+ if (selected.size >= maxNodes) break;
201
+ if (addSelected(candidate)) next.push(candidate);
202
+ }
203
+
204
+ if (selected.size >= maxNodes) break;
205
+ for (const nextComponent of next) {
206
+ queue.push(nextComponent);
207
+ }
208
+ if (selected.size >= maxNodes) break;
209
+ }
210
+ levelStart = levelEnd;
211
+ depth += 1;
212
+ }
213
+
214
+ return [...selected.values()];
215
+ }
216
+
217
+ /**
218
+ * Build diagram context for a role-based component graph.
219
+ *
220
+ * Produces a connected component list and supporting lookup maps used for diagram generation.
221
+ *
222
+ * @param {Object} data - Source data object containing components.
223
+ * @param {Array<Object>} seeds - Seed components from which the graph expansion begins.
224
+ * @param {number} [maxDepth=2] - Maximum traversal depth from each seed.
225
+ * @param {number} [maxNodes=30] - Maximum number of components to include.
226
+ * @returns {{connected: Array<Object>, byName: Map<string, Object>, safeNames: Map<Object, string>}}
227
+ * An object with:
228
+ * - `connected`: the selected components reachable from `seeds` within the specified limits.
229
+ * - `byName`: a Map from component name to component for members of `connected`.
230
+ * - `safeNames`: a Map from component object to a unique, sanitized node name.
231
+ */
232
+ function buildRoleDiagramContext(data, seeds, maxDepth = 2, maxNodes = 30) {
233
+ const connected = collectConnectedComponents(data.components, seeds, maxDepth, maxNodes);
234
+ return {
235
+ connected,
236
+ byName: byNameIndex(connected),
237
+ safeNames: mapSafeNames(connected),
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Append directed dependency edges for a set of components to a lines array using safe node identifiers.
243
+ *
244
+ * Iterates each component's `dependencies` and, for each dependency that exists in `byName` and has a mapped safe name in `safeNames`, appends a Mermaid-style edge line to `lines`. Each edge is emitted at most once according to the `edges` set; if `edgeLabelFn` is provided and returns a truthy label for a component→dependency pair that label is included.
245
+ *
246
+ * @param {string[]} lines - Array to which edge lines will be appended.
247
+ * @param {Object[]} sourceComponents - Components whose dependencies will be rendered; each component may have a `dependencies` array of names.
248
+ * @param {Map<string, Object>} byName - Map from component name to component object for dependency lookup.
249
+ * @param {Map<Object, string>} safeNames - Map from component object to its safe string identifier used in edge lines.
250
+ * @param {Set<string>} edges - Set used to deduplicate emitted edges; edge keys are of the form `from->to`.
251
+ * @param {(component: Object, dependency: Object) => string|null} [edgeLabelFn] - Optional function returning a label for an edge; return a truthy string to include a label, or a falsy value to omit it.
252
+ */
253
+ function appendDependencyEdges(lines, sourceComponents, byName, safeNames, edges, edgeLabelFn) {
254
+ for (const comp of sourceComponents) {
255
+ const from = safeNames.get(comp);
256
+ if (!from) continue;
257
+ for (const depName of comp.dependencies || []) {
258
+ const dep = byName.get(depName);
259
+ if (!dep) continue;
260
+ const to = safeNames.get(dep);
261
+ if (!to) continue;
262
+ const key = `${from}->${to}`;
263
+ if (edges.has(key)) continue;
264
+ edges.add(key);
265
+
266
+ const edgeSpec = typeof edgeLabelFn === 'function' ? edgeLabelFn(comp, dep) : null;
267
+ if (typeof edgeSpec === 'string' && edgeSpec.trim() !== '') {
268
+ const trimmed = edgeSpec.trim();
269
+ if (trimmed.includes('-->')) {
270
+ lines.push(trimmed.startsWith(' ') ? trimmed : ` ${trimmed}`);
271
+ } else {
272
+ lines.push(` ${from} -->|${trimmed}| ${to}`);
273
+ }
274
+ } else {
275
+ lines.push(` ${from} --> ${to}`);
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Append a Mermaid class assignment line for the given nodes to the provided lines array.
283
+ *
284
+ * Filters out falsy and duplicate node IDs; if no valid IDs remain the lines array is not modified.
285
+ * @param {string[]} lines - Array of diagram lines to append to.
286
+ * @param {(string|number)[]} nodeIds - Node identifiers to assign the class to; falsy values are ignored.
287
+ * @param {string} className - Class name to assign to the nodes.
288
+ */
289
+ function appendClassAssignment(lines, nodeIds, className) {
290
+ if (!Array.isArray(nodeIds) || nodeIds.length === 0) return;
291
+ const unique = [...new Set(nodeIds.filter(Boolean))];
292
+ if (unique.length === 0) return;
293
+ lines.push(` class ${unique.join(',')} ${className}`);
294
+ }
295
+
296
+ /**
297
+ * Infer whether a component likely performs read or write database operations from its metadata.
298
+ * @param {Object} component - Component object whose `filePath`, `originalName` and `name` fields are inspected.
299
+ * @returns {{ hasLookup: boolean, hasWrite: boolean }} `hasLookup` is `true` if read/query-related keywords are present; `hasWrite` is `true` if write/modify-related keywords are present, `false` otherwise.
300
+ */
301
+ function inferDbIntent(component) {
302
+ const source = `${component.filePath || ''} ${component.originalName || ''} ${component.name || ''}`.toLowerCase();
303
+ const hasLookup = /\b(read|find|query|select|get|lookup|exists|fetch)\b/.test(source);
304
+ const hasWrite = /\b(create|insert|update|upsert|save|delete|remove|write|transaction)\b/.test(source);
305
+ return { hasLookup, hasWrite };
306
+ }
307
+
308
+ module.exports = {
309
+ hasRole,
310
+ componentsByRole,
311
+ uniqueComponents,
312
+ mergeRoleComponents,
313
+ mapSafeNames,
314
+ byNameIndex,
315
+ buildReverseDependencyIndex,
316
+ collectConnectedComponents,
317
+ buildRoleDiagramContext,
318
+ appendDependencyEdges,
319
+ appendClassAssignment,
320
+ inferDbIntent,
321
+ };
@@ -0,0 +1,76 @@
1
+ const path = require('path');
2
+ const { normalizePath, toComparablePath } = require('./analysis-generation-utils-core');
3
+
4
+ const IMPORT_RESOLUTION_SUFFIXES = [
5
+ '',
6
+ '.ts',
7
+ '.tsx',
8
+ '.js',
9
+ '.jsx',
10
+ '.mjs',
11
+ '.mts',
12
+ '.cts',
13
+ '/index.ts',
14
+ '/index.tsx',
15
+ '/index.js',
16
+ '/index.jsx',
17
+ '/index.mjs',
18
+ '/index.mts',
19
+ '/index.cts'
20
+ ];
21
+
22
+ /**
23
+ * Resolve a relative import from a source file to a comparable POSIX-style path or null when it cannot be resolved.
24
+ *
25
+ * When `rootPath` is provided, the result is returned relative to that root; if the resolved target would be outside
26
+ * `rootPath` the function returns `null`.
27
+ *
28
+ * @param {string} fromFilePath - Path of the file containing the import.
29
+ * @param {string} importPath - The import specifier; must be a relative path (start with `.`).
30
+ * @param {string} [rootPath] - Optional root directory to constrain and relativise resolution.
31
+ * @returns {string|null} The comparable resolved path (POSIX-style), or `null` for invalid inputs, non-relative imports,
32
+ * or when the target cannot be resolved within `rootPath`.
33
+ */
34
+ function resolveInternalImport(fromFilePath, importPath, rootPath) {
35
+ if (typeof fromFilePath !== 'string' || typeof importPath !== 'string') {
36
+ return null;
37
+ }
38
+ if (!importPath.startsWith('.')) {
39
+ return null;
40
+ }
41
+
42
+ const fromDir = path.dirname(fromFilePath);
43
+
44
+ if (rootPath) {
45
+ const absoluteTarget = path.resolve(rootPath, fromDir, importPath);
46
+ const relativeToRoot = toComparablePath(path.relative(rootPath, absoluteTarget));
47
+ if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {
48
+ return null;
49
+ }
50
+ return relativeToRoot;
51
+ }
52
+
53
+ const posixFromDir = normalizePath(fromDir);
54
+ const posixImport = normalizePath(importPath);
55
+ return toComparablePath(path.posix.normalize(path.posix.join(posixFromDir, posixImport)));
56
+ }
57
+
58
+ /**
59
+ * Locate a component whose `filePath` matches a resolved import path after applying known resolution suffixes.
60
+ *
61
+ * @param {Iterable<Object>} components - Iterable of component objects that contain a `filePath` property.
62
+ * @param {string} resolvedPath - The resolved import path to match against component file paths.
63
+ * @returns {Object|undefined} The first component whose `filePath`, when normalised for comparison, matches the resolved path with any recognised resolution suffix; `undefined` if no match is found.
64
+ */
65
+ function findComponentByResolvedPath(components, resolvedPath) {
66
+ const comparablePath = toComparablePath(resolvedPath);
67
+ const candidates = new Set(
68
+ IMPORT_RESOLUTION_SUFFIXES.map((suffix) => toComparablePath(comparablePath + suffix))
69
+ );
70
+ return components.find((component) => candidates.has(toComparablePath(component.filePath)));
71
+ }
72
+
73
+ module.exports = {
74
+ resolveInternalImport,
75
+ findComponentByResolvedPath,
76
+ };
@@ -0,0 +1,9 @@
1
+ const coreUtils = require('./analysis-generation-utils-core');
2
+ const resolutionUtils = require('./analysis-generation-utils-resolution');
3
+ const graphUtils = require('./analysis-generation-utils-graph');
4
+
5
+ module.exports = {
6
+ ...coreUtils,
7
+ ...resolutionUtils,
8
+ ...graphUtils,
9
+ };
@@ -0,0 +1,44 @@
1
+ const {
2
+ detectLanguage,
3
+ inferType,
4
+ extractImports,
5
+ extractImportsWithPositions,
6
+ sanitize,
7
+ escapeMermaid,
8
+ normalizePath,
9
+ getImportPath,
10
+ resolveInternalImport,
11
+ findComponentByResolvedPath,
12
+ getExternalPackageName,
13
+ } = require('./analysis-generation-utils');
14
+ const { inferRoleTags } = require('./analysis-generation-role-tags');
15
+ const { SUPPORTED_DIAGRAM_TYPES, ROLE_COLOURS } = require('./analysis-generation-constants');
16
+ const { analyze } = require('./analysis-generation-analyze');
17
+ const {
18
+ generate,
19
+ generateDiagramArtifact,
20
+ isPlaceholderDiagram,
21
+ toManifestEntry,
22
+ } = require('./analysis-generation-diagrams');
23
+
24
+ module.exports = {
25
+ detectLanguage,
26
+ inferType,
27
+ extractImports,
28
+ extractImportsWithPositions,
29
+ sanitize,
30
+ escapeMermaid,
31
+ normalizePath,
32
+ getImportPath,
33
+ resolveInternalImport,
34
+ findComponentByResolvedPath,
35
+ getExternalPackageName,
36
+ inferRoleTags,
37
+ SUPPORTED_DIAGRAM_TYPES,
38
+ ROLE_COLOURS,
39
+ analyze,
40
+ generate,
41
+ generateDiagramArtifact,
42
+ isPlaceholderDiagram,
43
+ toManifestEntry,
44
+ };