@linklabjs/core 0.1.0 → 0.1.2
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,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduler - Exécution d'actions par priorité (mode SCHEDULE)
|
|
3
|
+
*
|
|
4
|
+
* À chaque step :
|
|
5
|
+
* 1. Filtre les actions disponibles (condition when + cooldown + terminal)
|
|
6
|
+
* 2. Sélectionne la plus prioritaire (weight le plus élevé)
|
|
7
|
+
* 3. L'exécute et met à jour l'état interne
|
|
8
|
+
*
|
|
9
|
+
* C'est le cœur du moteur d'agent : une boucle de décision
|
|
10
|
+
* déterministe basée sur les poids et l'état de la stack.
|
|
11
|
+
*/
|
|
12
|
+
export class Scheduler {
|
|
13
|
+
actions;
|
|
14
|
+
graph;
|
|
15
|
+
actionStates;
|
|
16
|
+
constructor(actions, graph) {
|
|
17
|
+
this.actions = actions;
|
|
18
|
+
this.graph = graph;
|
|
19
|
+
// Initialise l'état de chaque action
|
|
20
|
+
this.actionStates = new Map(actions.map(a => [
|
|
21
|
+
a.name,
|
|
22
|
+
{ cooldownUntil: 0, executionCount: 0, executed: false }
|
|
23
|
+
]));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Exécute un step du scheduler.
|
|
27
|
+
* Retourne null si aucune action n'est disponible (terminaison naturelle).
|
|
28
|
+
*/
|
|
29
|
+
async step(time, stack) {
|
|
30
|
+
const available = this.getAvailableActions(time, stack);
|
|
31
|
+
if (available.length === 0)
|
|
32
|
+
return null;
|
|
33
|
+
// Sélection déterministe : weight le plus élevé
|
|
34
|
+
const selected = available.reduce((best, action) => action.weight > best.weight ? action : best);
|
|
35
|
+
console.log(` ⚙️ [Scheduler t=${time}] → ${selected.name} (weight: ${selected.weight})`);
|
|
36
|
+
let result;
|
|
37
|
+
let updatedStack = stack;
|
|
38
|
+
try {
|
|
39
|
+
updatedStack = await selected.execute(stack, this.graph);
|
|
40
|
+
result = { type: 'SUCCESS', data: updatedStack };
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
result = {
|
|
44
|
+
type: 'FAIL',
|
|
45
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
46
|
+
};
|
|
47
|
+
console.error(` ❌ [Scheduler] Action échouée: ${selected.name}`, err);
|
|
48
|
+
}
|
|
49
|
+
// Callback optionnel (analytics, logging externe...)
|
|
50
|
+
if (selected.onUse) {
|
|
51
|
+
try {
|
|
52
|
+
selected.onUse(stack, result);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Silencieux — le callback ne doit pas planter le scheduler
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Mise à jour de l'état de l'action
|
|
59
|
+
this.updateState(selected, result, time);
|
|
60
|
+
return {
|
|
61
|
+
selectedAction: selected.name,
|
|
62
|
+
result,
|
|
63
|
+
updatedStack: result.type === 'SUCCESS' ? updatedStack : stack
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Retourne les actions disponibles à un instant t pour une stack donnée.
|
|
68
|
+
* Filtre : terminal déjà exécuté, cooldown, maxExecutions, condition when().
|
|
69
|
+
*/
|
|
70
|
+
getAvailableActions(time, stack) {
|
|
71
|
+
return this.actions.filter(action => {
|
|
72
|
+
const state = this.actionStates.get(action.name);
|
|
73
|
+
// Action terminale déjà exécutée
|
|
74
|
+
if (action.terminal && state.executed)
|
|
75
|
+
return false;
|
|
76
|
+
// En cooldown
|
|
77
|
+
if (state.cooldownUntil > time)
|
|
78
|
+
return false;
|
|
79
|
+
// Limite d'exécutions atteinte
|
|
80
|
+
if (action.maxExecutions !== undefined && state.executionCount >= action.maxExecutions) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
// Condition métier
|
|
84
|
+
if (!action.when)
|
|
85
|
+
return true;
|
|
86
|
+
try {
|
|
87
|
+
return action.when(stack);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
updateState(action, result, time) {
|
|
95
|
+
const current = this.actionStates.get(action.name);
|
|
96
|
+
this.actionStates.set(action.name, {
|
|
97
|
+
cooldownUntil: result.type === 'DEFER' ? time + (action.cooldown ?? 0) : 0,
|
|
98
|
+
executionCount: current.executionCount + 1,
|
|
99
|
+
executed: action.terminal ? true : current.executed,
|
|
100
|
+
lastResult: result
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
getActionState(name) {
|
|
104
|
+
return this.actionStates.get(name);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=Scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scheduler.js","sourceRoot":"","sources":["../../src/navigation/Scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trail — Contexte de navigation vivant
|
|
3
|
+
*
|
|
4
|
+
* Trois niveaux de contexte, trois durées de vie :
|
|
5
|
+
*
|
|
6
|
+
* global — vit aussi longtemps que l'instance LinkLab
|
|
7
|
+
* config, feature flags, métriques globales
|
|
8
|
+
*
|
|
9
|
+
* user — vit le temps d'une session
|
|
10
|
+
* userId, permissions, préférences, historique récent
|
|
11
|
+
*
|
|
12
|
+
* frames — vit le temps d'une navigation
|
|
13
|
+
* le chemin parcouru, position courante
|
|
14
|
+
*
|
|
15
|
+
* Deux niveaux d'API :
|
|
16
|
+
*
|
|
17
|
+
* Bas niveau — trail.push(frame), trail.pop(), trail.compact()
|
|
18
|
+
* fondation sur laquelle tout repose
|
|
19
|
+
*
|
|
20
|
+
* Haut niveau — API fluente, construite sur push()
|
|
21
|
+
* cinema.people('Nolan').movies
|
|
22
|
+
*
|
|
23
|
+
* Contrat de sérialisation :
|
|
24
|
+
* global et user ne contiennent que des données — jamais de fonctions.
|
|
25
|
+
* Un Trail sérialisé peut être rejoué exactement.
|
|
26
|
+
*/
|
|
27
|
+
import type { Frame } from '../types/index.js';
|
|
28
|
+
export interface TrailInit {
|
|
29
|
+
global?: Record<string, any>;
|
|
30
|
+
user?: Record<string, any>;
|
|
31
|
+
frames?: Frame[];
|
|
32
|
+
}
|
|
33
|
+
/** Format de sérialisation — versionné pour les migrations futures */
|
|
34
|
+
export interface SerializedTrail {
|
|
35
|
+
v: number;
|
|
36
|
+
global: Record<string, any>;
|
|
37
|
+
user: Record<string, any>;
|
|
38
|
+
frames: Frame[];
|
|
39
|
+
savedAt: string;
|
|
40
|
+
}
|
|
41
|
+
export declare class Trail {
|
|
42
|
+
/** Contexte global — long terme */
|
|
43
|
+
readonly global: Record<string, any>;
|
|
44
|
+
/** Contexte utilisateur — session */
|
|
45
|
+
readonly user: Record<string, any>;
|
|
46
|
+
/** Frames de navigation — readonly depuis l'extérieur */
|
|
47
|
+
private _frames;
|
|
48
|
+
private constructor();
|
|
49
|
+
/** Crée un Trail vierge, avec contextes optionnels */
|
|
50
|
+
static create(init?: TrailInit): Trail;
|
|
51
|
+
/** Restaure un Trail depuis sa forme sérialisée */
|
|
52
|
+
static from(serialized: string | SerializedTrail): Trail;
|
|
53
|
+
/** Toutes les frames — tableau immuable depuis l'extérieur */
|
|
54
|
+
get frames(): readonly Frame[];
|
|
55
|
+
/** Dernière frame — position courante */
|
|
56
|
+
get current(): Frame | undefined;
|
|
57
|
+
/** Nombre de frames */
|
|
58
|
+
get depth(): number;
|
|
59
|
+
/** Vrai si toutes les frames sont résolues */
|
|
60
|
+
get isFullyResolved(): boolean;
|
|
61
|
+
/** Frames non résolues */
|
|
62
|
+
get unresolved(): Frame[];
|
|
63
|
+
/**
|
|
64
|
+
* Pousse une frame sur le Trail.
|
|
65
|
+
* Retourne this pour le chaînage.
|
|
66
|
+
*
|
|
67
|
+
* Si state n'est pas précisé :
|
|
68
|
+
* - id fourni → RESOLVED
|
|
69
|
+
* - id absent → UNRESOLVED
|
|
70
|
+
*/
|
|
71
|
+
push(frame: Frame): this;
|
|
72
|
+
/**
|
|
73
|
+
* Retire et retourne la dernière frame.
|
|
74
|
+
* Retourne undefined si le Trail est vide.
|
|
75
|
+
*/
|
|
76
|
+
pop(): Frame | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Met à jour une frame existante par index ou par entity.
|
|
79
|
+
* Réservé à LinkLab — permet au moteur de synchroniser les frames résolues.
|
|
80
|
+
*
|
|
81
|
+
* @param entity - L'entité de la frame à mettre à jour
|
|
82
|
+
* @param updated - Les nouvelles valeurs à merger
|
|
83
|
+
*/
|
|
84
|
+
updateFrame(entity: string, updated: Partial<Frame>): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Compacte le Trail — supprime les frames non-discriminantes
|
|
87
|
+
* en conservant uniquement les frames qui portent un id
|
|
88
|
+
* ou qui sont la position courante.
|
|
89
|
+
*
|
|
90
|
+
* Exemple :
|
|
91
|
+
* [cinema][people(Nolan)][movies(Interstellar)][actors]
|
|
92
|
+
* → [people(Nolan)][movies(Interstellar)][actors]
|
|
93
|
+
*
|
|
94
|
+
* Note : réservé à LinkLab — appelé par le moteur, pas par les hooks.
|
|
95
|
+
*/
|
|
96
|
+
compact(): this;
|
|
97
|
+
/**
|
|
98
|
+
* Retourne la frame à l'index donné (0 = première).
|
|
99
|
+
* Accepte les index négatifs (-1 = dernière).
|
|
100
|
+
*/
|
|
101
|
+
at(index: number): Frame | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Retourne la dernière frame dont l'entity correspond.
|
|
104
|
+
*/
|
|
105
|
+
find(entity: string): Frame | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Retourne un Trail tronqué jusqu'à l'index donné (non inclus).
|
|
108
|
+
* Utile pour le replay partiel.
|
|
109
|
+
*/
|
|
110
|
+
slice(end: number): Trail;
|
|
111
|
+
/**
|
|
112
|
+
* Sérialise le Trail en JSON.
|
|
113
|
+
* global et user ne doivent contenir que des données — les fonctions
|
|
114
|
+
* sont silencieusement ignorées par JSON.stringify.
|
|
115
|
+
*/
|
|
116
|
+
serialize(): string;
|
|
117
|
+
toJSON(): SerializedTrail;
|
|
118
|
+
/**
|
|
119
|
+
* Deep copy — utile pour le replay ou les tests.
|
|
120
|
+
* Le clone est indépendant — modifier l'un ne modifie pas l'autre.
|
|
121
|
+
*/
|
|
122
|
+
clone(): Trail;
|
|
123
|
+
/**
|
|
124
|
+
* Représentation lisible du Trail courant.
|
|
125
|
+
* ex: [people(Nolan)] → [movies(Interstellar)] → [actors?]
|
|
126
|
+
*/
|
|
127
|
+
toString(): string;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=Trail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Trail.d.ts","sourceRoot":"","sources":["../../src/navigation/Trail.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAI9C,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,IAAI,CAAC,EAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;CACjB;AAED,sEAAsE;AACtE,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAQ,MAAM,CAAA;IACf,MAAM,EAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,IAAI,EAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,MAAM,EAAG,KAAK,EAAE,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAID,qBAAa,KAAK;IAChB,mCAAmC;IACnC,SAAgB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE3C,qCAAqC;IACrC,SAAgB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEzC,yDAAyD;IACzD,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO;IAQP,sDAAsD;IACtD,MAAM,CAAC,MAAM,CAAC,IAAI,GAAE,SAAc,GAAG,KAAK;IAI1C,mDAAmD;IACnD,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,KAAK;IAkBxD,8DAA8D;IAC9D,IAAI,MAAM,IAAI,SAAS,KAAK,EAAE,CAE7B;IAED,yCAAyC;IACzC,IAAI,OAAO,IAAI,KAAK,GAAG,SAAS,CAE/B;IAED,uBAAuB;IACvB,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,8CAA8C;IAC9C,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,0BAA0B;IAC1B,IAAI,UAAU,IAAI,KAAK,EAAE,CAExB;IAID;;;;;;;OAOG;IACH,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IASxB;;;OAGG;IACH,GAAG,IAAI,KAAK,GAAG,SAAS;IAIxB;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO;IAS7D;;;;;;;;;;OAUG;IACH,OAAO,IAAI,IAAI;IAQf;;;OAGG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAKpC;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIvC;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAUzB;;;;OAIG;IACH,SAAS,IAAI,MAAM;IAInB,MAAM,IAAI,eAAe;IAUzB;;;OAGG;IACH,KAAK,IAAI,KAAK;IAMd;;;OAGG;IACH,QAAQ,IAAI,MAAM;CAWnB"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trail — Contexte de navigation vivant
|
|
3
|
+
*
|
|
4
|
+
* Trois niveaux de contexte, trois durées de vie :
|
|
5
|
+
*
|
|
6
|
+
* global — vit aussi longtemps que l'instance LinkLab
|
|
7
|
+
* config, feature flags, métriques globales
|
|
8
|
+
*
|
|
9
|
+
* user — vit le temps d'une session
|
|
10
|
+
* userId, permissions, préférences, historique récent
|
|
11
|
+
*
|
|
12
|
+
* frames — vit le temps d'une navigation
|
|
13
|
+
* le chemin parcouru, position courante
|
|
14
|
+
*
|
|
15
|
+
* Deux niveaux d'API :
|
|
16
|
+
*
|
|
17
|
+
* Bas niveau — trail.push(frame), trail.pop(), trail.compact()
|
|
18
|
+
* fondation sur laquelle tout repose
|
|
19
|
+
*
|
|
20
|
+
* Haut niveau — API fluente, construite sur push()
|
|
21
|
+
* cinema.people('Nolan').movies
|
|
22
|
+
*
|
|
23
|
+
* Contrat de sérialisation :
|
|
24
|
+
* global et user ne contiennent que des données — jamais de fonctions.
|
|
25
|
+
* Un Trail sérialisé peut être rejoué exactement.
|
|
26
|
+
*/
|
|
27
|
+
// ── Trail ─────────────────────────────────────────────────────
|
|
28
|
+
export class Trail {
|
|
29
|
+
/** Contexte global — long terme */
|
|
30
|
+
global;
|
|
31
|
+
/** Contexte utilisateur — session */
|
|
32
|
+
user;
|
|
33
|
+
/** Frames de navigation — readonly depuis l'extérieur */
|
|
34
|
+
_frames;
|
|
35
|
+
constructor(init = {}) {
|
|
36
|
+
this.global = init.global ?? {};
|
|
37
|
+
this.user = init.user ?? {};
|
|
38
|
+
this._frames = init.frames ? init.frames.map(f => ({ ...f })) : [];
|
|
39
|
+
}
|
|
40
|
+
// ── Factories ──────────────────────────────────────────────
|
|
41
|
+
/** Crée un Trail vierge, avec contextes optionnels */
|
|
42
|
+
static create(init = {}) {
|
|
43
|
+
return new Trail(init);
|
|
44
|
+
}
|
|
45
|
+
/** Restaure un Trail depuis sa forme sérialisée */
|
|
46
|
+
static from(serialized) {
|
|
47
|
+
const data = typeof serialized === 'string'
|
|
48
|
+
? JSON.parse(serialized)
|
|
49
|
+
: serialized;
|
|
50
|
+
if (data.v !== 1) {
|
|
51
|
+
throw new Error(`Trail.from: version ${data.v} non supportée`);
|
|
52
|
+
}
|
|
53
|
+
return new Trail({
|
|
54
|
+
global: data.global ?? {},
|
|
55
|
+
user: data.user ?? {},
|
|
56
|
+
frames: data.frames ?? [],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ── Accesseurs frames ──────────────────────────────────────
|
|
60
|
+
/** Toutes les frames — tableau immuable depuis l'extérieur */
|
|
61
|
+
get frames() {
|
|
62
|
+
return this._frames;
|
|
63
|
+
}
|
|
64
|
+
/** Dernière frame — position courante */
|
|
65
|
+
get current() {
|
|
66
|
+
return this._frames[this._frames.length - 1];
|
|
67
|
+
}
|
|
68
|
+
/** Nombre de frames */
|
|
69
|
+
get depth() {
|
|
70
|
+
return this._frames.length;
|
|
71
|
+
}
|
|
72
|
+
/** Vrai si toutes les frames sont résolues */
|
|
73
|
+
get isFullyResolved() {
|
|
74
|
+
return this._frames.every(f => f.state === 'RESOLVED');
|
|
75
|
+
}
|
|
76
|
+
/** Frames non résolues */
|
|
77
|
+
get unresolved() {
|
|
78
|
+
return this._frames.filter(f => f.state === 'UNRESOLVED');
|
|
79
|
+
}
|
|
80
|
+
// ── API bas niveau ─────────────────────────────────────────
|
|
81
|
+
/**
|
|
82
|
+
* Pousse une frame sur le Trail.
|
|
83
|
+
* Retourne this pour le chaînage.
|
|
84
|
+
*
|
|
85
|
+
* Si state n'est pas précisé :
|
|
86
|
+
* - id fourni → RESOLVED
|
|
87
|
+
* - id absent → UNRESOLVED
|
|
88
|
+
*/
|
|
89
|
+
push(frame) {
|
|
90
|
+
const normalized = {
|
|
91
|
+
...frame,
|
|
92
|
+
state: frame.state ?? (frame.id !== undefined ? 'RESOLVED' : 'UNRESOLVED'),
|
|
93
|
+
};
|
|
94
|
+
this._frames.push(normalized);
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Retire et retourne la dernière frame.
|
|
99
|
+
* Retourne undefined si le Trail est vide.
|
|
100
|
+
*/
|
|
101
|
+
pop() {
|
|
102
|
+
return this._frames.pop();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Met à jour une frame existante par index ou par entity.
|
|
106
|
+
* Réservé à LinkLab — permet au moteur de synchroniser les frames résolues.
|
|
107
|
+
*
|
|
108
|
+
* @param entity - L'entité de la frame à mettre à jour
|
|
109
|
+
* @param updated - Les nouvelles valeurs à merger
|
|
110
|
+
*/
|
|
111
|
+
updateFrame(entity, updated) {
|
|
112
|
+
const idx = this._frames.findIndex(f => f.entity === entity && f.state === 'UNRESOLVED');
|
|
113
|
+
if (idx === -1)
|
|
114
|
+
return false;
|
|
115
|
+
this._frames[idx] = { ...this._frames[idx], ...updated };
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Compacte le Trail — supprime les frames non-discriminantes
|
|
120
|
+
* en conservant uniquement les frames qui portent un id
|
|
121
|
+
* ou qui sont la position courante.
|
|
122
|
+
*
|
|
123
|
+
* Exemple :
|
|
124
|
+
* [cinema][people(Nolan)][movies(Interstellar)][actors]
|
|
125
|
+
* → [people(Nolan)][movies(Interstellar)][actors]
|
|
126
|
+
*
|
|
127
|
+
* Note : réservé à LinkLab — appelé par le moteur, pas par les hooks.
|
|
128
|
+
*/
|
|
129
|
+
compact() {
|
|
130
|
+
const last = this._frames.length - 1;
|
|
131
|
+
this._frames = this._frames.filter((f, i) => i === last || f.id !== undefined);
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Retourne la frame à l'index donné (0 = première).
|
|
136
|
+
* Accepte les index négatifs (-1 = dernière).
|
|
137
|
+
*/
|
|
138
|
+
at(index) {
|
|
139
|
+
if (index < 0)
|
|
140
|
+
index = this._frames.length + index;
|
|
141
|
+
return this._frames[index];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Retourne la dernière frame dont l'entity correspond.
|
|
145
|
+
*/
|
|
146
|
+
find(entity) {
|
|
147
|
+
return [...this._frames].reverse().find(f => f.entity === entity);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Retourne un Trail tronqué jusqu'à l'index donné (non inclus).
|
|
151
|
+
* Utile pour le replay partiel.
|
|
152
|
+
*/
|
|
153
|
+
slice(end) {
|
|
154
|
+
return new Trail({
|
|
155
|
+
global: { ...this.global },
|
|
156
|
+
user: { ...this.user },
|
|
157
|
+
frames: this._frames.slice(0, end),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// ── Sérialisation ──────────────────────────────────────────
|
|
161
|
+
/**
|
|
162
|
+
* Sérialise le Trail en JSON.
|
|
163
|
+
* global et user ne doivent contenir que des données — les fonctions
|
|
164
|
+
* sont silencieusement ignorées par JSON.stringify.
|
|
165
|
+
*/
|
|
166
|
+
serialize() {
|
|
167
|
+
return JSON.stringify(this.toJSON());
|
|
168
|
+
}
|
|
169
|
+
toJSON() {
|
|
170
|
+
return {
|
|
171
|
+
v: 1,
|
|
172
|
+
global: this.global,
|
|
173
|
+
user: this.user,
|
|
174
|
+
frames: [...this._frames],
|
|
175
|
+
savedAt: new Date().toISOString(),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Deep copy — utile pour le replay ou les tests.
|
|
180
|
+
* Le clone est indépendant — modifier l'un ne modifie pas l'autre.
|
|
181
|
+
*/
|
|
182
|
+
clone() {
|
|
183
|
+
return Trail.from(this.toJSON());
|
|
184
|
+
}
|
|
185
|
+
// ── Debug ──────────────────────────────────────────────────
|
|
186
|
+
/**
|
|
187
|
+
* Représentation lisible du Trail courant.
|
|
188
|
+
* ex: [people(Nolan)] → [movies(Interstellar)] → [actors?]
|
|
189
|
+
*/
|
|
190
|
+
toString() {
|
|
191
|
+
if (this._frames.length === 0)
|
|
192
|
+
return '(trail vide)';
|
|
193
|
+
return this._frames
|
|
194
|
+
.map(f => {
|
|
195
|
+
const id = f.id !== undefined ? `(${f.id})` : '';
|
|
196
|
+
const state = f.state === 'UNRESOLVED' ? '?' : f.state === 'DEFERRED' ? '…' : '';
|
|
197
|
+
return `[${f.entity}${id}${state}]`;
|
|
198
|
+
})
|
|
199
|
+
.join(' → ');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=Trail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Trail.js","sourceRoot":"","sources":["../../src/navigation/Trail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TrailParser — Désérialise des représentations externes vers un Trail
|
|
3
|
+
*
|
|
4
|
+
* Trois sources supportées :
|
|
5
|
+
*
|
|
6
|
+
* URL path → /cinema/people/Nolan/movies/Interstellar/actors
|
|
7
|
+
* URL fluent → cinema.people(Nolan).movies(Interstellar).actors
|
|
8
|
+
* JSON → SerializedTrail (via Trail.from)
|
|
9
|
+
*
|
|
10
|
+
* Le parser est stateless — toutes les méthodes sont statiques.
|
|
11
|
+
* Il ne valide pas les entités contre le graphe — c'est le rôle du moteur.
|
|
12
|
+
*/
|
|
13
|
+
import { Trail } from './Trail.js';
|
|
14
|
+
export declare class TrailParser {
|
|
15
|
+
/**
|
|
16
|
+
* Parse un path HTTP en Trail.
|
|
17
|
+
*
|
|
18
|
+
* Convention :
|
|
19
|
+
* /entity → Frame(entity, UNRESOLVED)
|
|
20
|
+
* /entity/id → Frame(entity, id, RESOLVED)
|
|
21
|
+
* /entity/id/other → Frame(entity, id) + Frame(other, UNRESOLVED)
|
|
22
|
+
*
|
|
23
|
+
* Exemples :
|
|
24
|
+
* /people → [people?]
|
|
25
|
+
* /people/Nolan → [people(Nolan)]
|
|
26
|
+
* /people/Nolan/movies → [people(Nolan)] → [movies?]
|
|
27
|
+
* /people/Nolan/movies/2 → [people(Nolan)] → [movies(2)]
|
|
28
|
+
* /cinema/people/Nolan/movies → [cinema] → [people(Nolan)] → [movies?]
|
|
29
|
+
*
|
|
30
|
+
* @param path - URL path, avec ou sans slash initial
|
|
31
|
+
* @param init - Contextes global/user à injecter
|
|
32
|
+
*/
|
|
33
|
+
static fromPath(path: string, init?: {
|
|
34
|
+
global?: Record<string, any>;
|
|
35
|
+
user?: Record<string, any>;
|
|
36
|
+
}): Trail;
|
|
37
|
+
/**
|
|
38
|
+
* Parse une expression fluente en Trail.
|
|
39
|
+
*
|
|
40
|
+
* Syntaxe :
|
|
41
|
+
* entity → Frame(entity, UNRESOLVED)
|
|
42
|
+
* entity(id) → Frame(entity, id, RESOLVED)
|
|
43
|
+
* entity.other → Frame(entity) + Frame(other)
|
|
44
|
+
* entity(id).other(id2) → Frame(entity,id) + Frame(other,id2)
|
|
45
|
+
*
|
|
46
|
+
* Exemples :
|
|
47
|
+
* people → [people?]
|
|
48
|
+
* people(Nolan) → [people(Nolan)]
|
|
49
|
+
* people(Nolan).movies → [people(Nolan)] → [movies?]
|
|
50
|
+
* cinema.people(Nolan).movies(2) → [cinema] → [people(Nolan)] → [movies(2)]
|
|
51
|
+
*
|
|
52
|
+
* @param expr - Expression fluente
|
|
53
|
+
* @param init - Contextes global/user à injecter
|
|
54
|
+
*/
|
|
55
|
+
static fromFluent(expr: string, init?: {
|
|
56
|
+
global?: Record<string, any>;
|
|
57
|
+
user?: Record<string, any>;
|
|
58
|
+
}): Trail;
|
|
59
|
+
/**
|
|
60
|
+
* Sérialise un Trail en path HTTP.
|
|
61
|
+
*
|
|
62
|
+
* Exemple :
|
|
63
|
+
* Trail([people(Nolan)][movies?]) → /people/Nolan/movies
|
|
64
|
+
*/
|
|
65
|
+
static toPath(trail: Trail): string;
|
|
66
|
+
/**
|
|
67
|
+
* Sérialise un Trail en expression fluente.
|
|
68
|
+
*
|
|
69
|
+
* Exemple :
|
|
70
|
+
* Trail([people(Nolan)][movies?]) → people(Nolan).movies
|
|
71
|
+
*/
|
|
72
|
+
static toFluent(trail: Trail): string;
|
|
73
|
+
/**
|
|
74
|
+
* Heuristique : un segment ressemble-t-il à un nom d'entité ?
|
|
75
|
+
* Les entités commencent par une lettre minuscule et ne contiennent
|
|
76
|
+
* que des lettres, chiffres et tirets.
|
|
77
|
+
*/
|
|
78
|
+
private static looksLikeEntity;
|
|
79
|
+
/**
|
|
80
|
+
* Essaie de convertir un id en nombre, sinon garde la string.
|
|
81
|
+
*/
|
|
82
|
+
private static coerceId;
|
|
83
|
+
/**
|
|
84
|
+
* Tokenise une expression fluente en segments.
|
|
85
|
+
* Préserve le contenu des parenthèses (les ids peuvent contenir des points).
|
|
86
|
+
*
|
|
87
|
+
* ex: "cinema.people(Nolan.Jr).movies"
|
|
88
|
+
* → ["cinema", "people(Nolan.Jr)", "movies"]
|
|
89
|
+
*/
|
|
90
|
+
private static tokenizeFluent;
|
|
91
|
+
/**
|
|
92
|
+
* Parse un token "entity" ou "entity(id)" en Frame.
|
|
93
|
+
*/
|
|
94
|
+
private static parseToken;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=TrailParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TrailParser.d.ts","sourceRoot":"","sources":["../../src/navigation/TrailParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAGlC,qBAAa,WAAW;IAItB;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAO,GACtE,KAAK;IAyBR;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,UAAU,CACf,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAO,GACtE,KAAK;IAcR;;;;;OAKG;IACH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAanC;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAQrC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAI9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ;IAKvB;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAwB7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAqB1B"}
|