@linklabjs/core 0.1.0 → 0.1.1
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/dist/api/DomainNode.d.ts +154 -0
- package/dist/api/DomainNode.d.ts.map +1 -0
- package/dist/api/DomainNode.js +1157 -0
- package/dist/api/DomainNode.js.map +1 -0
- package/dist/api/Graph.d.ts +117 -0
- package/dist/api/Graph.d.ts.map +1 -0
- package/dist/api/Graph.js +212 -0
- package/dist/api/Graph.js.map +1 -0
- package/dist/api/PathBuilder.d.ts +76 -0
- package/dist/api/PathBuilder.d.ts.map +1 -0
- package/dist/api/PathBuilder.js +182 -0
- package/dist/api/PathBuilder.js.map +1 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +7 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/loadGraph.d.ts +57 -0
- package/dist/api/loadGraph.d.ts.map +1 -0
- package/dist/api/loadGraph.js +153 -0
- package/dist/api/loadGraph.js.map +1 -0
- package/dist/api/test-api.d.ts +9 -0
- package/dist/api/test-api.d.ts.map +1 -0
- package/dist/api/test-api.js +133 -0
- package/dist/api/test-api.js.map +1 -0
- package/dist/api/test-domain.d.ts +13 -0
- package/dist/api/test-domain.d.ts.map +1 -0
- package/dist/api/test-domain.js +105 -0
- package/dist/api/test-domain.js.map +1 -0
- package/dist/api/types.d.ts +69 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +22 -0
- package/dist/api/types.js.map +1 -0
- package/dist/config/synonyms.json +25 -0
- package/dist/core/EventBus.d.ts +56 -0
- package/dist/core/EventBus.d.ts.map +1 -0
- package/dist/core/EventBus.js +147 -0
- package/dist/core/EventBus.js.map +1 -0
- package/dist/core/GraphEvents.d.ts +118 -0
- package/dist/core/GraphEvents.d.ts.map +1 -0
- package/dist/core/GraphEvents.js +23 -0
- package/dist/core/GraphEvents.js.map +1 -0
- package/dist/core/PathFinder.d.ts +43 -0
- package/dist/core/PathFinder.d.ts.map +1 -0
- package/dist/core/PathFinder.js +264 -0
- package/dist/core/PathFinder.js.map +1 -0
- package/dist/formatters/BaseFormatter.d.ts +15 -0
- package/dist/formatters/BaseFormatter.d.ts.map +1 -0
- package/dist/formatters/BaseFormatter.js +9 -0
- package/dist/formatters/BaseFormatter.js.map +1 -0
- package/dist/graph/GraphAssembler.d.ts +14 -0
- package/dist/graph/GraphAssembler.d.ts.map +1 -0
- package/dist/graph/GraphAssembler.js +44 -0
- package/dist/graph/GraphAssembler.js.map +1 -0
- package/dist/graph/GraphCompiler.d.ts +37 -0
- package/dist/graph/GraphCompiler.d.ts.map +1 -0
- package/dist/graph/GraphCompiler.js +355 -0
- package/dist/graph/GraphCompiler.js.map +1 -0
- package/dist/graph/GraphExtractor.d.ts +21 -0
- package/dist/graph/GraphExtractor.d.ts.map +1 -0
- package/dist/graph/GraphExtractor.js +145 -0
- package/dist/graph/GraphExtractor.js.map +1 -0
- package/dist/graph/GraphOptimizer.d.ts +104 -0
- package/dist/graph/GraphOptimizer.d.ts.map +1 -0
- package/dist/graph/GraphOptimizer.js +306 -0
- package/dist/graph/GraphOptimizer.js.map +1 -0
- package/dist/graph/GraphTrainer.d.ts +52 -0
- package/dist/graph/GraphTrainer.d.ts.map +1 -0
- package/dist/graph/GraphTrainer.js +188 -0
- package/dist/graph/GraphTrainer.js.map +1 -0
- package/dist/http/LinkBuilder.d.ts +82 -0
- package/dist/http/LinkBuilder.d.ts.map +1 -0
- package/dist/http/LinkBuilder.js +190 -0
- package/dist/http/LinkBuilder.js.map +1 -0
- package/dist/http/TrailRequest.d.ts +39 -0
- package/dist/http/TrailRequest.d.ts.map +1 -0
- package/dist/http/TrailRequest.js +22 -0
- package/dist/http/TrailRequest.js.map +1 -0
- package/dist/http/example-netflix.d.ts +6 -0
- package/dist/http/example-netflix.d.ts.map +1 -0
- package/dist/http/example-netflix.js +52 -0
- package/dist/http/example-netflix.js.map +1 -0
- package/dist/http/index.d.ts +32 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +27 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/plugin.d.ts +110 -0
- package/dist/http/plugin.d.ts.map +1 -0
- package/dist/http/plugin.js +217 -0
- package/dist/http/plugin.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation/TelemetryShim.d.ts +114 -0
- package/dist/instrumentation/TelemetryShim.d.ts.map +1 -0
- package/dist/instrumentation/TelemetryShim.js +107 -0
- package/dist/instrumentation/TelemetryShim.js.map +1 -0
- package/dist/navigation/NavigationEngine.d.ts +69 -0
- package/dist/navigation/NavigationEngine.d.ts.map +1 -0
- package/dist/navigation/NavigationEngine.js +361 -0
- package/dist/navigation/NavigationEngine.js.map +1 -0
- package/dist/navigation/Resolver.d.ts +35 -0
- package/dist/navigation/Resolver.d.ts.map +1 -0
- package/dist/navigation/Resolver.js +113 -0
- package/dist/navigation/Resolver.js.map +1 -0
- package/dist/navigation/Scheduler.d.ts +36 -0
- package/dist/navigation/Scheduler.d.ts.map +1 -0
- package/dist/navigation/Scheduler.js +107 -0
- package/dist/navigation/Scheduler.js.map +1 -0
- package/dist/navigation/Trail.d.ts +129 -0
- package/dist/navigation/Trail.d.ts.map +1 -0
- package/dist/navigation/Trail.js +202 -0
- package/dist/navigation/Trail.js.map +1 -0
- package/dist/navigation/TrailParser.d.ts +96 -0
- package/dist/navigation/TrailParser.d.ts.map +1 -0
- package/dist/navigation/TrailParser.js +180 -0
- package/dist/navigation/TrailParser.js.map +1 -0
- package/dist/navigation/index.d.ts +10 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +9 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/providers/MockProvider.d.ts +29 -0
- package/dist/providers/MockProvider.d.ts.map +1 -0
- package/dist/providers/MockProvider.js +55 -0
- package/dist/providers/MockProvider.js.map +1 -0
- package/dist/providers/PostgresProvider.d.ts +46 -0
- package/dist/providers/PostgresProvider.d.ts.map +1 -0
- package/dist/providers/PostgresProvider.js +152 -0
- package/dist/providers/PostgresProvider.js.map +1 -0
- package/dist/runtime/CompiledGraphEngine.d.ts +74 -0
- package/dist/runtime/CompiledGraphEngine.d.ts.map +1 -0
- package/dist/runtime/CompiledGraphEngine.js +211 -0
- package/dist/runtime/CompiledGraphEngine.js.map +1 -0
- package/dist/runtime/DataLoader.d.ts +90 -0
- package/dist/runtime/DataLoader.d.ts.map +1 -0
- package/dist/runtime/DataLoader.js +178 -0
- package/dist/runtime/DataLoader.js.map +1 -0
- package/dist/runtime/Engine.d.ts +36 -0
- package/dist/runtime/Engine.d.ts.map +1 -0
- package/dist/runtime/Engine.js +128 -0
- package/dist/runtime/Engine.js.map +1 -0
- package/dist/runtime/QueryEngine.d.ts +80 -0
- package/dist/runtime/QueryEngine.d.ts.map +1 -0
- package/dist/runtime/QueryEngine.js +188 -0
- package/dist/runtime/QueryEngine.js.map +1 -0
- package/dist/scenarios/test-metro-paris/config.json +6 -0
- package/dist/scenarios/test-metro-paris/graph.json +16325 -0
- package/dist/scenarios/test-metro-paris/queries.d.ts +22 -0
- package/dist/scenarios/test-metro-paris/queries.d.ts.map +1 -0
- package/dist/scenarios/test-metro-paris/queries.js +128 -0
- package/dist/scenarios/test-metro-paris/queries.js.map +1 -0
- package/dist/scenarios/test-metro-paris/stack.json +1 -0
- package/dist/scenarios/test-musicians/config.json +10 -0
- package/dist/scenarios/test-musicians/graph.json +20 -0
- package/dist/scenarios/test-musicians/stack.json +1 -0
- package/dist/scenarios/test-netflix/actions.d.ts +14 -0
- package/dist/scenarios/test-netflix/actions.d.ts.map +1 -0
- package/dist/scenarios/test-netflix/actions.js +86 -0
- package/dist/scenarios/test-netflix/actions.js.map +1 -0
- package/dist/scenarios/test-netflix/config.json +6 -0
- package/dist/scenarios/test-netflix/data/categories.json +1 -0
- package/dist/scenarios/test-netflix/data/companies.json +1 -0
- package/dist/scenarios/test-netflix/data/credits.json +19797 -0
- package/dist/scenarios/test-netflix/data/departments.json +18 -0
- package/dist/scenarios/test-netflix/data/jobs.json +142 -0
- package/dist/scenarios/test-netflix/data/movies.json +3497 -0
- package/dist/scenarios/test-netflix/data/people.json +1 -0
- package/dist/scenarios/test-netflix/data/synonyms.json +7 -0
- package/dist/scenarios/test-netflix/data/users.json +70 -0
- package/dist/scenarios/test-netflix/graph.json +1017 -0
- package/dist/scenarios/test-netflix/queries.d.ts +29 -0
- package/dist/scenarios/test-netflix/queries.d.ts.map +1 -0
- package/dist/scenarios/test-netflix/queries.js +134 -0
- package/dist/scenarios/test-netflix/queries.js.map +1 -0
- package/dist/scenarios/test-netflix/stack.json +14 -0
- package/dist/schema/GraphBuilder.d.ts +9 -0
- package/dist/schema/GraphBuilder.d.ts.map +1 -0
- package/dist/schema/GraphBuilder.js +90 -0
- package/dist/schema/GraphBuilder.js.map +1 -0
- package/dist/schema/JsonSchemaExtractor.d.ts +21 -0
- package/dist/schema/JsonSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/JsonSchemaExtractor.js +88 -0
- package/dist/schema/JsonSchemaExtractor.js.map +1 -0
- package/dist/schema/SchemaAnalyzer.d.ts +41 -0
- package/dist/schema/SchemaAnalyzer.d.ts.map +1 -0
- package/dist/schema/SchemaAnalyzer.js +144 -0
- package/dist/schema/SchemaAnalyzer.js.map +1 -0
- package/dist/schema/SchemaExtractor.d.ts +10 -0
- package/dist/schema/SchemaExtractor.d.ts.map +1 -0
- package/dist/schema/SchemaExtractor.js +90 -0
- package/dist/schema/SchemaExtractor.js.map +1 -0
- package/dist/schema/SynonymResolver.d.ts +55 -0
- package/dist/schema/SynonymResolver.d.ts.map +1 -0
- package/dist/schema/SynonymResolver.js +121 -0
- package/dist/schema/SynonymResolver.js.map +1 -0
- package/dist/scripts/dictionary.json +796 -0
- package/dist/scripts/graph.json +664 -0
- package/dist/scripts/regenerate.d.ts +23 -0
- package/dist/scripts/regenerate.d.ts.map +1 -0
- package/dist/scripts/regenerate.js +206 -0
- package/dist/scripts/regenerate.js.map +1 -0
- package/dist/types/index.d.ts +394 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphCompiler — v2.0.0
|
|
3
|
+
*
|
|
4
|
+
* Changements vs v1 :
|
|
5
|
+
* - Routes sémantiques (semantic_view) compilées et incluses
|
|
6
|
+
* - compiled-graph contient physical + semantic routes
|
|
7
|
+
* - version bump : '2.0.0'
|
|
8
|
+
*
|
|
9
|
+
* v2.1 :
|
|
10
|
+
* - Support expose config (ADR-0010)
|
|
11
|
+
* - node.exposed compilé depuis CompilerConfig.expose
|
|
12
|
+
*/
|
|
13
|
+
import { PathFinder } from '../core/PathFinder.js';
|
|
14
|
+
export class GraphCompiler {
|
|
15
|
+
config;
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
this.config = {
|
|
18
|
+
weightThreshold: config.weightThreshold ?? 1000,
|
|
19
|
+
minUsage: config.minUsage ?? 0,
|
|
20
|
+
keepFallbacks: config.keepFallbacks ?? true,
|
|
21
|
+
maxFallbacks: config.maxFallbacks ?? 2,
|
|
22
|
+
expose: config.expose ?? 'none'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
compile(graph, metrics) {
|
|
26
|
+
console.log('🔧 Compiling optimized graph (v2 — physical + semantic)...\n');
|
|
27
|
+
const compiled = {
|
|
28
|
+
version: '2.0.0',
|
|
29
|
+
compiledAt: new Date().toISOString(),
|
|
30
|
+
config: this.config,
|
|
31
|
+
nodes: this.compileNodes(graph.nodes, this.config.expose),
|
|
32
|
+
routes: [],
|
|
33
|
+
stats: { totalPairs: 0, routesCompiled: 0, routesFiltered: 0, compressionRatio: '0%' }
|
|
34
|
+
};
|
|
35
|
+
// ── Nœuds réels (depuis les edges) ───────────────────────────────────────
|
|
36
|
+
const realNodes = new Set();
|
|
37
|
+
graph.edges.forEach(e => {
|
|
38
|
+
realNodes.add(e.from);
|
|
39
|
+
realNodes.add(e.to);
|
|
40
|
+
});
|
|
41
|
+
const nodeIds = Array.from(realNodes);
|
|
42
|
+
// ── 1. Routes physiques ───────────────────────────────────────────────────
|
|
43
|
+
const fkEdges = graph.edges.filter((e) => e.metadata?.type !== 'semantic_view' &&
|
|
44
|
+
e.metadata?.type !== 'virtual' &&
|
|
45
|
+
e.metadata?.type !== 'SEMANTIC');
|
|
46
|
+
const existingPairs = new Set(fkEdges.map((e) => `${e.from}→${e.to}`));
|
|
47
|
+
const inverseEdges = fkEdges
|
|
48
|
+
.filter((e) => !existingPairs.has(`${e.to}→${e.from}`))
|
|
49
|
+
.map((e) => ({
|
|
50
|
+
...e,
|
|
51
|
+
from: e.to,
|
|
52
|
+
to: e.from,
|
|
53
|
+
name: `${e.name}_inv`,
|
|
54
|
+
metadata: { ...e.metadata, type: 'physical_reverse' }
|
|
55
|
+
}));
|
|
56
|
+
const physicalGraph = { ...graph, edges: [...fkEdges, ...inverseEdges] };
|
|
57
|
+
let kept = 0, filtered = 0;
|
|
58
|
+
const pairs = this.getAllPairs(nodeIds);
|
|
59
|
+
for (const { from, to } of pairs) {
|
|
60
|
+
const route = this.compilePath(from, to, physicalGraph, metrics);
|
|
61
|
+
if (route) {
|
|
62
|
+
compiled.routes.push(route);
|
|
63
|
+
kept++;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
filtered++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ── 2. Routes sémantiques ─────────────────────────────────────────────────
|
|
70
|
+
const semanticEdges = graph.edges.filter((e) => e.metadata?.type === 'semantic_view' && e.metadata?.condition != null);
|
|
71
|
+
let semanticKept = 0;
|
|
72
|
+
for (const edge of semanticEdges) {
|
|
73
|
+
const route = this.compileSemanticRoute(edge, graph);
|
|
74
|
+
if (route) {
|
|
75
|
+
compiled.routes.push(route);
|
|
76
|
+
semanticKept++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ── 2b. Routes virtuelles ─────────────────────────────────────────────────
|
|
80
|
+
const virtualEdges = graph.edges.filter((e) => e.metadata?.type === 'virtual');
|
|
81
|
+
let virtualKept = 0;
|
|
82
|
+
for (const edge of virtualEdges) {
|
|
83
|
+
const { from, to, via, name, weight } = edge;
|
|
84
|
+
if (!nodeIds.includes(from) || !nodeIds.includes(to))
|
|
85
|
+
continue;
|
|
86
|
+
const viaTable = via && nodeIds.includes(via) ? via : null;
|
|
87
|
+
const path = viaTable ? [from, viaTable, to] : [from, to];
|
|
88
|
+
const edges = viaTable
|
|
89
|
+
? [
|
|
90
|
+
{ fromCol: 'id', toCol: 'id' },
|
|
91
|
+
{ fromCol: 'id', toCol: 'id' }
|
|
92
|
+
]
|
|
93
|
+
: [{ fromCol: 'id', toCol: 'id' }];
|
|
94
|
+
compiled.routes.push({
|
|
95
|
+
from,
|
|
96
|
+
to,
|
|
97
|
+
semantic: false,
|
|
98
|
+
composed: false,
|
|
99
|
+
label: name ?? `virtual_${from}_${to}`,
|
|
100
|
+
virtual: true,
|
|
101
|
+
primary: {
|
|
102
|
+
path,
|
|
103
|
+
edges,
|
|
104
|
+
weight: weight ?? 1,
|
|
105
|
+
joins: path.length - 1,
|
|
106
|
+
avgTime: weight ?? 1
|
|
107
|
+
},
|
|
108
|
+
fallbacks: [],
|
|
109
|
+
alternativesDiscarded: 0
|
|
110
|
+
});
|
|
111
|
+
virtualKept++;
|
|
112
|
+
}
|
|
113
|
+
// ── 3. Routes composées ───────────────────────────────────────────────────
|
|
114
|
+
const compiledSemRoutes = compiled.routes.filter((r) => r.semantic);
|
|
115
|
+
let composedKept = 0;
|
|
116
|
+
const semByFrom = new Map();
|
|
117
|
+
for (const r of compiledSemRoutes) {
|
|
118
|
+
if (!semByFrom.has(r.from))
|
|
119
|
+
semByFrom.set(r.from, []);
|
|
120
|
+
semByFrom.get(r.from).push(r);
|
|
121
|
+
}
|
|
122
|
+
for (const [entityId, outRoutes] of semByFrom) {
|
|
123
|
+
const inRoutes = compiledSemRoutes.filter((r) => r.to === entityId);
|
|
124
|
+
if (!inRoutes.length)
|
|
125
|
+
continue;
|
|
126
|
+
for (const rOut of outRoutes) {
|
|
127
|
+
const pivot = rOut.to;
|
|
128
|
+
const matchingIn = inRoutes.filter((r) => r.from === pivot);
|
|
129
|
+
for (const rIn of matchingIn) {
|
|
130
|
+
if (rOut.label === rIn.label)
|
|
131
|
+
continue;
|
|
132
|
+
const composedLabel = `${rOut.label}→${rIn.label}`;
|
|
133
|
+
const composedWeight = rOut.primary.weight + rIn.primary.weight;
|
|
134
|
+
const composedPath = [...rOut.primary.path, ...rIn.primary.path.slice(1)];
|
|
135
|
+
const composedEdges = [...rOut.primary.edges, ...rIn.primary.edges];
|
|
136
|
+
const metricKey = `composed:${entityId}→${entityId}:${composedLabel}`;
|
|
137
|
+
const metric = metrics.get(metricKey);
|
|
138
|
+
if (metrics.size > 0) {
|
|
139
|
+
if (!metric)
|
|
140
|
+
continue;
|
|
141
|
+
const w = metric.avgTime ?? composedWeight;
|
|
142
|
+
if (!metric.used || w > this.config.weightThreshold)
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
compiled.routes.push({
|
|
146
|
+
from: entityId,
|
|
147
|
+
to: entityId,
|
|
148
|
+
semantic: true,
|
|
149
|
+
composed: true,
|
|
150
|
+
label: composedLabel,
|
|
151
|
+
primary: {
|
|
152
|
+
path: composedPath,
|
|
153
|
+
edges: composedEdges,
|
|
154
|
+
weight: composedWeight,
|
|
155
|
+
joins: composedPath.length - 1,
|
|
156
|
+
avgTime: composedWeight
|
|
157
|
+
},
|
|
158
|
+
fallbacks: [],
|
|
159
|
+
alternativesDiscarded: 0
|
|
160
|
+
});
|
|
161
|
+
composedKept++;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
compiled.stats = {
|
|
166
|
+
totalPairs: pairs.length,
|
|
167
|
+
routesCompiled: kept + semanticKept + virtualKept + composedKept,
|
|
168
|
+
routesFiltered: filtered,
|
|
169
|
+
compressionRatio: '—'
|
|
170
|
+
};
|
|
171
|
+
console.log('\n✅ Compilation complete:');
|
|
172
|
+
console.log(` Physical routes: ${kept}`);
|
|
173
|
+
console.log(` Semantic routes: ${semanticKept}`);
|
|
174
|
+
console.log(` Composed routes: ${composedKept}`);
|
|
175
|
+
console.log(` Filtered: ${filtered}`);
|
|
176
|
+
return compiled;
|
|
177
|
+
}
|
|
178
|
+
// ── Compile exposed flag sur chaque node ────────────────────────────────────
|
|
179
|
+
compileNodes(nodes, expose) {
|
|
180
|
+
return nodes.map(node => {
|
|
181
|
+
let exposed;
|
|
182
|
+
if (expose === 'all') {
|
|
183
|
+
exposed = true;
|
|
184
|
+
}
|
|
185
|
+
else if (expose === 'none') {
|
|
186
|
+
exposed = false;
|
|
187
|
+
}
|
|
188
|
+
else if ('include' in expose) {
|
|
189
|
+
exposed = expose.include.includes(node.id);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
exposed = !expose.exclude.includes(node.id);
|
|
193
|
+
}
|
|
194
|
+
return { ...node, exposed };
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// ── Route sémantique ─────────────────────────────────────────────────────────
|
|
198
|
+
compileSemanticRoute(edge, graph) {
|
|
199
|
+
const { from, to, via, metadata } = edge;
|
|
200
|
+
const condition = metadata.condition ?? {};
|
|
201
|
+
const label = edge.name ?? metadata.label ?? 'view';
|
|
202
|
+
const e1Raw = graph.edges.find((e) => ((e.from === from && e.to === via) || (e.from === via && e.to === from)) &&
|
|
203
|
+
(e.metadata?.type === 'physical' || e.metadata?.type === 'physical_reverse'));
|
|
204
|
+
const e2Raw = graph.edges.find((e) => ((e.from === via && e.to === to) || (e.from === to && e.to === via)) &&
|
|
205
|
+
(e.metadata?.type === 'physical' || e.metadata?.type === 'physical_reverse'));
|
|
206
|
+
if (!e1Raw || !e2Raw)
|
|
207
|
+
return null;
|
|
208
|
+
const e1IsReversed = e1Raw.from === via;
|
|
209
|
+
const e1 = {
|
|
210
|
+
fromCol: e1IsReversed ? 'id' : (e1Raw.via ?? 'id'),
|
|
211
|
+
toCol: e1IsReversed ? (e1Raw.via ?? 'id') : 'id',
|
|
212
|
+
condition,
|
|
213
|
+
label
|
|
214
|
+
};
|
|
215
|
+
const e2IsReversed = e2Raw.from === to;
|
|
216
|
+
const e2 = {
|
|
217
|
+
fromCol: e2IsReversed ? 'id' : (e2Raw.via ?? 'id'),
|
|
218
|
+
toCol: e2IsReversed ? (e2Raw.via ?? 'id') : 'id'
|
|
219
|
+
};
|
|
220
|
+
return {
|
|
221
|
+
from,
|
|
222
|
+
to,
|
|
223
|
+
semantic: true,
|
|
224
|
+
label,
|
|
225
|
+
primary: {
|
|
226
|
+
path: [from, via, to],
|
|
227
|
+
edges: [e1, e2],
|
|
228
|
+
weight: edge.weight ?? 0.8,
|
|
229
|
+
joins: 2,
|
|
230
|
+
avgTime: edge.weight ?? 0.8
|
|
231
|
+
},
|
|
232
|
+
fallbacks: [],
|
|
233
|
+
alternativesDiscarded: 0
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
// ── Routes physiques ──────────────────────────────────────────────────────────
|
|
237
|
+
getAllPairs(nodeIds) {
|
|
238
|
+
const pairs = [];
|
|
239
|
+
for (const from of nodeIds)
|
|
240
|
+
for (const to of nodeIds)
|
|
241
|
+
if (from !== to)
|
|
242
|
+
pairs.push({ from, to });
|
|
243
|
+
return pairs;
|
|
244
|
+
}
|
|
245
|
+
compilePath(from, to, graph, metrics) {
|
|
246
|
+
const finder = new PathFinder(graph);
|
|
247
|
+
const allPaths = finder.findAllPaths(from, to, 5);
|
|
248
|
+
if (!allPaths.length)
|
|
249
|
+
return null;
|
|
250
|
+
const pathsWithMetrics = allPaths.map(path => {
|
|
251
|
+
const key = path.join('→');
|
|
252
|
+
const metric = metrics.get(key);
|
|
253
|
+
let w = 0;
|
|
254
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
255
|
+
const ee = graph.edges.filter(e => (e.from === path[i] && e.to === path[i + 1]) ||
|
|
256
|
+
(e.from === path[i + 1] && e.to === path[i]));
|
|
257
|
+
const ws = ee.map(e => Number(e.weight)).filter(x => !isNaN(x));
|
|
258
|
+
w += ws.length ? Math.min(...ws) : 1;
|
|
259
|
+
}
|
|
260
|
+
const finalWeight = metric && !isNaN(metric.avgTime) ? metric.avgTime : w;
|
|
261
|
+
return {
|
|
262
|
+
path,
|
|
263
|
+
key,
|
|
264
|
+
weight: finalWeight,
|
|
265
|
+
failed: metric?.failed === true,
|
|
266
|
+
used: metric ? metric.used : true
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
const valid = pathsWithMetrics
|
|
270
|
+
.filter(p => !p.failed && p.used !== false)
|
|
271
|
+
.filter(p => !isNaN(p.weight) && p.weight <= this.config.weightThreshold)
|
|
272
|
+
.sort((a, b) => a.weight - b.weight);
|
|
273
|
+
if (!valid.length)
|
|
274
|
+
return null;
|
|
275
|
+
const unique = [];
|
|
276
|
+
const seen = new Set();
|
|
277
|
+
for (const p of valid) {
|
|
278
|
+
if (!seen.has(p.key)) {
|
|
279
|
+
unique.push(p);
|
|
280
|
+
seen.add(p.key);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const best = unique[0];
|
|
284
|
+
const fallbacks = this.config.keepFallbacks ? unique.slice(1, this.config.maxFallbacks + 1) : [];
|
|
285
|
+
const primaryEdges = this.resolveEdges(best.path, graph);
|
|
286
|
+
if (!primaryEdges)
|
|
287
|
+
return null;
|
|
288
|
+
return {
|
|
289
|
+
from,
|
|
290
|
+
to,
|
|
291
|
+
primary: {
|
|
292
|
+
path: best.path,
|
|
293
|
+
edges: primaryEdges,
|
|
294
|
+
weight: best.weight,
|
|
295
|
+
joins: best.path.length - 1,
|
|
296
|
+
avgTime: best.weight
|
|
297
|
+
},
|
|
298
|
+
fallbacks: fallbacks
|
|
299
|
+
.map(fb => {
|
|
300
|
+
const ee = this.resolveEdges(fb.path, graph);
|
|
301
|
+
if (!ee)
|
|
302
|
+
return null;
|
|
303
|
+
return {
|
|
304
|
+
path: fb.path,
|
|
305
|
+
edges: ee,
|
|
306
|
+
weight: fb.weight,
|
|
307
|
+
joins: fb.path.length - 1,
|
|
308
|
+
avgTime: fb.weight
|
|
309
|
+
};
|
|
310
|
+
})
|
|
311
|
+
.filter((fb) => fb !== null),
|
|
312
|
+
alternativesDiscarded: unique.length - 1 - fallbacks.length
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
resolveEdges(path, graph) {
|
|
316
|
+
const result = [];
|
|
317
|
+
const nodeNames = new Set(graph.nodes.map((n) => n.id));
|
|
318
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
319
|
+
const from = path[i], to = path[i + 1];
|
|
320
|
+
const edgeDirect = graph.edges.find((e) => e.from === from && e.to === to);
|
|
321
|
+
const edgeReverse = graph.edges.find((e) => e.from === to && e.to === from);
|
|
322
|
+
const edge = edgeDirect ?? edgeReverse;
|
|
323
|
+
const isReversed = !edgeDirect && !!edgeReverse;
|
|
324
|
+
if (!edge) {
|
|
325
|
+
result.push({ fromCol: 'id', toCol: `${from.toLowerCase()}Id` });
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (edge.metadata?.type === 'semantic_view' && nodeNames.has(edge.via))
|
|
329
|
+
return null;
|
|
330
|
+
const flipCols = edge.metadata?.type === 'physical_reverse' || isReversed;
|
|
331
|
+
result.push({
|
|
332
|
+
fromCol: flipCols ? 'id' : edge.via || 'id',
|
|
333
|
+
toCol: flipCols ? edge.via || 'id' : 'id'
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
static getStats(compiled) {
|
|
339
|
+
const routes = compiled.routes;
|
|
340
|
+
const semantic = routes.filter(r => r.semantic && !r.composed).length;
|
|
341
|
+
const composed = routes.filter(r => r.composed).length;
|
|
342
|
+
const physical = routes.length - semantic - composed;
|
|
343
|
+
if (!routes.length)
|
|
344
|
+
return { totalRoutes: 0, fallbackRatio: '0%', semantic: 0, physical: 0, composed: 0 };
|
|
345
|
+
const withFallbacks = routes.filter(r => r.fallbacks.length > 0).length;
|
|
346
|
+
return {
|
|
347
|
+
totalRoutes: routes.length,
|
|
348
|
+
physical,
|
|
349
|
+
semantic,
|
|
350
|
+
composed,
|
|
351
|
+
fallbackRatio: ((withFallbacks / routes.length) * 100).toFixed(1) + '%'
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
//# sourceMappingURL=GraphCompiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphCompiler.js","sourceRoot":"","sources":["../../src/graph/GraphCompiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Graph, Provider, ActionRegistry } from '../types/index.js';
|
|
2
|
+
export declare class GraphExtractor {
|
|
3
|
+
private provider;
|
|
4
|
+
private actionRegistry?;
|
|
5
|
+
constructor(provider: Provider, actionRegistry?: ActionRegistry);
|
|
6
|
+
/**
|
|
7
|
+
* Extrait le graphe complet : Tables + Actions + Relations
|
|
8
|
+
*/
|
|
9
|
+
extract(): Promise<Graph>;
|
|
10
|
+
private getTables;
|
|
11
|
+
private getColumns;
|
|
12
|
+
private getRowCount;
|
|
13
|
+
private getForeignKeys;
|
|
14
|
+
/**
|
|
15
|
+
* Calcul du poids initial (Physique de la donnée)
|
|
16
|
+
* On utilise le logarithme de la taille pour ne pas pénaliser trop lourdement
|
|
17
|
+
* les grosses tables, mais garder une notion de "frais de déplacement".
|
|
18
|
+
*/
|
|
19
|
+
private calculateInitialWeight;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=GraphExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphExtractor.d.ts","sourceRoot":"","sources":["../../src/graph/GraphExtractor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,KAAK,EAGL,QAAQ,EAER,cAAc,EACf,MAAM,mBAAmB,CAAA;AAe1B,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,cAAc,CAAC,CAAgB;gBAE3B,QAAQ,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,cAAc;IAK/D;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC;YAmDjB,SAAS;YAgCT,UAAU;YA0BV,WAAW;YAUX,cAAc;IAwB5B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAO/B"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
export class GraphExtractor {
|
|
3
|
+
provider;
|
|
4
|
+
actionRegistry;
|
|
5
|
+
constructor(provider, actionRegistry) {
|
|
6
|
+
this.provider = provider;
|
|
7
|
+
this.actionRegistry = actionRegistry;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Extrait le graphe complet : Tables + Actions + Relations
|
|
11
|
+
*/
|
|
12
|
+
async extract() {
|
|
13
|
+
console.log('📊 LinkLab : Extraction du graphe sémantique...');
|
|
14
|
+
// 1. Extraction des tables et leurs métadonnées
|
|
15
|
+
const tables = await this.getTables();
|
|
16
|
+
console.log(` Found ${tables.length} tables`);
|
|
17
|
+
// 2. Extraction des clés étrangères (Relations natives)
|
|
18
|
+
const foreignKeys = await this.getForeignKeys();
|
|
19
|
+
console.log(` Found ${foreignKeys.length} foreign keys`);
|
|
20
|
+
// 3. Construction des Nœuds (Tables)
|
|
21
|
+
const nodes = tables.map(t => ({
|
|
22
|
+
id: t.name,
|
|
23
|
+
type: 'table',
|
|
24
|
+
columns: t.columns,
|
|
25
|
+
rowCount: t.rowCount,
|
|
26
|
+
description: t.description || ''
|
|
27
|
+
}));
|
|
28
|
+
// 4. Injection des Nœuds (Actions) - Si présentes dans le registre
|
|
29
|
+
if (this.actionRegistry) {
|
|
30
|
+
const actions = this.actionRegistry.getAll();
|
|
31
|
+
actions.forEach(action => {
|
|
32
|
+
nodes.push({
|
|
33
|
+
id: action.id,
|
|
34
|
+
type: 'action',
|
|
35
|
+
description: action.description || 'Action système',
|
|
36
|
+
params: action.requiredParams
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// 5. Construction des Edges (Liaisons)
|
|
41
|
+
const edges = foreignKeys.map(fk => ({
|
|
42
|
+
name: `rel_${fk.fromTable}_${fk.toTable}`,
|
|
43
|
+
from: fk.fromTable,
|
|
44
|
+
to: fk.toTable,
|
|
45
|
+
via: fk.column,
|
|
46
|
+
type: 'foreign_key',
|
|
47
|
+
weight: this.calculateInitialWeight(fk, tables)
|
|
48
|
+
}));
|
|
49
|
+
const graph = { nodes, edges };
|
|
50
|
+
console.log('✅ Graphe LinkLab extrait avec succès');
|
|
51
|
+
fs.writeFileSync('./graph.json', JSON.stringify(graph, null, 2));
|
|
52
|
+
return graph;
|
|
53
|
+
}
|
|
54
|
+
async getTables() {
|
|
55
|
+
// On récupère aussi la description de la table (COMMENT ON TABLE)
|
|
56
|
+
const query = `
|
|
57
|
+
SELECT
|
|
58
|
+
t.table_name as name,
|
|
59
|
+
obj_description(pgc.oid, 'pg_class') as description
|
|
60
|
+
FROM information_schema.tables t
|
|
61
|
+
JOIN pg_class pgc ON t.table_name = pgc.relname
|
|
62
|
+
JOIN pg_namespace pgn ON pgc.relnamespace = pgn.oid
|
|
63
|
+
WHERE t.table_schema = 'public'
|
|
64
|
+
AND t.table_type = 'BASE TABLE'
|
|
65
|
+
AND pgn.nspname = 'public'
|
|
66
|
+
`;
|
|
67
|
+
const result = await this.provider.query(query);
|
|
68
|
+
const tables = [];
|
|
69
|
+
for (const table of result) {
|
|
70
|
+
const columns = await this.getColumns(table.name);
|
|
71
|
+
const rowCount = await this.getRowCount(table.name);
|
|
72
|
+
tables.push({
|
|
73
|
+
name: table.name,
|
|
74
|
+
columns,
|
|
75
|
+
rowCount,
|
|
76
|
+
description: table.description
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return tables;
|
|
80
|
+
}
|
|
81
|
+
async getColumns(tableName) {
|
|
82
|
+
// Récupère les colonnes ET leurs descriptions (COMMENT ON COLUMN)
|
|
83
|
+
const query = `
|
|
84
|
+
SELECT
|
|
85
|
+
cols.column_name,
|
|
86
|
+
cols.data_type,
|
|
87
|
+
(SELECT pg_catalog.col_description(c.oid, cols.ordinal_position::int)
|
|
88
|
+
FROM pg_catalog.pg_class c
|
|
89
|
+
WHERE c.relname = cols.table_name) as description
|
|
90
|
+
FROM information_schema.columns cols
|
|
91
|
+
WHERE table_name = $1
|
|
92
|
+
`;
|
|
93
|
+
const result = await this.provider.query(query, [tableName]);
|
|
94
|
+
return result.map(c => ({
|
|
95
|
+
name: c.column_name,
|
|
96
|
+
type: c.data_type,
|
|
97
|
+
description: c.description || ''
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
async getRowCount(tableName) {
|
|
101
|
+
try {
|
|
102
|
+
const query = `SELECT reltuples::bigint as count FROM pg_class WHERE relname = $1`;
|
|
103
|
+
const result = await this.provider.query(query, [tableName]);
|
|
104
|
+
return parseInt(result[0]?.count || '0', 10);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async getForeignKeys() {
|
|
111
|
+
const query = `
|
|
112
|
+
SELECT
|
|
113
|
+
tc.table_name as from_table,
|
|
114
|
+
kcu.column_name as column,
|
|
115
|
+
ccu.table_name as to_table,
|
|
116
|
+
-- Vérifie si la colonne est unique ou PK pour la cardinalité
|
|
117
|
+
(SELECT COUNT(*)
|
|
118
|
+
FROM information_schema.table_constraints i_tc
|
|
119
|
+
JOIN information_schema.key_column_usage i_kcu
|
|
120
|
+
ON i_tc.constraint_name = i_kcu.constraint_name
|
|
121
|
+
WHERE i_tc.table_name = tc.table_name
|
|
122
|
+
AND i_kcu.column_name = kcu.column_name
|
|
123
|
+
AND (i_tc.constraint_type = 'PRIMARY KEY' OR i_tc.constraint_type = 'UNIQUE')
|
|
124
|
+
) > 0 as is_unique
|
|
125
|
+
FROM information_schema.table_constraints tc
|
|
126
|
+
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
|
|
127
|
+
JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
|
|
128
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
129
|
+
`;
|
|
130
|
+
return await this.provider.query(query);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Calcul du poids initial (Physique de la donnée)
|
|
134
|
+
* On utilise le logarithme de la taille pour ne pas pénaliser trop lourdement
|
|
135
|
+
* les grosses tables, mais garder une notion de "frais de déplacement".
|
|
136
|
+
*/
|
|
137
|
+
calculateInitialWeight(fk, tables) {
|
|
138
|
+
const targetTable = tables.find(t => t.name === fk.toTable);
|
|
139
|
+
if (!targetTable || targetTable.rowCount <= 0)
|
|
140
|
+
return 1;
|
|
141
|
+
// Formule : 1 + log10(n) -> 100 lignes = poids 3, 1M lignes = poids 7.
|
|
142
|
+
return 1 + Math.log10(targetTable.rowCount);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=GraphExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphExtractor.js","sourceRoot":"","sources":["../../src/graph/GraphExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphOptimizer — Analyse et rapport sur la qualité du graphe
|
|
3
|
+
*
|
|
4
|
+
* PRINCIPE : signaler, jamais détruire silencieusement.
|
|
5
|
+
*
|
|
6
|
+
* Chaque étape produit un rapport (warnings, suggestions).
|
|
7
|
+
* Le dev décide ensuite de ce qu'il fait.
|
|
8
|
+
*
|
|
9
|
+
* Seules deux opérations sont automatiques et non destructives :
|
|
10
|
+
* - Suppression des nœuds orphelins (aucune arête — objectivement inutiles)
|
|
11
|
+
* - Suppression des nœuds dead-end stricts (aucune arête entrante ET sortante)
|
|
12
|
+
*
|
|
13
|
+
* Les cycles sont DÉTECTÉS et CLASSIFIÉS, jamais supprimés :
|
|
14
|
+
* - SELF_LOOP : arête A → A (ex: Station-chatelet → Station-chatelet TRANSFER)
|
|
15
|
+
* - BIDIRECTIONAL : A → B et B → A (ex: CREATED + CREDITED — intentionnel)
|
|
16
|
+
* - STRUCTURAL_CYCLE : A → B → C → A (même type de relation — potentiellement problématique)
|
|
17
|
+
*/
|
|
18
|
+
import type { Graph } from '../types/index.js';
|
|
19
|
+
export type CycleType = 'SELF_LOOP' | 'BIDIRECTIONAL' | 'STRUCTURAL_CYCLE';
|
|
20
|
+
export type WarningSeverity = 'INFO' | 'WARNING';
|
|
21
|
+
export interface CycleWarning {
|
|
22
|
+
type: CycleType;
|
|
23
|
+
severity: WarningSeverity;
|
|
24
|
+
edges: string[];
|
|
25
|
+
nodes: string[];
|
|
26
|
+
note: string;
|
|
27
|
+
}
|
|
28
|
+
export interface DuplicatePathWarning {
|
|
29
|
+
from: string;
|
|
30
|
+
to: string;
|
|
31
|
+
paths: string[][];
|
|
32
|
+
note: string;
|
|
33
|
+
}
|
|
34
|
+
export interface GraphOptimizationReport {
|
|
35
|
+
graph: Graph;
|
|
36
|
+
summary: {
|
|
37
|
+
nodes: {
|
|
38
|
+
before: number;
|
|
39
|
+
after: number;
|
|
40
|
+
removed: number;
|
|
41
|
+
};
|
|
42
|
+
edges: {
|
|
43
|
+
before: number;
|
|
44
|
+
after: number;
|
|
45
|
+
removed: number;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
cycles: CycleWarning[];
|
|
49
|
+
duplicatePaths: DuplicatePathWarning[];
|
|
50
|
+
removedOrphans: string[];
|
|
51
|
+
removedDeadEnds: string[];
|
|
52
|
+
isClean: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface GraphOptimizerConfig {
|
|
55
|
+
/**
|
|
56
|
+
* Types de relations bidirectionnelles considérés comme intentionnels (INFO, pas WARNING).
|
|
57
|
+
* Ex: ['DIRECT', 'TRANSFER', 'physical_reverse', 'INFLUENCE']
|
|
58
|
+
* Par défaut : ['physical_reverse'] — les inverses FK sont toujours intentionnels.
|
|
59
|
+
*/
|
|
60
|
+
intentionalBidirectional?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Types de self-loops considérés comme intentionnels (INFO, pas WARNING).
|
|
63
|
+
* Ex: ['TRANSFER'] — les correspondances métro sont des self-loops normaux.
|
|
64
|
+
* Par défaut : [] — tout self-loop est signalé.
|
|
65
|
+
*/
|
|
66
|
+
intentionalSelfLoops?: string[];
|
|
67
|
+
}
|
|
68
|
+
export declare class GraphOptimizer {
|
|
69
|
+
private graph;
|
|
70
|
+
private config;
|
|
71
|
+
constructor(graph: Graph, config?: GraphOptimizerConfig);
|
|
72
|
+
/**
|
|
73
|
+
* Pipeline complet — retourne un rapport, ne modifie pas le graphe original.
|
|
74
|
+
* Seuls orphelins et dead-ends stricts sont supprimés (safe).
|
|
75
|
+
*/
|
|
76
|
+
optimize(): GraphOptimizationReport;
|
|
77
|
+
/**
|
|
78
|
+
* Détecte et classifie les cycles — ne supprime rien.
|
|
79
|
+
*/
|
|
80
|
+
private detectCycles;
|
|
81
|
+
/**
|
|
82
|
+
* Détecte les cycles structurels A → B → ... → A
|
|
83
|
+
* en ne suivant que les arêtes du même type.
|
|
84
|
+
*/
|
|
85
|
+
private detectStructuralCycles;
|
|
86
|
+
/**
|
|
87
|
+
* Supprime les nœuds sans aucune arête (entrante ou sortante).
|
|
88
|
+
* Inoffensif — un nœud isolé ne contribue à aucune traversée.
|
|
89
|
+
*/
|
|
90
|
+
private removeOrphans;
|
|
91
|
+
/**
|
|
92
|
+
* Supprime les nœuds sans arête entrante ET sans arête sortante
|
|
93
|
+
* après suppression des orphelins.
|
|
94
|
+
* Différent de removeOrphans — cible les nœuds stricts.
|
|
95
|
+
*/
|
|
96
|
+
private removeStrictDeadEnds;
|
|
97
|
+
/**
|
|
98
|
+
* Détecte les paires de nœuds avec plusieurs chemins possibles.
|
|
99
|
+
* Informatif — les chemins multiples sont souvent intentionnels (fallbacks).
|
|
100
|
+
*/
|
|
101
|
+
private detectDuplicatePaths;
|
|
102
|
+
private printReport;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=GraphOptimizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphOptimizer.d.ts","sourceRoot":"","sources":["../../src/graph/GraphOptimizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAwB,MAAM,mBAAmB,CAAA;AAKpE,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,eAAe,GAAG,kBAAkB,CAAA;AAC1E,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,CAAA;AAEhD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,eAAe,CAAA;IACzB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,EAAE,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE;QACP,KAAK,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;QACzD,KAAK,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAC1D,CAAA;IACD,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,cAAc,EAAE,oBAAoB,EAAE,CAAA;IACtC,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,OAAO,EAAE,OAAO,CAAA;CACjB;AAID,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAA;IAEnC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;CAChC;AAOD,qBAAa,cAAc;IAIb,OAAO,CAAC,KAAK;IAFzB,OAAO,CAAC,MAAM,CAAgC;gBAE1B,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,oBAAyB;IAOnE;;;OAGG;IACH,QAAQ,IAAI,uBAAuB;IA4DnC;;OAEG;IACH,OAAO,CAAC,YAAY;IA8DpB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAmE9B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAoBrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAsB5B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA6B5B,OAAO,CAAC,WAAW;CA+BpB"}
|