@archinsight/cli 3.0.2 → 3.0.3
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/README.md +95 -8
- package/build/index.js +1396 -311
- package/package.json +3 -2
package/build/index.js
CHANGED
|
@@ -33442,7 +33442,7 @@ var coreSources = [
|
|
|
33442
33442
|
},
|
|
33443
33443
|
{
|
|
33444
33444
|
"sourceName": "core_deployment.ai",
|
|
33445
|
-
"source": "define type DeploymentElement of BoundaryElement\n\nextend type Element\n List of Edge deployment\n InfrastructureComponent runsOn\n List of InfrastructureComponent uses\n\ndefine type InfrastructureComponent of DeploymentElement\n constructor infrastructureComponent\n\n Text name\n Text technology\n Text description\n InfrastructureComponent runsOn\n List of PhysicalWire projection\n List of InfrastructureComponent _\n\ndefine type ProjectionTerm\n\ndefine type DeploymentProfile of BoundaryElement\n constructor deploymentProfile\n\n required List of Deployment appliesTo\n\ndefine type Storage of InfrastructureComponent\n constructor storage\n\ndefine presentation Storage\n graphviz\n shape = cylinder\n\ndefine type Broker of
|
|
33445
|
+
"source": "define type DeploymentElement of BoundaryElement\n\nextend type Element\n List of Edge deployment\n InfrastructureComponent runsOn\n List of InfrastructureComponent uses\n\ndefine type InfrastructureComponent of DeploymentElement\n constructor infrastructureComponent\n\n Text name\n Text technology\n Text description\n InfrastructureComponent runsOn\n List of PhysicalWire projection\n List of InfrastructureComponent _\n\ndefine type ProjectionTerm\n\ndefine type DeploymentProfile of BoundaryElement\n constructor deploymentProfile\n\n required List of Deployment appliesTo\n\ndefine type Storage of InfrastructureComponent\n constructor storage\n\ndefine presentation Storage\n graphviz\n shape = cylinder\n\ndefine type Broker of NetworkConnection\n constructor broker\n\n Text address\n\ndefine presentation Broker\n graphviz\n visible = true\n shape = box\n style = filled,dashed\n\ndefine type Compute of InfrastructureComponent\n constructor compute\n\n Text address\n List of InfrastructureComponent components\n\ndefine type NetworkConnection of InfrastructureComponent\n constructor networkConnection\n\ndefine type Environment of BoundaryElement\n constructor environment\n\n required Text name\n Text region\n List of DeploymentElement _\n\ndefine type Deployment of DeploymentElement\n constructor deployment\n\n Text name\n List of DeploymentElement _\n\ndefine presentation DeploymentProfile\n graphviz\n visible = false\n\ndefine presentation NetworkConnection\n graphviz\n visible = false\n"
|
|
33446
33446
|
},
|
|
33447
33447
|
{
|
|
33448
33448
|
"sourceName": "core_operator.ai",
|
|
@@ -35171,6 +35171,7 @@ var SYSTEM_TYPE = "System";
|
|
|
35171
35171
|
var ACTOR_TYPE = "Actor";
|
|
35172
35172
|
var ORIGINAL_LINK_OPERATOR = "originalLink";
|
|
35173
35173
|
var DEPLOYMENT_PROFILE_TYPE = "DeploymentProfile";
|
|
35174
|
+
var ENVIRONMENT_TYPE = "Environment";
|
|
35174
35175
|
var INFRASTRUCTURE_COMPONENT_TYPE = "InfrastructureComponent";
|
|
35175
35176
|
var NETWORK_CONNECTION_TYPE = "NetworkConnection";
|
|
35176
35177
|
var DEPLOYMENT_TYPE = "Deployment";
|
|
@@ -35249,8 +35250,8 @@ function linkProject(request) {
|
|
|
35249
35250
|
element.id,
|
|
35250
35251
|
mergeResolvedReferenceAttributes(resolvedElementAttributes.get(element.id) ?? {}, {
|
|
35251
35252
|
[APPLIES_TO_ATTRIBUTE]: effectiveDeployments.map((deployment) => resolvedValueForElement(deployment, deployment)),
|
|
35252
|
-
[RUNS_ON_ATTRIBUTE]: application.runsOn.map(
|
|
35253
|
-
[USES_ATTRIBUTE]: application.uses.map(
|
|
35253
|
+
[RUNS_ON_ATTRIBUTE]: application.runsOn.map(resolvedValueForDeploymentUse),
|
|
35254
|
+
[USES_ATTRIBUTE]: application.uses.map(resolvedValueForDeploymentUse)
|
|
35254
35255
|
})
|
|
35255
35256
|
);
|
|
35256
35257
|
}
|
|
@@ -35306,6 +35307,12 @@ function linkProject(request) {
|
|
|
35306
35307
|
attributes: effectiveEdgeAttributes,
|
|
35307
35308
|
projectedAttributes: materialized.edge.attributes,
|
|
35308
35309
|
projectedOperator: materialized.edge.operator,
|
|
35310
|
+
projectionOrigin: {
|
|
35311
|
+
source: edge.source,
|
|
35312
|
+
target: target.id,
|
|
35313
|
+
sourceIdentity: materialized.edge.sourceIdentity,
|
|
35314
|
+
...materialized.edge.declaration === void 0 ? {} : { declaration: materialized.edge.declaration }
|
|
35315
|
+
},
|
|
35309
35316
|
...materialized.edge.annotations === void 0 ? {} : { annotations: materialized.edge.annotations },
|
|
35310
35317
|
...coverage === void 0 ? {} : { coverage }
|
|
35311
35318
|
});
|
|
@@ -35313,7 +35320,7 @@ function linkProject(request) {
|
|
|
35313
35320
|
}
|
|
35314
35321
|
}
|
|
35315
35322
|
for (const projection of pendingProjections) {
|
|
35316
|
-
addProjectedEdges(linkedEdges, projection.sourceIdentity, projection.fromId, projection.toId, projection.attributes, linkedElementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, void 0, projection.annotations, projection.projectedAttributes, projection.projectedOperator, /* @__PURE__ */ new Set(), projection.coverage);
|
|
35323
|
+
addProjectedEdges(linkedEdges, projection.sourceIdentity, projection.fromId, projection.toId, projection.attributes, linkedElementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, void 0, projection.annotations, projection.projectedAttributes, projection.projectedOperator, /* @__PURE__ */ new Set(), projection.coverage, projection.projectionOrigin);
|
|
35317
35324
|
}
|
|
35318
35325
|
const slotDomainTypes = typeSystem.slotDomainTypes();
|
|
35319
35326
|
for (const element of elements) {
|
|
@@ -35597,7 +35604,7 @@ function collectBodyItems(body, ownerType, owner, document, typeSystem) {
|
|
|
35597
35604
|
collectBodyItem(item, ownerType, owner, document, typeSystem);
|
|
35598
35605
|
}
|
|
35599
35606
|
}
|
|
35600
|
-
function collectBodyItem(item, ownerType, owner, document, typeSystem) {
|
|
35607
|
+
function collectBodyItem(item, ownerType, owner, document, typeSystem, expectedObjectType) {
|
|
35601
35608
|
const assignment = firstChild2(item, "assignment");
|
|
35602
35609
|
if (assignment !== void 0) {
|
|
35603
35610
|
if (owner !== void 0) {
|
|
@@ -35633,7 +35640,15 @@ function collectBodyItem(item, ownerType, owner, document, typeSystem) {
|
|
|
35633
35640
|
}
|
|
35634
35641
|
}
|
|
35635
35642
|
if (object !== void 0) {
|
|
35636
|
-
const element = collectObject(
|
|
35643
|
+
const element = collectObject(
|
|
35644
|
+
object,
|
|
35645
|
+
ownerType,
|
|
35646
|
+
owner,
|
|
35647
|
+
document,
|
|
35648
|
+
typeSystem,
|
|
35649
|
+
annotations(annotatedObject, document),
|
|
35650
|
+
expectedObjectType ?? expectedNestedType(typeSystem, ownerType)
|
|
35651
|
+
);
|
|
35637
35652
|
if (owner !== void 0 && element !== void 0 && typeSystem.anonymousListAttribute(ownerType) !== void 0) {
|
|
35638
35653
|
addAttributeValue(owner.attributes, "_", elementReference(element));
|
|
35639
35654
|
}
|
|
@@ -35773,11 +35788,12 @@ function collectGroupingList(list, ownerType, owner, document, typeSystem) {
|
|
|
35773
35788
|
if (collectImplicitDeploymentGroupObject(list, listName, owner, document, typeSystem)) {
|
|
35774
35789
|
return true;
|
|
35775
35790
|
}
|
|
35791
|
+
const expectedObjectType = deploymentGroupAttributeType(owner, listName, document, typeSystem);
|
|
35776
35792
|
for (const item of children(list, "listBodyItem")) {
|
|
35777
35793
|
const bodyItem = firstChild2(item, "architectureBodyItem");
|
|
35778
35794
|
if (bodyItem !== void 0) {
|
|
35779
35795
|
const before = document.elements.length;
|
|
35780
|
-
collectBodyItem(bodyItem, ownerType, owner, document, typeSystem);
|
|
35796
|
+
collectBodyItem(bodyItem, ownerType, owner, document, typeSystem, expectedObjectType);
|
|
35781
35797
|
for (const element of document.elements.slice(before)) {
|
|
35782
35798
|
if (element.parent === owner.id && element.slotName === void 0) {
|
|
35783
35799
|
element.slotName = listName;
|
|
@@ -35802,9 +35818,7 @@ function collectImplicitDeploymentGroupObject(list, listName, owner, document, t
|
|
|
35802
35818
|
return true;
|
|
35803
35819
|
}
|
|
35804
35820
|
function resolveDeploymentGroupConstructor(listName, listNameNode, owner, document, typeSystem) {
|
|
35805
|
-
const
|
|
35806
|
-
const parentAttribute = parent === void 0 ? void 0 : typeSystem.attribute(parent.type, listName);
|
|
35807
|
-
const attributeType2 = parentAttribute === void 0 ? void 0 : parentAttribute.list === true ? parentAttribute.listElementType ?? parentAttribute.type : parentAttribute.type;
|
|
35821
|
+
const attributeType2 = deploymentGroupAttributeType(owner, listName, document, typeSystem);
|
|
35808
35822
|
if (attributeType2 !== void 0) {
|
|
35809
35823
|
return resolveImplicitObjectConstructor(attributeType2, listName, listNameNode, document, typeSystem);
|
|
35810
35824
|
}
|
|
@@ -35823,6 +35837,14 @@ function resolveDeploymentGroupConstructor(listName, listNameNode, owner, docume
|
|
|
35823
35837
|
}
|
|
35824
35838
|
return constructors[0];
|
|
35825
35839
|
}
|
|
35840
|
+
function deploymentGroupAttributeType(owner, listName, document, typeSystem) {
|
|
35841
|
+
const parent = owner.parent === void 0 ? void 0 : document.elements.find((element) => element.id === owner.parent);
|
|
35842
|
+
const attribute = parent === void 0 ? void 0 : typeSystem.attribute(parent.type, listName);
|
|
35843
|
+
if (attribute === void 0) {
|
|
35844
|
+
return void 0;
|
|
35845
|
+
}
|
|
35846
|
+
return attribute.list === true ? attribute.listElementType ?? attribute.type : attribute.type;
|
|
35847
|
+
}
|
|
35826
35848
|
function collectImplicitObjectAttribute(list, attributeName, attributeNameNode, ownerType, owner, document, typeSystem) {
|
|
35827
35849
|
if (owner === void 0 || attributeName.length === 0) {
|
|
35828
35850
|
return false;
|
|
@@ -35864,16 +35886,18 @@ function resolveImplicitObjectConstructor(attributeType2, attributeName, attribu
|
|
|
35864
35886
|
});
|
|
35865
35887
|
return void 0;
|
|
35866
35888
|
}
|
|
35867
|
-
|
|
35889
|
+
const exactConstructors = constructors.filter((constructor) => constructor.ownerType === attributeType2);
|
|
35890
|
+
const candidates = exactConstructors.length > 0 ? exactConstructors : constructors;
|
|
35891
|
+
if (candidates.length > 1) {
|
|
35868
35892
|
document.diagnostics.push({
|
|
35869
35893
|
code: "CONSTRUCTOR_AMBIGUOUS",
|
|
35870
|
-
message: `Type '${attributeType2}' has multiple constructors for implicit attribute '${attributeName}': ${
|
|
35894
|
+
message: `Type '${attributeType2}' has multiple constructors for implicit attribute '${attributeName}': ${candidates.map((constructor) => `'${constructor.spelling}'`).join(", ")}`,
|
|
35871
35895
|
sourceName: document.sourceName,
|
|
35872
35896
|
...position2(attributeNameNode, document.sourceName)
|
|
35873
35897
|
});
|
|
35874
35898
|
return void 0;
|
|
35875
35899
|
}
|
|
35876
|
-
return
|
|
35900
|
+
return candidates[0];
|
|
35877
35901
|
}
|
|
35878
35902
|
function collectImplicitObjectElement(list, attributeNameNode, constructor, parent, document, slotName) {
|
|
35879
35903
|
const localId = nextAnonymousLocalId(document);
|
|
@@ -36750,7 +36774,7 @@ function deploymentAttributesForWire(edge, target, context) {
|
|
|
36750
36774
|
);
|
|
36751
36775
|
const application = resolveDeploymentApplication(source, edge.deploymentActions, true, context, deployments);
|
|
36752
36776
|
return {
|
|
36753
|
-
[USES_ATTRIBUTE]: application.uses.map(
|
|
36777
|
+
[USES_ATTRIBUTE]: application.uses.map(resolvedValueForDeploymentUse)
|
|
36754
36778
|
};
|
|
36755
36779
|
}
|
|
36756
36780
|
function resolveDeploymentApplication(owner, actions, wire, context, initialDeployments = []) {
|
|
@@ -36896,6 +36920,15 @@ function resolveDeploymentInfrastructure(owner, action, target, deployments, inh
|
|
|
36896
36920
|
});
|
|
36897
36921
|
return [];
|
|
36898
36922
|
}
|
|
36923
|
+
if (!isDeclaredDeploymentInfrastructureSlot(action.targetId, context.typeSystem)) {
|
|
36924
|
+
context.diagnostics.push({
|
|
36925
|
+
code: "UNDECLARED_IDENTIFIER",
|
|
36926
|
+
message: `Deployment slot '${action.targetId}' is not declared by any Environment type`,
|
|
36927
|
+
sourceName: action.sourceName,
|
|
36928
|
+
...diagnosticPosition2(action)
|
|
36929
|
+
});
|
|
36930
|
+
return [];
|
|
36931
|
+
}
|
|
36899
36932
|
if (deployments.length === 0) {
|
|
36900
36933
|
if (wire) {
|
|
36901
36934
|
return [];
|
|
@@ -36931,6 +36964,22 @@ function resolveDeploymentInfrastructure(owner, action, target, deployments, inh
|
|
|
36931
36964
|
}
|
|
36932
36965
|
return result;
|
|
36933
36966
|
}
|
|
36967
|
+
function isDeclaredDeploymentInfrastructureSlot(slotName, typeSystem) {
|
|
36968
|
+
for (const type of typeSystem.declaredTypes()) {
|
|
36969
|
+
if (!typeSystem.isAssignable(type, ENVIRONMENT_TYPE)) {
|
|
36970
|
+
continue;
|
|
36971
|
+
}
|
|
36972
|
+
const attribute = typeSystem.attribute(type, slotName);
|
|
36973
|
+
if (attribute === void 0) {
|
|
36974
|
+
continue;
|
|
36975
|
+
}
|
|
36976
|
+
const valueType = attribute.list === true ? attribute.listElementType ?? attribute.type : attribute.type;
|
|
36977
|
+
if (typeSystem.isAssignable(valueType, INFRASTRUCTURE_COMPONENT_TYPE)) {
|
|
36978
|
+
return true;
|
|
36979
|
+
}
|
|
36980
|
+
}
|
|
36981
|
+
return false;
|
|
36982
|
+
}
|
|
36934
36983
|
function materializeInfrastructureUse(owner, source, action, deploymentId, context, inherited) {
|
|
36935
36984
|
if (!deploymentActionHasOverrides(action)) {
|
|
36936
36985
|
return {
|
|
@@ -37052,6 +37101,12 @@ function resolvedValueForElement(element, source) {
|
|
|
37052
37101
|
...source.endColumn === void 0 ? {} : { endColumn: source.endColumn }
|
|
37053
37102
|
};
|
|
37054
37103
|
}
|
|
37104
|
+
function resolvedValueForDeploymentUse(use) {
|
|
37105
|
+
return {
|
|
37106
|
+
...resolvedValueForElement(use.element, use.action),
|
|
37107
|
+
...use.deploymentId === void 0 ? {} : { deploymentId: use.deploymentId }
|
|
37108
|
+
};
|
|
37109
|
+
}
|
|
37055
37110
|
function mergeResolvedReferenceAttributes(base, override) {
|
|
37056
37111
|
const result = Object.fromEntries(
|
|
37057
37112
|
Object.entries(base).map(([name, values]) => [name, [...values]])
|
|
@@ -37086,7 +37141,7 @@ function mergeUniqueElements(left, right) {
|
|
|
37086
37141
|
function sanitizeLocalId(value) {
|
|
37087
37142
|
return value.replace(/[^A-Za-z0-9_]/g, "_");
|
|
37088
37143
|
}
|
|
37089
|
-
function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes, elementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, projectionScope, annotations2 = [], projectedAttributes, projectedOperator, visitedProjectionElements = /* @__PURE__ */ new Set(), coverage) {
|
|
37144
|
+
function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes, elementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, projectionScope, annotations2 = [], projectedAttributes, projectedOperator, visitedProjectionElements = /* @__PURE__ */ new Set(), coverage, projectionOrigin = { source: fromId, target: toId }) {
|
|
37090
37145
|
for (const [attributeName, values] of Object.entries(attributes)) {
|
|
37091
37146
|
if (attributeName === "_") {
|
|
37092
37147
|
continue;
|
|
@@ -37098,7 +37153,7 @@ function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes
|
|
|
37098
37153
|
if (!isGraphElement(value.element)) {
|
|
37099
37154
|
continue;
|
|
37100
37155
|
}
|
|
37101
|
-
const visitKey = `${fromId}\0${toId}\0${value.element.id}`;
|
|
37156
|
+
const visitKey = `${fromId}\0${toId}\0${value.element.id}\0${value.deploymentId ?? ""}`;
|
|
37102
37157
|
if (visitedProjectionElements.has(visitKey)) {
|
|
37103
37158
|
continue;
|
|
37104
37159
|
}
|
|
@@ -37106,6 +37161,13 @@ function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes
|
|
|
37106
37161
|
if (isDirectSlotReferenceSelfProjection(value.element, fromId, toId)) {
|
|
37107
37162
|
continue;
|
|
37108
37163
|
}
|
|
37164
|
+
const effectiveProjectionScope = projectionScope ?? projectionScopeFor(
|
|
37165
|
+
fromId,
|
|
37166
|
+
toId,
|
|
37167
|
+
value,
|
|
37168
|
+
elementsById,
|
|
37169
|
+
resolvedElementAttributes
|
|
37170
|
+
);
|
|
37109
37171
|
const rules = value.element.projectionRules;
|
|
37110
37172
|
if (fromId === toId && rules.some(projectionRuleUsesTo)) {
|
|
37111
37173
|
const position3 = value.line === void 0 || value.column === void 0 ? value.element : {
|
|
@@ -37123,7 +37185,7 @@ function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes
|
|
|
37123
37185
|
continue;
|
|
37124
37186
|
}
|
|
37125
37187
|
for (const rule3 of rules) {
|
|
37126
|
-
addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, value.element, rule3, elementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics,
|
|
37188
|
+
addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, value.element, rule3, elementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, effectiveProjectionScope, annotations2, projectedAttributes, projectedOperator, coverage, projectionOrigin);
|
|
37127
37189
|
}
|
|
37128
37190
|
addProjectedEdges(
|
|
37129
37191
|
linkedEdges,
|
|
@@ -37136,12 +37198,13 @@ function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes
|
|
|
37136
37198
|
ownerIndependentProjectionKeys,
|
|
37137
37199
|
typeSystem,
|
|
37138
37200
|
diagnostics,
|
|
37139
|
-
|
|
37201
|
+
effectiveProjectionScope,
|
|
37140
37202
|
annotations2,
|
|
37141
37203
|
void 0,
|
|
37142
37204
|
projectedOperator,
|
|
37143
37205
|
visitedProjectionElements,
|
|
37144
|
-
coverage
|
|
37206
|
+
coverage,
|
|
37207
|
+
projectionOrigin
|
|
37145
37208
|
);
|
|
37146
37209
|
}
|
|
37147
37210
|
}
|
|
@@ -37149,7 +37212,7 @@ function addProjectedEdges(linkedEdges, sourceIdentity, fromId, toId, attributes
|
|
|
37149
37212
|
function isDirectSlotReferenceSelfProjection(element, fromId, toId) {
|
|
37150
37213
|
return fromId === toId && element.parent === fromId && element.scalarAttributes.parentType !== void 0 && element.scalarAttributes.attributeName !== void 0;
|
|
37151
37214
|
}
|
|
37152
|
-
function addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, projectionElement, rule3, elementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, projectionScope, annotations2 = [], projectedAttributes, projectedOperator, coverage) {
|
|
37215
|
+
function addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, projectionElement, rule3, elementsById, resolvedElementAttributes, ownerIndependentProjectionKeys, typeSystem, diagnostics, projectionScope, annotations2 = [], projectedAttributes, projectedOperator, coverage, projectionOrigin = { source: fromId, target: toId }) {
|
|
37153
37216
|
if (!validateConcreteProjectionRule(rule3, typeSystem, diagnostics)) {
|
|
37154
37217
|
return;
|
|
37155
37218
|
}
|
|
@@ -37158,19 +37221,22 @@ function addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, project
|
|
|
37158
37221
|
const effectiveOperator = rule3.operator === ORIGINAL_LINK_OPERATOR ? projectedOperator ?? "->" : rule3.operator;
|
|
37159
37222
|
const edgeOwnerPlacement = projectionRuleOwnerPlacement(rule3);
|
|
37160
37223
|
const edgeProjectionScope = projectionPlacementScope(edgeOwnerPlacement, projectionScope);
|
|
37224
|
+
const sourcePlacement = projectionPlacementScope(rule3.source.placement, projectionScope);
|
|
37225
|
+
const targetPlacement = projectionPlacementScope(rule3.target.placement, projectionScope);
|
|
37161
37226
|
const edgeSourceIdentity = projectionPlacementSourceIdentity(edgeOwnerPlacement, fromId, toId, elementsById) ?? sourceIdentity;
|
|
37162
37227
|
const carriedAttributes = mergeAttributeValues(
|
|
37163
37228
|
rule3.operator === ORIGINAL_LINK_OPERATOR ? projectedAttributes : void 0,
|
|
37164
37229
|
rule3.attributes ?? {}
|
|
37165
37230
|
);
|
|
37166
|
-
const
|
|
37231
|
+
const preservesLogicalRelationship = rule3.operator === ORIGINAL_LINK_OPERATOR;
|
|
37232
|
+
const originKey = projectionOriginKey(projectionOrigin);
|
|
37167
37233
|
for (const source of sources) {
|
|
37168
37234
|
for (const target of targets) {
|
|
37169
37235
|
if (coverage !== void 0) {
|
|
37170
37236
|
coverage.projected = true;
|
|
37171
37237
|
}
|
|
37172
37238
|
if (!projectionRuleUsesOwner(rule3)) {
|
|
37173
|
-
const key = `${projectionElement.id}\0${source}\0${effectiveOperator}\0${target}`;
|
|
37239
|
+
const key = `${projectionElement.id}\0${source}\0${effectiveOperator}\0${target}\0${preservesLogicalRelationship ? originKey : ""}`;
|
|
37174
37240
|
if (ownerIndependentProjectionKeys.has(key)) {
|
|
37175
37241
|
mergeProjectedEdge(
|
|
37176
37242
|
linkedEdges,
|
|
@@ -37190,7 +37256,7 @@ function addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, project
|
|
|
37190
37256
|
const targetElement = elementsById.get(target);
|
|
37191
37257
|
const operator = sourceElement === void 0 || targetElement === void 0 ? void 0 : typeSystem.operatorConstructor(effectiveOperator, sourceElement.type, targetElement.type);
|
|
37192
37258
|
const type = operator?.ownerType ?? effectiveOperator;
|
|
37193
|
-
const existingIndex = linkedEdges.findIndex((edge) => edge.projected === true && edge.source === source && edge.operator === effectiveOperator && edge.target === target && edge.projectionRoot === projectionElement.id && edge.projectionScope === edgeProjectionScope);
|
|
37259
|
+
const existingIndex = linkedEdges.findIndex((edge) => edge.projected === true && edge.source === source && edge.operator === effectiveOperator && edge.target === target && edge.projectionRoot === projectionElement.id && edge.projectionScope === edgeProjectionScope && edge.sourcePlacement === sourcePlacement && edge.targetPlacement === targetPlacement && (!preservesLogicalRelationship || edge.projectionOrigins?.some((origin) => projectionOriginKey(origin) === originKey) === true));
|
|
37194
37260
|
if (existingIndex >= 0) {
|
|
37195
37261
|
const edge = linkedEdges[existingIndex];
|
|
37196
37262
|
if (edge !== void 0) {
|
|
@@ -37213,10 +37279,13 @@ function addProjectedRuleEdge(linkedEdges, sourceIdentity, fromId, toId, project
|
|
|
37213
37279
|
operator: effectiveOperator,
|
|
37214
37280
|
type,
|
|
37215
37281
|
sourceIdentity: edgeSourceIdentity,
|
|
37282
|
+
...preservesLogicalRelationship && projectionOrigin.declaration !== void 0 ? { declaration: projectionOrigin.declaration } : {},
|
|
37216
37283
|
attributes: carriedAttributes ?? {},
|
|
37217
37284
|
...listAttributesProperty(typeSystem, type),
|
|
37218
37285
|
projected: true,
|
|
37219
37286
|
...edgeProjectionScope === void 0 ? {} : { projectionScope: edgeProjectionScope },
|
|
37287
|
+
...sourcePlacement === void 0 ? {} : { sourcePlacement },
|
|
37288
|
+
...targetPlacement === void 0 ? {} : { targetPlacement },
|
|
37220
37289
|
...annotations2.length === 0 ? {} : { annotations: annotations2 }
|
|
37221
37290
|
});
|
|
37222
37291
|
}
|
|
@@ -37265,7 +37334,7 @@ function uniqueProjectionOrigins(origins) {
|
|
|
37265
37334
|
const seen = /* @__PURE__ */ new Set();
|
|
37266
37335
|
const result = [];
|
|
37267
37336
|
for (const origin of origins) {
|
|
37268
|
-
const key =
|
|
37337
|
+
const key = projectionOriginKey(origin);
|
|
37269
37338
|
if (seen.has(key)) {
|
|
37270
37339
|
continue;
|
|
37271
37340
|
}
|
|
@@ -37274,6 +37343,19 @@ function uniqueProjectionOrigins(origins) {
|
|
|
37274
37343
|
}
|
|
37275
37344
|
return result;
|
|
37276
37345
|
}
|
|
37346
|
+
function projectionOriginKey(origin) {
|
|
37347
|
+
const declaration = origin.declaration;
|
|
37348
|
+
return [
|
|
37349
|
+
origin.source,
|
|
37350
|
+
origin.target,
|
|
37351
|
+
origin.sourceIdentity ?? "",
|
|
37352
|
+
declaration?.sourceName ?? "",
|
|
37353
|
+
declaration?.line ?? "",
|
|
37354
|
+
declaration?.column ?? "",
|
|
37355
|
+
declaration?.endLine ?? "",
|
|
37356
|
+
declaration?.endColumn ?? ""
|
|
37357
|
+
].join("\0");
|
|
37358
|
+
}
|
|
37277
37359
|
function mergeAttributeValues(base, override) {
|
|
37278
37360
|
if (base === void 0 || Object.keys(base).length === 0) {
|
|
37279
37361
|
return override;
|
|
@@ -37356,8 +37438,58 @@ function uniqueIds(values) {
|
|
|
37356
37438
|
function projectionRuleOwnerPlacement(rule3) {
|
|
37357
37439
|
return rule3.operator === ORIGINAL_LINK_OPERATOR ? rule3.target.placement : rule3.source.placement;
|
|
37358
37440
|
}
|
|
37359
|
-
function
|
|
37360
|
-
|
|
37441
|
+
function projectionScopeFor(fromId, toId, projectionValue, elementsById, resolvedElementAttributes) {
|
|
37442
|
+
const sourcePlacement = endpointPlacement(
|
|
37443
|
+
fromId,
|
|
37444
|
+
projectionValue.deploymentId,
|
|
37445
|
+
projectionValue.element?.context,
|
|
37446
|
+
elementsById,
|
|
37447
|
+
resolvedElementAttributes
|
|
37448
|
+
);
|
|
37449
|
+
const targetPlacement = endpointPlacement(
|
|
37450
|
+
toId,
|
|
37451
|
+
projectionValue.deploymentId,
|
|
37452
|
+
projectionValue.element?.context,
|
|
37453
|
+
elementsById,
|
|
37454
|
+
resolvedElementAttributes
|
|
37455
|
+
);
|
|
37456
|
+
return sourcePlacement === void 0 && targetPlacement === void 0 ? void 0 : {
|
|
37457
|
+
...sourcePlacement === void 0 ? {} : { sourcePlacement },
|
|
37458
|
+
...targetPlacement === void 0 ? {} : { targetPlacement }
|
|
37459
|
+
};
|
|
37460
|
+
}
|
|
37461
|
+
function endpointPlacement(endpointId, deploymentId, projectionContext, elementsById, resolvedElementAttributes) {
|
|
37462
|
+
const placements = endpointPlacementValues(endpointId, elementsById, resolvedElementAttributes);
|
|
37463
|
+
if (deploymentId !== void 0) {
|
|
37464
|
+
const inDeployment = uniqueIds(placements.filter((placement) => placement.deploymentId === deploymentId).map((placement) => placement.id));
|
|
37465
|
+
if (inDeployment.length === 1) {
|
|
37466
|
+
return inDeployment[0];
|
|
37467
|
+
}
|
|
37468
|
+
}
|
|
37469
|
+
if (projectionContext !== void 0) {
|
|
37470
|
+
const inContext = uniqueIds(placements.filter((placement) => placement.element?.context === projectionContext).map((placement) => placement.id));
|
|
37471
|
+
if (inContext.length === 1) {
|
|
37472
|
+
return inContext[0];
|
|
37473
|
+
}
|
|
37474
|
+
}
|
|
37475
|
+
const uniquePlacements = uniqueIds(placements.map((placement) => placement.id));
|
|
37476
|
+
return uniquePlacements.length === 1 ? uniquePlacements[0] : void 0;
|
|
37477
|
+
}
|
|
37478
|
+
function endpointPlacementValues(endpointId, elementsById, resolvedElementAttributes) {
|
|
37479
|
+
const visited = /* @__PURE__ */ new Set();
|
|
37480
|
+
let current = elementsById.get(endpointId);
|
|
37481
|
+
while (current !== void 0 && !visited.has(current.id)) {
|
|
37482
|
+
visited.add(current.id);
|
|
37483
|
+
const placements = resolvedElementAttributes.get(current.id)?.[RUNS_ON_ATTRIBUTE] ?? [];
|
|
37484
|
+
if (placements.length > 0) {
|
|
37485
|
+
return placements;
|
|
37486
|
+
}
|
|
37487
|
+
current = current.parent === void 0 ? void 0 : elementsById.get(current.parent);
|
|
37488
|
+
}
|
|
37489
|
+
return [];
|
|
37490
|
+
}
|
|
37491
|
+
function projectionPlacementScope(placement, projectionScope) {
|
|
37492
|
+
return placement === "source" ? projectionScope?.sourcePlacement : projectionScope?.targetPlacement;
|
|
37361
37493
|
}
|
|
37362
37494
|
function projectionPlacementSourceIdentity(placement, fromId, toId, elementsById) {
|
|
37363
37495
|
return elementsById.get(placement === "target" ? toId : fromId)?.sourceName;
|
|
@@ -38263,6 +38395,8 @@ function selectGraph(result, scope, query) {
|
|
|
38263
38395
|
const selectedElements = /* @__PURE__ */ new Map();
|
|
38264
38396
|
const selectedEdges = [];
|
|
38265
38397
|
const selectedEdgeIdentities = /* @__PURE__ */ new Map();
|
|
38398
|
+
const returnedRelationshipPatterns = relationshipPatternsReturnedBy(parsed);
|
|
38399
|
+
const selectedStructuralRelationships = /* @__PURE__ */ new Set();
|
|
38266
38400
|
const groups = /* @__PURE__ */ new Map();
|
|
38267
38401
|
const nodeById = queryNodeIndex(result);
|
|
38268
38402
|
for (const row of rows) {
|
|
@@ -38292,6 +38426,8 @@ function selectGraph(result, scope, query) {
|
|
|
38292
38426
|
derived: edge.derived,
|
|
38293
38427
|
projected: edge.projected
|
|
38294
38428
|
}, edge.edge, selectedEdgeIdentities);
|
|
38429
|
+
} else if (returnedRelationshipPatterns.has(alias)) {
|
|
38430
|
+
selectedStructuralRelationships.add(alias);
|
|
38295
38431
|
}
|
|
38296
38432
|
}
|
|
38297
38433
|
}
|
|
@@ -38301,7 +38437,7 @@ function selectGraph(result, scope, query) {
|
|
|
38301
38437
|
}
|
|
38302
38438
|
let groupedSelectedElements = /* @__PURE__ */ new Set();
|
|
38303
38439
|
if (parsed.groupBy !== void 0) {
|
|
38304
|
-
groupedSelectedElements = collectSelectedReferenceGroups(selectedElements, groups, parsed.groupBy);
|
|
38440
|
+
groupedSelectedElements = collectSelectedReferenceGroups(selectedElements, selectedEdges, groups, parsed.groupBy);
|
|
38305
38441
|
for (const owner of completeReferenceGroupClosure(result, groups, parsed.groupBy)) {
|
|
38306
38442
|
const element = linkedElementForNode(nodeById.get(owner));
|
|
38307
38443
|
if (element !== void 0) {
|
|
@@ -38309,7 +38445,7 @@ function selectGraph(result, scope, query) {
|
|
|
38309
38445
|
}
|
|
38310
38446
|
}
|
|
38311
38447
|
}
|
|
38312
|
-
const completedEdges = selectedEdges.length > 0 ? selectedEdges : result.edges.filter((edge) => edge.projected !== true && selectedElements.has(edge.source) && selectedElements.has(edge.target)).map((edge) => ({ edge, source: edge.source, target: edge.target, derived: false, projected: false }));
|
|
38448
|
+
const completedEdges = selectedEdges.length > 0 ? selectedEdges : hasAuthoritativeEdgeSelection(returnedRelationshipPatterns, selectedStructuralRelationships) ? [] : result.edges.filter((edge) => edge.projected !== true && selectedElements.has(edge.source) && selectedElements.has(edge.target)).map((edge) => ({ edge, source: edge.source, target: edge.target, derived: false, projected: false }));
|
|
38313
38449
|
const internalElementIds = new Set([...internalElements(result, rows, parsed)].filter((id) => selectedElements.has(id)));
|
|
38314
38450
|
const externalElements = [...selectedElements.keys()].filter((id) => !internalElementIds.has(id) && !groupedSelectedElements.has(id));
|
|
38315
38451
|
const selectedGraph2 = {
|
|
@@ -38322,7 +38458,113 @@ function selectGraph(result, scope, query) {
|
|
|
38322
38458
|
})).filter((group) => group.elements.length > 0),
|
|
38323
38459
|
externalElements
|
|
38324
38460
|
};
|
|
38325
|
-
|
|
38461
|
+
const bounded = applyViewBoundary(result, selectedGraph2, scope);
|
|
38462
|
+
const systemSeedFiltered = scope.view === "deployment-container" || scope.view === "deployment-system" ? removeDescendantProjectionsCapturedBySystemSeeds(result, bounded, scope) : bounded;
|
|
38463
|
+
const materialized = materializeGroupedView(
|
|
38464
|
+
systemSeedFiltered,
|
|
38465
|
+
scope.view === "deployment" || scope.view === "deployment-container" || scope.view === "deployment-system"
|
|
38466
|
+
);
|
|
38467
|
+
if (scope.view === "deployment-container") {
|
|
38468
|
+
return applyDeploymentEnvironmentScope(result, materialized, scope);
|
|
38469
|
+
}
|
|
38470
|
+
if (scope.view === "deployment-system") {
|
|
38471
|
+
return simplifyDeploymentSystemInfrastructure(result, rollUpDeploymentSystems(result, materialized, scope));
|
|
38472
|
+
}
|
|
38473
|
+
return materialized;
|
|
38474
|
+
}
|
|
38475
|
+
function removeDescendantProjectionsCapturedBySystemSeeds(result, graph, scope) {
|
|
38476
|
+
const sourceSystems = new Set(result.elements.filter((element) => element.sourceIdentity === scope.tab && elementHasType(element, "SystemElement")).map((element) => element.id));
|
|
38477
|
+
const edges = graph.edges.filter((edge) => {
|
|
38478
|
+
const originSource = edge.edge.originSource ?? edge.edge.source;
|
|
38479
|
+
const originTarget = edge.edge.originTarget ?? edge.edge.target;
|
|
38480
|
+
return ![edge.source, edge.target].some((endpoint) => {
|
|
38481
|
+
const system = baseOccurrenceId(endpoint);
|
|
38482
|
+
return sourceSystems.has(system) && originSource !== system && originTarget !== system;
|
|
38483
|
+
});
|
|
38484
|
+
});
|
|
38485
|
+
const referenced = new Set(edges.flatMap((edge) => [edge.source, edge.target]));
|
|
38486
|
+
const grouped = new Set(graph.groups.flatMap((group) => group.elements));
|
|
38487
|
+
const retained = new Set(Object.keys(graph.elements).filter(
|
|
38488
|
+
(id) => referenced.has(id) || grouped.has(id) || !sourceSystems.has(baseOccurrenceId(id))
|
|
38489
|
+
));
|
|
38490
|
+
return {
|
|
38491
|
+
...graph,
|
|
38492
|
+
elements: Object.fromEntries(Object.entries(graph.elements).filter(([id]) => retained.has(id))),
|
|
38493
|
+
edges,
|
|
38494
|
+
groups: graph.groups.map((group) => ({
|
|
38495
|
+
...group,
|
|
38496
|
+
elements: group.elements.filter((id) => retained.has(id))
|
|
38497
|
+
})).filter((group) => group.elements.length > 0),
|
|
38498
|
+
externalElements: graph.externalElements.filter((id) => retained.has(id))
|
|
38499
|
+
};
|
|
38500
|
+
}
|
|
38501
|
+
function discoverDeploymentEnvironments(result, scope) {
|
|
38502
|
+
const closure = tabClosure(result, scope.tab);
|
|
38503
|
+
const elementsById = new Map(result.elements.map((element) => [element.id, element]));
|
|
38504
|
+
const environmentIds = /* @__PURE__ */ new Set();
|
|
38505
|
+
const wireEnvironmentIds = /* @__PURE__ */ new Set();
|
|
38506
|
+
for (const element of result.elements) {
|
|
38507
|
+
if (!closure.has(element.id) || element.deployed !== true) {
|
|
38508
|
+
continue;
|
|
38509
|
+
}
|
|
38510
|
+
for (const targetId of [...element.attributes.runsOn ?? [], ...element.attributes.uses ?? []]) {
|
|
38511
|
+
const target = elementsById.get(targetId);
|
|
38512
|
+
if (target !== void 0 && target.context !== element.context) {
|
|
38513
|
+
environmentIds.add(target.context);
|
|
38514
|
+
}
|
|
38515
|
+
}
|
|
38516
|
+
}
|
|
38517
|
+
for (const edge of result.edges) {
|
|
38518
|
+
if (edge.projected === true || edge.sourceIdentity !== scope.tab) {
|
|
38519
|
+
continue;
|
|
38520
|
+
}
|
|
38521
|
+
for (const targetId of edge.attributes.uses ?? []) {
|
|
38522
|
+
const target = elementsById.get(targetId);
|
|
38523
|
+
if (target !== void 0 && target.context !== elementsById.get(edge.source)?.context) {
|
|
38524
|
+
wireEnvironmentIds.add(target.context);
|
|
38525
|
+
}
|
|
38526
|
+
}
|
|
38527
|
+
}
|
|
38528
|
+
for (const context of result.contexts) {
|
|
38529
|
+
const ownsConcreteDeployment = result.elements.some(
|
|
38530
|
+
(element) => element.context === context.id && elementHasType(element, "Deployment")
|
|
38531
|
+
);
|
|
38532
|
+
if (context.synthetic !== true && context.sourceIdentity === scope.tab && (context.type === "Environment" || ownsConcreteDeployment)) {
|
|
38533
|
+
environmentIds.add(context.id);
|
|
38534
|
+
}
|
|
38535
|
+
}
|
|
38536
|
+
if (environmentIds.size === 0) {
|
|
38537
|
+
for (const environment of wireEnvironmentIds) {
|
|
38538
|
+
environmentIds.add(environment);
|
|
38539
|
+
}
|
|
38540
|
+
}
|
|
38541
|
+
const contextsById = new Map(result.contexts.map((context) => [context.id, context]));
|
|
38542
|
+
const environmentNamesByContext = /* @__PURE__ */ new Map();
|
|
38543
|
+
for (const element of result.elements) {
|
|
38544
|
+
if (element.synthetic === true || element.parent !== void 0 || !elementHasType(element, "Environment")) {
|
|
38545
|
+
continue;
|
|
38546
|
+
}
|
|
38547
|
+
const name = element.attributes.name?.[0];
|
|
38548
|
+
if (name !== void 0) {
|
|
38549
|
+
environmentNamesByContext.set(element.context, name);
|
|
38550
|
+
}
|
|
38551
|
+
}
|
|
38552
|
+
return [...environmentIds].map((id) => {
|
|
38553
|
+
const name = environmentNamesByContext.get(id) ?? contextsById.get(id)?.attributes.name?.[0];
|
|
38554
|
+
return { id, ...name === void 0 ? {} : { name } };
|
|
38555
|
+
}).sort((left, right) => (left.name ?? left.id).localeCompare(right.name ?? right.id) || left.id.localeCompare(right.id));
|
|
38556
|
+
}
|
|
38557
|
+
function relationshipPatternsReturnedBy(query) {
|
|
38558
|
+
const returned = new Set(query.returns);
|
|
38559
|
+
return new Map(query.matches.flatMap((match) => {
|
|
38560
|
+
const relationship = match.pattern.relationship;
|
|
38561
|
+
return relationship?.alias !== void 0 && returned.has(relationship.alias) ? [[relationship.alias, relationship]] : [];
|
|
38562
|
+
}));
|
|
38563
|
+
}
|
|
38564
|
+
function hasAuthoritativeEdgeSelection(returned, selectedStructuralRelationships) {
|
|
38565
|
+
return [...returned].some(
|
|
38566
|
+
([alias, pattern]) => pattern.type === "REFERENCES" || pattern.type === void 0 && !selectedStructuralRelationships.has(alias)
|
|
38567
|
+
);
|
|
38326
38568
|
}
|
|
38327
38569
|
function addSelectedEdge(edges, next, identity, identities) {
|
|
38328
38570
|
const endpointKey = `${next.source}\0${next.target}`;
|
|
@@ -38347,16 +38589,27 @@ function contextualLinkedEdge(relationship) {
|
|
|
38347
38589
|
...originTarget === void 0 ? {} : { originTarget }
|
|
38348
38590
|
};
|
|
38349
38591
|
}
|
|
38350
|
-
function materializeGroupedView(graph) {
|
|
38592
|
+
function materializeGroupedView(graph, materializeDeploymentPlacements = true) {
|
|
38351
38593
|
const groupsByElement = /* @__PURE__ */ new Map();
|
|
38352
38594
|
for (const group of graph.groups) {
|
|
38353
38595
|
for (const element of group.elements) {
|
|
38354
38596
|
groupsByElement.set(element, [...groupsByElement.get(element) ?? [], group]);
|
|
38355
38597
|
}
|
|
38356
38598
|
}
|
|
38599
|
+
const placementMaterializationRequired = materializeDeploymentPlacements && [...groupsByElement].some(([elementId]) => {
|
|
38600
|
+
const element = graph.elements[elementId];
|
|
38601
|
+
return element?.deployed === true && (element.attributes.runsOn?.length ?? 0) > 1;
|
|
38602
|
+
});
|
|
38603
|
+
const clonedElementIds = new Set([...groupsByElement].flatMap(([elementId, memberships]) => {
|
|
38604
|
+
const element = graph.elements[elementId];
|
|
38605
|
+
return memberships.length > 1 || placementMaterializationRequired && element?.deployed === true ? [elementId] : [];
|
|
38606
|
+
}));
|
|
38607
|
+
if (clonedElementIds.size === 0) {
|
|
38608
|
+
return graph;
|
|
38609
|
+
}
|
|
38357
38610
|
const cloneIdsByElementAndGroup = /* @__PURE__ */ new Map();
|
|
38358
38611
|
for (const [elementId, memberships] of groupsByElement) {
|
|
38359
|
-
if (
|
|
38612
|
+
if (!clonedElementIds.has(elementId)) {
|
|
38360
38613
|
continue;
|
|
38361
38614
|
}
|
|
38362
38615
|
for (const group of memberships) {
|
|
@@ -38368,11 +38621,8 @@ function materializeGroupedView(graph) {
|
|
|
38368
38621
|
}
|
|
38369
38622
|
const elements = { ...graph.elements };
|
|
38370
38623
|
for (const [elementId, memberships] of groupsByElement) {
|
|
38371
|
-
if (memberships.length < 2) {
|
|
38372
|
-
continue;
|
|
38373
|
-
}
|
|
38374
38624
|
const element = graph.elements[elementId];
|
|
38375
|
-
if (element === void 0) {
|
|
38625
|
+
if (element === void 0 || !clonedElementIds.has(elementId)) {
|
|
38376
38626
|
continue;
|
|
38377
38627
|
}
|
|
38378
38628
|
for (const group of memberships) {
|
|
@@ -38393,15 +38643,15 @@ function materializeGroupedView(graph) {
|
|
|
38393
38643
|
}));
|
|
38394
38644
|
const edges = graph.edges.map((edge) => ({
|
|
38395
38645
|
...edge,
|
|
38396
|
-
source: cloneEndpoint(edge.source, edge.edge.
|
|
38397
|
-
target: cloneEndpoint(edge.target, edge.edge.
|
|
38646
|
+
source: cloneEndpoint(edge.source, edge.edge.sourcePlacement, cloneIdsByElementAndGroup),
|
|
38647
|
+
target: cloneEndpoint(edge.target, edge.edge.targetPlacement, cloneIdsByElementAndGroup)
|
|
38398
38648
|
}));
|
|
38399
38649
|
const referenced = /* @__PURE__ */ new Set([
|
|
38400
38650
|
...groups.flatMap((group) => group.elements),
|
|
38401
38651
|
...edges.flatMap((edge) => [edge.source, edge.target])
|
|
38402
38652
|
]);
|
|
38403
|
-
for (const
|
|
38404
|
-
if (
|
|
38653
|
+
for (const elementId of clonedElementIds) {
|
|
38654
|
+
if (!referenced.has(elementId)) {
|
|
38405
38655
|
delete elements[elementId];
|
|
38406
38656
|
}
|
|
38407
38657
|
}
|
|
@@ -38412,7 +38662,11 @@ function materializeGroupedView(graph) {
|
|
|
38412
38662
|
groups,
|
|
38413
38663
|
externalElements: graph.externalElements.flatMap((element) => {
|
|
38414
38664
|
const memberships = groupsByElement.get(element) ?? [];
|
|
38415
|
-
|
|
38665
|
+
const clones = memberships.flatMap((group) => {
|
|
38666
|
+
const clone = cloneIdsByElementAndGroup.get(groupedCloneKey(element, group.owner));
|
|
38667
|
+
return clone === void 0 ? [] : [clone];
|
|
38668
|
+
});
|
|
38669
|
+
return elements[element] === void 0 ? clones : [element, ...clones];
|
|
38416
38670
|
})
|
|
38417
38671
|
};
|
|
38418
38672
|
}
|
|
@@ -38425,6 +38679,338 @@ function groupedCloneKey(elementId, groupOwner) {
|
|
|
38425
38679
|
function groupedCloneId(elementId, groupOwner) {
|
|
38426
38680
|
return `${elementId}@@${groupOwner}`;
|
|
38427
38681
|
}
|
|
38682
|
+
function applyDeploymentEnvironmentScope(result, graph, scope) {
|
|
38683
|
+
const environments = discoverDeploymentEnvironments(result, scope);
|
|
38684
|
+
const environment = scope.environment ?? (environments.length === 1 ? environments[0]?.id : void 0);
|
|
38685
|
+
if (environment === void 0) {
|
|
38686
|
+
return emptyScopedGraph(graph);
|
|
38687
|
+
}
|
|
38688
|
+
if (!environments.some((candidate) => candidate.id === environment)) {
|
|
38689
|
+
return emptyScopedGraph(graph);
|
|
38690
|
+
}
|
|
38691
|
+
const elementsById = new Map(result.elements.map((element) => [element.id, element]));
|
|
38692
|
+
const sourceElements = tabClosure(result, scope.tab);
|
|
38693
|
+
const groups = graph.groups.filter((group) => elementEnvironment(group.owner, elementsById) === environment);
|
|
38694
|
+
const selectedIds = new Set(groups.flatMap((group) => [group.owner, ...group.elements]));
|
|
38695
|
+
const candidateEdges = graph.edges.filter((edge) => deploymentEdgeInEnvironment(edge, environment, elementsById));
|
|
38696
|
+
const edges = candidateEdges.filter((edge) => {
|
|
38697
|
+
const sourceAllowed = deploymentEndpointAllowed(edge.source, environment, elementsById);
|
|
38698
|
+
const targetAllowed = deploymentEndpointAllowed(edge.target, environment, elementsById);
|
|
38699
|
+
return sourceAllowed && targetAllowed;
|
|
38700
|
+
});
|
|
38701
|
+
for (const edge of edges) {
|
|
38702
|
+
selectedIds.add(edge.source);
|
|
38703
|
+
selectedIds.add(edge.target);
|
|
38704
|
+
}
|
|
38705
|
+
const elements = Object.fromEntries(Object.entries(graph.elements).filter(([id]) => selectedIds.has(id)));
|
|
38706
|
+
const externalElements = new Set(graph.externalElements.filter((id) => selectedIds.has(id)));
|
|
38707
|
+
for (const id of selectedIds) {
|
|
38708
|
+
const occurrenceEnvironment = deploymentOccurrenceEnvironment(id, elementsById);
|
|
38709
|
+
if (occurrenceEnvironment !== void 0 && occurrenceEnvironment !== environment && isLogicalDeploymentEndpoint(id, elementsById)) {
|
|
38710
|
+
externalElements.add(id);
|
|
38711
|
+
}
|
|
38712
|
+
if (isLogicalDeploymentEndpoint(id, elementsById) && !sourceElements.has(baseOccurrenceId(id))) {
|
|
38713
|
+
externalElements.add(id);
|
|
38714
|
+
}
|
|
38715
|
+
}
|
|
38716
|
+
return {
|
|
38717
|
+
...graph,
|
|
38718
|
+
elements,
|
|
38719
|
+
edges,
|
|
38720
|
+
groups: groups.map((group) => ({ ...group, elements: group.elements.filter((id) => selectedIds.has(id)) })),
|
|
38721
|
+
externalElements: [...externalElements]
|
|
38722
|
+
};
|
|
38723
|
+
}
|
|
38724
|
+
function emptyScopedGraph(graph) {
|
|
38725
|
+
return { ...graph, elements: {}, edges: [], groups: [], externalElements: [] };
|
|
38726
|
+
}
|
|
38727
|
+
function deploymentEdgeInEnvironment(edge, environment, elementsById) {
|
|
38728
|
+
const scopes = [edge.edge.projectionRoot, edge.edge.sourcePlacement, edge.edge.targetPlacement].filter((id) => id !== void 0);
|
|
38729
|
+
if (scopes.some((id) => elementEnvironment(id, elementsById) === environment)) {
|
|
38730
|
+
return true;
|
|
38731
|
+
}
|
|
38732
|
+
return [edge.source, edge.target].some((id) => elementEnvironment(id, elementsById) === environment);
|
|
38733
|
+
}
|
|
38734
|
+
function deploymentEndpointAllowed(id, environment, elementsById) {
|
|
38735
|
+
return isLogicalDeploymentEndpoint(id, elementsById) || elementEnvironment(id, elementsById) === environment;
|
|
38736
|
+
}
|
|
38737
|
+
function isLogicalDeploymentEndpoint(id, elementsById) {
|
|
38738
|
+
const element = elementsById.get(baseOccurrenceId(id));
|
|
38739
|
+
return element !== void 0 && !elementHasType(element, "InfrastructureComponent");
|
|
38740
|
+
}
|
|
38741
|
+
function deploymentOccurrenceEnvironment(id, elementsById) {
|
|
38742
|
+
const separator = id.indexOf("@@");
|
|
38743
|
+
if (separator >= 0) {
|
|
38744
|
+
return elementEnvironment(id.slice(separator + 2), elementsById);
|
|
38745
|
+
}
|
|
38746
|
+
const runsOn = elementsById.get(id)?.attributes.runsOn ?? [];
|
|
38747
|
+
return runsOn.length === 1 ? elementEnvironment(runsOn[0], elementsById) : void 0;
|
|
38748
|
+
}
|
|
38749
|
+
function elementEnvironment(id, elementsById) {
|
|
38750
|
+
return elementsById.get(baseOccurrenceId(id))?.context;
|
|
38751
|
+
}
|
|
38752
|
+
function baseOccurrenceId(id) {
|
|
38753
|
+
const separator = id.indexOf("@@");
|
|
38754
|
+
return separator < 0 ? id : id.slice(0, separator);
|
|
38755
|
+
}
|
|
38756
|
+
function rollUpDeploymentSystems(result, graph, scope) {
|
|
38757
|
+
const elementsById = new Map(result.elements.map((element) => [element.id, element]));
|
|
38758
|
+
const parentByChild = new Map(result.elements.flatMap(
|
|
38759
|
+
(element) => element.parent === void 0 ? [] : [[element.id, element.parent]]
|
|
38760
|
+
));
|
|
38761
|
+
const systemFor = (id) => lineage(baseOccurrenceId(id), parentByChild).find((candidate) => elementHasType(elementsById.get(candidate), "SystemElement"));
|
|
38762
|
+
const fold = (id) => {
|
|
38763
|
+
const system = systemFor(id);
|
|
38764
|
+
if (system === void 0) {
|
|
38765
|
+
return id;
|
|
38766
|
+
}
|
|
38767
|
+
const separator = id.indexOf("@@");
|
|
38768
|
+
return separator < 0 ? system : `${system}${id.slice(separator)}`;
|
|
38769
|
+
};
|
|
38770
|
+
const foldedElement = (id) => {
|
|
38771
|
+
const folded = fold(id);
|
|
38772
|
+
const base = elementsById.get(baseOccurrenceId(folded));
|
|
38773
|
+
if (base === void 0) {
|
|
38774
|
+
return graph.elements[id];
|
|
38775
|
+
}
|
|
38776
|
+
return folded === base.id ? base : { ...base, id: folded, attributes: { ...base.attributes, projectedFrom: [base.id] } };
|
|
38777
|
+
};
|
|
38778
|
+
const groups = graph.groups.map((group) => ({
|
|
38779
|
+
...group,
|
|
38780
|
+
elements: [...new Set(group.elements.map(fold))]
|
|
38781
|
+
})).filter((group) => group.elements.length > 0);
|
|
38782
|
+
const edges = [];
|
|
38783
|
+
for (const edge of graph.edges) {
|
|
38784
|
+
const originSource = edge.edge.originSource ?? edge.edge.source;
|
|
38785
|
+
const originTarget = edge.edge.originTarget ?? edge.edge.target;
|
|
38786
|
+
const originSourceSystem = systemFor(originSource);
|
|
38787
|
+
const originTargetSystem = systemFor(originTarget);
|
|
38788
|
+
if (originSource !== originTarget && originSourceSystem !== void 0 && originSourceSystem === originTargetSystem) {
|
|
38789
|
+
continue;
|
|
38790
|
+
}
|
|
38791
|
+
const next = { ...edge, source: fold(edge.source), target: fold(edge.target) };
|
|
38792
|
+
if (next.source !== next.target) {
|
|
38793
|
+
addFoldedViewEdge(edges, next);
|
|
38794
|
+
}
|
|
38795
|
+
}
|
|
38796
|
+
const referenced = /* @__PURE__ */ new Set([
|
|
38797
|
+
...groups.flatMap((group) => [group.owner, ...group.elements]),
|
|
38798
|
+
...edges.flatMap((edge) => [edge.source, edge.target])
|
|
38799
|
+
]);
|
|
38800
|
+
const elements = {};
|
|
38801
|
+
for (const id of referenced) {
|
|
38802
|
+
const direct = graph.elements[id];
|
|
38803
|
+
const element = direct ?? [...Object.keys(graph.elements)].filter((candidate) => fold(candidate) === id).map(foldedElement).find((candidate) => candidate !== void 0);
|
|
38804
|
+
if (element !== void 0) {
|
|
38805
|
+
elements[id] = element.id === id ? element : { ...element, id };
|
|
38806
|
+
}
|
|
38807
|
+
}
|
|
38808
|
+
const sourceElements = tabClosure(result, scope.tab);
|
|
38809
|
+
const externalElements = new Set(graph.externalElements.map(fold).filter((id) => referenced.has(id)));
|
|
38810
|
+
for (const id of referenced) {
|
|
38811
|
+
const system = systemFor(id);
|
|
38812
|
+
if (system !== void 0 && !sourceElements.has(system)) {
|
|
38813
|
+
externalElements.add(id);
|
|
38814
|
+
}
|
|
38815
|
+
}
|
|
38816
|
+
return {
|
|
38817
|
+
...graph,
|
|
38818
|
+
elements,
|
|
38819
|
+
edges,
|
|
38820
|
+
groups,
|
|
38821
|
+
externalElements: [...externalElements]
|
|
38822
|
+
};
|
|
38823
|
+
}
|
|
38824
|
+
function simplifyDeploymentSystemInfrastructure(result, graph) {
|
|
38825
|
+
const elementsById = new Map(result.elements.map((element) => [element.id, element]));
|
|
38826
|
+
const parentByChild = new Map(result.elements.flatMap(
|
|
38827
|
+
(element) => element.parent === void 0 ? [] : [[element.id, element.parent]]
|
|
38828
|
+
));
|
|
38829
|
+
const externalElements = new Set(graph.externalElements);
|
|
38830
|
+
const placementGroupOwners = new Set(graph.groups.map((group) => group.owner));
|
|
38831
|
+
const retained = new Set(Object.keys(graph.elements).filter((id) => {
|
|
38832
|
+
const element = elementsById.get(baseOccurrenceId(id)) ?? graph.elements[id];
|
|
38833
|
+
return !elementHasType(element, "InfrastructureComponent") || externalElements.has(id) && !placementGroupOwners.has(id);
|
|
38834
|
+
}));
|
|
38835
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
38836
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
38837
|
+
for (const edge of graph.edges) {
|
|
38838
|
+
const sourceEdges = outgoing.get(edge.source) ?? [];
|
|
38839
|
+
sourceEdges.push(edge);
|
|
38840
|
+
outgoing.set(edge.source, sourceEdges);
|
|
38841
|
+
const targetEdges = incoming.get(edge.target) ?? [];
|
|
38842
|
+
targetEdges.push(edge);
|
|
38843
|
+
incoming.set(edge.target, targetEdges);
|
|
38844
|
+
}
|
|
38845
|
+
const edges = [];
|
|
38846
|
+
const trace = (source, first) => {
|
|
38847
|
+
const visited = /* @__PURE__ */ new Set();
|
|
38848
|
+
const follow = (edge, carrier) => {
|
|
38849
|
+
const target = edge.target;
|
|
38850
|
+
const nextCarrier = logicalRelationshipCarrier(carrier, edge);
|
|
38851
|
+
if (target === source) {
|
|
38852
|
+
return;
|
|
38853
|
+
}
|
|
38854
|
+
if (retained.has(target)) {
|
|
38855
|
+
addFoldedViewEdge(edges, { ...nextCarrier, source, target });
|
|
38856
|
+
return;
|
|
38857
|
+
}
|
|
38858
|
+
if (visited.has(target)) {
|
|
38859
|
+
return;
|
|
38860
|
+
}
|
|
38861
|
+
visited.add(target);
|
|
38862
|
+
for (const next of outgoing.get(target) ?? []) {
|
|
38863
|
+
follow(next, nextCarrier);
|
|
38864
|
+
}
|
|
38865
|
+
};
|
|
38866
|
+
follow(first, first);
|
|
38867
|
+
};
|
|
38868
|
+
for (const source of retained) {
|
|
38869
|
+
for (const edge of outgoing.get(source) ?? []) {
|
|
38870
|
+
trace(source, edge);
|
|
38871
|
+
}
|
|
38872
|
+
}
|
|
38873
|
+
const systemFor = (id) => lineage(baseOccurrenceId(id), parentByChild).find((candidate) => elementHasType(elementsById.get(candidate), "SystemElement"));
|
|
38874
|
+
for (const source of Object.keys(graph.elements)) {
|
|
38875
|
+
if (retained.has(source) || (incoming.get(source)?.length ?? 0) > 0) {
|
|
38876
|
+
continue;
|
|
38877
|
+
}
|
|
38878
|
+
for (const edge of outgoing.get(source) ?? []) {
|
|
38879
|
+
const originSource = edge.edge.originSource ?? edge.edge.source;
|
|
38880
|
+
const system = systemFor(originSource);
|
|
38881
|
+
if (system === void 0) {
|
|
38882
|
+
continue;
|
|
38883
|
+
}
|
|
38884
|
+
const placement = edge.edge.sourcePlacement ?? edge.edge.targetPlacement ?? edge.edge.projectionScope;
|
|
38885
|
+
const occurrence = placement === void 0 ? system : `${system}@@${placement}`;
|
|
38886
|
+
const logicalSource = retained.has(occurrence) ? occurrence : retained.has(system) ? system : void 0;
|
|
38887
|
+
if (logicalSource !== void 0) {
|
|
38888
|
+
trace(logicalSource, edge);
|
|
38889
|
+
}
|
|
38890
|
+
}
|
|
38891
|
+
}
|
|
38892
|
+
const projectedByLogicalEdge = /* @__PURE__ */ new Map();
|
|
38893
|
+
for (const edge of graph.edges) {
|
|
38894
|
+
const originSource = edge.edge.originSource;
|
|
38895
|
+
const originTarget = edge.edge.originTarget;
|
|
38896
|
+
if (edge.projected !== true || originSource === void 0 || originTarget === void 0) {
|
|
38897
|
+
continue;
|
|
38898
|
+
}
|
|
38899
|
+
const projectionScope = edge.edge.projectionRoot ?? edge.edge.projectionScope ?? edge.edge.sourcePlacement ?? edge.edge.targetPlacement ?? "";
|
|
38900
|
+
const key = `${originSource}\0${originTarget}\0${projectionScope}`;
|
|
38901
|
+
const related = projectedByLogicalEdge.get(key) ?? [];
|
|
38902
|
+
related.push(edge);
|
|
38903
|
+
projectedByLogicalEdge.set(key, related);
|
|
38904
|
+
}
|
|
38905
|
+
for (const related of projectedByLogicalEdge.values()) {
|
|
38906
|
+
const first = related[0];
|
|
38907
|
+
const originSource = first.edge.originSource;
|
|
38908
|
+
const originTarget = first.edge.originTarget;
|
|
38909
|
+
const sourceSystem = systemFor(originSource);
|
|
38910
|
+
const targetSystem = systemFor(originTarget);
|
|
38911
|
+
if (sourceSystem === void 0 || targetSystem === void 0 || sourceSystem === targetSystem) {
|
|
38912
|
+
continue;
|
|
38913
|
+
}
|
|
38914
|
+
const projectionEnvironment = first.edge.projectionRoot === void 0 ? void 0 : elementEnvironment(first.edge.projectionRoot, elementsById);
|
|
38915
|
+
const occurrence = (system) => {
|
|
38916
|
+
const relatedCandidates = related.flatMap((edge) => [edge.source, edge.target]).filter((id) => retained.has(id) && systemFor(id) === system);
|
|
38917
|
+
const retainedCandidates = [...retained].filter((id) => systemFor(id) === system);
|
|
38918
|
+
const candidates = [.../* @__PURE__ */ new Set([...relatedCandidates, ...retainedCandidates])];
|
|
38919
|
+
if (projectionEnvironment !== void 0) {
|
|
38920
|
+
return candidates.find((id) => deploymentOccurrenceEnvironment(id, elementsById) === projectionEnvironment) ?? candidates.find((id) => id === system);
|
|
38921
|
+
}
|
|
38922
|
+
return candidates[0];
|
|
38923
|
+
};
|
|
38924
|
+
const source = occurrence(sourceSystem);
|
|
38925
|
+
const target = occurrence(targetSystem);
|
|
38926
|
+
const relatedSimplifiedEdges = edges.filter(
|
|
38927
|
+
(edge) => linkedEdgeHasProjectionOrigin(edge.edge, originSource, originTarget) && (edge.edge.projectionRoot ?? edge.edge.projectionScope ?? edge.edge.sourcePlacement ?? edge.edge.targetPlacement ?? "") === (first.edge.projectionRoot ?? first.edge.projectionScope ?? first.edge.sourcePlacement ?? first.edge.targetPlacement ?? "")
|
|
38928
|
+
);
|
|
38929
|
+
if (source === void 0 || target === void 0 || source === target || endpointsConnected(source, target, relatedSimplifiedEdges)) {
|
|
38930
|
+
continue;
|
|
38931
|
+
}
|
|
38932
|
+
for (const carrier of related.filter((edge) => (edge.edge.attributes.model?.length ?? 0) > 0)) {
|
|
38933
|
+
addFoldedViewEdge(edges, { ...carrier, source, target });
|
|
38934
|
+
}
|
|
38935
|
+
}
|
|
38936
|
+
const environmentRootByContext = new Map(result.elements.filter((element) => element.synthetic !== true && element.parent === void 0 && elementHasType(element, "Environment")).map((element) => [element.context, element.id]));
|
|
38937
|
+
const groupedEnvironmentsByElement = /* @__PURE__ */ new Map();
|
|
38938
|
+
for (const group of graph.groups) {
|
|
38939
|
+
const environment = elementEnvironment(group.owner, elementsById);
|
|
38940
|
+
if (environment === void 0 || !environmentRootByContext.has(environment)) {
|
|
38941
|
+
continue;
|
|
38942
|
+
}
|
|
38943
|
+
for (const id of group.elements) {
|
|
38944
|
+
if (!retained.has(id)) {
|
|
38945
|
+
continue;
|
|
38946
|
+
}
|
|
38947
|
+
const environments = groupedEnvironmentsByElement.get(id) ?? /* @__PURE__ */ new Set();
|
|
38948
|
+
environments.add(environment);
|
|
38949
|
+
groupedEnvironmentsByElement.set(id, environments);
|
|
38950
|
+
}
|
|
38951
|
+
}
|
|
38952
|
+
const groupMembersByEnvironment = /* @__PURE__ */ new Map();
|
|
38953
|
+
for (const id of retained) {
|
|
38954
|
+
const element = elementsById.get(baseOccurrenceId(id)) ?? graph.elements[id];
|
|
38955
|
+
const environments = new Set(groupedEnvironmentsByElement.get(id) ?? []);
|
|
38956
|
+
const occurrenceEnvironment = deploymentOccurrenceEnvironment(id, elementsById);
|
|
38957
|
+
if (occurrenceEnvironment !== void 0) {
|
|
38958
|
+
environments.add(occurrenceEnvironment);
|
|
38959
|
+
}
|
|
38960
|
+
if (environments.size === 0 && elementHasType(element, "InfrastructureComponent") && environmentRootByContext.has(element?.context ?? "")) {
|
|
38961
|
+
environments.add(element.context);
|
|
38962
|
+
}
|
|
38963
|
+
for (const environment of environments) {
|
|
38964
|
+
const members = groupMembersByEnvironment.get(environment) ?? [];
|
|
38965
|
+
members.push(id);
|
|
38966
|
+
groupMembersByEnvironment.set(environment, members);
|
|
38967
|
+
}
|
|
38968
|
+
}
|
|
38969
|
+
const groups = [...groupMembersByEnvironment].map(([environment, members]) => ({
|
|
38970
|
+
owner: environmentRootByContext.get(environment) ?? environment,
|
|
38971
|
+
elements: members
|
|
38972
|
+
}));
|
|
38973
|
+
return {
|
|
38974
|
+
...graph,
|
|
38975
|
+
elements: Object.fromEntries(Object.entries(graph.elements).filter(([id]) => retained.has(id))),
|
|
38976
|
+
edges,
|
|
38977
|
+
groups,
|
|
38978
|
+
externalElements: graph.externalElements.filter((id) => retained.has(id))
|
|
38979
|
+
};
|
|
38980
|
+
}
|
|
38981
|
+
function linkedEdgeHasProjectionOrigin(edge, source, target) {
|
|
38982
|
+
return edge.originSource === source && edge.originTarget === target || edge.projectionOrigins?.some((origin) => origin.source === source && origin.target === target) === true;
|
|
38983
|
+
}
|
|
38984
|
+
function endpointsConnected(source, target, edges) {
|
|
38985
|
+
const neighbors = /* @__PURE__ */ new Map();
|
|
38986
|
+
for (const edge of edges) {
|
|
38987
|
+
const sourceNeighbors = neighbors.get(edge.source) ?? /* @__PURE__ */ new Set();
|
|
38988
|
+
sourceNeighbors.add(edge.target);
|
|
38989
|
+
neighbors.set(edge.source, sourceNeighbors);
|
|
38990
|
+
const targetNeighbors = neighbors.get(edge.target) ?? /* @__PURE__ */ new Set();
|
|
38991
|
+
targetNeighbors.add(edge.source);
|
|
38992
|
+
neighbors.set(edge.target, targetNeighbors);
|
|
38993
|
+
}
|
|
38994
|
+
const pending = [source];
|
|
38995
|
+
const visited = /* @__PURE__ */ new Set();
|
|
38996
|
+
while (pending.length > 0) {
|
|
38997
|
+
const current = pending.pop();
|
|
38998
|
+
if (current === target) {
|
|
38999
|
+
return true;
|
|
39000
|
+
}
|
|
39001
|
+
if (visited.has(current)) {
|
|
39002
|
+
continue;
|
|
39003
|
+
}
|
|
39004
|
+
visited.add(current);
|
|
39005
|
+
pending.push(...neighbors.get(current) ?? []);
|
|
39006
|
+
}
|
|
39007
|
+
return false;
|
|
39008
|
+
}
|
|
39009
|
+
function logicalRelationshipCarrier(current, candidate) {
|
|
39010
|
+
const currentModel = current.edge.attributes.model;
|
|
39011
|
+
const candidateModel = candidate.edge.attributes.model;
|
|
39012
|
+
return (currentModel === void 0 || currentModel.length === 0) && candidateModel !== void 0 && candidateModel.length > 0 ? candidate : current;
|
|
39013
|
+
}
|
|
38428
39014
|
function internalElements(result, rows, query) {
|
|
38429
39015
|
const aliases = new Set(query.matches.flatMap(
|
|
38430
39016
|
(match) => match.optional ? [] : patternNodeAliases(match.pattern)
|
|
@@ -39323,6 +39909,9 @@ function edgePropertyValue(relationship, name) {
|
|
|
39323
39909
|
if (name === "context") {
|
|
39324
39910
|
return relationship.context;
|
|
39325
39911
|
}
|
|
39912
|
+
if (name === "projectionRoot") {
|
|
39913
|
+
return edge?.projectionRoot;
|
|
39914
|
+
}
|
|
39326
39915
|
const values = edge?.attributes[name];
|
|
39327
39916
|
if (edge?.listAttributes?.includes(name) === true) {
|
|
39328
39917
|
return values;
|
|
@@ -39364,11 +39953,16 @@ function collectGroupValue(groups, node, owner, label) {
|
|
|
39364
39953
|
elements: [...elements]
|
|
39365
39954
|
});
|
|
39366
39955
|
}
|
|
39367
|
-
function collectSelectedReferenceGroups(selectedElements, groups, expression) {
|
|
39956
|
+
function collectSelectedReferenceGroups(selectedElements, selectedEdges, groups, expression) {
|
|
39368
39957
|
const grouped = /* @__PURE__ */ new Set();
|
|
39369
39958
|
if (expression.kind !== "property") {
|
|
39370
39959
|
return grouped;
|
|
39371
39960
|
}
|
|
39961
|
+
for (const group of groups.values()) {
|
|
39962
|
+
for (const element of group.elements) {
|
|
39963
|
+
grouped.add(element);
|
|
39964
|
+
}
|
|
39965
|
+
}
|
|
39372
39966
|
for (const element of selectedElements.values()) {
|
|
39373
39967
|
if (element.referenceAttributes?.includes(expression.property) !== true) {
|
|
39374
39968
|
continue;
|
|
@@ -39376,13 +39970,29 @@ function collectSelectedReferenceGroups(selectedElements, groups, expression) {
|
|
|
39376
39970
|
const node = { kind: "element", id: element.id, element };
|
|
39377
39971
|
const value = propertyValue(node, expression.property);
|
|
39378
39972
|
const owners = Array.isArray(value) ? value : isQueryNode(value) ? [value.id] : [];
|
|
39379
|
-
|
|
39973
|
+
const selectedOwners = expression.property === "runsOn" && owners.length > 1 ? [] : owners;
|
|
39974
|
+
for (const owner of selectedOwners) {
|
|
39380
39975
|
collectGroupValue(groups, node, owner, void 0);
|
|
39381
39976
|
grouped.add(element.id);
|
|
39382
39977
|
}
|
|
39383
39978
|
}
|
|
39979
|
+
for (const edge of selectedEdges) {
|
|
39980
|
+
collectSelectedEdgePlacementGroup(selectedElements, groups, grouped, expression.property, edge.source, edge.edge.sourcePlacement);
|
|
39981
|
+
collectSelectedEdgePlacementGroup(selectedElements, groups, grouped, expression.property, edge.target, edge.edge.targetPlacement);
|
|
39982
|
+
}
|
|
39384
39983
|
return grouped;
|
|
39385
39984
|
}
|
|
39985
|
+
function collectSelectedEdgePlacementGroup(selectedElements, groups, grouped, propertyName, elementId, placement) {
|
|
39986
|
+
if (placement === void 0) {
|
|
39987
|
+
return;
|
|
39988
|
+
}
|
|
39989
|
+
const element = selectedElements.get(elementId);
|
|
39990
|
+
if (element?.referenceAttributes?.includes(propertyName) !== true || element.attributes[propertyName]?.includes(placement) !== true) {
|
|
39991
|
+
return;
|
|
39992
|
+
}
|
|
39993
|
+
collectGroupValue(groups, { kind: "element", id: element.id, element }, placement, void 0);
|
|
39994
|
+
grouped.add(element.id);
|
|
39995
|
+
}
|
|
39386
39996
|
function completeReferenceGroupClosure(result, groups, expression) {
|
|
39387
39997
|
if (expression.kind !== "property") {
|
|
39388
39998
|
return /* @__PURE__ */ new Set();
|
|
@@ -39800,11 +40410,13 @@ var BUILTIN_VIEW_QUERIES = {
|
|
|
39800
40410
|
"c2": "MATCH (container:ContainerElement)\nWHERE container.sourceIdentity = $tab\nOPTIONAL MATCH (container)-[containerLink:REFERENCES {withDerived}]-(related:Element)\nWHERE related IS ContainerElement OR related IS SystemElement\nMATCH (boundaryContainer:ContainerElement)\nWHERE boundaryContainer = container OR boundaryContainer = related\nGROUP BY boundaryContainer.parent\nRETURN boundaryContainer, containerLink, related",
|
|
39801
40411
|
"c3": "MATCH (container:ContainerElement)-[contains:CONTAINS]->(component:ComponentElement)\nWHERE container.sourceIdentity = $tab\nOPTIONAL MATCH (component)-[componentLink:REFERENCES {withDerived}]-(related:Element)\nWHERE related IS ComponentElement OR related IS ContainerElement OR related IS SystemElement\nGROUP BY component.parent\nRETURN component, componentLink, related",
|
|
39802
40412
|
"c4": "MATCH (code:CodeElement)\nWHERE code.sourceIdentity = $tab\nOPTIONAL MATCH (code)-[link:REFERENCES]-(related:Element)\nWHERE related IS CodeElement OR related IS ComponentElement OR related IS ContainerElement OR related IS SystemElement\nGROUP BY code.parent\nRETURN code, link, related",
|
|
39803
|
-
"deployment": "MATCH (node:Element)\nWHERE node.sourceIdentity = $tab\n AND (node IS InfrastructureComponent\n OR ((node IS ContainerElement OR node IS External) AND node.deployed = true))\nOPTIONAL MATCH (deploymentTarget:InfrastructureComponent)\nWHERE deploymentTarget IN node.uses OR deploymentTarget
|
|
40413
|
+
"deployment-system": "MATCH (node:Element)\nWHERE node.sourceIdentity = $tab\n AND (node IS InfrastructureComponent\n OR node IS SystemElement\n OR ((node IS ContainerElement OR node IS External) AND node.deployed = true))\n AND node.id = node.id\nOPTIONAL MATCH (deploymentTarget:InfrastructureComponent)\nWHERE deploymentTarget IN node.uses OR deploymentTarget IN node.runsOn\nOPTIONAL MATCH ROLLUP (node)-[projectedLink:REFERENCES {projected}]-(projectedPeer:Element)\nWHERE (projectedPeer IS InfrastructureComponent\n OR (projectedPeer IS ContainerElement AND projectedPeer.deployed = true)\n OR projectedPeer IS SystemElement\n OR projectedPeer IS External)\n AND projectedPeer.id <> node.id\nOPTIONAL MATCH (node)-[directDeploymentLink:REFERENCES]-(directDeploymentTarget:Element)\nWHERE node IS InfrastructureComponent\n AND (directDeploymentTarget IS InfrastructureComponent OR directDeploymentTarget IS External)\nGROUP BY node.runsOn\nRETURN node, deploymentTarget, projectedLink, projectedPeer, directDeploymentLink, directDeploymentTarget",
|
|
40414
|
+
"deployment-container": "MATCH (node:Element)\nWHERE node.sourceIdentity = $tab\n AND (node IS InfrastructureComponent\n OR node IS SystemElement\n OR ((node IS ContainerElement OR node IS External) AND node.deployed = true))\n AND node.context = node.context\nOPTIONAL MATCH (deploymentTarget:InfrastructureComponent)\nWHERE deploymentTarget IN node.uses OR deploymentTarget IN node.runsOn\nOPTIONAL MATCH ROLLUP (node)-[projectedLink:REFERENCES {projected}]-(projectedPeer:Element)\nWHERE (projectedPeer IS InfrastructureComponent\n OR (projectedPeer IS ContainerElement AND projectedPeer.deployed = true)\n OR projectedPeer IS SystemElement\n OR projectedPeer IS External)\n AND projectedPeer.id <> node.id\nOPTIONAL MATCH (node)-[directDeploymentLink:REFERENCES]-(directDeploymentTarget:Element)\nWHERE node IS InfrastructureComponent\n AND (directDeploymentTarget IS InfrastructureComponent OR directDeploymentTarget IS External)\nGROUP BY node.runsOn\nRETURN node, deploymentTarget, projectedLink, projectedPeer, directDeploymentLink, directDeploymentTarget",
|
|
40415
|
+
"deployment": "MATCH (node:Element)\nWHERE node.sourceIdentity = $tab\n AND (node IS InfrastructureComponent\n OR ((node IS ContainerElement OR node IS External) AND node.deployed = true))\nOPTIONAL MATCH (deploymentTarget:InfrastructureComponent)\nWHERE deploymentTarget IN node.uses OR deploymentTarget IN node.runsOn\nOPTIONAL MATCH ROLLUP (node)-[projectedLink:REFERENCES {projected}]-(projectedPeer:Element)\nWHERE (projectedPeer IS InfrastructureComponent\n OR (projectedPeer IS ContainerElement AND projectedPeer.deployed = true)\n OR projectedPeer IS External)\n AND projectedPeer.id <> node.id\nOPTIONAL MATCH (node)-[directDeploymentLink:REFERENCES]-(directDeploymentTarget:Element)\nWHERE node IS InfrastructureComponent\n AND (directDeploymentTarget IS InfrastructureComponent OR directDeploymentTarget IS External)\nGROUP BY node.runsOn\nRETURN node, deploymentTarget, projectedLink, projectedPeer, directDeploymentLink, directDeploymentTarget"
|
|
39804
40416
|
};
|
|
39805
40417
|
|
|
39806
40418
|
// src/version.ts
|
|
39807
|
-
var version = "3.0.
|
|
40419
|
+
var version = "3.0.3";
|
|
39808
40420
|
|
|
39809
40421
|
// src/index.ts
|
|
39810
40422
|
var hiddenStructureTypes = /* @__PURE__ */ new Set(["List", "Nothing", "Text"]);
|
|
@@ -39860,6 +40472,9 @@ async function main() {
|
|
|
39860
40472
|
case "structure":
|
|
39861
40473
|
await runStructure(args);
|
|
39862
40474
|
return;
|
|
40475
|
+
case "environments":
|
|
40476
|
+
await runEnvironments(args);
|
|
40477
|
+
return;
|
|
39863
40478
|
case "skill":
|
|
39864
40479
|
await runSkill(args);
|
|
39865
40480
|
return;
|
|
@@ -39945,8 +40560,38 @@ async function runStructure(args) {
|
|
|
39945
40560
|
}
|
|
39946
40561
|
await writeOutput(args.output, formatStructure(structure));
|
|
39947
40562
|
}
|
|
39948
|
-
async function
|
|
39949
|
-
|
|
40563
|
+
async function runEnvironments(args) {
|
|
40564
|
+
const project = await loadProject(projectPath(args));
|
|
40565
|
+
if (hasErrors(project.diagnostics)) {
|
|
40566
|
+
process.stderr.write(formatDiagnostics(project.diagnostics));
|
|
40567
|
+
process.exitCode = 1;
|
|
40568
|
+
return;
|
|
40569
|
+
}
|
|
40570
|
+
const source = args.tab === void 0 ? void 0 : selectedSource(project, args.tab, false, void 0);
|
|
40571
|
+
const declared = declaredDeploymentEnvironments(project.result);
|
|
40572
|
+
const declaredById = new Map(declared.map((environment) => [environment.id, environment]));
|
|
40573
|
+
const environments = source === void 0 ? declared : discoverDeploymentEnvironments(project.result, { tab: source }).map((environment) => {
|
|
40574
|
+
const declaration = declaredById.get(environment.id);
|
|
40575
|
+
if (declaration === void 0) {
|
|
40576
|
+
throw new CliError(`Environment '${environment.id}' is relevant to '${source}' but has no environment declaration`);
|
|
40577
|
+
}
|
|
40578
|
+
const name = environment.name ?? declaration.name;
|
|
40579
|
+
return {
|
|
40580
|
+
id: environment.id,
|
|
40581
|
+
...name === void 0 ? {} : { name },
|
|
40582
|
+
source: declaration.source
|
|
40583
|
+
};
|
|
40584
|
+
});
|
|
40585
|
+
const result = {
|
|
40586
|
+
schemaVersion: "deployment-environments.v1",
|
|
40587
|
+
source: source ?? null,
|
|
40588
|
+
environments
|
|
40589
|
+
};
|
|
40590
|
+
const format = outputFormat(args.format, "text");
|
|
40591
|
+
await writeOutput(args.output, format === "json" ? JSON.stringify(result, null, 2) : formatDeploymentEnvironments(result.environments));
|
|
40592
|
+
}
|
|
40593
|
+
async function runSkill(args) {
|
|
40594
|
+
if (args.skillAction !== "init") {
|
|
39950
40595
|
throw new CliError("Usage: archinsight skill init [project-dir] [--target generic|codex|claude] [--out dir] [--force]");
|
|
39951
40596
|
}
|
|
39952
40597
|
const target = skillTarget(args.target);
|
|
@@ -40046,13 +40691,70 @@ async function loadProject(input) {
|
|
|
40046
40691
|
};
|
|
40047
40692
|
}
|
|
40048
40693
|
async function selectedGraph(project, args) {
|
|
40049
|
-
const
|
|
40050
|
-
const tab = selectedSource(project, args.tab);
|
|
40051
|
-
const view = args.view ?? (args.queryFile === void 0 ? "c1" : void 0);
|
|
40052
|
-
const scope = { context, tab, ...view === void 0 ? {} : { view } };
|
|
40694
|
+
const view = args.queryFile === void 0 ? args.view ?? "c1" : void 0;
|
|
40053
40695
|
const query = args.queryFile === void 0 ? viewQueries[view ?? "c1"] : await readQueryFile(project.root, args.queryFile);
|
|
40696
|
+
const queryNeedsTab = queryUsesVariable(query, "tab");
|
|
40697
|
+
const queryNeedsContext = queryUsesVariable(query, "context");
|
|
40698
|
+
const sourceRequired = view !== void 0 && view !== "c1" && view !== "no-filter" || queryNeedsTab;
|
|
40699
|
+
const tab = selectedSource(project, args.tab, sourceRequired, view);
|
|
40700
|
+
const context = selectedContext(project, args.context, tab, view !== void 0 || queryNeedsContext, view);
|
|
40701
|
+
const environment = deploymentEnvironmentOption(project, args, tab, view);
|
|
40702
|
+
const scope = {
|
|
40703
|
+
...context === void 0 ? {} : { context },
|
|
40704
|
+
...tab === void 0 ? {} : { tab },
|
|
40705
|
+
...view === void 0 ? {} : { view },
|
|
40706
|
+
...environment === void 0 ? {} : { environment }
|
|
40707
|
+
};
|
|
40054
40708
|
return selectGraph(project.result, scope, query);
|
|
40055
40709
|
}
|
|
40710
|
+
function deploymentEnvironmentOption(project, args, tab, view) {
|
|
40711
|
+
if (view !== "deployment-container") {
|
|
40712
|
+
if (args.environment !== void 0) {
|
|
40713
|
+
throw new CliError("Option '--environment' is supported only by the 'deployment-container' view");
|
|
40714
|
+
}
|
|
40715
|
+
return void 0;
|
|
40716
|
+
}
|
|
40717
|
+
if (tab === void 0) {
|
|
40718
|
+
throw new CliError("View 'deployment-container' requires --source");
|
|
40719
|
+
}
|
|
40720
|
+
const environments = discoverDeploymentEnvironments(project.result, { tab });
|
|
40721
|
+
if (args.environment !== void 0) {
|
|
40722
|
+
if (!environments.some((candidate) => candidate.id === args.environment)) {
|
|
40723
|
+
throw new CliError(`Environment '${args.environment}' is not relevant to '${tab}'. Available environments: ${environmentList(environments)}`);
|
|
40724
|
+
}
|
|
40725
|
+
return args.environment;
|
|
40726
|
+
}
|
|
40727
|
+
if (environments.length === 1) {
|
|
40728
|
+
return environments[0].id;
|
|
40729
|
+
}
|
|
40730
|
+
if (environments.length === 0) {
|
|
40731
|
+
throw new CliError(`No deployment environments are relevant to '${tab}'`);
|
|
40732
|
+
}
|
|
40733
|
+
throw new CliError(`View 'deployment-container' requires --environment. Available environments: ${environmentList(environments)}`);
|
|
40734
|
+
}
|
|
40735
|
+
function environmentList(environments) {
|
|
40736
|
+
return environments.map(
|
|
40737
|
+
(environment) => environment.name === void 0 || environment.name === environment.id ? environment.id : `${environment.id} (${environment.name})`
|
|
40738
|
+
).join(", ") || "none";
|
|
40739
|
+
}
|
|
40740
|
+
function declaredDeploymentEnvironments(result) {
|
|
40741
|
+
return result.elements.filter((element) => element.synthetic !== true && element.parent === void 0 && (element.type === "Environment" || element.baseTypes.includes("Environment"))).map((element) => ({
|
|
40742
|
+
id: element.context,
|
|
40743
|
+
...element.attributes.name?.[0] === void 0 ? {} : { name: element.attributes.name[0] },
|
|
40744
|
+
source: element.sourceIdentity
|
|
40745
|
+
})).sort(
|
|
40746
|
+
(left, right) => (left.name ?? left.id).localeCompare(right.name ?? right.id) || left.id.localeCompare(right.id)
|
|
40747
|
+
);
|
|
40748
|
+
}
|
|
40749
|
+
function formatDeploymentEnvironments(environments) {
|
|
40750
|
+
if (environments.length === 0) {
|
|
40751
|
+
return "";
|
|
40752
|
+
}
|
|
40753
|
+
return `${environments.map(
|
|
40754
|
+
(environment) => `${environment.id} ${environment.name ?? ""} ${environment.source}`
|
|
40755
|
+
).join("\n")}
|
|
40756
|
+
`;
|
|
40757
|
+
}
|
|
40056
40758
|
async function readQueryFile(projectRoot, queryFile) {
|
|
40057
40759
|
const file = path.isAbsolute(queryFile) ? queryFile : path.resolve(projectRoot, queryFile);
|
|
40058
40760
|
return readFile(file, "utf8");
|
|
@@ -40060,19 +40762,16 @@ async function readQueryFile(projectRoot, queryFile) {
|
|
|
40060
40762
|
function projectPath(args) {
|
|
40061
40763
|
return args.input ?? ".";
|
|
40062
40764
|
}
|
|
40063
|
-
function
|
|
40064
|
-
|
|
40065
|
-
|
|
40066
|
-
throw new CliError("No context found; pass --context explicitly after fixing diagnostics");
|
|
40765
|
+
function selectedSource(project, source, required, view) {
|
|
40766
|
+
if (source === void 0 && project.sources.length === 1) {
|
|
40767
|
+
return project.sources[0].sourceName;
|
|
40067
40768
|
}
|
|
40068
|
-
return context;
|
|
40069
|
-
}
|
|
40070
|
-
function firstTab(project) {
|
|
40071
|
-
return project.sources[0]?.sourceName ?? "";
|
|
40072
|
-
}
|
|
40073
|
-
function selectedSource(project, source) {
|
|
40074
40769
|
if (source === void 0) {
|
|
40075
|
-
|
|
40770
|
+
if (required) {
|
|
40771
|
+
const subject = view === void 0 ? "This query" : `View '${view}'`;
|
|
40772
|
+
throw new CliError(`${subject} requires --source because it is scoped to a model file`);
|
|
40773
|
+
}
|
|
40774
|
+
return void 0;
|
|
40076
40775
|
}
|
|
40077
40776
|
const normalized = normalizeSourceName(project.root, source);
|
|
40078
40777
|
if (project.sources.some((item) => item.sourceName === normalized)) {
|
|
@@ -40080,6 +40779,41 @@ function selectedSource(project, source) {
|
|
|
40080
40779
|
}
|
|
40081
40780
|
throw new CliError(`Source '${source}' is not part of project '${project.root}'`);
|
|
40082
40781
|
}
|
|
40782
|
+
function selectedContext(project, explicitContext, source, required, view) {
|
|
40783
|
+
const sourceContext = source === void 0 ? void 0 : project.result.contexts.find((context) => context.sourceIdentity === source);
|
|
40784
|
+
if (sourceContext?.synthetic === true && required) {
|
|
40785
|
+
throw new CliError(`Source '${source}' contains definitions and does not declare a renderable context or environment`);
|
|
40786
|
+
}
|
|
40787
|
+
if (view === "c1" && sourceContext !== void 0 && sourceContext.type !== "Context") {
|
|
40788
|
+
throw new CliError(`Source '${source}' does not declare a logical context for the C1 view`);
|
|
40789
|
+
}
|
|
40790
|
+
const available = availableContextIds(project, view);
|
|
40791
|
+
if (explicitContext !== void 0 && !available.includes(explicitContext)) {
|
|
40792
|
+
throw new CliError(`Context '${explicitContext}' is not declared. Available contexts: ${available.join(", ") || "none"}`);
|
|
40793
|
+
}
|
|
40794
|
+
if (explicitContext !== void 0 && sourceContext?.synthetic !== true && sourceContext !== void 0 && sourceContext.id !== explicitContext) {
|
|
40795
|
+
throw new CliError(`Context '${explicitContext}' conflicts with source '${source}', which declares context '${sourceContext.id}'`);
|
|
40796
|
+
}
|
|
40797
|
+
if (explicitContext !== void 0) {
|
|
40798
|
+
return explicitContext;
|
|
40799
|
+
}
|
|
40800
|
+
if (sourceContext?.synthetic !== true && sourceContext !== void 0) {
|
|
40801
|
+
return sourceContext.id;
|
|
40802
|
+
}
|
|
40803
|
+
if (!required) {
|
|
40804
|
+
return void 0;
|
|
40805
|
+
}
|
|
40806
|
+
if (available.length === 1) {
|
|
40807
|
+
return available[0];
|
|
40808
|
+
}
|
|
40809
|
+
throw new CliError(`Cannot infer context. Pass --source or --context. Available contexts: ${available.join(", ") || "none"}`);
|
|
40810
|
+
}
|
|
40811
|
+
function availableContextIds(project, view) {
|
|
40812
|
+
return [...new Set(project.result.contexts.filter((context) => context.synthetic !== true && (view !== "c1" || context.type === "Context")).map((context) => context.id))].sort();
|
|
40813
|
+
}
|
|
40814
|
+
function queryUsesVariable(query, variable) {
|
|
40815
|
+
return new RegExp(`\\$${variable}\\b`).test(query);
|
|
40816
|
+
}
|
|
40083
40817
|
function normalizeSourceName(root, source) {
|
|
40084
40818
|
const value = path.isAbsolute(source) ? path.relative(root, source) : source;
|
|
40085
40819
|
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
@@ -40358,6 +41092,7 @@ function parseArgs(argv) {
|
|
|
40358
41092
|
context: stringOption(options.context),
|
|
40359
41093
|
tab: stringOption(options.tab),
|
|
40360
41094
|
view: viewOption(options.view),
|
|
41095
|
+
environment: stringOption(options.environment),
|
|
40361
41096
|
queryFile: stringOption(options.query),
|
|
40362
41097
|
output: stringOption(options.output),
|
|
40363
41098
|
format: stringOption(options.format),
|
|
@@ -40377,6 +41112,8 @@ function optionKey(arg) {
|
|
|
40377
41112
|
"-s": "tab",
|
|
40378
41113
|
"--view": "view",
|
|
40379
41114
|
"-v": "view",
|
|
41115
|
+
"--environment": "environment",
|
|
41116
|
+
"-e": "environment",
|
|
40380
41117
|
"--query": "query",
|
|
40381
41118
|
"-q": "query",
|
|
40382
41119
|
"--out": "output",
|
|
@@ -40389,7 +41126,7 @@ function optionKey(arg) {
|
|
|
40389
41126
|
}[arg];
|
|
40390
41127
|
}
|
|
40391
41128
|
function command(value) {
|
|
40392
|
-
if (value === "link" || value === "render" || value === "query" || value === "structure" || value === "skill") {
|
|
41129
|
+
if (value === "link" || value === "render" || value === "query" || value === "structure" || value === "environments" || value === "skill") {
|
|
40393
41130
|
return value;
|
|
40394
41131
|
}
|
|
40395
41132
|
if (value === void 0) {
|
|
@@ -40425,7 +41162,7 @@ function viewOption(value) {
|
|
|
40425
41162
|
if (value === void 0) {
|
|
40426
41163
|
return void 0;
|
|
40427
41164
|
}
|
|
40428
|
-
if (value === "c1" || value === "c2" || value === "c3" || value === "c4" || value === "deployment" || value === "no-filter") {
|
|
41165
|
+
if (value === "c1" || value === "c2" || value === "c3" || value === "c4" || value === "deployment" || value === "deployment-system" || value === "deployment-container" || value === "no-filter") {
|
|
40429
41166
|
return value;
|
|
40430
41167
|
}
|
|
40431
41168
|
throw new CliError(`Unknown view '${String(value)}'`);
|
|
@@ -40463,17 +41200,19 @@ function helpText() {
|
|
|
40463
41200
|
|
|
40464
41201
|
Usage:
|
|
40465
41202
|
archinsight link [project-dir] [--format text|json] [--out file]
|
|
40466
|
-
archinsight render [project-dir] -
|
|
40467
|
-
archinsight query [project-dir] -
|
|
41203
|
+
archinsight render [project-dir] [-s <source>] [-c <context>] [-v c1|c2|c3|c4|deployment-system|deployment-container|deployment|no-filter] [-e <environment>] [-q query.aiq] [-f dot|svg|json] [-o file]
|
|
41204
|
+
archinsight query [project-dir] [-s <source>] [-c <context>] [-v c1|c2|c3|c4|deployment-system|deployment-container|deployment|no-filter] [-e <environment>] [-q query.aiq] [-f text|json] [-o file]
|
|
40468
41205
|
archinsight structure [project-dir] [--format text|json] [--out file]
|
|
41206
|
+
archinsight environments [project-dir] [-s <source>] [--format text|json] [--out file]
|
|
40469
41207
|
archinsight skill init [project-dir] [--target generic|codex|claude] [--out dir] [--force]
|
|
40470
41208
|
|
|
40471
41209
|
Options:
|
|
40472
41210
|
project-dir Project directory to scan recursively, default: current directory.
|
|
40473
|
-
-
|
|
40474
|
-
-
|
|
41211
|
+
-s, --source <file> Selected model file. Supplies $tab and infers its context.
|
|
41212
|
+
-c, --context <id> Context for context-wide execution without --source; must match it when both are passed.
|
|
40475
41213
|
--tab <source> Backward-compatible alias for --source.
|
|
40476
|
-
-v, --view <name> Built-in view: c1, c2, c3, c4, deployment, no-filter.
|
|
41214
|
+
-v, --view <name> Built-in view: c1, c2, c3, c4, deployment-system, deployment-container, deployment, no-filter.
|
|
41215
|
+
-e, --environment <id> Environment scope for deployment-container; optional when exactly one is relevant.
|
|
40477
41216
|
-q, --query <file> Query file; overrides --view.
|
|
40478
41217
|
-f, --format <format> Output format.
|
|
40479
41218
|
-o, --out <file> Write output to file instead of stdout; for skill init, write the guide directory.
|
|
@@ -40483,6 +41222,16 @@ Options:
|
|
|
40483
41222
|
-V, --version Print version.
|
|
40484
41223
|
-h, --help Show help.
|
|
40485
41224
|
|
|
41225
|
+
Scope:
|
|
41226
|
+
C1 and no-filter accept either --source or --context. C2-C4 and Deployment
|
|
41227
|
+
views require --source unless project-dir is one .ai file. Source-scoped
|
|
41228
|
+
commands infer context from that file. D2 additionally requires --environment
|
|
41229
|
+
when more than one environment is relevant.
|
|
41230
|
+
|
|
41231
|
+
Environment discovery:
|
|
41232
|
+
environments lists every declared environment. With --source, it returns only
|
|
41233
|
+
the environments relevant to that source for the D2 view.
|
|
41234
|
+
|
|
40486
41235
|
Diagnostics text format is TSV:
|
|
40487
41236
|
level<TAB>code<TAB>source<TAB>line<TAB>column<TAB>message
|
|
40488
41237
|
`;
|
|
@@ -40622,10 +41371,12 @@ function sharedSkillFiles() {
|
|
|
40622
41371
|
path: "examples/c2-containers.ai",
|
|
40623
41372
|
content: genericC2ContainersExample()
|
|
40624
41373
|
},
|
|
41374
|
+
...genericC2FileSplitExampleFiles(),
|
|
40625
41375
|
{
|
|
40626
41376
|
path: "examples/c3-components.ai",
|
|
40627
41377
|
content: genericC3ComponentsExample()
|
|
40628
41378
|
},
|
|
41379
|
+
...genericC3FileSplitExampleFiles(),
|
|
40629
41380
|
...genericC4CodeExampleFiles(),
|
|
40630
41381
|
{
|
|
40631
41382
|
path: "examples/deployment-framework.ai",
|
|
@@ -40665,6 +41416,14 @@ function sharedSkillFiles() {
|
|
|
40665
41416
|
path: "examples/builtin-views/c4.aiq",
|
|
40666
41417
|
content: textFileContent(viewQueries.c4)
|
|
40667
41418
|
},
|
|
41419
|
+
{
|
|
41420
|
+
path: "examples/builtin-views/deployment-system.aiq",
|
|
41421
|
+
content: textFileContent(viewQueries["deployment-system"])
|
|
41422
|
+
},
|
|
41423
|
+
{
|
|
41424
|
+
path: "examples/builtin-views/deployment-container.aiq",
|
|
41425
|
+
content: textFileContent(viewQueries["deployment-container"])
|
|
41426
|
+
},
|
|
40668
41427
|
{
|
|
40669
41428
|
path: "examples/builtin-views/deployment.aiq",
|
|
40670
41429
|
content: textFileContent(viewQueries.deployment)
|
|
@@ -40677,6 +41436,14 @@ function sharedSkillFiles() {
|
|
|
40677
41436
|
path: "examples/queries/direct-service-dependencies.aiq",
|
|
40678
41437
|
content: genericDirectServiceDependenciesQuery()
|
|
40679
41438
|
},
|
|
41439
|
+
{
|
|
41440
|
+
path: "examples/queries/direct-authored-dependencies.aiq",
|
|
41441
|
+
content: genericDirectAuthoredDependenciesQuery()
|
|
41442
|
+
},
|
|
41443
|
+
{
|
|
41444
|
+
path: "examples/queries/async-topic-dependencies.aiq",
|
|
41445
|
+
content: genericAsyncTopicDependenciesQuery()
|
|
41446
|
+
},
|
|
40680
41447
|
{
|
|
40681
41448
|
path: "examples/queries/kafka-service-dependencies.aiq",
|
|
40682
41449
|
content: genericKafkaServiceDependenciesQuery()
|
|
@@ -40986,11 +41753,11 @@ archinsight link . --format text
|
|
|
40986
41753
|
archinsight structure . --format text
|
|
40987
41754
|
\`\`\`
|
|
40988
41755
|
|
|
40989
|
-
If rendering is needed, ask for the
|
|
40990
|
-
|
|
41756
|
+
If rendering is needed, ask for the source file when it is not obvious. The CLI
|
|
41757
|
+
infers the context declared by that source:
|
|
40991
41758
|
|
|
40992
41759
|
\`\`\`shell
|
|
40993
|
-
archinsight render . -
|
|
41760
|
+
archinsight render . -s <source.ai> -v c2 -f svg -o diagram.svg
|
|
40994
41761
|
\`\`\`
|
|
40995
41762
|
|
|
40996
41763
|
Report diagnostics by source, line, column, and message. Avoid rewriting large
|
|
@@ -41086,6 +41853,50 @@ Never update a generated skill by running plain \`skill init\` repeatedly or by
|
|
|
41086
41853
|
copying only the files that happen to be missing. Regenerate the entire package
|
|
41087
41854
|
with the installed CLI, then restart the agent session when its runtime discovers
|
|
41088
41855
|
skills only at startup.
|
|
41856
|
+
|
|
41857
|
+
## Query and Render Scope
|
|
41858
|
+
|
|
41859
|
+
Use the model source as the normal diagram entry point:
|
|
41860
|
+
|
|
41861
|
+
\`\`\`shell
|
|
41862
|
+
archinsight query . -s <source.ai> -v c2 --format json
|
|
41863
|
+
archinsight render . -s <source.ai> -v c2 -f svg -o diagram.svg
|
|
41864
|
+
\`\`\`
|
|
41865
|
+
|
|
41866
|
+
The selected source supplies \`$tab\` and determines \`$context\`. C2, C3, C4,
|
|
41867
|
+
D1 (\`deployment-system\`), D2 (\`deployment-container\`), and the legacy
|
|
41868
|
+
Deployment view require a source when a project contains several model files.
|
|
41869
|
+
When the command input is one \`.ai\` file, the CLI selects it automatically.
|
|
41870
|
+
|
|
41871
|
+
C1 opens the complete context boundary declared by the selected source. For a
|
|
41872
|
+
context-wide C1 or \`no-filter\` query without a source, pass
|
|
41873
|
+
\`--context <context-id>\` instead. If both \`--source\` and \`--context\` are
|
|
41874
|
+
present, they must resolve to the same context; the context does not override
|
|
41875
|
+
the source.
|
|
41876
|
+
|
|
41877
|
+
A custom query file overrides \`--view\`. Pass \`--source\` when it uses
|
|
41878
|
+
\`$tab\`; the same source also supplies \`$context\`. A query that uses only
|
|
41879
|
+
\`$context\` may use an explicit \`--context\` without a source.
|
|
41880
|
+
|
|
41881
|
+
D1 spans every environment relevant to the selected source and rejects
|
|
41882
|
+
\`--environment\`. D2 selects the only relevant environment automatically. If
|
|
41883
|
+
several are relevant, pass one of the ids reported by the CLI with
|
|
41884
|
+
\`--environment <id>\`.
|
|
41885
|
+
|
|
41886
|
+
Discover environments through the linked model instead of parsing Insight
|
|
41887
|
+
sources:
|
|
41888
|
+
|
|
41889
|
+
\`\`\`shell
|
|
41890
|
+
archinsight environments . --format json
|
|
41891
|
+
archinsight environments . -s <source.ai> --format json
|
|
41892
|
+
\`\`\`
|
|
41893
|
+
|
|
41894
|
+
The first command returns every declared environment. The source-scoped command
|
|
41895
|
+
returns exactly the environments relevant to that source's D2 view. Its JSON
|
|
41896
|
+
uses schema \`deployment-environments.v1\` and contains the selected \`source\`
|
|
41897
|
+
plus \`environments\` entries with \`id\`, optional \`name\`, and the source file
|
|
41898
|
+
that declares the environment. Use this command before choosing D2
|
|
41899
|
+
\`--environment\`; do not scan source text to reconstruct the list.
|
|
41089
41900
|
`;
|
|
41090
41901
|
}
|
|
41091
41902
|
function genericModelingReference() {
|
|
@@ -41240,12 +42051,11 @@ Deployment view. The wire must select an environment slot whose concrete value
|
|
|
41240
42051
|
has a projection.
|
|
41241
42052
|
|
|
41242
42053
|
A wire can use only a \`NetworkConnection\` descendant. The built-in \`Broker\`
|
|
41243
|
-
is an
|
|
41244
|
-
|
|
41245
|
-
|
|
41246
|
-
|
|
41247
|
-
|
|
41248
|
-
that path.
|
|
42054
|
+
is one, so an environment can expose a \`Broker\` slot directly and a wire can
|
|
42055
|
+
select it with \`uses\`. Derive product-specific types such as Kafka or RabbitMQ
|
|
42056
|
+
from \`Broker\`, then put the physical path projection on the concrete broker
|
|
42057
|
+
instance. Read the complete [Broker](deployment-projections.md#broker) example
|
|
42058
|
+
before modeling that path.
|
|
41249
42059
|
|
|
41250
42060
|
If the chosen style is pragmatic mixed C2, a broker-like node can be acceptable,
|
|
41251
42061
|
but document that the view mixes levels. If the producer or consumer is not
|
|
@@ -41613,7 +42423,7 @@ An explicit assignment on an instance replaces the constructor default.
|
|
|
41613
42423
|
### Object-valued attributes
|
|
41614
42424
|
|
|
41615
42425
|
A named object attribute supports a full named declaration, a full anonymous
|
|
41616
|
-
declaration, or a shortened declaration
|
|
42426
|
+
declaration, or a shortened declaration whose constructor can be inferred:
|
|
41617
42427
|
|
|
41618
42428
|
\`\`\`insight
|
|
41619
42429
|
config:
|
|
@@ -41628,8 +42438,10 @@ config:
|
|
|
41628
42438
|
|
|
41629
42439
|
Use a named id when another declaration must reference the nested object. The
|
|
41630
42440
|
\`_\` form creates an anonymous instance. The shortened form infers both its
|
|
41631
|
-
constructor and anonymous identity
|
|
41632
|
-
|
|
42441
|
+
constructor and anonymous identity. A constructor declared directly by the
|
|
42442
|
+
attribute type takes precedence over constructors inherited through descendant
|
|
42443
|
+
types. Without a direct constructor, more than one compatible descendant makes
|
|
42444
|
+
the shortened form ambiguous.
|
|
41633
42445
|
|
|
41634
42446
|
## Attributes
|
|
41635
42447
|
|
|
@@ -41694,7 +42506,7 @@ links:
|
|
|
41694
42506
|
technology = HTTPS, JSON
|
|
41695
42507
|
call = POST /checkout
|
|
41696
42508
|
description = Places an order
|
|
41697
|
-
~>
|
|
42509
|
+
~> order_service
|
|
41698
42510
|
technology = Kafka
|
|
41699
42511
|
via = orders.created
|
|
41700
42512
|
description = Consumes order events
|
|
@@ -42062,7 +42874,7 @@ is about boundaries and responsibilities, not implementation structure.
|
|
|
42062
42874
|
4. Add \`external system\` declarations for dependencies outside the boundary.
|
|
42063
42875
|
5. Add high-level links that explain business or capability flow.
|
|
42064
42876
|
6. Validate with \`archinsight link . --format text\`.
|
|
42065
|
-
7. Render with \`archinsight render . -
|
|
42877
|
+
7. Render with \`archinsight render . -s <c1-source.ai> -v c1 -f svg -o c1.svg\`.
|
|
42066
42878
|
|
|
42067
42879
|
## Boundary Choices
|
|
42068
42880
|
|
|
@@ -42247,13 +43059,60 @@ external system analytics_platform
|
|
|
42247
43059
|
\`\`\`shell
|
|
42248
43060
|
archinsight structure . --format text
|
|
42249
43061
|
archinsight link . --format text
|
|
42250
|
-
archinsight render . -
|
|
43062
|
+
archinsight render . -s c1-context.ai -v c1 -f svg -o commerce-c1.svg
|
|
42251
43063
|
\`\`\`
|
|
42252
43064
|
|
|
42253
43065
|
Use \`examples/c1-context.ai\` as a compact valid C1 model when syntax is
|
|
42254
43066
|
unclear.
|
|
42255
43067
|
`;
|
|
42256
43068
|
}
|
|
43069
|
+
function genericC2FileSplitExampleFiles() {
|
|
43070
|
+
return [
|
|
43071
|
+
{
|
|
43072
|
+
path: "examples/c2-file-split/context.ai",
|
|
43073
|
+
content: `context commerce
|
|
43074
|
+
name = Commerce Platform
|
|
43075
|
+
|
|
43076
|
+
external system payment_provider
|
|
43077
|
+
name = Payment Provider
|
|
43078
|
+
technology = HTTPS API
|
|
43079
|
+
|
|
43080
|
+
system storefront
|
|
43081
|
+
name = Storefront
|
|
43082
|
+
technology = Commerce system
|
|
43083
|
+
description = Lets shoppers browse products and place orders
|
|
43084
|
+
`
|
|
43085
|
+
},
|
|
43086
|
+
{
|
|
43087
|
+
path: "examples/c2-file-split/storefront.ai",
|
|
43088
|
+
content: `context commerce
|
|
43089
|
+
|
|
43090
|
+
import payment_provider from context commerce
|
|
43091
|
+
|
|
43092
|
+
extend system storefront
|
|
43093
|
+
container web_app
|
|
43094
|
+
name = Web app
|
|
43095
|
+
technology = SvelteKit, TypeScript
|
|
43096
|
+
description = Renders product pages and checkout screens
|
|
43097
|
+
links:
|
|
43098
|
+
-> checkout_api
|
|
43099
|
+
technology = HTTPS, JSON
|
|
43100
|
+
call = POST /checkout
|
|
43101
|
+
description = Starts checkout and shows order status
|
|
43102
|
+
|
|
43103
|
+
service checkout_api
|
|
43104
|
+
name = Checkout API
|
|
43105
|
+
technology = Kotlin, PostgreSQL
|
|
43106
|
+
description = Prices carts, creates orders, and coordinates payment
|
|
43107
|
+
links:
|
|
43108
|
+
-> payment_provider
|
|
43109
|
+
technology = HTTPS
|
|
43110
|
+
call = POST /payments/authorizations
|
|
43111
|
+
description = Requests payment authorization
|
|
43112
|
+
`
|
|
43113
|
+
}
|
|
43114
|
+
];
|
|
43115
|
+
}
|
|
42257
43116
|
function genericC2ContainersReference() {
|
|
42258
43117
|
return `# C2 Containers and Services
|
|
42259
43118
|
|
|
@@ -42301,58 +43160,32 @@ because one system needs that style.
|
|
|
42301
43160
|
1. Run \`archinsight structure . --format text\` to find the exact system id,
|
|
42302
43161
|
existing containers/services, and external declarations.
|
|
42303
43162
|
2. Create or edit a C2 file in the same \`context <id>\`.
|
|
42304
|
-
3. Import
|
|
43163
|
+
3. Import every referenced declaration owned by another source, including a
|
|
43164
|
+
declaration in another file of the same context.
|
|
42305
43165
|
4. Add \`container\` or \`service\` declarations for the system's logical runtime
|
|
42306
43166
|
units, choosing the word that best communicates each unit's role.
|
|
42307
43167
|
5. Add runtime links between containers/services and real external systems.
|
|
42308
43168
|
6. Validate with \`archinsight link . --format text\`.
|
|
42309
|
-
7. Render with \`archinsight render . -
|
|
43169
|
+
7. Render with \`archinsight render . -s <c2-file.ai> -v c2 -f svg -o c2.svg\`.
|
|
42310
43170
|
|
|
42311
43171
|
## File Split Pattern
|
|
42312
43172
|
|
|
42313
43173
|
Keep C1 focused on the system boundary:
|
|
42314
43174
|
|
|
42315
43175
|
\`\`\`insight
|
|
42316
|
-
|
|
42317
|
-
name = Commerce Platform
|
|
42318
|
-
|
|
42319
|
-
external system payment_provider
|
|
42320
|
-
name = Payment Provider
|
|
42321
|
-
technology = HTTPS API
|
|
42322
|
-
|
|
42323
|
-
system storefront
|
|
42324
|
-
name = Storefront
|
|
42325
|
-
technology = Commerce system
|
|
42326
|
-
description = Lets shoppers browse products and place orders
|
|
43176
|
+
${genericC2FileSplitExampleFiles()[0].content.trimEnd()}
|
|
42327
43177
|
\`\`\`
|
|
42328
43178
|
|
|
42329
43179
|
Put C2 details in a system file:
|
|
42330
43180
|
|
|
42331
43181
|
\`\`\`insight
|
|
42332
|
-
|
|
42333
|
-
|
|
42334
|
-
extend system storefront
|
|
42335
|
-
container web_app
|
|
42336
|
-
name = Web app
|
|
42337
|
-
technology = SvelteKit, TypeScript
|
|
42338
|
-
description = Renders product pages and checkout screens
|
|
42339
|
-
links:
|
|
42340
|
-
-> checkout_api
|
|
42341
|
-
technology = HTTPS, JSON
|
|
42342
|
-
call = POST /checkout
|
|
42343
|
-
description = Starts checkout and shows order status
|
|
42344
|
-
|
|
42345
|
-
service checkout_api
|
|
42346
|
-
name = Checkout API
|
|
42347
|
-
technology = Kotlin, PostgreSQL
|
|
42348
|
-
description = Prices carts, creates orders, and coordinates payment
|
|
42349
|
-
links:
|
|
42350
|
-
-> payment_provider
|
|
42351
|
-
technology = HTTPS
|
|
42352
|
-
call = POST /payments/authorizations
|
|
42353
|
-
description = Requests payment authorization
|
|
43182
|
+
${genericC2FileSplitExampleFiles()[1].content.trimEnd()}
|
|
42354
43183
|
\`\`\`
|
|
42355
43184
|
|
|
43185
|
+
The extension target is resolved in the shared context and does not need an
|
|
43186
|
+
import. The ordinary reference to \`payment_provider\` crosses a source boundary,
|
|
43187
|
+
so the C2 file imports it even though both files use \`context commerce\`.
|
|
43188
|
+
|
|
42356
43189
|
## Frontend and Backend Pattern
|
|
42357
43190
|
|
|
42358
43191
|
Use \`container\` when "application" or "executable unit" best communicates the
|
|
@@ -42499,55 +43332,18 @@ not compete with a broad duplicate.
|
|
|
42499
43332
|
\`\`\`shell
|
|
42500
43333
|
archinsight structure . --format text
|
|
42501
43334
|
archinsight link . --format text
|
|
42502
|
-
archinsight render . -
|
|
43335
|
+
archinsight render . -s storefront-containers.ai -v c2 -f svg -o storefront-c2.svg
|
|
42503
43336
|
\`\`\`
|
|
42504
43337
|
|
|
42505
43338
|
Use \`examples/c2-containers.ai\` as a compact valid C2 model when syntax is
|
|
42506
43339
|
unclear.
|
|
42507
43340
|
`;
|
|
42508
43341
|
}
|
|
42509
|
-
function
|
|
42510
|
-
return
|
|
42511
|
-
|
|
42512
|
-
|
|
42513
|
-
|
|
42514
|
-
|
|
42515
|
-
## What C3 Answers
|
|
42516
|
-
|
|
42517
|
-
A C3 view answers: "Inside this container/service, what named responsibilities
|
|
42518
|
-
collaborate to deliver its behavior?"
|
|
42519
|
-
|
|
42520
|
-
Prefer one focal container or service per C3 source file. The built-in C3 view
|
|
42521
|
-
is scoped by the selected source file, so the C3 file should usually contain an
|
|
42522
|
-
\`extend container <id>\` or \`extend service <id>\` block for the focal element.
|
|
42523
|
-
|
|
42524
|
-
If the selected source opens several containers or services, components inside
|
|
42525
|
-
all of them are internal to one diagram. A dependency leaving that set is
|
|
42526
|
-
folded to the nearest closed container or service and shown as external to the
|
|
42527
|
-
C3 view.
|
|
42528
|
-
|
|
42529
|
-
Do not model every class, function, method, or package. A component should be a
|
|
42530
|
-
stable architectural responsibility that is useful in a diagram and review.
|
|
42531
|
-
|
|
42532
|
-
## C3 Workflow
|
|
42533
|
-
|
|
42534
|
-
1. Run \`archinsight structure . --format text\` to find the exact container or
|
|
42535
|
-
service id, available constructors, and existing imports.
|
|
42536
|
-
2. Create or edit a C3 file in the same \`context <id>\`.
|
|
42537
|
-
3. Import elements from other contexts only when the component links to them.
|
|
42538
|
-
4. Use \`extend container <id>\` or \`extend service <id>\`.
|
|
42539
|
-
5. Add \`component\` declarations with \`name\`, \`technology\`, and
|
|
42540
|
-
\`responsibility\`.
|
|
42541
|
-
6. Add links between components and to real external endpoints.
|
|
42542
|
-
7. Validate with \`archinsight link . --format text\`.
|
|
42543
|
-
8. Render with \`archinsight render . -c <context-id> -s <c3-file.ai> -v c3 -f svg -o c3.svg\`.
|
|
42544
|
-
|
|
42545
|
-
## File Split Pattern
|
|
42546
|
-
|
|
42547
|
-
Keep the C2 declaration small:
|
|
42548
|
-
|
|
42549
|
-
\`\`\`insight
|
|
42550
|
-
context commerce
|
|
43342
|
+
function genericC3FileSplitExampleFiles() {
|
|
43343
|
+
return [
|
|
43344
|
+
{
|
|
43345
|
+
path: "examples/c3-file-split/system.ai",
|
|
43346
|
+
content: `context commerce
|
|
42551
43347
|
name = Commerce Platform
|
|
42552
43348
|
|
|
42553
43349
|
external system payment_provider
|
|
@@ -42557,16 +43353,21 @@ external system payment_provider
|
|
|
42557
43353
|
system storefront
|
|
42558
43354
|
name = Storefront
|
|
42559
43355
|
|
|
43356
|
+
container web_app
|
|
43357
|
+
name = Web app
|
|
43358
|
+
technology = SvelteKit, TypeScript
|
|
43359
|
+
|
|
42560
43360
|
service checkout_api
|
|
42561
43361
|
name = Checkout API
|
|
42562
43362
|
technology = Kotlin, PostgreSQL
|
|
42563
43363
|
description = Handles cart pricing, order placement, and payment orchestration
|
|
42564
|
-
|
|
43364
|
+
`
|
|
43365
|
+
},
|
|
43366
|
+
{
|
|
43367
|
+
path: "examples/c3-file-split/checkout-components.ai",
|
|
43368
|
+
content: `context commerce
|
|
42565
43369
|
|
|
42566
|
-
|
|
42567
|
-
|
|
42568
|
-
\`\`\`insight
|
|
42569
|
-
context commerce
|
|
43370
|
+
import payment_provider from context commerce
|
|
42570
43371
|
|
|
42571
43372
|
extend service checkout_api
|
|
42572
43373
|
component checkout_controller
|
|
@@ -42598,15 +43399,13 @@ extend service checkout_api
|
|
|
42598
43399
|
name = Order repository
|
|
42599
43400
|
technology = SQL
|
|
42600
43401
|
responsibility = Persists order state and checkout audit records
|
|
42601
|
-
|
|
42602
|
-
|
|
42603
|
-
|
|
42604
|
-
|
|
42605
|
-
|
|
42606
|
-
architectural parts:
|
|
43402
|
+
`
|
|
43403
|
+
},
|
|
43404
|
+
{
|
|
43405
|
+
path: "examples/c3-file-split/web-components.ai",
|
|
43406
|
+
content: `context commerce
|
|
42607
43407
|
|
|
42608
|
-
|
|
42609
|
-
context commerce
|
|
43408
|
+
import checkout_api from context commerce
|
|
42610
43409
|
|
|
42611
43410
|
extend container web_app
|
|
42612
43411
|
component route_shell
|
|
@@ -42637,8 +43436,77 @@ extend container web_app
|
|
|
42637
43436
|
-> checkout_api
|
|
42638
43437
|
technology = HTTPS, JSON
|
|
42639
43438
|
call = POST /checkout
|
|
43439
|
+
`
|
|
43440
|
+
}
|
|
43441
|
+
];
|
|
43442
|
+
}
|
|
43443
|
+
function genericC3ComponentsReference() {
|
|
43444
|
+
return `# C3 Components
|
|
43445
|
+
|
|
43446
|
+
Use this reference only for C3 work: decomposing one selected container or
|
|
43447
|
+
service into internal components and their collaborations.
|
|
43448
|
+
|
|
43449
|
+
## What C3 Answers
|
|
43450
|
+
|
|
43451
|
+
A C3 view answers: "Inside this container/service, what named responsibilities
|
|
43452
|
+
collaborate to deliver its behavior?"
|
|
43453
|
+
|
|
43454
|
+
Prefer one focal container or service per C3 source file. The built-in C3 view
|
|
43455
|
+
is scoped by the selected source file, so the C3 file should usually contain an
|
|
43456
|
+
\`extend container <id>\` or \`extend service <id>\` block for the focal element.
|
|
43457
|
+
|
|
43458
|
+
If the selected source opens several containers or services, components inside
|
|
43459
|
+
all of them are internal to one diagram. A dependency leaving that set is
|
|
43460
|
+
folded to the nearest closed container or service and shown as external to the
|
|
43461
|
+
C3 view.
|
|
43462
|
+
|
|
43463
|
+
Do not model every class, function, method, or package. A component should be a
|
|
43464
|
+
stable architectural responsibility that is useful in a diagram and review.
|
|
43465
|
+
|
|
43466
|
+
## C3 Workflow
|
|
43467
|
+
|
|
43468
|
+
1. Run \`archinsight structure . --format text\` to find the exact container or
|
|
43469
|
+
service id, available constructors, and existing imports.
|
|
43470
|
+
2. Create or edit a C3 file in the same \`context <id>\`.
|
|
43471
|
+
3. Import every referenced declaration owned by another source, including a
|
|
43472
|
+
declaration in another file of the same context.
|
|
43473
|
+
4. Use \`extend container <id>\` or \`extend service <id>\`.
|
|
43474
|
+
5. Add \`component\` declarations with \`name\`, \`technology\`, and
|
|
43475
|
+
\`responsibility\`.
|
|
43476
|
+
6. Add links between components and to real external endpoints.
|
|
43477
|
+
7. Validate with \`archinsight link . --format text\`.
|
|
43478
|
+
8. Render with \`archinsight render . -s <c3-file.ai> -v c3 -f svg -o c3.svg\`.
|
|
43479
|
+
|
|
43480
|
+
## File Split Pattern
|
|
43481
|
+
|
|
43482
|
+
Keep the C2 declaration small:
|
|
43483
|
+
|
|
43484
|
+
\`\`\`insight
|
|
43485
|
+
${genericC3FileSplitExampleFiles()[0].content.trimEnd()}
|
|
43486
|
+
\`\`\`
|
|
43487
|
+
|
|
43488
|
+
Put component details in a C3 file:
|
|
43489
|
+
|
|
43490
|
+
\`\`\`insight
|
|
43491
|
+
${genericC3FileSplitExampleFiles()[1].content.trimEnd()}
|
|
42640
43492
|
\`\`\`
|
|
42641
43493
|
|
|
43494
|
+
The extension target is resolved in the shared context without an import.
|
|
43495
|
+
\`payment_provider\` is an ordinary cross-source reference and therefore has an
|
|
43496
|
+
explicit same-context import.
|
|
43497
|
+
|
|
43498
|
+
## Frontend Container Pattern
|
|
43499
|
+
|
|
43500
|
+
Use C3 for UI responsibilities when the frontend container has distinct
|
|
43501
|
+
architectural parts:
|
|
43502
|
+
|
|
43503
|
+
\`\`\`insight
|
|
43504
|
+
${genericC3FileSplitExampleFiles()[2].content.trimEnd()}
|
|
43505
|
+
\`\`\`
|
|
43506
|
+
|
|
43507
|
+
Here \`checkout_api\` is declared in the system file, so the frontend component
|
|
43508
|
+
file imports it before creating the cross-container link.
|
|
43509
|
+
|
|
42642
43510
|
This is useful when frontend structure affects architecture. If the frontend is
|
|
42643
43511
|
only a thin page with no meaningful internal decisions, leave it at C2.
|
|
42644
43512
|
|
|
@@ -42804,7 +43672,7 @@ declaration. Keep a broader wire only when it describes a different interaction.
|
|
|
42804
43672
|
\`\`\`shell
|
|
42805
43673
|
archinsight structure . --format text
|
|
42806
43674
|
archinsight link . --format text
|
|
42807
|
-
archinsight render . -
|
|
43675
|
+
archinsight render . -s checkout_components.ai -v c3 -f svg -o checkout-c3.svg
|
|
42808
43676
|
\`\`\`
|
|
42809
43677
|
|
|
42810
43678
|
Use \`examples/c3-components.ai\` as a compact valid C3 model when syntax is
|
|
@@ -42906,13 +43774,13 @@ different type filter or grouping rule.
|
|
|
42906
43774
|
|
|
42907
43775
|
\`\`\`shell
|
|
42908
43776
|
archinsight link . --format text
|
|
42909
|
-
archinsight query . -
|
|
42910
|
-
archinsight render . -
|
|
43777
|
+
archinsight query . -s <code-source.ai> -v c4 --format json
|
|
43778
|
+
archinsight render . -s <code-source.ai> -v c4 -f svg -o code.svg
|
|
42911
43779
|
\`\`\`
|
|
42912
43780
|
|
|
42913
43781
|
Use the self-contained \`examples/c4-code\` project when the syntax for a code
|
|
42914
|
-
framework or model is unclear. Deployment is a separate view selected
|
|
42915
|
-
\`--view deployment\`; never use C4 as an alias for Deployment.
|
|
43782
|
+
framework or model is unclear. Deployment is a separate view family selected
|
|
43783
|
+
with \`--view deployment-system\` or \`--view deployment-container\`; never use C4 as an alias for Deployment.
|
|
42916
43784
|
`;
|
|
42917
43785
|
}
|
|
42918
43786
|
function genericDeploymentReference() {
|
|
@@ -42923,10 +43791,34 @@ logical elements run, which infrastructure they use, and how their wires pass
|
|
|
42923
43791
|
through the physical world. Keep C1-C4 logical; deployment inventory and
|
|
42924
43792
|
projections supply the physical view.
|
|
42925
43793
|
|
|
42926
|
-
The built-in Deployment
|
|
42927
|
-
resolves at least one \`runsOn\` or \`uses\` infrastructure object.
|
|
42928
|
-
|
|
42929
|
-
|
|
43794
|
+
The built-in Deployment views include a placed logical element when its deployment
|
|
43795
|
+
resolves at least one \`runsOn\` or \`uses\` infrastructure object. An unplaced
|
|
43796
|
+
system or actor can remain visible as an endpoint of a projected wire; wire
|
|
43797
|
+
infrastructure supplies the relevant environments when the selected source has
|
|
43798
|
+
no placements of its own. A logical wire appears only through physical edges
|
|
43799
|
+
created by its deployment projection. A plain logical wire is intentionally
|
|
43800
|
+
omitted from Deployment.
|
|
43801
|
+
|
|
43802
|
+
Use \`deployment-system\` (D1) for a system-level overview across the environments
|
|
43803
|
+
relevant to the selected source. It folds deployed containers and services into
|
|
43804
|
+
their owning systems, contracts internal infrastructure paths, and retains the
|
|
43805
|
+
external integrations reached in each environment. Use \`deployment-container\`
|
|
43806
|
+
(D2) to inspect containers, services, and physical infrastructure in one
|
|
43807
|
+
environment. Pass \`--environment <id>\` when several environments are relevant;
|
|
43808
|
+
the CLI selects the environment automatically when there is only one. The older
|
|
43809
|
+
\`deployment\` view keeps the complete all-environment container graph for
|
|
43810
|
+
backward compatibility.
|
|
43811
|
+
|
|
43812
|
+
Obtain the available D2 choices from the linked model:
|
|
43813
|
+
|
|
43814
|
+
\`\`\`shell
|
|
43815
|
+
archinsight environments . -s <logical-source.ai> --format json
|
|
43816
|
+
\`\`\`
|
|
43817
|
+
|
|
43818
|
+
Read the ids from \`environments\` and pass the selected id to
|
|
43819
|
+
\`deployment-container --environment <id>\`. Run the command without
|
|
43820
|
+
\`--source\` only when the task needs the complete environment inventory rather
|
|
43821
|
+
than the choices relevant to one logical source.
|
|
42930
43822
|
|
|
42931
43823
|
Model the infrastructure immediately relevant to those logical elements and
|
|
42932
43824
|
connections. Do not expand a Deployment view into a complete provider, transit, replication,
|
|
@@ -42970,6 +43862,13 @@ The built-in Deployment view renders concrete \`InfrastructureComponent\`
|
|
|
42970
43862
|
instances. A \`Deployment\` object organizes the inventory and is not itself a
|
|
42971
43863
|
physical node, so projected relationships do not roll up to that owner.
|
|
42972
43864
|
|
|
43865
|
+
When one logical element resolves to several concrete compute placements,
|
|
43866
|
+
Deployment query output creates one visible occurrence per selected placement.
|
|
43867
|
+
Occurrence ids use \`<logical-id>@@<compute-id>\`, and their \`projectedFrom\`
|
|
43868
|
+
attribute retains the logical id. Projected edges connect the matching source
|
|
43869
|
+
and target occurrences. A graph whose logical elements all have one placement
|
|
43870
|
+
keeps their ordinary ids.
|
|
43871
|
+
|
|
42973
43872
|
## Framework and inventory
|
|
42974
43873
|
|
|
42975
43874
|
Define the available slots on an environment type:
|
|
@@ -43121,10 +44020,11 @@ service frontend
|
|
|
43121
44020
|
\`\`\`
|
|
43122
44021
|
|
|
43123
44022
|
Do not attach \`DeploymentProfile\`, \`runsOn\`, \`Storage\`, \`Compute\`, or another
|
|
43124
|
-
non-network infrastructure type to a wire.
|
|
43125
|
-
|
|
43126
|
-
\`
|
|
43127
|
-
|
|
44023
|
+
non-network infrastructure type to a wire. Ingress, egress, service-mesh, and
|
|
44024
|
+
VPN path types used by wires must inherit \`NetworkConnection\`. The built-in
|
|
44025
|
+
\`Broker\` already does; derive product-specific broker types from \`Broker\` and
|
|
44026
|
+
place their projection on the concrete instance. Read
|
|
44027
|
+
\`references/deployment-projections.md\` before defining the physical path.
|
|
43128
44028
|
|
|
43129
44029
|
For each relevant concrete deployment, the linker checks the requested slot:
|
|
43130
44030
|
|
|
@@ -43179,8 +44079,9 @@ Run:
|
|
|
43179
44079
|
|
|
43180
44080
|
\`\`\`shell
|
|
43181
44081
|
archinsight link . --format text
|
|
43182
|
-
archinsight query . -
|
|
43183
|
-
archinsight
|
|
44082
|
+
archinsight query . -s <logical-source.ai> -v deployment-system --format json
|
|
44083
|
+
archinsight query . -s <logical-source.ai> -v deployment-container --environment <environment> --format json
|
|
44084
|
+
archinsight render . -s <logical-source.ai> -v deployment-container --environment <environment> -f svg -o deployment.svg
|
|
43184
44085
|
\`\`\`
|
|
43185
44086
|
|
|
43186
44087
|
A clean link proves that syntax, types, imports, and deployment references are
|
|
@@ -43242,14 +44143,13 @@ define type PublicGateway of NetworkConnection
|
|
|
43242
44143
|
required InfrastructureComponent cdn
|
|
43243
44144
|
required InfrastructureComponent loadBalancer
|
|
43244
44145
|
|
|
43245
|
-
define type
|
|
43246
|
-
constructor
|
|
43247
|
-
required Broker transport
|
|
44146
|
+
define type KafkaBroker of Broker
|
|
44147
|
+
constructor kafka
|
|
43248
44148
|
|
|
43249
44149
|
extend type Environment
|
|
43250
44150
|
Compute compute
|
|
43251
44151
|
Storage storage
|
|
43252
|
-
|
|
44152
|
+
Broker events
|
|
43253
44153
|
PublicGateway publicGateway
|
|
43254
44154
|
NetworkConnection network
|
|
43255
44155
|
\`\`\`
|
|
@@ -43266,16 +44166,13 @@ deployment production
|
|
|
43266
44166
|
name = ECS
|
|
43267
44167
|
technology = AWS ECS
|
|
43268
44168
|
events:
|
|
43269
|
-
|
|
43270
|
-
name =
|
|
43271
|
-
|
|
43272
|
-
|
|
43273
|
-
name = Kafka
|
|
43274
|
-
technology = MSK
|
|
43275
|
-
address = kafka.prod.eu.internal
|
|
44169
|
+
kafka event_bus
|
|
44170
|
+
name = Kafka
|
|
44171
|
+
technology = MSK
|
|
44172
|
+
address = kafka.prod.eu.internal
|
|
43276
44173
|
projection:
|
|
43277
|
-
target $to connectTo target
|
|
43278
|
-
target
|
|
44174
|
+
target $to connectTo target $this
|
|
44175
|
+
target $this originalLink source $from
|
|
43279
44176
|
\`\`\`
|
|
43280
44177
|
|
|
43281
44178
|
\`\`\`insight
|
|
@@ -43292,7 +44189,8 @@ System files in the same logical context should import the context-owned profile
|
|
|
43292
44189
|
when it is declared in a different source identity. Wires name compatible
|
|
43293
44190
|
\`NetworkConnection\` slots directly. Read the
|
|
43294
44191
|
[Broker](deployment-projections.md#broker) example before adding an event path;
|
|
43295
|
-
|
|
44192
|
+
the built-in \`Broker\` can fill a wire-facing slot directly, and
|
|
44193
|
+
product-specific broker types should derive from it.
|
|
43296
44194
|
|
|
43297
44195
|
## System Files and External Contexts
|
|
43298
44196
|
|
|
@@ -43444,8 +44342,9 @@ Deployment output after changing which root a traffic relationship extends:
|
|
|
43444
44342
|
|
|
43445
44343
|
\`\`\`shell
|
|
43446
44344
|
archinsight link . --format text
|
|
43447
|
-
archinsight query . -
|
|
43448
|
-
archinsight
|
|
44345
|
+
archinsight query . -s deployment.ai -v deployment-system --format json
|
|
44346
|
+
archinsight query . -s deployment.ai -v deployment-container --environment eu --format json
|
|
44347
|
+
archinsight render . -s deployment.ai -v deployment-container --environment eu -f svg -o deployment.svg
|
|
43449
44348
|
\`\`\`
|
|
43450
44349
|
|
|
43451
44350
|
If projected infrastructure edges disappear after a split, first check whether
|
|
@@ -43624,9 +44523,12 @@ sed -n '1,160p' .core/core_system.ai
|
|
|
43624
44523
|
\`\`\`insight
|
|
43625
44524
|
define type System of SystemElement
|
|
43626
44525
|
constructor system
|
|
44526
|
+
kind = internal
|
|
43627
44527
|
|
|
43628
44528
|
required Text name
|
|
44529
|
+
required Text kind
|
|
43629
44530
|
Text technology
|
|
44531
|
+
Text description
|
|
43630
44532
|
List of Wire links
|
|
43631
44533
|
List of Container _
|
|
43632
44534
|
\`\`\`
|
|
@@ -43636,6 +44538,8 @@ Interpretation:
|
|
|
43636
44538
|
- \`define type System of SystemElement\` means \`System\` inherits from
|
|
43637
44539
|
\`SystemElement\`.
|
|
43638
44540
|
- \`constructor system\` means \`system <id>\` is valid syntax for that type.
|
|
44541
|
+
- The constructor assigns \`kind = internal\`, so model authors do not repeat the
|
|
44542
|
+
built-in default on every system.
|
|
43639
44543
|
- \`required Text name\` means \`name = ...\` is required.
|
|
43640
44544
|
- \`Text technology\` means \`technology = ...\` is optional.
|
|
43641
44545
|
- \`List of Wire links\` enables a \`links:\` block whose children are wires.
|
|
@@ -43661,8 +44565,9 @@ C4 query.
|
|
|
43661
44565
|
\`description\`, plus deployment references.
|
|
43662
44566
|
- \`Storage\` / constructor \`storage\`: for databases, buckets, volumes, and
|
|
43663
44567
|
other stateful stores.
|
|
43664
|
-
- \`Broker\` / constructor \`broker\`:
|
|
43665
|
-
adds optional \`address
|
|
44568
|
+
- \`Broker\` / constructor \`broker\`: a \`NetworkConnection\` specialization
|
|
44569
|
+
for message brokers and event buses; adds optional \`address\` and can carry
|
|
44570
|
+
a projected logical wire.
|
|
43666
44571
|
- \`Compute\` / constructor \`compute\`: for runtimes, clusters, nodes, and
|
|
43667
44572
|
platforms; adds optional \`address\` and can contain nested infrastructure
|
|
43668
44573
|
components in a \`components:\` block.
|
|
@@ -43903,28 +44808,30 @@ Inspect the selected graph before rendering whenever a change affects C2, C3,
|
|
|
43903
44808
|
C4, Deployment, projections, or query text:
|
|
43904
44809
|
|
|
43905
44810
|
\`\`\`shell
|
|
43906
|
-
archinsight query . -
|
|
43907
|
-
archinsight query . -
|
|
43908
|
-
archinsight query . -
|
|
43909
|
-
archinsight query . -
|
|
44811
|
+
archinsight query . -s <source.ai> -v c2 --format json
|
|
44812
|
+
archinsight query . -s <source.ai> -v c3 --format json
|
|
44813
|
+
archinsight query . -s <source.ai> -v c4 --format json
|
|
44814
|
+
archinsight query . -s <source.ai> -v deployment-system --format json
|
|
44815
|
+
archinsight query . -s <source.ai> -v deployment-container --environment <environment> --format json
|
|
43910
44816
|
\`\`\`
|
|
43911
44817
|
|
|
43912
|
-
Then render the same
|
|
44818
|
+
Then render the same source and view; the source carries the same context:
|
|
43913
44819
|
|
|
43914
44820
|
\`\`\`shell
|
|
43915
|
-
archinsight render . -
|
|
43916
|
-
archinsight render . -
|
|
43917
|
-
archinsight render . -
|
|
43918
|
-
archinsight render . -
|
|
43919
|
-
archinsight render . -
|
|
44821
|
+
archinsight render . -s <source.ai> -v c1 -f svg -o diagram.svg
|
|
44822
|
+
archinsight render . -s <source.ai> -v c2 -f svg -o diagram.svg
|
|
44823
|
+
archinsight render . -s <source.ai> -v c3 -f svg -o diagram.svg
|
|
44824
|
+
archinsight render . -s <source.ai> -v c4 -f svg -o diagram.svg
|
|
44825
|
+
archinsight render . -s <source.ai> -v deployment-system -f svg -o deployment-system.svg
|
|
44826
|
+
archinsight render . -s <source.ai> -v deployment-container --environment <environment> -f svg -o deployment-container.svg
|
|
43920
44827
|
\`\`\`
|
|
43921
44828
|
|
|
43922
44829
|
Run a custom query from a file:
|
|
43923
44830
|
|
|
43924
44831
|
\`\`\`shell
|
|
43925
|
-
archinsight query . -
|
|
43926
|
-
archinsight query . -
|
|
43927
|
-
archinsight render . -
|
|
44832
|
+
archinsight query . -s <source.ai> -q query.aiq -f text
|
|
44833
|
+
archinsight query . -s <source.ai> -q query.aiq -f json
|
|
44834
|
+
archinsight render . -s <source.ai> -q query.aiq -f svg -o diagram.svg
|
|
43928
44835
|
\`\`\`
|
|
43929
44836
|
|
|
43930
44837
|
Use three validation layers:
|
|
@@ -43945,12 +44852,17 @@ Useful built-in views:
|
|
|
43945
44852
|
- \`c2\` for containers/services in the selected source.
|
|
43946
44853
|
- \`c3\` for components in the selected source.
|
|
43947
44854
|
- \`c4\` for project-defined code elements in the selected source.
|
|
43948
|
-
- \`deployment\` for deployment
|
|
44855
|
+
- \`deployment-system\` for the D1 system deployment overview across relevant
|
|
44856
|
+
environments.
|
|
44857
|
+
- \`deployment-container --environment <id>\` for D2 physical detail in one
|
|
44858
|
+
environment.
|
|
44859
|
+
- \`deployment\` only when an all-environment container graph is intentionally
|
|
44860
|
+
required for backward compatibility or analysis.
|
|
43949
44861
|
- \`no-filter\` for the full context.
|
|
43950
44862
|
|
|
43951
|
-
C2, C3, C4, Deployment, and custom queries
|
|
43952
|
-
\`--source <file>\` / \`-s <file
|
|
43953
|
-
|
|
44863
|
+
C2, C3, C4, Deployment, and custom queries that use \`$tab\` depend on the
|
|
44864
|
+
active file. Pass \`--source <file>\` / \`-s <file>\`; the CLI will not guess
|
|
44865
|
+
between several project files. That source also supplies \`$context\`.
|
|
43954
44866
|
|
|
43955
44867
|
The bundled \`examples\` directory contains several independent model projects,
|
|
43956
44868
|
not one project to link as a whole. Validate \`layered-architecture.ai\`, the C1,
|
|
@@ -44007,9 +44919,10 @@ the Insight query and which result was computed from its output.
|
|
|
44007
44919
|
\`no-filter\` for a broad logical export.
|
|
44008
44920
|
4. Inspect query JSON before rendering. Distinguish selected outer endpoints,
|
|
44009
44921
|
underlying edge endpoints, derived relationships, and projection origins.
|
|
44010
|
-
5. If the question needs traversal, aggregation,
|
|
44011
|
-
compute them over the exported JSON without changing the model or
|
|
44012
|
-
the computation was supported by the query DSL.
|
|
44922
|
+
5. If the question needs traversal, aggregation, set intersection, or absence
|
|
44923
|
+
checks, compute them over the exported JSON without changing the model or
|
|
44924
|
+
pretending the computation was supported by the query DSL. Ordinary
|
|
44925
|
+
property equality and inequality can stay in the Insight query.
|
|
44013
44926
|
6. Report the scope: context, selected source when \`$tab\` is used, query or
|
|
44014
44927
|
built-in view, and whether derived or projected edges were included.
|
|
44015
44928
|
|
|
@@ -44043,21 +44956,25 @@ MATCH (service:Service {id: 'checkout_api', context: $context})-[dependency:REFE
|
|
|
44043
44956
|
RETURN service, dependency, target
|
|
44044
44957
|
\`\`\`
|
|
44045
44958
|
|
|
44046
|
-
Incoming dependencies
|
|
44047
|
-
|
|
44959
|
+
Incoming dependencies can keep the inspected service at the start of the
|
|
44960
|
+
pattern by using the reverse arrow:
|
|
44048
44961
|
|
|
44049
44962
|
\`\`\`cypher
|
|
44050
|
-
MATCH (
|
|
44051
|
-
RETURN
|
|
44963
|
+
MATCH (service:Service {id: 'checkout_api', context: $context})<-[dependency:REFERENCES]-(caller:Element)
|
|
44964
|
+
RETURN service, dependency, caller
|
|
44052
44965
|
\`\`\`
|
|
44053
44966
|
|
|
44967
|
+
This selects the same stored edge as placing \`caller\` on the left with \`->\`.
|
|
44968
|
+
Pattern orientation changes matching readability, not the relationship stored
|
|
44969
|
+
in the architecture model.
|
|
44970
|
+
|
|
44054
44971
|
These answer one-hop questions. To find all transitively affected elements,
|
|
44055
44972
|
export the relevant context graph and traverse its direct \`REFERENCES\` edges
|
|
44056
44973
|
outside the query language. State whether derived and projected edges were
|
|
44057
44974
|
excluded or analyzed separately so the same dependency is not counted at
|
|
44058
44975
|
several architectural levels.
|
|
44059
44976
|
|
|
44060
|
-
##
|
|
44977
|
+
## Choose the Dependency Scope
|
|
44061
44978
|
|
|
44062
44979
|
The bundled \`examples/queries/direct-service-dependencies.aiq\` selects the
|
|
44063
44980
|
one-hop dependency graph at container/service ownership level:
|
|
@@ -44070,9 +44987,9 @@ RETURN source, dependency, target
|
|
|
44070
44987
|
|
|
44071
44988
|
\`withDerived\` includes relationships lifted from components to their owning
|
|
44072
44989
|
containers or services. This is appropriate for a service dependency map, but
|
|
44073
|
-
it is not an inventory of authored wires.
|
|
44074
|
-
|
|
44075
|
-
|
|
44990
|
+
it is not an inventory of authored wires. Because both endpoints must be
|
|
44991
|
+
\`ContainerElement\`, it intentionally omits a direct service-to-system or
|
|
44992
|
+
system-to-system relationship.
|
|
44076
44993
|
|
|
44077
44994
|
Run the query once for the context instead of querying every service
|
|
44078
44995
|
individually:
|
|
@@ -44088,41 +45005,70 @@ preserve dependency ownership. The source depends on the target. Use qualified
|
|
|
44088
45005
|
ids from those fields when building an adjacency map; do not infer direction
|
|
44089
45006
|
from diagram placement.
|
|
44090
45007
|
|
|
44091
|
-
|
|
45008
|
+
For every authored one-hop dependency regardless of architectural level, use
|
|
45009
|
+
\`examples/queries/direct-authored-dependencies.aiq\`:
|
|
45010
|
+
|
|
45011
|
+
\`\`\`cypher
|
|
45012
|
+
MATCH (source:Element)-[dependency:REFERENCES]->(target:Element)
|
|
45013
|
+
WHERE source.context = $context
|
|
45014
|
+
RETURN source, dependency, target
|
|
45015
|
+
\`\`\`
|
|
45016
|
+
|
|
45017
|
+
\`\`\`shell
|
|
45018
|
+
archinsight query . -c <context-id> \\
|
|
45019
|
+
-q <skill-path>/examples/queries/direct-authored-dependencies.aiq \\
|
|
45020
|
+
--format json
|
|
45021
|
+
\`\`\`
|
|
45022
|
+
|
|
45023
|
+
This query excludes derived and projected copies. It is the correct starting
|
|
45024
|
+
point for questions such as "what does this service or system directly depend
|
|
45025
|
+
on?" when the target may live at another architectural level.
|
|
45026
|
+
|
|
45027
|
+
## Analyze Async Topics and Channels
|
|
44092
45028
|
|
|
44093
|
-
The bundled \`examples/queries/
|
|
44094
|
-
|
|
45029
|
+
The bundled \`examples/queries/async-topic-dependencies.aiq\` selects every
|
|
45030
|
+
authored async dependency without requiring a particular transport or endpoint
|
|
45031
|
+
level:
|
|
44095
45032
|
|
|
44096
45033
|
\`\`\`cypher
|
|
44097
|
-
MATCH (consumer:
|
|
45034
|
+
MATCH (consumer:Element)-[event:REFERENCES]->(producer:Element)
|
|
44098
45035
|
WHERE consumer.context = $context
|
|
44099
45036
|
AND event.type = 'AsyncWire'
|
|
44100
|
-
AND event.technology CONTAINS 'Kafka'
|
|
44101
45037
|
RETURN consumer, event, producer
|
|
44102
45038
|
\`\`\`
|
|
44103
45039
|
|
|
44104
45040
|
Insight eventing is consumer-owned: the consumer declares \`~> producer\`, and
|
|
44105
45041
|
\`via\` names the topic or channel. Therefore an outgoing async edge lists what
|
|
44106
|
-
|
|
44107
|
-
producer's topic contract.
|
|
45042
|
+
an element consumes, while incoming async edges list the modeled consumers of a
|
|
45043
|
+
producer's topic contract. The endpoints may be systems, services, components,
|
|
45044
|
+
or project-defined element types.
|
|
45045
|
+
|
|
45046
|
+
Run the generic query for the whole context:
|
|
45047
|
+
|
|
45048
|
+
\`\`\`shell
|
|
45049
|
+
archinsight query . -c <context-id> \\
|
|
45050
|
+
-q <skill-path>/examples/queries/async-topic-dependencies.aiq \\
|
|
45051
|
+
--format json
|
|
45052
|
+
\`\`\`
|
|
45053
|
+
|
|
45054
|
+
To select a topic family, copy the query and add a case-sensitive membership or
|
|
45055
|
+
substring predicate such as \`AND event.via CONTAINS 'orders.'\`.
|
|
44108
45056
|
|
|
44109
45057
|
For one consumer, constrain its local id in the first node pattern:
|
|
44110
45058
|
|
|
44111
45059
|
\`\`\`cypher
|
|
44112
|
-
MATCH (consumer:
|
|
44113
|
-
-[event:REFERENCES]->(producer:
|
|
45060
|
+
MATCH (consumer:Element {id: 'order_processor', context: $context})
|
|
45061
|
+
-[event:REFERENCES]->(producer:Element)
|
|
44114
45062
|
WHERE event.type = 'AsyncWire'
|
|
44115
|
-
AND event.technology CONTAINS 'Kafka'
|
|
44116
45063
|
RETURN consumer, event, producer
|
|
44117
45064
|
\`\`\`
|
|
44118
45065
|
|
|
44119
45066
|
For one producer, use the reverse pattern:
|
|
44120
45067
|
|
|
44121
45068
|
\`\`\`cypher
|
|
44122
|
-
MATCH (producer:
|
|
44123
|
-
<-[event:REFERENCES]-(consumer:
|
|
45069
|
+
MATCH (producer:Element {id: 'order_processor', context: $context})
|
|
45070
|
+
<-[event:REFERENCES]-(consumer:Element)
|
|
44124
45071
|
WHERE event.type = 'AsyncWire'
|
|
44125
|
-
AND event.technology CONTAINS 'Kafka'
|
|
44126
45072
|
RETURN producer, event, consumer
|
|
44127
45073
|
\`\`\`
|
|
44128
45074
|
|
|
@@ -44132,7 +45078,7 @@ into the agent's context:
|
|
|
44132
45078
|
|
|
44133
45079
|
\`\`\`shell
|
|
44134
45080
|
archinsight query . -c <context-id> \\
|
|
44135
|
-
-q <skill-path>/examples/queries/
|
|
45081
|
+
-q <skill-path>/examples/queries/async-topic-dependencies.aiq \\
|
|
44136
45082
|
--format json |
|
|
44137
45083
|
jq -r '.edges[] | [
|
|
44138
45084
|
.edge.source,
|
|
@@ -44146,6 +45092,62 @@ This reports topic contracts used by at least one modeled consumer. Do not
|
|
|
44146
45092
|
claim it is a complete producer catalog: a topic with no modeled wire is not
|
|
44147
45093
|
discoverable unless the project represents that contract separately.
|
|
44148
45094
|
|
|
45095
|
+
The bundled \`examples/queries/kafka-service-dependencies.aiq\` is a narrower
|
|
45096
|
+
specialization for projects that consistently record \`technology = Kafka\`
|
|
45097
|
+
and want only authored container-to-container dependencies without derived or
|
|
45098
|
+
projected copies:
|
|
45099
|
+
|
|
45100
|
+
\`\`\`cypher
|
|
45101
|
+
MATCH (consumer:ContainerElement)-[event:REFERENCES]->(producer:ContainerElement)
|
|
45102
|
+
WHERE consumer.context = $context
|
|
45103
|
+
AND event.type = 'AsyncWire'
|
|
45104
|
+
AND event.technology CONTAINS 'Kafka'
|
|
45105
|
+
RETURN consumer, event, producer
|
|
45106
|
+
\`\`\`
|
|
45107
|
+
|
|
45108
|
+
Do not use this specialization when \`technology\` is absent or inconsistent;
|
|
45109
|
+
the generic async query still finds those modeled relationships.
|
|
45110
|
+
|
|
45111
|
+
## Compare Endpoint Attributes
|
|
45112
|
+
|
|
45113
|
+
Equality and inequality can compare properties on two bound endpoints:
|
|
45114
|
+
|
|
45115
|
+
\`\`\`cypher
|
|
45116
|
+
MATCH (source:Element)-[dependency:REFERENCES]->(target:Element)
|
|
45117
|
+
WHERE source.runsOn <> target.runsOn
|
|
45118
|
+
RETURN source, dependency, target
|
|
45119
|
+
\`\`\`
|
|
45120
|
+
|
|
45121
|
+
Scalar references compare by qualified element id. List properties compare as
|
|
45122
|
+
complete ordered lists. If either property is absent, both \`=\` and \`<>\`
|
|
45123
|
+
evaluate to false for that row. The query language does not calculate list
|
|
45124
|
+
intersection or set difference; export JSON and post-process it when the
|
|
45125
|
+
question is whether two multi-valued placements overlap.
|
|
45126
|
+
|
|
45127
|
+
## Report Annotations
|
|
45128
|
+
|
|
45129
|
+
Annotations are present in query JSON, but the current query language has no
|
|
45130
|
+
annotation predicate. Select a sufficiently broad graph and filter the JSON:
|
|
45131
|
+
|
|
45132
|
+
\`\`\`shell
|
|
45133
|
+
archinsight query . -c <context-id> -v no-filter --format json |
|
|
45134
|
+
jq '{
|
|
45135
|
+
elements: [
|
|
45136
|
+
.elements[] |
|
|
45137
|
+
select((.annotations // []) | length > 0) |
|
|
45138
|
+
{id, annotations}
|
|
45139
|
+
],
|
|
45140
|
+
edges: [
|
|
45141
|
+
.edges[] |
|
|
45142
|
+
select((.edge.annotations // []) | length > 0) |
|
|
45143
|
+
{source, target, annotations: .edge.annotations}
|
|
45144
|
+
]
|
|
45145
|
+
}'
|
|
45146
|
+
\`\`\`
|
|
45147
|
+
|
|
45148
|
+
Each annotation retains its name, optional value, and source position. This is
|
|
45149
|
+
a read-only reporting workaround, not an Insight query predicate.
|
|
45150
|
+
|
|
44149
45151
|
## Analyze a Source Fragment
|
|
44150
45152
|
|
|
44151
45153
|
Use \`$tab\` when the question concerns the semantic fragment rooted in one
|
|
@@ -44164,13 +45166,19 @@ it is not a raw inventory of lines physically present in that file.
|
|
|
44164
45166
|
|
|
44165
45167
|
## Analyze Deployment Realization
|
|
44166
45168
|
|
|
44167
|
-
Use
|
|
44168
|
-
realized physically
|
|
45169
|
+
Use built-in Deployment query JSON when the question is how logical architecture
|
|
45170
|
+
is realized physically. D1 answers which systems and external integrations are
|
|
45171
|
+
present across relevant environments. D2 shows container and infrastructure
|
|
45172
|
+
detail inside one selected environment:
|
|
44169
45173
|
|
|
44170
45174
|
\`\`\`shell
|
|
44171
|
-
archinsight query . -
|
|
45175
|
+
archinsight query . -s <logical-source.ai> -v deployment-system --format json
|
|
45176
|
+
archinsight query . -s <logical-source.ai> -v deployment-container --environment <environment> --format json
|
|
44172
45177
|
\`\`\`
|
|
44173
45178
|
|
|
45179
|
+
Use the legacy \`deployment\` view only when the question intentionally requires
|
|
45180
|
+
one container-level graph across every relevant environment.
|
|
45181
|
+
|
|
44174
45182
|
For each projected edge, compare outer \`source\` and \`target\` with nested
|
|
44175
45183
|
\`edge.source\` and \`edge.target\`. Use \`edge.originSource\` and
|
|
44176
45184
|
\`edge.originTarget\` for the logical origin selected by the query. When
|
|
@@ -44203,19 +45211,22 @@ diagram.
|
|
|
44203
45211
|
## CLI Shape
|
|
44204
45212
|
|
|
44205
45213
|
\`\`\`shell
|
|
44206
|
-
archinsight query . -
|
|
44207
|
-
archinsight query . -
|
|
44208
|
-
archinsight
|
|
45214
|
+
archinsight query . -s <source.ai> -q query.aiq -f text
|
|
45215
|
+
archinsight query . -s <source.ai> -v deployment-system --format json
|
|
45216
|
+
archinsight query . -s <source.ai> -v deployment-container --environment <environment> --format json
|
|
45217
|
+
archinsight render . -s <source.ai> -q query.aiq -f svg -o diagram.svg
|
|
44209
45218
|
\`\`\`
|
|
44210
45219
|
|
|
44211
45220
|
The scope variables are:
|
|
44212
45221
|
|
|
44213
|
-
- \`$context\` -
|
|
45222
|
+
- \`$context\` - context declared by \`--source\`, or the explicit
|
|
45223
|
+
\`--context\` used for context-wide execution without a source.
|
|
44214
45224
|
- \`$tab\` - the semantic model fragment rooted in the source selected by
|
|
44215
45225
|
\`--source\` / \`--tab\`. It includes content contributed to those roots by
|
|
44216
45226
|
\`extend\` in other files.
|
|
44217
45227
|
|
|
44218
|
-
Pass \`--source\` when a query uses \`$tab\`.
|
|
45228
|
+
Pass \`--source\` when a query uses \`$tab\`. A selected source also supplies
|
|
45229
|
+
\`$context\`, so do not repeat its context on the command line.
|
|
44219
45230
|
|
|
44220
45231
|
Path handling:
|
|
44221
45232
|
|
|
@@ -44227,7 +45238,7 @@ Path handling:
|
|
|
44227
45238
|
Prefer paths relative to the project root:
|
|
44228
45239
|
|
|
44229
45240
|
\`\`\`shell
|
|
44230
|
-
archinsight query path/to/project -
|
|
45241
|
+
archinsight query path/to/project -s models/storefront.ai -q queries/c2.aiq -f text
|
|
44231
45242
|
\`\`\`
|
|
44232
45243
|
|
|
44233
45244
|
## Query Shape
|
|
@@ -44317,7 +45328,10 @@ OPTIONAL MATCH (container)-[link]->(target)
|
|
|
44317
45328
|
RETURN container, link, target
|
|
44318
45329
|
\`\`\`
|
|
44319
45330
|
|
|
44320
|
-
|
|
45331
|
+
Return relationship aliases when the query must select or filter exact edges. A
|
|
45332
|
+
node-only query completes direct authored relationships between selected nodes.
|
|
45333
|
+
Once a returned relationship alias is present, its result is authoritative: if
|
|
45334
|
+
the relationship predicate matches nothing, no fallback edges are added.
|
|
44321
45335
|
|
|
44322
45336
|
## Filtering
|
|
44323
45337
|
|
|
@@ -44330,6 +45344,7 @@ WHERE node.deployed = true
|
|
|
44330
45344
|
WHERE node IS External
|
|
44331
45345
|
WHERE NOT node IS DeploymentElement
|
|
44332
45346
|
WHERE edge.projected = 'true'
|
|
45347
|
+
WHERE edge.projectionRoot = 'eu/service_network'
|
|
44333
45348
|
WHERE node.id IN ['api', 'web_app']
|
|
44334
45349
|
WHERE node.technology CONTAINS 'PostgreSQL'
|
|
44335
45350
|
WHERE node.type <> 'Context'
|
|
@@ -44341,10 +45356,46 @@ Use single quotes for string literals.
|
|
|
44341
45356
|
\`CONTAINS\` is case-sensitive. For scalar text it performs substring matching;
|
|
44342
45357
|
for a list property it tests membership. Match the stored spelling exactly.
|
|
44343
45358
|
|
|
45359
|
+
Attribute cardinality comes from the Insight type system, not from the JSON
|
|
45360
|
+
representation. Use \`CONTAINS\` for list-valued attributes such as \`uses\`.
|
|
45361
|
+
\`runsOn\` is declared as a scalar typed reference. When it has one resolved
|
|
45362
|
+
target, it resolves to one graph node: compare it with another bound node, or
|
|
45363
|
+
test its qualified id with \`node.runsOn IN ['eu/cluster']\`.
|
|
45364
|
+
\`node.runsOn CONTAINS 'eu/cluster'\` does not match a scalar reference because
|
|
45365
|
+
that value is neither scalar text nor a list.
|
|
45366
|
+
|
|
45367
|
+
A logical element materialized through several deployments can have several
|
|
45368
|
+
resolved \`runsOn\` targets. In that case bind a candidate infrastructure node
|
|
45369
|
+
and use \`candidate IN node.runsOn\`.
|
|
45370
|
+
|
|
45371
|
+
Query JSON serializes attribute values as arrays for a stable transport shape.
|
|
45372
|
+
The linked element or edge also exposes \`listAttributes\` and
|
|
45373
|
+
\`referenceAttributes\`; use that metadata when an automated analysis needs to
|
|
45374
|
+
recover the language-level cardinality and reference kind.
|
|
45375
|
+
|
|
45376
|
+
Properties of two bound aliases can be compared directly:
|
|
45377
|
+
|
|
45378
|
+
\`\`\`cypher
|
|
45379
|
+
WHERE source.runsOn = target.runsOn
|
|
45380
|
+
WHERE source.runsOn <> target.runsOn
|
|
45381
|
+
\`\`\`
|
|
45382
|
+
|
|
45383
|
+
Scalar references compare by qualified id and lists compare as complete ordered
|
|
45384
|
+
lists. If either property is absent, both comparisons evaluate to false. Set
|
|
45385
|
+
intersection and overlap tests are not supported; post-process query JSON for
|
|
45386
|
+
those operations.
|
|
45387
|
+
|
|
44344
45388
|
\`node.deployed\` is true when an element's deployment resolves to at least one
|
|
44345
45389
|
\`runsOn\` or \`uses\` infrastructure object. The built-in Deployment view uses it to keep
|
|
44346
45390
|
undeployed logical elements out of the physical diagram.
|
|
44347
45391
|
|
|
45392
|
+
\`edge.projectionRoot\` is available on projected relationships and identifies
|
|
45393
|
+
the infrastructure element whose projection produced the selected segment.
|
|
45394
|
+
It can be used in relationship predicates and has the same value shown in
|
|
45395
|
+
\`query --format json\` output. Resolved \`node.runsOn\` can contain several
|
|
45396
|
+
concrete infrastructure objects, so use \`candidate IN node.runsOn\` when
|
|
45397
|
+
matching placement targets.
|
|
45398
|
+
|
|
44348
45399
|
## Relationship Selectors
|
|
44349
45400
|
|
|
44350
45401
|
Relationship selectors are boolean flags inside relationship braces:
|
|
@@ -44407,15 +45458,21 @@ The top-level shape is:
|
|
|
44407
45458
|
- \`groups\`: render groups created by \`GROUP BY\`;
|
|
44408
45459
|
- \`externalElements\`: selected ids drawn outside the internal boundary.
|
|
44409
45460
|
|
|
45461
|
+
Elements expose their linked \`attributes\`, optional \`listAttributes\` and
|
|
45462
|
+
\`referenceAttributes\` metadata, and any \`annotations\`. Relationship data is
|
|
45463
|
+
nested under each result item's \`edge\` field and carries the same attribute
|
|
45464
|
+
metadata plus edge annotations. Annotations can be inspected in JSON but cannot
|
|
45465
|
+
currently be referenced by a \`WHERE\` predicate.
|
|
45466
|
+
|
|
44410
45467
|
For built-in C1-C4 execution, this list combines explicit model externality
|
|
44411
45468
|
with externality relative to the opened diagram boundaries. C2 folds a closed
|
|
44412
45469
|
endpoint to its system, C3 to its container or service, and C4 to its component.
|
|
44413
45470
|
\`IS External\` in a custom query continues to match only the explicit model
|
|
44414
45471
|
marker.
|
|
44415
45472
|
|
|
44416
|
-
|
|
44417
|
-
|
|
44418
|
-
|
|
45473
|
+
A custom query file supplies its own selection and grouping contract and
|
|
45474
|
+
overrides \`--view\`. To customize C1-C4 boundary behavior, copy the nearest
|
|
45475
|
+
bundled built-in \`.aiq\` file and modify its predicates or grouping explicitly.
|
|
44419
45476
|
|
|
44420
45477
|
Each edge contains its selected category and two endpoint pairs:
|
|
44421
45478
|
|
|
@@ -44429,7 +45486,9 @@ Each edge contains its selected category and two endpoint pairs:
|
|
|
44429
45486
|
- nested \`edge.projectionOrigins\`, when present, lists every logical source and
|
|
44430
45487
|
target that shares the physical segment;
|
|
44431
45488
|
- nested \`edge.projectionRoot\` identifies the infrastructure element whose
|
|
44432
|
-
projection produced the segment
|
|
45489
|
+
projection produced the segment;
|
|
45490
|
+
- nested \`edge.sourcePlacement\` and \`edge.targetPlacement\`, when present,
|
|
45491
|
+
identify the concrete placement of each logical endpoint independently.
|
|
44433
45492
|
|
|
44434
45493
|
An abridged response remains ordinary JSON:
|
|
44435
45494
|
|
|
@@ -44503,6 +45562,8 @@ examples/builtin-views/c1.aiq
|
|
|
44503
45562
|
examples/builtin-views/c2.aiq
|
|
44504
45563
|
examples/builtin-views/c3.aiq
|
|
44505
45564
|
examples/builtin-views/c4.aiq
|
|
45565
|
+
examples/builtin-views/deployment-system.aiq
|
|
45566
|
+
examples/builtin-views/deployment-container.aiq
|
|
44506
45567
|
examples/builtin-views/deployment.aiq
|
|
44507
45568
|
\`\`\`
|
|
44508
45569
|
|
|
@@ -44519,9 +45580,15 @@ C4 opens every component rooted in \`$tab\`, selects direct Code-element
|
|
|
44519
45580
|
neighborhoods in either direction, and folds outside code to closed components.
|
|
44520
45581
|
Concrete code types and containment remain project-defined.
|
|
44521
45582
|
|
|
44522
|
-
|
|
44523
|
-
|
|
44524
|
-
placement lookup separate from relationship matching.
|
|
45583
|
+
D1 and D2 select physically deployed logical nodes and source-owned system
|
|
45584
|
+
endpoints from \`$tab\`, use one undirected \`OPTIONAL MATCH ROLLUP\` for projected
|
|
45585
|
+
paths, and keep placement lookup separate from relationship matching. When the
|
|
45586
|
+
source owns no deployed elements, environment discovery falls back to
|
|
45587
|
+
infrastructure used by its authored wires. D1 folds logical nodes to systems.
|
|
45588
|
+
D1 then contracts internal infrastructure paths and groups the remaining systems
|
|
45589
|
+
and external integrations by environment. D2 applies the structured environment
|
|
45590
|
+
scope after discovery and retains its physical detail. The legacy Deployment
|
|
45591
|
+
query retains all relevant environments.
|
|
44525
45592
|
|
|
44526
45593
|
When a built-in view is close but hides the wrong thing, read
|
|
44527
45594
|
\`references/query-recipes.md\`, copy the nearest built-in \`.aiq\`, and change
|
|
@@ -44554,16 +45621,23 @@ examples/builtin-views/c1.aiq
|
|
|
44554
45621
|
examples/builtin-views/c2.aiq
|
|
44555
45622
|
examples/builtin-views/c3.aiq
|
|
44556
45623
|
examples/builtin-views/c4.aiq
|
|
45624
|
+
examples/builtin-views/deployment-system.aiq
|
|
45625
|
+
examples/builtin-views/deployment-container.aiq
|
|
44557
45626
|
examples/builtin-views/deployment.aiq
|
|
44558
45627
|
\`\`\`
|
|
44559
45628
|
|
|
44560
45629
|
Before inventing a query from scratch, open the nearest built-in query, copy it
|
|
44561
45630
|
to the project, and make the smallest change.
|
|
44562
45631
|
|
|
45632
|
+
Choose \`deployment-system.aiq\` for a D1 overview and
|
|
45633
|
+
\`deployment-container.aiq\` for D2 detail in one environment. Start from the
|
|
45634
|
+
legacy \`deployment.aiq\` only when the intended result is one container-level
|
|
45635
|
+
graph across every relevant environment.
|
|
45636
|
+
|
|
44563
45637
|
\`\`\`shell
|
|
44564
|
-
archinsight query . -
|
|
44565
|
-
archinsight query . -
|
|
44566
|
-
archinsight render . -
|
|
45638
|
+
archinsight query . -s <source.ai> -q queries/custom.aiq -f text
|
|
45639
|
+
archinsight query . -s <source.ai> -q queries/custom.aiq -f json
|
|
45640
|
+
archinsight render . -s <source.ai> -q queries/custom.aiq -f svg -o custom.svg
|
|
44567
45641
|
\`\`\`
|
|
44568
45642
|
|
|
44569
45643
|
Use \`references/queries.md\` for syntax details. Use this file for common
|
|
@@ -44616,10 +45690,12 @@ archinsight link . --format text
|
|
|
44616
45690
|
archinsight structure . --format text
|
|
44617
45691
|
\`\`\`
|
|
44618
45692
|
|
|
44619
|
-
3. Run the built-in query explicitly and inspect its JSON
|
|
45693
|
+
3. Run the built-in query explicitly and inspect its JSON. Choose the command
|
|
45694
|
+
that matches the diagram being investigated:
|
|
44620
45695
|
|
|
44621
45696
|
\`\`\`shell
|
|
44622
|
-
archinsight query . -
|
|
45697
|
+
archinsight query . -s <source.ai> -v deployment-system -f json
|
|
45698
|
+
archinsight query . -s <source.ai> -v deployment-container --environment <environment> -f json
|
|
44623
45699
|
\`\`\`
|
|
44624
45700
|
|
|
44625
45701
|
4. Check the query filters:
|
|
@@ -44627,17 +45703,17 @@ archinsight query . -c <context-id> -s <source.ai> -q examples/builtin-views/dep
|
|
|
44627
45703
|
- \`node.sourceIdentity = $tab\` selects the semantic fragment rooted in the
|
|
44628
45704
|
selected source, including contributions added to those roots through
|
|
44629
45705
|
\`extend\` in other files.
|
|
44630
|
-
- The built-in
|
|
45706
|
+
- The built-in D1 and D2 node filters include deployment elements and logical
|
|
44631
45707
|
container or external elements whose deployment resolves to physical
|
|
44632
45708
|
infrastructure. External endpoints without their own placement still enter
|
|
44633
45709
|
through projected paths attached to a deployed logical node.
|
|
44634
45710
|
- \`{projected}\` means only deployment-projected edges are selected.
|
|
44635
45711
|
- \`{derived}\` means only rolled-up relationships are selected.
|
|
44636
45712
|
- A relationship property such as \`sourceIdentity: $tab\` is available for a
|
|
44637
|
-
deliberately narrow custom view. The
|
|
44638
|
-
|
|
44639
|
-
|
|
44640
|
-
- The built-in
|
|
45713
|
+
deliberately narrow custom view. The built-in D1 and D2 queries rely on the
|
|
45714
|
+
selected node scope and semantic tab closure instead of applying that filter
|
|
45715
|
+
to projected relationships.
|
|
45716
|
+
- The built-in D1 and D2 views use one undirected \`MATCH ROLLUP\` for the
|
|
44641
45717
|
projected neighborhood. Projection origin metadata lets that clause find
|
|
44642
45718
|
ingress and egress segments while every segment preserves its real physical
|
|
44643
45719
|
source and target.
|
|
@@ -44672,19 +45748,20 @@ traceability, not for inventing a direct physical connection.
|
|
|
44672
45748
|
|
|
44673
45749
|
## Include Internal Actors In Deployment
|
|
44674
45750
|
|
|
44675
|
-
The built-in Deployment
|
|
44676
|
-
path. If
|
|
44677
|
-
tested customization:
|
|
45751
|
+
The built-in Deployment views include external actors reached by a projected
|
|
45752
|
+
physical path. If an all-environment deployment diagram also needs internal
|
|
45753
|
+
actors, use the bundled, tested legacy-view customization:
|
|
44678
45754
|
|
|
44679
45755
|
\`\`\`shell
|
|
44680
|
-
archinsight query . -
|
|
45756
|
+
archinsight query . -s <source.ai> -q examples/queries/deployment-internal-actors.aiq -f json
|
|
44681
45757
|
\`\`\`
|
|
44682
45758
|
|
|
44683
|
-
This query is generated from the exact
|
|
44684
|
-
node, projected-target, and incoming-source predicates to admit
|
|
44685
|
-
|
|
44686
|
-
|
|
44687
|
-
|
|
45759
|
+
This query is generated from the exact legacy \`deployment.aiq\` source and
|
|
45760
|
+
changes only the node, projected-target, and incoming-source predicates to admit
|
|
45761
|
+
\`Actor\`. For a D1 or D2 customization, copy the corresponding
|
|
45762
|
+
\`deployment-system.aiq\` or \`deployment-container.aiq\` source and apply the
|
|
45763
|
+
same actor predicates there so its current scope and environment behavior remain
|
|
45764
|
+
intact.
|
|
44688
45765
|
|
|
44689
45766
|
If the actor is declared in another source file, either render from that source
|
|
44690
45767
|
or relax the \`node.sourceIdentity = $tab\` condition intentionally.
|
|
@@ -44722,8 +45799,8 @@ exist in the file but the diagram question is still logical.
|
|
|
44722
45799
|
|
|
44723
45800
|
## Projected Edges Across Split Files
|
|
44724
45801
|
|
|
44725
|
-
The current built-in
|
|
44726
|
-
\`sourceIdentity: $tab\` relationship filter. The query engine expands \`$tab\`
|
|
45802
|
+
The current built-in D1 and D2 queries match \`{projected}\` edges without an
|
|
45803
|
+
explicit \`sourceIdentity: $tab\` relationship filter. The query engine expands \`$tab\`
|
|
44727
45804
|
to the roots declared by the selected source and contributions made to those
|
|
44728
45805
|
roots through \`extend\`, so a normal multi-file split does not require a looser
|
|
44729
45806
|
edge selector.
|
|
@@ -44733,7 +45810,8 @@ filter while keeping the node scope. Start again from the bundled current query
|
|
|
44733
45810
|
instead of preserving the rest of the older copy:
|
|
44734
45811
|
|
|
44735
45812
|
\`\`\`text
|
|
44736
|
-
copy examples/builtin-views/deployment.aiq
|
|
45813
|
+
copy examples/builtin-views/deployment-system.aiq for D1
|
|
45814
|
+
or copy examples/builtin-views/deployment-container.aiq for D2
|
|
44737
45815
|
remove sourceIdentity: $tab only from the relationship selector if an old copy has it
|
|
44738
45816
|
keep node.sourceIdentity = $tab
|
|
44739
45817
|
\`\`\`
|
|
@@ -44744,17 +45822,16 @@ by the tab before changing the model or broadening the node scope.
|
|
|
44744
45822
|
|
|
44745
45823
|
## Change Grouping
|
|
44746
45824
|
|
|
44747
|
-
Grouping controls visual clusters. If
|
|
44748
|
-
|
|
45825
|
+
Grouping controls visual clusters. If D1 or D2 grouping is not helpful, copy the
|
|
45826
|
+
complete corresponding built-in query and change only its \`GROUP BY\` expression:
|
|
44749
45827
|
|
|
44750
45828
|
\`\`\`cypher
|
|
44751
45829
|
GROUP BY node.parent
|
|
44752
45830
|
\`\`\`
|
|
44753
45831
|
|
|
44754
45832
|
Use \`GROUP BY node.runsOn\` for deployment placement; use \`GROUP BY node.parent\`
|
|
44755
|
-
for logical ownership.
|
|
44756
|
-
|
|
44757
|
-
the incoming projection aliases stay in the \`RETURN\`.
|
|
45833
|
+
for logical ownership. Preserve the rest of the selected D1 or D2 query so its
|
|
45834
|
+
projected-neighborhood aliases and environment behavior remain unchanged.
|
|
44758
45835
|
|
|
44759
45836
|
## Working Rule
|
|
44760
45837
|
|
|
@@ -45225,11 +46302,10 @@ system commerce
|
|
|
45225
46302
|
files: [
|
|
45226
46303
|
projectionFile("definitions.ai", `define type BrokerEnvironment of Environment
|
|
45227
46304
|
Compute compute
|
|
45228
|
-
|
|
46305
|
+
Broker events
|
|
45229
46306
|
|
|
45230
|
-
define type
|
|
45231
|
-
constructor
|
|
45232
|
-
required Broker transport
|
|
46307
|
+
define type KafkaBroker of Broker
|
|
46308
|
+
constructor kafka
|
|
45233
46309
|
`),
|
|
45234
46310
|
projectionFile("infrastructure.ai", `environment eu
|
|
45235
46311
|
name = Europe
|
|
@@ -45240,16 +46316,13 @@ deployment production
|
|
|
45240
46316
|
name = Kubernetes
|
|
45241
46317
|
|
|
45242
46318
|
events:
|
|
45243
|
-
|
|
45244
|
-
name =
|
|
45245
|
-
|
|
45246
|
-
broker kafka
|
|
45247
|
-
name = Kafka
|
|
45248
|
-
technology = Managed Kafka
|
|
46319
|
+
kafka kafka
|
|
46320
|
+
name = Kafka
|
|
46321
|
+
technology = Managed Kafka
|
|
45249
46322
|
projection:
|
|
45250
|
-
target $to connectTo target
|
|
46323
|
+
target $to connectTo target $this
|
|
45251
46324
|
technology = Kafka
|
|
45252
|
-
target
|
|
46325
|
+
target $this originalLink source $from
|
|
45253
46326
|
`),
|
|
45254
46327
|
projectionFile("model.ai", `context broker_example
|
|
45255
46328
|
|
|
@@ -45436,7 +46509,7 @@ Run:
|
|
|
45436
46509
|
|
|
45437
46510
|
\`\`\`shell
|
|
45438
46511
|
archinsight link examples/deployment-projections/${example.slug} --format text
|
|
45439
|
-
archinsight query examples/deployment-projections/${example.slug} -
|
|
46512
|
+
archinsight query examples/deployment-projections/${example.slug} -s model.ai -v deployment-container --environment eu --format json
|
|
45440
46513
|
\`\`\`
|
|
45441
46514
|
|
|
45442
46515
|
Expected physical result:
|
|
@@ -45474,11 +46547,10 @@ receives only attributes written on that rule, while projection origin metadata
|
|
|
45474
46547
|
still provides traceability. A path made entirely from \`connectTo\` therefore
|
|
45475
46548
|
does not carry the logical operator or authored relationship attributes.
|
|
45476
46549
|
|
|
45477
|
-
Wire \`uses\` accepts only a \`NetworkConnection\` descendant.
|
|
45478
|
-
\`Broker\` is
|
|
45479
|
-
|
|
45480
|
-
|
|
45481
|
-
path. See [Broker](#broker), the consumer-owned relationship rules in
|
|
46550
|
+
Wire \`uses\` accepts only a \`NetworkConnection\` descendant. The built-in
|
|
46551
|
+
\`Broker\` is one and can fill a wire-facing environment slot directly. Derive
|
|
46552
|
+
product-specific broker types from \`Broker\`, and put the physical projection
|
|
46553
|
+
on the concrete broker instance. See [Broker](#broker), the consumer-owned relationship rules in
|
|
45482
46554
|
[Eventing](modeling.md#eventing), and the shared-definition layout in
|
|
45483
46555
|
[Scaling](scaling.md#framework-once-use-everywhere).
|
|
45484
46556
|
|
|
@@ -45753,6 +46825,19 @@ WHERE source.context = $context
|
|
|
45753
46825
|
RETURN source, dependency, target
|
|
45754
46826
|
`;
|
|
45755
46827
|
}
|
|
46828
|
+
function genericDirectAuthoredDependenciesQuery() {
|
|
46829
|
+
return `MATCH (source:Element)-[dependency:REFERENCES]->(target:Element)
|
|
46830
|
+
WHERE source.context = $context
|
|
46831
|
+
RETURN source, dependency, target
|
|
46832
|
+
`;
|
|
46833
|
+
}
|
|
46834
|
+
function genericAsyncTopicDependenciesQuery() {
|
|
46835
|
+
return `MATCH (consumer:Element)-[event:REFERENCES]->(producer:Element)
|
|
46836
|
+
WHERE consumer.context = $context
|
|
46837
|
+
AND event.type = 'AsyncWire'
|
|
46838
|
+
RETURN consumer, event, producer
|
|
46839
|
+
`;
|
|
46840
|
+
}
|
|
45756
46841
|
function genericKafkaServiceDependenciesQuery() {
|
|
45757
46842
|
return `MATCH (consumer:ContainerElement)-[event:REFERENCES]->(producer:ContainerElement)
|
|
45758
46843
|
WHERE consumer.context = $context
|