@living-architecture/riviere-query 0.2.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.
Files changed (50) hide show
  1. package/README.md +11 -0
  2. package/dist/RiviereQuery.d.ts +486 -0
  3. package/dist/RiviereQuery.d.ts.map +1 -0
  4. package/dist/RiviereQuery.js +553 -0
  5. package/dist/component-queries.d.ts +8 -0
  6. package/dist/component-queries.d.ts.map +1 -0
  7. package/dist/component-queries.js +24 -0
  8. package/dist/cross-domain-queries.d.ts +5 -0
  9. package/dist/cross-domain-queries.d.ts.map +1 -0
  10. package/dist/cross-domain-queries.js +92 -0
  11. package/dist/depth-queries.d.ts +4 -0
  12. package/dist/depth-queries.d.ts.map +1 -0
  13. package/dist/depth-queries.js +54 -0
  14. package/dist/domain-queries.d.ts +10 -0
  15. package/dist/domain-queries.d.ts.map +1 -0
  16. package/dist/domain-queries.js +101 -0
  17. package/dist/domain-types.d.ts +307 -0
  18. package/dist/domain-types.d.ts.map +1 -0
  19. package/dist/domain-types.js +111 -0
  20. package/dist/errors.d.ts +6 -0
  21. package/dist/errors.d.ts.map +1 -0
  22. package/dist/errors.js +10 -0
  23. package/dist/event-queries.d.ts +5 -0
  24. package/dist/event-queries.d.ts.map +1 -0
  25. package/dist/event-queries.js +32 -0
  26. package/dist/event-types.d.ts +88 -0
  27. package/dist/event-types.d.ts.map +1 -0
  28. package/dist/event-types.js +1 -0
  29. package/dist/external-system-queries.d.ts +13 -0
  30. package/dist/external-system-queries.d.ts.map +1 -0
  31. package/dist/external-system-queries.js +54 -0
  32. package/dist/flow-queries.d.ts +17 -0
  33. package/dist/flow-queries.d.ts.map +1 -0
  34. package/dist/flow-queries.js +127 -0
  35. package/dist/graph-diff.d.ts +4 -0
  36. package/dist/graph-diff.d.ts.map +1 -0
  37. package/dist/graph-diff.js +53 -0
  38. package/dist/graph-validation.d.ts +5 -0
  39. package/dist/graph-validation.d.ts.map +1 -0
  40. package/dist/graph-validation.js +72 -0
  41. package/dist/index.d.ts +5 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +4 -0
  44. package/dist/riviere-graph-fixtures.d.ts +37 -0
  45. package/dist/riviere-graph-fixtures.d.ts.map +1 -0
  46. package/dist/riviere-graph-fixtures.js +73 -0
  47. package/dist/stats-queries.d.ts +4 -0
  48. package/dist/stats-queries.d.ts.map +1 -0
  49. package/dist/stats-queries.js +14 -0
  50. package/package.json +29 -0
@@ -0,0 +1,88 @@
1
+ import type { DomainOpComponent } from '@living-architecture/riviere-schema';
2
+ import type { EntityName, DomainName, State, OperationName, EventId, EventName, HandlerId, HandlerName } from './domain-types';
3
+ /**
4
+ * A domain entity with its associated operations.
5
+ */
6
+ export interface Entity {
7
+ /** The entity name. */
8
+ name: EntityName;
9
+ /** The domain containing the entity. */
10
+ domain: DomainName;
11
+ /** All domain operations targeting this entity. */
12
+ operations: DomainOpComponent[];
13
+ }
14
+ /**
15
+ * A state transition in an entity's state machine.
16
+ */
17
+ export interface EntityTransition {
18
+ /** The state before the transition. */
19
+ from: State;
20
+ /** The state after the transition. */
21
+ to: State;
22
+ /** The operation that triggers this transition. */
23
+ triggeredBy: OperationName;
24
+ }
25
+ /**
26
+ * An event handler that subscribes to an event.
27
+ */
28
+ export interface EventSubscriber {
29
+ /** The handler's component ID. */
30
+ handlerId: HandlerId;
31
+ /** The handler's name. */
32
+ handlerName: HandlerName;
33
+ /** The domain containing the handler. */
34
+ domain: DomainName;
35
+ }
36
+ /**
37
+ * A published event with its subscribers.
38
+ */
39
+ export interface PublishedEvent {
40
+ /** The event component's ID. */
41
+ id: EventId;
42
+ /** The event name. */
43
+ eventName: EventName;
44
+ /** The domain that publishes the event. */
45
+ domain: DomainName;
46
+ /** Event handlers subscribed to this event. */
47
+ handlers: EventSubscriber[];
48
+ }
49
+ /**
50
+ * A subscribed event where the source domain is known.
51
+ */
52
+ export interface KnownSourceEvent {
53
+ /** The event name. */
54
+ eventName: EventName;
55
+ /** The domain that publishes this event. */
56
+ sourceDomain: DomainName;
57
+ /** Indicates the source is known. */
58
+ sourceKnown: true;
59
+ }
60
+ /**
61
+ * A subscribed event where the source domain is unknown.
62
+ */
63
+ export interface UnknownSourceEvent {
64
+ /** The event name. */
65
+ eventName: EventName;
66
+ /** Indicates the source is unknown. */
67
+ sourceKnown: false;
68
+ }
69
+ /**
70
+ * A subscribed event with optional source domain information.
71
+ */
72
+ export type SubscribedEventWithDomain = KnownSourceEvent | UnknownSourceEvent;
73
+ /**
74
+ * Information about an event handler component.
75
+ */
76
+ export interface EventHandlerInfo {
77
+ /** The handler's component ID. */
78
+ id: HandlerId;
79
+ /** The handler's name. */
80
+ handlerName: HandlerName;
81
+ /** The domain containing the handler. */
82
+ domain: DomainName;
83
+ /** List of event names this handler subscribes to. */
84
+ subscribedEvents: EventName[];
85
+ /** Subscribed events with source domain information. */
86
+ subscribedEventsWithDomain: SubscribedEventWithDomain[];
87
+ }
88
+ //# sourceMappingURL=event-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-types.d.ts","sourceRoot":"","sources":["../src/event-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAA;AAC5E,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,KAAK,EACL,aAAa,EACb,OAAO,EACP,SAAS,EACT,SAAS,EACT,WAAW,EACZ,MAAM,gBAAgB,CAAA;AAEvB;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,uBAAuB;IACvB,IAAI,EAAE,UAAU,CAAA;IAChB,wCAAwC;IACxC,MAAM,EAAE,UAAU,CAAA;IAClB,mDAAmD;IACnD,UAAU,EAAE,iBAAiB,EAAE,CAAA;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,IAAI,EAAE,KAAK,CAAA;IACX,sCAAsC;IACtC,EAAE,EAAE,KAAK,CAAA;IACT,mDAAmD;IACnD,WAAW,EAAE,aAAa,CAAA;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,0BAA0B;IAC1B,WAAW,EAAE,WAAW,CAAA;IACxB,yCAAyC;IACzC,MAAM,EAAE,UAAU,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,EAAE,EAAE,OAAO,CAAA;IACX,sBAAsB;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,2CAA2C;IAC3C,MAAM,EAAE,UAAU,CAAA;IAClB,+CAA+C;IAC/C,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,4CAA4C;IAC5C,YAAY,EAAE,UAAU,CAAA;IACxB,qCAAqC;IACrC,WAAW,EAAE,IAAI,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,sBAAsB;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,uCAAuC;IACvC,WAAW,EAAE,KAAK,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,gBAAgB,GAAG,kBAAkB,CAAA;AAE7E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,EAAE,EAAE,SAAS,CAAA;IACb,0BAA0B;IAC1B,WAAW,EAAE,WAAW,CAAA;IACxB,yCAAyC;IACzC,MAAM,EAAE,UAAU,CAAA;IAClB,sDAAsD;IACtD,gBAAgB,EAAE,SAAS,EAAE,CAAA;IAC7B,wDAAwD;IACxD,0BAA0B,EAAE,yBAAyB,EAAE,CAAA;CACxD"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { RiviereGraph } from '@living-architecture/riviere-schema';
2
+ import type { ExternalDomain } from './domain-types';
3
+ /**
4
+ * Returns external domains that components connect to.
5
+ *
6
+ * Each external target from externalLinks becomes a separate ExternalDomain entry,
7
+ * with aggregated connection counts and source domains.
8
+ *
9
+ * @param graph - The RiviereGraph to query
10
+ * @returns Array of ExternalDomain objects, sorted alphabetically by name
11
+ */
12
+ export declare function queryExternalDomains(graph: RiviereGraph): ExternalDomain[];
13
+ //# sourceMappingURL=external-system-queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-system-queries.d.ts","sourceRoot":"","sources":["../src/external-system-queries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAmDpD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,cAAc,EAAE,CAQ1E"}
@@ -0,0 +1,54 @@
1
+ import { parseDomainName } from './domain-types';
2
+ function buildComponentDomainMap(graph) {
3
+ const componentDomains = new Map();
4
+ for (const component of graph.components) {
5
+ componentDomains.set(component.id, component.domain);
6
+ }
7
+ return componentDomains;
8
+ }
9
+ function aggregateExternalDomains(externalLinks, componentDomains) {
10
+ const domains = new Map();
11
+ for (const extLink of externalLinks) {
12
+ const sourceDomain = componentDomains.get(extLink.source);
13
+ if (sourceDomain === undefined)
14
+ continue;
15
+ const existing = domains.get(extLink.target.name);
16
+ if (existing === undefined) {
17
+ domains.set(extLink.target.name, {
18
+ sourceDomains: new Set([sourceDomain]),
19
+ connectionCount: 1,
20
+ });
21
+ }
22
+ else {
23
+ existing.sourceDomains.add(sourceDomain);
24
+ existing.connectionCount += 1;
25
+ }
26
+ }
27
+ return domains;
28
+ }
29
+ function convertToExternalDomains(domains) {
30
+ return Array.from(domains.entries())
31
+ .map(([name, acc]) => ({
32
+ name,
33
+ sourceDomains: Array.from(acc.sourceDomains).map((d) => parseDomainName(d)),
34
+ connectionCount: acc.connectionCount,
35
+ }))
36
+ .sort((a, b) => a.name.localeCompare(b.name));
37
+ }
38
+ /**
39
+ * Returns external domains that components connect to.
40
+ *
41
+ * Each external target from externalLinks becomes a separate ExternalDomain entry,
42
+ * with aggregated connection counts and source domains.
43
+ *
44
+ * @param graph - The RiviereGraph to query
45
+ * @returns Array of ExternalDomain objects, sorted alphabetically by name
46
+ */
47
+ export function queryExternalDomains(graph) {
48
+ if (graph.externalLinks === undefined || graph.externalLinks.length === 0) {
49
+ return [];
50
+ }
51
+ const componentDomains = buildComponentDomainMap(graph);
52
+ const domains = aggregateExternalDomains(graph.externalLinks, componentDomains);
53
+ return convertToExternalDomains(domains);
54
+ }
@@ -0,0 +1,17 @@
1
+ import type { RiviereGraph, Component } from '@living-architecture/riviere-schema';
2
+ import type { ComponentId, LinkId, Flow, SearchWithFlowResult } from './domain-types';
3
+ export declare function findEntryPoints(graph: RiviereGraph): Component[];
4
+ export declare function traceFlowFrom(graph: RiviereGraph, startComponentId: ComponentId): {
5
+ componentIds: ComponentId[];
6
+ linkIds: LinkId[];
7
+ };
8
+ export declare function queryFlows(graph: RiviereGraph): Flow[];
9
+ /**
10
+ * Options for searchWithFlow.
11
+ */
12
+ export interface SearchWithFlowOptions {
13
+ /** If true, returns all components when the query is empty. */
14
+ returnAllOnEmptyQuery: boolean;
15
+ }
16
+ export declare function searchWithFlowContext(graph: RiviereGraph, query: string, options: SearchWithFlowOptions): SearchWithFlowResult;
17
+ //# sourceMappingURL=flow-queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-queries.d.ts","sourceRoot":"","sources":["../src/flow-queries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAqC,MAAM,qCAAqC,CAAA;AACrH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAKrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,CAIhE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,GAAG;IAAE,YAAY,EAAE,WAAW,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA8BpI;AASD,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,EAAE,CAsCtD;AAgCD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CA4BtB"}
@@ -0,0 +1,127 @@
1
+ import { parseComponentId, parseLinkId } from './domain-types';
2
+ import { componentById, searchComponents } from './component-queries';
3
+ import { ComponentNotFoundError } from './errors';
4
+ export function findEntryPoints(graph) {
5
+ const targets = new Set(graph.links.map((link) => link.target));
6
+ const entryPointTypes = new Set(['UI', 'API', 'EventHandler', 'Custom']);
7
+ return graph.components.filter((c) => entryPointTypes.has(c.type) && !targets.has(c.id));
8
+ }
9
+ export function traceFlowFrom(graph, startComponentId) {
10
+ const component = componentById(graph, startComponentId);
11
+ if (!component) {
12
+ throw new ComponentNotFoundError(startComponentId);
13
+ }
14
+ const visited = new Set();
15
+ const visitedLinks = new Set();
16
+ const queue = [startComponentId];
17
+ while (queue.length > 0) {
18
+ const currentId = queue.shift();
19
+ if (currentId === undefined || visited.has(currentId))
20
+ continue;
21
+ visited.add(currentId);
22
+ for (const link of graph.links) {
23
+ const sourceId = parseComponentId(link.source);
24
+ const targetId = parseComponentId(link.target);
25
+ if (link.source === currentId && !visited.has(targetId)) {
26
+ queue.push(targetId);
27
+ visitedLinks.add(createLinkKey(link));
28
+ }
29
+ if (link.target === currentId && !visited.has(sourceId)) {
30
+ queue.push(sourceId);
31
+ visitedLinks.add(createLinkKey(link));
32
+ }
33
+ }
34
+ }
35
+ return { componentIds: Array.from(visited), linkIds: Array.from(visitedLinks) };
36
+ }
37
+ function createLinkKey(link) {
38
+ if (link.id !== undefined) {
39
+ return parseLinkId(link.id);
40
+ }
41
+ return parseLinkId(`${link.source}->${link.target}`);
42
+ }
43
+ export function queryFlows(graph) {
44
+ const componentByIdMap = new Map(graph.components.map((c) => [c.id, c]));
45
+ const outgoingEdges = buildOutgoingEdges(graph);
46
+ const externalLinksBySource = buildExternalLinksBySource(graph);
47
+ const traceForward = (entryPointId) => {
48
+ const steps = [];
49
+ const visited = new Set();
50
+ const traverse = (nodeId, depth) => {
51
+ if (visited.has(nodeId))
52
+ return;
53
+ visited.add(nodeId);
54
+ const component = componentByIdMap.get(nodeId);
55
+ if (!component)
56
+ return;
57
+ const edges = outgoingEdges.get(nodeId);
58
+ const firstEdge = edges !== undefined && edges.length > 0 ? edges[0] : undefined;
59
+ const linkType = firstEdge !== undefined ? firstEdge.type : undefined;
60
+ const externalLinks = externalLinksBySource.get(nodeId) ?? [];
61
+ steps.push({ component, linkType, depth, externalLinks });
62
+ if (edges) {
63
+ for (const edge of edges) {
64
+ traverse(edge.target, depth + 1);
65
+ }
66
+ }
67
+ };
68
+ traverse(entryPointId, 0);
69
+ return steps;
70
+ };
71
+ return findEntryPoints(graph).map((entryPoint) => ({
72
+ entryPoint,
73
+ steps: traceForward(entryPoint.id),
74
+ }));
75
+ }
76
+ function buildExternalLinksBySource(graph) {
77
+ const externalLinks = graph.externalLinks ?? [];
78
+ const bySource = new Map();
79
+ for (const link of externalLinks) {
80
+ const existing = bySource.get(link.source);
81
+ if (existing) {
82
+ existing.push(link);
83
+ }
84
+ else {
85
+ bySource.set(link.source, [link]);
86
+ }
87
+ }
88
+ return bySource;
89
+ }
90
+ function buildOutgoingEdges(graph) {
91
+ const edges = new Map();
92
+ for (const link of graph.links) {
93
+ const entry = { target: link.target, type: link.type };
94
+ const existing = edges.get(link.source);
95
+ if (existing) {
96
+ existing.push(entry);
97
+ }
98
+ else {
99
+ edges.set(link.source, [entry]);
100
+ }
101
+ }
102
+ return edges;
103
+ }
104
+ export function searchWithFlowContext(graph, query, options) {
105
+ const trimmedQuery = query.trim().toLowerCase();
106
+ const isEmptyQuery = trimmedQuery === '';
107
+ if (isEmptyQuery) {
108
+ if (options.returnAllOnEmptyQuery) {
109
+ const allIds = graph.components.map((c) => parseComponentId(c.id));
110
+ return { matchingIds: allIds, visibleIds: allIds };
111
+ }
112
+ return { matchingIds: [], visibleIds: [] };
113
+ }
114
+ const matchingComponents = searchComponents(graph, query);
115
+ if (matchingComponents.length === 0) {
116
+ return { matchingIds: [], visibleIds: [] };
117
+ }
118
+ const matchingIds = matchingComponents.map((c) => parseComponentId(c.id));
119
+ const visibleIds = new Set();
120
+ for (const component of matchingComponents) {
121
+ const flow = traceFlowFrom(graph, parseComponentId(component.id));
122
+ for (const id of flow.componentIds) {
123
+ visibleIds.add(id);
124
+ }
125
+ }
126
+ return { matchingIds, visibleIds: Array.from(visibleIds) };
127
+ }
@@ -0,0 +1,4 @@
1
+ import type { RiviereGraph } from '@living-architecture/riviere-schema';
2
+ import type { GraphDiff } from './domain-types';
3
+ export declare function diffGraphs(current: RiviereGraph, other: RiviereGraph): GraphDiff;
4
+ //# sourceMappingURL=graph-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-diff.d.ts","sourceRoot":"","sources":["../src/graph-diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,qCAAqC,CAAA;AACxF,OAAO,KAAK,EAAyB,SAAS,EAAU,MAAM,gBAAgB,CAAA;AAG9E,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,SAAS,CAkChF"}
@@ -0,0 +1,53 @@
1
+ import { parseComponentId, parseLinkId } from './domain-types';
2
+ export function diffGraphs(current, other) {
3
+ const thisIds = new Set(current.components.map((c) => c.id));
4
+ const otherIds = new Set(other.components.map((c) => c.id));
5
+ const otherById = new Map(other.components.map((c) => [c.id, c]));
6
+ const added = other.components.filter((c) => !thisIds.has(c.id));
7
+ const removed = current.components.filter((c) => !otherIds.has(c.id));
8
+ const modified = [];
9
+ for (const tc of current.components) {
10
+ const oc = otherById.get(tc.id);
11
+ if (oc === undefined)
12
+ continue;
13
+ const changedFields = findChangedFields(tc, oc);
14
+ if (changedFields.length > 0) {
15
+ modified.push({ id: parseComponentId(tc.id), before: tc, after: oc, changedFields });
16
+ }
17
+ }
18
+ const thisLinkKeys = new Set(current.links.map((l) => createLinkKey(l)));
19
+ const otherLinkKeys = new Set(other.links.map((l) => createLinkKey(l)));
20
+ const linksAdded = other.links.filter((l) => !thisLinkKeys.has(createLinkKey(l)));
21
+ const linksRemoved = current.links.filter((l) => !otherLinkKeys.has(createLinkKey(l)));
22
+ return {
23
+ components: { added, removed, modified },
24
+ links: { added: linksAdded, removed: linksRemoved },
25
+ stats: {
26
+ componentsAdded: added.length,
27
+ componentsRemoved: removed.length,
28
+ componentsModified: modified.length,
29
+ linksAdded: linksAdded.length,
30
+ linksRemoved: linksRemoved.length,
31
+ },
32
+ };
33
+ }
34
+ function createLinkKey(link) {
35
+ if (link.id !== undefined) {
36
+ return parseLinkId(link.id);
37
+ }
38
+ return parseLinkId(`${link.source}->${link.target}`);
39
+ }
40
+ function findChangedFields(before, after) {
41
+ const beforeEntries = new Map(Object.entries(before));
42
+ const afterEntries = new Map(Object.entries(after));
43
+ const changedFields = [];
44
+ const allKeys = new Set([...beforeEntries.keys(), ...afterEntries.keys()]);
45
+ for (const key of allKeys) {
46
+ if (key === 'id')
47
+ continue;
48
+ if (JSON.stringify(beforeEntries.get(key)) !== JSON.stringify(afterEntries.get(key))) {
49
+ changedFields.push(key);
50
+ }
51
+ }
52
+ return changedFields;
53
+ }
@@ -0,0 +1,5 @@
1
+ import type { RiviereGraph } from '@living-architecture/riviere-schema';
2
+ import type { ComponentId, ValidationResult } from './domain-types';
3
+ export declare function validateGraph(graph: RiviereGraph): ValidationResult;
4
+ export declare function detectOrphanComponents(graph: RiviereGraph): ComponentId[];
5
+ //# sourceMappingURL=graph-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-validation.d.ts","sourceRoot":"","sources":["../src/graph-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,qCAAqC,CAAA;AACxF,OAAO,KAAK,EAAE,WAAW,EAAmB,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAOpF,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,gBAAgB,CAwBnE;AA6CD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAUzE"}
@@ -0,0 +1,72 @@
1
+ import { parseComponentId } from './domain-types';
2
+ function isCustomComponent(component) {
3
+ return component.type === 'Custom';
4
+ }
5
+ export function validateGraph(graph) {
6
+ const errors = [];
7
+ const componentIds = new Set(graph.components.map((c) => c.id));
8
+ graph.links.forEach((link, index) => {
9
+ if (!componentIds.has(link.source)) {
10
+ errors.push({
11
+ path: `/links/${index}/source`,
12
+ message: `Link references non-existent source: ${link.source}`,
13
+ code: 'INVALID_LINK_SOURCE',
14
+ });
15
+ }
16
+ if (!componentIds.has(link.target)) {
17
+ errors.push({
18
+ path: `/links/${index}/target`,
19
+ message: `Link references non-existent target: ${link.target}`,
20
+ code: 'INVALID_LINK_TARGET',
21
+ });
22
+ }
23
+ });
24
+ errors.push(...validateCustomTypes(graph));
25
+ return { valid: errors.length === 0, errors };
26
+ }
27
+ function validateCustomTypes(graph) {
28
+ const errors = [];
29
+ const customTypes = graph.metadata.customTypes;
30
+ graph.components.forEach((component, index) => {
31
+ if (!isCustomComponent(component)) {
32
+ return;
33
+ }
34
+ const customTypeName = component.customTypeName;
35
+ if (!customTypes || !(customTypeName in customTypes)) {
36
+ errors.push({
37
+ path: `/components/${index}/customTypeName`,
38
+ message: `Custom type '${customTypeName}' is not defined in metadata.customTypes`,
39
+ code: 'INVALID_TYPE',
40
+ });
41
+ return;
42
+ }
43
+ const typeDefinition = customTypes[customTypeName];
44
+ const requiredProperties = typeDefinition?.requiredProperties;
45
+ const hasNoRequiredProperties = requiredProperties === undefined;
46
+ if (hasNoRequiredProperties)
47
+ return;
48
+ const requiredPropertyNames = Object.keys(requiredProperties);
49
+ const componentMetadata = component.metadata;
50
+ const missingProperties = componentMetadata
51
+ ? requiredPropertyNames.filter((prop) => !(prop in componentMetadata))
52
+ : requiredPropertyNames;
53
+ if (missingProperties.length > 0) {
54
+ errors.push({
55
+ path: `/components/${index}`,
56
+ message: `Custom component is missing required properties for type '${customTypeName}': ${missingProperties.join(', ')}`,
57
+ code: 'INVALID_TYPE',
58
+ });
59
+ }
60
+ });
61
+ return errors;
62
+ }
63
+ export function detectOrphanComponents(graph) {
64
+ const connectedComponentIds = new Set();
65
+ graph.links.forEach((link) => {
66
+ connectedComponentIds.add(link.source);
67
+ connectedComponentIds.add(link.target);
68
+ });
69
+ return graph.components
70
+ .filter((c) => !connectedComponentIds.has(c.id))
71
+ .map((c) => parseComponentId(c.id));
72
+ }
@@ -0,0 +1,5 @@
1
+ export * from './RiviereQuery';
2
+ export * from './event-types';
3
+ export * from './domain-types';
4
+ export * from './errors';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './RiviereQuery';
2
+ export * from './event-types';
3
+ export * from './domain-types';
4
+ export * from './errors';
@@ -0,0 +1,37 @@
1
+ import type { RiviereGraph, APIComponent, EventComponent, EventHandlerComponent, CustomComponent, UseCaseComponent, DomainOpComponent, SourceLocation } from '@living-architecture/riviere-schema';
2
+ export declare const defaultSourceLocation: SourceLocation;
3
+ export declare function createMinimalValidGraph(): RiviereGraph;
4
+ export declare function createAPIComponent(overrides: Partial<APIComponent> & {
5
+ id: string;
6
+ name: string;
7
+ domain: string;
8
+ }): APIComponent;
9
+ export declare function createEventComponent(overrides: Partial<EventComponent> & {
10
+ id: string;
11
+ name: string;
12
+ domain: string;
13
+ eventName: string;
14
+ }): EventComponent;
15
+ export declare function createEventHandlerComponent(overrides: Partial<EventHandlerComponent> & {
16
+ id: string;
17
+ name: string;
18
+ domain: string;
19
+ }): EventHandlerComponent;
20
+ export declare function createCustomComponent(overrides: Partial<CustomComponent> & {
21
+ id: string;
22
+ name: string;
23
+ domain: string;
24
+ customTypeName: string;
25
+ }): CustomComponent;
26
+ export declare function createUseCaseComponent(overrides: Partial<UseCaseComponent> & {
27
+ id: string;
28
+ name: string;
29
+ domain: string;
30
+ }): UseCaseComponent;
31
+ export declare function createDomainOpComponent(overrides: Partial<DomainOpComponent> & {
32
+ id: string;
33
+ name: string;
34
+ domain: string;
35
+ operationName: string;
36
+ }): DomainOpComponent;
37
+ //# sourceMappingURL=riviere-graph-fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"riviere-graph-fixtures.d.ts","sourceRoot":"","sources":["../src/riviere-graph-fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,qCAAqC,CAAA;AAE5C,eAAO,MAAM,qBAAqB,EAAE,cAAiE,CAAA;AAErG,wBAAgB,uBAAuB,IAAI,YAAY,CAmBtD;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9E,YAAY,CAUd;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnG,cAAc,CAOhB;AAED,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvF,qBAAqB,CAQvB;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACzG,eAAe,CAOjB;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClF,gBAAgB,CAOlB;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAC1G,iBAAiB,CAOnB"}
@@ -0,0 +1,73 @@
1
+ export const defaultSourceLocation = { repository: 'test-repo', filePath: 'test.ts' };
2
+ export function createMinimalValidGraph() {
3
+ return {
4
+ version: '1.0',
5
+ metadata: {
6
+ domains: { test: { description: 'Test domain', systemType: 'domain' } },
7
+ },
8
+ components: [
9
+ {
10
+ id: 'test:mod:ui:page',
11
+ type: 'UI',
12
+ name: 'Test Page',
13
+ domain: 'test',
14
+ module: 'mod',
15
+ route: '/test',
16
+ sourceLocation: defaultSourceLocation,
17
+ },
18
+ ],
19
+ links: [],
20
+ };
21
+ }
22
+ export function createAPIComponent(overrides) {
23
+ return {
24
+ type: 'API',
25
+ module: 'mod',
26
+ apiType: 'REST',
27
+ httpMethod: 'GET',
28
+ path: '/test',
29
+ sourceLocation: defaultSourceLocation,
30
+ ...overrides,
31
+ };
32
+ }
33
+ export function createEventComponent(overrides) {
34
+ return {
35
+ type: 'Event',
36
+ module: 'mod',
37
+ sourceLocation: defaultSourceLocation,
38
+ ...overrides,
39
+ };
40
+ }
41
+ export function createEventHandlerComponent(overrides) {
42
+ return {
43
+ type: 'EventHandler',
44
+ module: 'mod',
45
+ subscribedEvents: ['TestEvent'],
46
+ sourceLocation: defaultSourceLocation,
47
+ ...overrides,
48
+ };
49
+ }
50
+ export function createCustomComponent(overrides) {
51
+ return {
52
+ type: 'Custom',
53
+ module: 'mod',
54
+ sourceLocation: defaultSourceLocation,
55
+ ...overrides,
56
+ };
57
+ }
58
+ export function createUseCaseComponent(overrides) {
59
+ return {
60
+ type: 'UseCase',
61
+ module: 'mod',
62
+ sourceLocation: defaultSourceLocation,
63
+ ...overrides,
64
+ };
65
+ }
66
+ export function createDomainOpComponent(overrides) {
67
+ return {
68
+ type: 'DomainOp',
69
+ module: 'mod',
70
+ sourceLocation: defaultSourceLocation,
71
+ ...overrides,
72
+ };
73
+ }
@@ -0,0 +1,4 @@
1
+ import type { RiviereGraph } from '@living-architecture/riviere-schema';
2
+ import type { GraphStats } from './domain-types';
3
+ export declare function queryStats(graph: RiviereGraph): GraphStats;
4
+ //# sourceMappingURL=stats-queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-queries.d.ts","sourceRoot":"","sources":["../src/stats-queries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,qCAAqC,CAAA;AAC1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEhD,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,UAAU,CAgB1D"}
@@ -0,0 +1,14 @@
1
+ export function queryStats(graph) {
2
+ const components = graph.components;
3
+ const uniqueDomains = new Set(components.map((c) => c.domain));
4
+ const domainOps = components.filter((c) => c.type === 'DomainOp');
5
+ const uniqueEntities = new Set(domainOps.filter((c) => c.entity).map((c) => c.entity));
6
+ return {
7
+ componentCount: components.length,
8
+ linkCount: graph.links.length,
9
+ domainCount: uniqueDomains.size,
10
+ apiCount: components.filter((c) => c.type === 'API').length,
11
+ entityCount: uniqueEntities.size,
12
+ eventCount: components.filter((c) => c.type === 'Event').length,
13
+ };
14
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@living-architecture/riviere-query",
3
+ "version": "0.2.1",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ "./package.json": "./package.json",
13
+ ".": {
14
+ "@living-architecture/source": "./src/index.ts",
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "!**/*.tsbuildinfo"
23
+ ],
24
+ "dependencies": {
25
+ "tslib": "^2.3.0",
26
+ "zod": "^4.2.1",
27
+ "@living-architecture/riviere-schema": "0.2.0"
28
+ }
29
+ }