@buun_group/plotwork-mcp 0.1.0-beta.6 → 0.1.0-beta.7
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/THIRD-PARTY-NOTICES.md +1 -1
- package/package.json +1 -1
- package/plotwork-mcp.mjs +1665 -198
package/plotwork-mcp.mjs
CHANGED
|
@@ -51,7 +51,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
51
51
|
var package_default;
|
|
52
52
|
var init_package = __esm({
|
|
53
53
|
"package.json"() {
|
|
54
|
-
package_default = { version: "0.1.0-beta.
|
|
54
|
+
package_default = { version: "0.1.0-beta.7" };
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
|
|
@@ -643,7 +643,7 @@ var init_view_links = __esm({
|
|
|
643
643
|
};
|
|
644
644
|
CLI_RELEASE = {
|
|
645
645
|
packageName: "@buun_group/plotwork",
|
|
646
|
-
version: "0.1.0-beta.
|
|
646
|
+
version: "0.1.0-beta.8",
|
|
647
647
|
onNpm: true
|
|
648
648
|
};
|
|
649
649
|
}
|
|
@@ -662,7 +662,7 @@ var init_mcp_release = __esm({
|
|
|
662
662
|
"use strict";
|
|
663
663
|
MCP_RELEASE = {
|
|
664
664
|
packageName: "@buun_group/plotwork-mcp",
|
|
665
|
-
version: "0.1.0-beta.
|
|
665
|
+
version: "0.1.0-beta.6"
|
|
666
666
|
};
|
|
667
667
|
}
|
|
668
668
|
});
|
|
@@ -6944,7 +6944,11 @@ var init_guide = __esm({
|
|
|
6944
6944
|
helm: { reads: "The output of helm template, or a chart folder (Chart.yaml, charts/, Chart.lock, values.yaml).", draws: "flow as kubernetes framed by release and chart, or a flow of charts and their dependencies", options: "none." },
|
|
6945
6945
|
kustomize: { reads: "The output of kustomize build, or a folder of kustomization.yaml files with what they list.", draws: "flow as kubernetes, or a flow of overlays, bases, and components", options: "none." },
|
|
6946
6946
|
backstage: { reads: "Backstage catalog descriptors (catalog-info.yaml), one file or a folder.", draws: "flow of components, APIs, and resources in systems and domains", options: "groupBy owner: frame by the owning group instead." },
|
|
6947
|
+
structurizr: { reads: "A Structurizr workspace: its DSL (workspace.dsl, with !identifiers hierarchical) or its JSON export.", draws: "c4 of one view: the containers of the first system that has some, or the view the workspace defines first", options: "view context, container, or component; root: the system or container, by identifier or name." },
|
|
6948
|
+
asyncapi: { reads: "AsyncAPI 2.x or 3.x documents in YAML or JSON; send one application's, or a folder of them in files.", draws: "flow of applications and channels in their brokers' frames, an arrow for each send or receive labelled with its messages", options: "none." },
|
|
6947
6949
|
"github-actions": { reads: "A GitHub Actions workflow file.", draws: "flow of the trigger, the jobs in needs order, and their steps", options: "none." },
|
|
6950
|
+
"gitlab-ci": { reads: "A .gitlab-ci.yml; extends and hidden jobs are resolved, include: is not fetched.", draws: "flow of stages as frames in order, jobs by needs or stage after stage, dashed when manual or by rules, triggers to downstream pipelines", options: "none." },
|
|
6951
|
+
"azure-pipelines": { reads: "An azure-pipelines.yml: stages, jobs, and deployment jobs, or a file of only jobs or steps; templates are not fetched.", draws: "flow of stages as frames, jobs by dependsOn at both levels, deployments with their environment", options: "none." },
|
|
6948
6952
|
csv: { reads: "A CSV, TSV, or semicolon-separated table.", draws: "the chart its shape suits: xychart, pie, sankey, treemap, or matrix", options: "chart: auto or one of those." },
|
|
6949
6953
|
json: { reads: "Records, rows, a name to number object, or nested objects of numbers.", draws: "the same charts as csv", options: "chart." },
|
|
6950
6954
|
tree: { reads: "tree output, a list of paths, or an indented outline.", draws: "tree", options: "none." },
|
|
@@ -6958,8 +6962,8 @@ var IMPORT_FORMATS, IMPORT_VIEWS, IMPORT_CHARTS, IMPORT_GROUP_BY, NO_STATS;
|
|
|
6958
6962
|
var init_types2 = __esm({
|
|
6959
6963
|
"../../packages/diagrams/src/importers/types.ts"() {
|
|
6960
6964
|
"use strict";
|
|
6961
|
-
IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "cdk", "compose", "kubernetes", "helm", "kustomize", "backstage", "github-actions", "csv", "json", "tree", "git-log"];
|
|
6962
|
-
IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline"];
|
|
6965
|
+
IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "cdk", "compose", "kubernetes", "helm", "kustomize", "backstage", "structurizr", "asyncapi", "github-actions", "gitlab-ci", "azure-pipelines", "csv", "json", "tree", "git-log"];
|
|
6966
|
+
IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline", "context", "container", "component"];
|
|
6963
6967
|
IMPORT_CHARTS = ["auto", "xychart", "pie", "sankey", "treemap", "matrix"];
|
|
6964
6968
|
IMPORT_GROUP_BY = ["module", "network", "file", "owner"];
|
|
6965
6969
|
NO_STATS = { items: 0, links: 0, groups: 0, dropped: 0 };
|
|
@@ -7023,7 +7027,8 @@ var init_looks = __esm({
|
|
|
7023
7027
|
system: { caption: "Software System", frame: "dashed", icon: null },
|
|
7024
7028
|
container: { caption: "Container", frame: "dashed", icon: null },
|
|
7025
7029
|
enterprise: { caption: "Enterprise", frame: "dashed", icon: null },
|
|
7026
|
-
deployment: { caption: "Deployment Node", frame: "solid", icon: "lucide:server" }
|
|
7030
|
+
deployment: { caption: "Deployment Node", frame: "solid", icon: "lucide:server" },
|
|
7031
|
+
group: { caption: "Group", frame: "dashed", icon: null }
|
|
7027
7032
|
};
|
|
7028
7033
|
}
|
|
7029
7034
|
});
|
|
@@ -102504,13 +102509,13 @@ var init_stretch = __esm({
|
|
|
102504
102509
|
function tryRoutes(scene, changes) {
|
|
102505
102510
|
const old = changes.map(({ edge }) => ({ edge, points: edge.points, label: edge.label, hits: intrusions(scene, edge, edge.points, edge.label) }));
|
|
102506
102511
|
const crossingsOf2 = (edge) => scene.edges.reduce((sum, other) => other === edge ? sum : sum + crossingsNear(edge.points, other.points), 0);
|
|
102507
|
-
const
|
|
102508
|
-
const before = changes.reduce((sum, { edge }) => ({ crossings: sum.crossings + crossingsOf2(edge), runs: sum.runs +
|
|
102512
|
+
const runsOf6 = (edge) => scene.edges.reduce((sum, other) => other === edge ? sum : sum + sharedRuns(edge.points, other.points), 0);
|
|
102513
|
+
const before = changes.reduce((sum, { edge }) => ({ crossings: sum.crossings + crossingsOf2(edge), runs: sum.runs + runsOf6(edge), bends: sum.bends + bends(edge.points) }), { crossings: 0, runs: 0, bends: 0 });
|
|
102509
102514
|
for (const change of changes) {
|
|
102510
102515
|
change.edge.points = change.points;
|
|
102511
102516
|
change.edge.label = change.label;
|
|
102512
102517
|
}
|
|
102513
|
-
const after = changes.reduce((sum, { edge }) => ({ crossings: sum.crossings + crossingsOf2(edge), runs: sum.runs +
|
|
102518
|
+
const after = changes.reduce((sum, { edge }) => ({ crossings: sum.crossings + crossingsOf2(edge), runs: sum.runs + runsOf6(edge), bends: sum.bends + bends(edge.points) }), { crossings: 0, runs: 0, bends: 0 });
|
|
102514
102519
|
const isClean = old.every(({ edge, hits }) => isSubset(intrusions(scene, edge, edge.points, edge.label), hits)) && after.crossings <= before.crossings && after.runs <= before.runs && after.bends <= before.bends;
|
|
102515
102520
|
if (isClean) return true;
|
|
102516
102521
|
for (const { edge, points, label } of old) {
|
|
@@ -105226,7 +105231,7 @@ var init_words = __esm({
|
|
|
105226
105231
|
C4_VIEWS = ["context", "container", "component", "deployment", "dynamic"];
|
|
105227
105232
|
DEFAULT_VIEW = "container";
|
|
105228
105233
|
C4_ELEMENT_WORDS = ["person", "system", "container", "component", "db"];
|
|
105229
|
-
C4_BOUNDARY_KINDS = ["system", "container", "enterprise", "deployment"];
|
|
105234
|
+
C4_BOUNDARY_KINDS = ["system", "container", "enterprise", "deployment", "group"];
|
|
105230
105235
|
DEFAULT_BOUNDARY_KIND = "system";
|
|
105231
105236
|
C4_HEADER_OPTIONS = ["view", "direction", "desc", "icons"];
|
|
105232
105237
|
C4_ELEMENT_OPTIONS = ["desc", "tech", "external", "icon", "tone"];
|
|
@@ -105351,7 +105356,7 @@ function resolveRelationships(state) {
|
|
|
105351
105356
|
const elementIds = new Set(state.elements.map((element) => element.id));
|
|
105352
105357
|
const boundaryIds = new Set(state.boundaries.map((boundary) => boundary.id));
|
|
105353
105358
|
const names8 = [...elementIds];
|
|
105354
|
-
const
|
|
105359
|
+
const resolved2 = [];
|
|
105355
105360
|
let suggested = 0;
|
|
105356
105361
|
for (const pending of state.pending) {
|
|
105357
105362
|
const missing = [pending.from, pending.to].filter((end) => !elementIds.has(end.text));
|
|
@@ -105362,19 +105367,19 @@ function resolveRelationships(state) {
|
|
|
105362
105367
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, message2, spanOf2(end), `${guess}Declare it first with: container ${end.text} "Name"`));
|
|
105363
105368
|
}
|
|
105364
105369
|
if (missing.length > 0) continue;
|
|
105365
|
-
|
|
105366
|
-
id: toEdgeId(
|
|
105370
|
+
resolved2.push({
|
|
105371
|
+
id: toEdgeId(resolved2.length),
|
|
105367
105372
|
from: toNodeId(pending.from.text),
|
|
105368
105373
|
to: toNodeId(pending.to.text),
|
|
105369
105374
|
label: pending.label,
|
|
105370
105375
|
tech: pending.tech,
|
|
105371
105376
|
line: pending.arrow.line,
|
|
105372
105377
|
heads: pending.arrow.heads,
|
|
105373
|
-
...state.view === "dynamic" ? { step: DEFAULT_FIRST_STEP +
|
|
105378
|
+
...state.view === "dynamic" ? { step: DEFAULT_FIRST_STEP + resolved2.length } : {},
|
|
105374
105379
|
at: pending.at
|
|
105375
105380
|
});
|
|
105376
105381
|
}
|
|
105377
|
-
return
|
|
105382
|
+
return resolved2;
|
|
105378
105383
|
}
|
|
105379
105384
|
function dispatch(line3, state, scopes) {
|
|
105380
105385
|
const cursor = new TokenCursor(line3.tokens);
|
|
@@ -106393,7 +106398,7 @@ function c4Vocabulary() {
|
|
|
106393
106398
|
example: 'container api "API Application" tech="Spring Boot" desc="Serves the banking data as JSON."'
|
|
106394
106399
|
},
|
|
106395
106400
|
{
|
|
106396
|
-
syntax: 'boundary <id> "Name" kind=system|container|enterprise|deployment tech="<technology>" {',
|
|
106401
|
+
syntax: 'boundary <id> "Name" kind=system|container|enterprise|deployment|group tech="<technology>" {',
|
|
106397
106402
|
meaning: "Opens a boundary: a frame with its name and a caption such as [Software System] in a corner tab, around the elements written inside it. Boundaries nest, up to four deep, and close with } on a line of its own. A deployment boundary is a solid frame with a server icon, and tech= is its technology, such as Ubuntu 22.04.",
|
|
106398
106403
|
example: 'boundary bank "Internet Banking System" kind=system {'
|
|
106399
106404
|
},
|
|
@@ -108974,15 +108979,15 @@ function resolveRelation(pending, state, ids, known3, index2) {
|
|
|
108974
108979
|
}
|
|
108975
108980
|
function resolveNotes(state) {
|
|
108976
108981
|
const ids = state.classes.map((node3) => node3.id);
|
|
108977
|
-
const
|
|
108982
|
+
const resolved2 = [];
|
|
108978
108983
|
for (const note of state.notes) {
|
|
108979
108984
|
if (note.target !== null && !ids.includes(note.target.text)) {
|
|
108980
108985
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown class "${note.target.text}"`, note.target, `${didYouMean(note.target.text, ids)} A note belongs to a class: note on Order : "text"`));
|
|
108981
108986
|
continue;
|
|
108982
108987
|
}
|
|
108983
|
-
|
|
108988
|
+
resolved2.push({ id: `note${resolved2.length}`, text: note.text, target: note.target === null ? null : toNodeId(note.target.text), at: note.at });
|
|
108984
108989
|
}
|
|
108985
|
-
return
|
|
108990
|
+
return resolved2;
|
|
108986
108991
|
}
|
|
108987
108992
|
function parseClass(lines, report3) {
|
|
108988
108993
|
const state = {
|
|
@@ -109017,8 +109022,8 @@ function parseClass(lines, report3) {
|
|
|
109017
109022
|
const ids = state.classes.map((node3) => node3.id);
|
|
109018
109023
|
const known3 = new Set(ids);
|
|
109019
109024
|
for (const pending of state.relations) {
|
|
109020
|
-
const
|
|
109021
|
-
if (
|
|
109025
|
+
const resolved2 = resolveRelation(pending, state, ids, known3, relations.length);
|
|
109026
|
+
if (resolved2 !== null) relations.push(resolved2);
|
|
109022
109027
|
}
|
|
109023
109028
|
return {
|
|
109024
109029
|
kind: "class",
|
|
@@ -110654,7 +110659,7 @@ function isRefused(member, at3, overlay, seen, state, parents) {
|
|
|
110654
110659
|
function resolveOverlays(state) {
|
|
110655
110660
|
const parents = parentsOf2(state);
|
|
110656
110661
|
const claimedBy = /* @__PURE__ */ new Map();
|
|
110657
|
-
const
|
|
110662
|
+
const resolved2 = [];
|
|
110658
110663
|
for (const overlay of state.overlays) {
|
|
110659
110664
|
const seen = /* @__PURE__ */ new Set();
|
|
110660
110665
|
let isSound = true;
|
|
@@ -110678,9 +110683,9 @@ function resolveOverlays(state) {
|
|
|
110678
110683
|
if (!isSound) continue;
|
|
110679
110684
|
for (const member of overlay.members) claimedBy.set(member, overlay.id);
|
|
110680
110685
|
const { memberAt: _memberAt, ...rest } = overlay;
|
|
110681
|
-
|
|
110686
|
+
resolved2.push(rest);
|
|
110682
110687
|
}
|
|
110683
|
-
return
|
|
110688
|
+
return resolved2;
|
|
110684
110689
|
}
|
|
110685
110690
|
var init_overlay_resolve = __esm({
|
|
110686
110691
|
"../../packages/diagrams/src/parse/overlay-resolve.ts"() {
|
|
@@ -110734,7 +110739,7 @@ function closeScope3(line3, state, scopes) {
|
|
|
110734
110739
|
function resolveEdges(state) {
|
|
110735
110740
|
const nodeIds = state.nodes.map((node3) => node3.id);
|
|
110736
110741
|
const known3 = new Set(nodeIds);
|
|
110737
|
-
const
|
|
110742
|
+
const resolved2 = [];
|
|
110738
110743
|
for (const edge of state.edges) {
|
|
110739
110744
|
const missing = [
|
|
110740
110745
|
{ id: edge.from, token: edge.fromToken },
|
|
@@ -110746,8 +110751,8 @@ function resolveEdges(state) {
|
|
|
110746
110751
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown node "${end.id}"`, end.token, hint2));
|
|
110747
110752
|
}
|
|
110748
110753
|
if (missing.length === 0) {
|
|
110749
|
-
|
|
110750
|
-
id: toEdgeId(
|
|
110754
|
+
resolved2.push({
|
|
110755
|
+
id: toEdgeId(resolved2.length),
|
|
110751
110756
|
from: toNodeId(edge.from),
|
|
110752
110757
|
to: toNodeId(edge.to),
|
|
110753
110758
|
label: edge.label,
|
|
@@ -110760,7 +110765,7 @@ function resolveEdges(state) {
|
|
|
110760
110765
|
});
|
|
110761
110766
|
}
|
|
110762
110767
|
}
|
|
110763
|
-
return
|
|
110768
|
+
return resolved2;
|
|
110764
110769
|
}
|
|
110765
110770
|
function parseFlow(lines, report3) {
|
|
110766
110771
|
const state = {
|
|
@@ -112649,19 +112654,19 @@ function resolve(declaration) {
|
|
|
112649
112654
|
if (fill !== null && tone === null) leftOut.unshift(`fill ${fill} has no tone`);
|
|
112650
112655
|
return { tone, fill, leftOut };
|
|
112651
112656
|
}
|
|
112652
|
-
function report2(state, declaration,
|
|
112657
|
+
function report2(state, declaration, resolved2, subject, isApplied) {
|
|
112653
112658
|
const { reporter } = state.ctx;
|
|
112654
|
-
const leftOut = [...
|
|
112655
|
-
if (
|
|
112659
|
+
const leftOut = [...resolved2.leftOut];
|
|
112660
|
+
if (resolved2.tone !== null && resolved2.fill !== null && isApplied) {
|
|
112656
112661
|
reporter.add(
|
|
112657
112662
|
DIAGNOSTIC_CODES.mermaidMappedToNearest,
|
|
112658
112663
|
declaration.span,
|
|
112659
|
-
`The fill ${
|
|
112664
|
+
`The fill ${resolved2.fill} of ${subject} became the tone ${resolved2.tone}.`,
|
|
112660
112665
|
"Check that the tone says what it means. The theme draws it in light and dark.",
|
|
112661
112666
|
"fill-tone"
|
|
112662
112667
|
);
|
|
112663
|
-
} else if (
|
|
112664
|
-
leftOut.unshift(`fill ${
|
|
112668
|
+
} else if (resolved2.tone !== null && resolved2.fill !== null) {
|
|
112669
|
+
leftOut.unshift(`fill ${resolved2.fill} has no node or subgraph to colour`);
|
|
112665
112670
|
}
|
|
112666
112671
|
if (leftOut.length > 0) reporter.dropped("styleLeftOut", declaration.span, leftOut.join(", "));
|
|
112667
112672
|
}
|
|
@@ -112669,9 +112674,9 @@ function applyStyles(state) {
|
|
|
112669
112674
|
const { builder, ctx } = state;
|
|
112670
112675
|
const classTones = /* @__PURE__ */ new Map();
|
|
112671
112676
|
for (const declaration of state.classDefs) {
|
|
112672
|
-
const
|
|
112673
|
-
if (
|
|
112674
|
-
report2(state, declaration,
|
|
112677
|
+
const resolved2 = resolve(declaration);
|
|
112678
|
+
if (resolved2.tone !== null) for (const name2 of declaration.targets) classTones.set(name2, resolved2.tone);
|
|
112679
|
+
report2(state, declaration, resolved2, `the class ${declaration.targets.map((name2) => `"${name2}"`).join(", ")}`, resolved2.tone !== null);
|
|
112675
112680
|
}
|
|
112676
112681
|
for (const node3 of builder.nodes) {
|
|
112677
112682
|
for (const name2 of node3.classes) {
|
|
@@ -112680,9 +112685,9 @@ function applyStyles(state) {
|
|
|
112680
112685
|
}
|
|
112681
112686
|
}
|
|
112682
112687
|
for (const declaration of state.styles) {
|
|
112683
|
-
const
|
|
112684
|
-
const applied =
|
|
112685
|
-
report2(state, declaration,
|
|
112688
|
+
const resolved2 = resolve(declaration);
|
|
112689
|
+
const applied = resolved2.tone === null ? [] : declaration.targets.filter((target) => builder.setTone(target, resolved2.tone));
|
|
112690
|
+
report2(state, declaration, resolved2, `the style of ${declaration.targets.map((target) => `"${target}"`).join(", ")}`, applied.length > 0);
|
|
112686
112691
|
}
|
|
112687
112692
|
for (const use of state.classUses) {
|
|
112688
112693
|
if (!classTones.has(use.name)) ctx.reporter.dropped("classAssign", use.span, use.name);
|
|
@@ -114278,7 +114283,7 @@ function resolveWindows(ir, calendar, ctx) {
|
|
|
114278
114283
|
if (target === void 0) return fail2(task, `${what} "${key}", which is not a task of this chart.`, hint2);
|
|
114279
114284
|
return windowOf(target, ir.tasks.indexOf(target)) ?? fail2(task, `${what} "${key}", which cannot be placed.`, "Fix that task first, or give this one a start date.");
|
|
114280
114285
|
};
|
|
114281
|
-
const
|
|
114286
|
+
const startOf4 = (task, index2) => {
|
|
114282
114287
|
if (task.start.kind === "date") return task.start.day;
|
|
114283
114288
|
if (task.start.kind === "previous") {
|
|
114284
114289
|
const previous = ir.tasks[index2 - 1];
|
|
@@ -114289,7 +114294,7 @@ function resolveWindows(ir, calendar, ctx) {
|
|
|
114289
114294
|
return ends.length === 0 || ends.includes(null) ? null : Math.max(...ends.map((day) => day ?? 0));
|
|
114290
114295
|
};
|
|
114291
114296
|
const place2 = (task, index2) => {
|
|
114292
|
-
const wanted2 =
|
|
114297
|
+
const wanted2 = startOf4(task, index2);
|
|
114293
114298
|
if (wanted2 === null) return null;
|
|
114294
114299
|
const start2 = task.start.kind === "date" || !calendar.isActive ? wanted2 : nextWorkingDay(calendar, wanted2);
|
|
114295
114300
|
const { end } = task;
|
|
@@ -119403,7 +119408,7 @@ function close(line3, state) {
|
|
|
119403
119408
|
function resolveLinks(state) {
|
|
119404
119409
|
const ids = state.layers.flatMap((layer2) => layer2.blocks.map((block) => block.id));
|
|
119405
119410
|
const inAside = new Set(state.asides.flatMap((aside) => aside.blocks.map((block) => block.id)));
|
|
119406
|
-
const
|
|
119411
|
+
const resolved2 = [];
|
|
119407
119412
|
for (const link2 of state.links) {
|
|
119408
119413
|
const missing = [link2.from, link2.to].filter((end) => !ids.includes(end.text));
|
|
119409
119414
|
for (const end of missing) {
|
|
@@ -119412,9 +119417,9 @@ function resolveLinks(state) {
|
|
|
119412
119417
|
}
|
|
119413
119418
|
if (missing.length > 0) continue;
|
|
119414
119419
|
if (link2.from.text === link2.to.text) syntax(state, `The block "${link2.from.text}" cannot link to itself`, link2.to, "Link two different blocks.");
|
|
119415
|
-
else
|
|
119420
|
+
else resolved2.push({ from: link2.from.text, to: link2.to.text, label: link2.label, line: link2.line, heads: link2.heads });
|
|
119416
119421
|
}
|
|
119417
|
-
return
|
|
119422
|
+
return resolved2;
|
|
119418
119423
|
}
|
|
119419
119424
|
function parseLayers(lines, report3) {
|
|
119420
119425
|
const state = { title: null, description: null, direction: "down", showCounts: false, layers: [], asides: [], links: [], open: [], declared: /* @__PURE__ */ new Map(), report: report3 };
|
|
@@ -127198,14 +127203,14 @@ function resolveEnd(token, tables, report3) {
|
|
|
127198
127203
|
return { table: table2, column: columnName2 };
|
|
127199
127204
|
}
|
|
127200
127205
|
function resolveRelations(state) {
|
|
127201
|
-
const
|
|
127206
|
+
const resolved2 = [];
|
|
127202
127207
|
for (const pending of state.relations) {
|
|
127203
127208
|
const from = resolveEnd(pending.from, state.tables, state.report);
|
|
127204
127209
|
const to = resolveEnd(pending.to, state.tables, state.report);
|
|
127205
127210
|
if (from === null || to === null) continue;
|
|
127206
127211
|
const fromColumn = from.table.columns.find((column) => column.name === from.column);
|
|
127207
|
-
|
|
127208
|
-
id: toEdgeId(
|
|
127212
|
+
resolved2.push({
|
|
127213
|
+
id: toEdgeId(resolved2.length),
|
|
127209
127214
|
fromTable: toTableId(from.table.id),
|
|
127210
127215
|
fromColumn: from.column,
|
|
127211
127216
|
toTable: toTableId(to.table.id),
|
|
@@ -127214,7 +127219,7 @@ function resolveRelations(state) {
|
|
|
127214
127219
|
cardinality: fromColumn?.isPrimaryKey === true || fromColumn?.isUnique === true ? "one-to-one" : "many-to-one"
|
|
127215
127220
|
});
|
|
127216
127221
|
}
|
|
127217
|
-
return
|
|
127222
|
+
return resolved2;
|
|
127218
127223
|
}
|
|
127219
127224
|
function parseSchema(lines, report3) {
|
|
127220
127225
|
const state = { title: null, description: null, tables: [], relations: [], openTable: null, declared: /* @__PURE__ */ new Map(), report: report3 };
|
|
@@ -131287,7 +131292,7 @@ function lineage(id, byId) {
|
|
|
131287
131292
|
}
|
|
131288
131293
|
function resolveTransitions(state, byId) {
|
|
131289
131294
|
const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice" || node3.kind === "fork" || node3.kind === "join" || node3.kind === "history").map((node3) => node3.id);
|
|
131290
|
-
const
|
|
131295
|
+
const resolved2 = [];
|
|
131291
131296
|
let suggested = 0;
|
|
131292
131297
|
for (const pending of state.transitions) {
|
|
131293
131298
|
const missing = [
|
|
@@ -131310,9 +131315,9 @@ function resolveTransitions(state, byId) {
|
|
|
131310
131315
|
continue;
|
|
131311
131316
|
}
|
|
131312
131317
|
const parts = pending.label === null ? { event: null, guard: null, action: null } : splitLabel(pending.label);
|
|
131313
|
-
|
|
131318
|
+
resolved2.push({ id: `t${resolved2.length}`, from: pending.from, to: pending.to, label: pending.label, ...parts, at: pending.at });
|
|
131314
131319
|
}
|
|
131315
|
-
return
|
|
131320
|
+
return resolved2;
|
|
131316
131321
|
}
|
|
131317
131322
|
function resolveNotes2(state, byId) {
|
|
131318
131323
|
const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice").map((node3) => node3.id);
|
|
@@ -132593,7 +132598,7 @@ function parseFlow2(cursor, p, line3) {
|
|
|
132593
132598
|
}
|
|
132594
132599
|
function resolveFlows(p) {
|
|
132595
132600
|
const names8 = p.items.map((item) => item.id);
|
|
132596
|
-
const
|
|
132601
|
+
const resolved2 = [];
|
|
132597
132602
|
let suggested = 0;
|
|
132598
132603
|
for (const pending of p.pending) {
|
|
132599
132604
|
const missing = [pending.from, pending.to].filter((end) => !names8.includes(end.text));
|
|
@@ -132608,9 +132613,9 @@ function resolveFlows(p) {
|
|
|
132608
132613
|
continue;
|
|
132609
132614
|
}
|
|
132610
132615
|
const parts = pending.label === null ? { event: null, guard: null, action: null } : splitLabel(pending.label);
|
|
132611
|
-
|
|
132616
|
+
resolved2.push({ id: `f${resolved2.length}`, from: pending.from.text, to: pending.to.text, label: pending.label, ...parts, line: pending.line, ...pending.step === void 0 ? {} : { step: pending.step }, at: pending.at });
|
|
132612
132617
|
}
|
|
132613
|
-
return
|
|
132618
|
+
return resolved2;
|
|
132614
132619
|
}
|
|
132615
132620
|
function dispatch11(line3, p, scope) {
|
|
132616
132621
|
const cursor = new TokenCursor(line3.tokens);
|
|
@@ -143355,7 +143360,7 @@ var init_schemas = __esm({
|
|
|
143355
143360
|
}
|
|
143356
143361
|
return propValues;
|
|
143357
143362
|
});
|
|
143358
|
-
const
|
|
143363
|
+
const isObject6 = isObject;
|
|
143359
143364
|
const catchall = def.catchall;
|
|
143360
143365
|
let value;
|
|
143361
143366
|
const memo3 = globalConfig.memoizer;
|
|
@@ -143363,7 +143368,7 @@ var init_schemas = __esm({
|
|
|
143363
143368
|
inst._zod.parse = (payload, ctx) => {
|
|
143364
143369
|
value ?? (value = _normalized.value);
|
|
143365
143370
|
const input2 = payload.value;
|
|
143366
|
-
if (!
|
|
143371
|
+
if (!isObject6(input2)) {
|
|
143367
143372
|
payload.issues.push({
|
|
143368
143373
|
expected: "object",
|
|
143369
143374
|
code: "invalid_type",
|
|
@@ -143499,7 +143504,7 @@ var init_schemas = __esm({
|
|
|
143499
143504
|
return doc.compile();
|
|
143500
143505
|
};
|
|
143501
143506
|
let fastpass;
|
|
143502
|
-
const
|
|
143507
|
+
const isObject6 = isObject;
|
|
143503
143508
|
const jit = !globalConfig.jitless;
|
|
143504
143509
|
const allowsEval2 = allowsEval;
|
|
143505
143510
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -143508,7 +143513,7 @@ var init_schemas = __esm({
|
|
|
143508
143513
|
inst._zod.parse = (payload, ctx) => {
|
|
143509
143514
|
value ?? (value = _normalized.value);
|
|
143510
143515
|
const input2 = payload.value;
|
|
143511
|
-
if (!
|
|
143516
|
+
if (!isObject6(input2)) {
|
|
143512
143517
|
payload.issues.push({
|
|
143513
143518
|
expected: "object",
|
|
143514
143519
|
code: "invalid_type",
|
|
@@ -159272,8 +159277,8 @@ function convertBaseSchema(schema, ctx) {
|
|
|
159272
159277
|
});
|
|
159273
159278
|
}
|
|
159274
159279
|
ctx.processing.add(refPath);
|
|
159275
|
-
const
|
|
159276
|
-
const zodSchema2 = convertSchema(
|
|
159280
|
+
const resolved2 = resolveRef(refPath, ctx);
|
|
159281
|
+
const zodSchema2 = convertSchema(resolved2, ctx);
|
|
159277
159282
|
ctx.refs.set(refPath, zodSchema2);
|
|
159278
159283
|
ctx.processing.delete(refPath);
|
|
159279
159284
|
return zodSchema2;
|
|
@@ -161646,9 +161651,9 @@ async function runSync(document2, settings, ops, cache, limit) {
|
|
|
161646
161651
|
const render = async (written3, id) => {
|
|
161647
161652
|
const source = applyDefaults(written3, settings.defaults).source;
|
|
161648
161653
|
if (calls.length >= limit) {
|
|
161649
|
-
const
|
|
161650
|
-
calls.push({ id, source, detail: null, capped });
|
|
161651
|
-
return { diagnostics:
|
|
161654
|
+
const capped2 = calls.length >= settings.countLimit ? "count" : "bytes";
|
|
161655
|
+
calls.push({ id, source, detail: null, capped: capped2 });
|
|
161656
|
+
return { diagnostics: capped2 === "count" ? CAPPED_BY_COUNT : CAPPED_BY_BYTES };
|
|
161652
161657
|
}
|
|
161653
161658
|
const key = `${id}\0${source}`;
|
|
161654
161659
|
let detail = cache.get(key);
|
|
@@ -171949,9 +171954,9 @@ var init_ajvProvider_CEoC_sr = __esm({
|
|
|
171949
171954
|
}
|
|
171950
171955
|
function resolve5(baseURI, relativeURI, options3) {
|
|
171951
171956
|
const schemelessOptions = options3 ? Object.assign({ scheme: "null" }, options3) : { scheme: "null" };
|
|
171952
|
-
const
|
|
171957
|
+
const resolved2 = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
171953
171958
|
schemelessOptions.skipEscape = true;
|
|
171954
|
-
return serialize(
|
|
171959
|
+
return serialize(resolved2, schemelessOptions);
|
|
171955
171960
|
}
|
|
171956
171961
|
function resolveComponent(base, relative, options3, skipNormalization) {
|
|
171957
171962
|
const target = {};
|
|
@@ -178123,7 +178128,7 @@ var init_sources = __esm({
|
|
|
178123
178128
|
tags: external_exports.array(external_exports.string().min(1).max(200)).max(200).optional().describe("openapi: the tags to read."),
|
|
178124
178129
|
groupBy: external_exports.enum(IMPORT_GROUP_BY).optional().describe("terraform, bicep, arm, pulumi, cloudformation, cdk: module (the default) frames each module's resources and nests them by what they name; network nests by what they name alone; file (terraform) frames them by their .tf file; owner (backstage) frames a catalog by the group that owns each entity."),
|
|
178125
178130
|
varFiles: external_exports.array(repositoryPath).max(20).optional().describe("terraform: the variables files to apply, as -var-file would; bicep: the .bicepparam file; arm: the parameters file; pulumi: the Pulumi.<stack>.yaml file."),
|
|
178126
|
-
root: repositoryPath.optional().describe("terraform, bicep, pulumi, cloudformation, cdk: the root module, deployment, program, template, or stack to draw when the files hold several, such as envs/prod; each is a part of its own when left out.")
|
|
178131
|
+
root: repositoryPath.optional().describe("terraform, bicep, pulumi, cloudformation, cdk: the root module, deployment, program, template, or stack to draw when the files hold several, such as envs/prod; each is a part of its own when left out. structurizr: the system or container the view is about.")
|
|
178127
178132
|
}).meta({ id: "SourceOptions", description: "The reader options of one source, as import_source takes them." });
|
|
178128
178133
|
SourcePublishSchema = external_exports.strictObject({
|
|
178129
178134
|
alias: external_exports.string().min(1).max(60).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "An alias is lower-case words joined by single hyphens, such as checkout-flow").optional().describe("A stable link of a personal key: one address that always shows the latest version."),
|
|
@@ -178139,7 +178144,7 @@ var init_sources = __esm({
|
|
|
178139
178144
|
from: external_exports.union([pattern2, external_exports.array(pattern2).min(1).max(GENERATE.maxPatterns)]).describe("The files to read: one pattern or a list."),
|
|
178140
178145
|
format: external_exports.enum(IMPORT_FORMATS).describe("The format of the files, as import_source reads them."),
|
|
178141
178146
|
out: outPath.describe("The diagram to write: a .diagram file, or a Markdown file and the id of a ```diagram id=<id> fence in it."),
|
|
178142
|
-
view: external_exports.enum(IMPORT_VIEWS).optional().describe("openapi: endpoints, map, or sequence; git-log: git or timeline."),
|
|
178147
|
+
view: external_exports.enum(IMPORT_VIEWS).optional().describe("openapi: endpoints, map, or sequence; git-log: git or timeline; structurizr: context, container, or component."),
|
|
178143
178148
|
title: external_exports.string().min(1).max(120).optional().describe("The title of the diagram; the reader takes one from the files when left out."),
|
|
178144
178149
|
options: SourceOptionsSchema.optional(),
|
|
178145
178150
|
overrides: repositoryPath.refine((path) => path.endsWith(".json"), { message: "An overrides file is a .json file" }).optional().describe("The overrides file, applied after every import. Left out: the out path with .overrides.json in place of .diagram, or <file>.<fence id>.overrides.json beside a Markdown file."),
|
|
@@ -183291,6 +183296,8 @@ var init_detect = __esm({
|
|
|
183291
183296
|
{ format: "cdk", test: (text3) => /"?aws:cdk:path"?\s*:/.test(text3) || /"artifacts"\s*:/.test(text3) && /"aws:cloudformation:stack"/.test(text3) },
|
|
183292
183297
|
{ format: "cloudformation", test: (text3) => /^\s*"?AWSTemplateFormatVersion"?\s*:/m.test(text3) || /^Transform\s*:\s*AWS::Serverless/m.test(text3) || /^\s*"?Resources"?\s*:/m.test(text3) && /"?Type"?\s*:\s*["']?AWS::[A-Za-z0-9]+::/.test(text3) },
|
|
183293
183298
|
{ format: "backstage", test: (text3) => /^apiVersion\s*:\s*["']?backstage\.io\//m.test(text3) },
|
|
183299
|
+
{ format: "asyncapi", test: (text3) => /^\s*["']?asyncapi["']?\s*:\s*["']?[23]\./m.test(text3) },
|
|
183300
|
+
{ format: "structurizr", test: (text3) => /^\s*workspace\b[^\n{]*\{/m.test(text3) && /^\s*model\s*\{/m.test(text3) || /^\s*\{/.test(text3) && /"model"\s*:\s*\{/.test(text3) && /"(?:softwareSystems|people)"\s*:\s*\[/.test(text3) },
|
|
183294
183301
|
// A kustomization, or what kustomize build makes of one: a generated ConfigMap or Secret whose name ends in its hash.
|
|
183295
183302
|
{ format: "kustomize", test: (text3) => isKustomization(text3) || /^kind\s*:\s*(?:ConfigMap|Secret)\s*$/m.test(text3) && /^\s+name\s*:\s*[\w.-]+-(?=[^-\s]*\d)[b-df-hj-np-tv-z0-9]{10}\s*$/m.test(text3) },
|
|
183296
183303
|
{ format: "helm", test: (text3) => /^\s*apiVersion\s*:/m.test(text3) && /^\s*kind\s*:\s*\w+/m.test(text3) && (/^# Source: [^\n]*\/templates\//m.test(text3) || /^\s*helm\.sh\/chart\s*:/m.test(text3)) || isChartFile(text3) },
|
|
@@ -183306,9 +183313,13 @@ var init_detect = __esm({
|
|
|
183306
183313
|
NAMES = [
|
|
183307
183314
|
{ format: "compose", words: /\b(?:docker[- ]compose|compose (?:file|yaml|yml|stack))\b/i },
|
|
183308
183315
|
{ format: "backstage", words: /\b(?:backstage|catalog-info(?:\.yaml)?|software catalog)\b/i },
|
|
183316
|
+
{ format: "asyncapi", words: /\b(?:asyncapi|async api)\b/i },
|
|
183317
|
+
{ format: "structurizr", words: /\b(?:structurizr|workspace\.dsl|c4 (?:model|workspace))\b/i },
|
|
183309
183318
|
{ format: "kustomize", words: /\b(?:kustomize|kustomization(?:\.yaml)?)\b/i },
|
|
183310
183319
|
{ format: "helm", words: /\b(?:helm (?:charts?|template|release)|chart\.yaml)\b/i },
|
|
183311
183320
|
{ format: "kubernetes", words: /\b(?:kubernetes|k8s)\b/i },
|
|
183321
|
+
{ format: "gitlab-ci", words: /(?:\.gitlab-ci\.ya?ml\b|\bgitlab(?:[- ]ci| pipelines?| ci\/cd)\b)/i },
|
|
183322
|
+
{ format: "azure-pipelines", words: /(?:\bazure-pipelines\.ya?ml\b|\bazure (?:devops )?pipelines?\b)/i },
|
|
183312
183323
|
{ format: "github-actions", words: /\b(?:github actions?|workflow (?:file|yaml|yml)|ci workflow)\b/i },
|
|
183313
183324
|
{ format: "terraform-plan", words: /\b(?:terraform|tofu) (?:plan|state|show -json)\b|\bplan\.json\b/i },
|
|
183314
183325
|
{ format: "terraform", words: /\b(?:terraform|opentofu|hcl|\.tf files?)\b/i },
|
|
@@ -183326,7 +183337,7 @@ var init_detect = __esm({
|
|
|
183326
183337
|
{ format: "json", words: /\bjson (?:data|file|records|export)\b/i },
|
|
183327
183338
|
{ format: "tree", words: /\b(?:tree output|folder (?:structure|tree|listing)|directory (?:tree|listing))\b/i }
|
|
183328
183339
|
];
|
|
183329
|
-
SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "cdk", "compose", "kubernetes", "helm", "kustomize", "backstage", "github-actions", "git-log"]);
|
|
183340
|
+
SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "cdk", "compose", "kubernetes", "helm", "kustomize", "backstage", "structurizr", "asyncapi", "github-actions", "git-log"]);
|
|
183330
183341
|
}
|
|
183331
183342
|
});
|
|
183332
183343
|
|
|
@@ -183638,8 +183649,8 @@ function rawValue(resource, name2) {
|
|
|
183638
183649
|
return resource.block.attributes.find((attribute2) => attribute2.name === name2)?.raw ?? null;
|
|
183639
183650
|
}
|
|
183640
183651
|
function tagName(resource) {
|
|
183641
|
-
const
|
|
183642
|
-
if (
|
|
183652
|
+
const resolved2 = resource.values.get("tags.Name");
|
|
183653
|
+
if (resolved2 !== void 0 && !resolved2.includes("{")) return resolved2;
|
|
183643
183654
|
const tags = rawValue(resource, "tags");
|
|
183644
183655
|
if (tags === null) return null;
|
|
183645
183656
|
const match = /\bName\s*=\s*"((?:[^"\\$\n]|\\.)*)"/.exec(tags);
|
|
@@ -186358,13 +186369,13 @@ function expression(value, depth) {
|
|
|
186358
186369
|
}
|
|
186359
186370
|
function body5(object2, depth, lines) {
|
|
186360
186371
|
for (const [key, value] of Object.entries(object2)) {
|
|
186361
|
-
const
|
|
186372
|
+
const isObject6 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
|
|
186362
186373
|
if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth > MAX_DEPTH9) lines.push(`${keyOf2(key)} = ${expression(value, depth)}`);
|
|
186363
|
-
else if (
|
|
186374
|
+
else if (isObject6(value)) {
|
|
186364
186375
|
lines.push(`${keyOf2(key)} {`);
|
|
186365
186376
|
body5(value, depth + 1, lines);
|
|
186366
186377
|
lines.push("}");
|
|
186367
|
-
} else if (Array.isArray(value) && value.length > 0 && value.every(
|
|
186378
|
+
} else if (Array.isArray(value) && value.length > 0 && value.every(isObject6)) {
|
|
186368
186379
|
for (const item of value) {
|
|
186369
186380
|
lines.push(`${keyOf2(key)} {`);
|
|
186370
186381
|
body5(item, depth + 1, lines);
|
|
@@ -186975,9 +186986,9 @@ var init_evaluate = __esm({
|
|
|
186975
186986
|
}
|
|
186976
186987
|
case "replace": {
|
|
186977
186988
|
const [value, search, replacement] = args();
|
|
186978
|
-
const [known3,
|
|
186979
|
-
if (known3 === null ||
|
|
186980
|
-
const out = known3.split(
|
|
186989
|
+
const [known3, find2, put] = [value instanceof Partial ? value.name : text3(value), text3(search), text3(replacement)];
|
|
186990
|
+
if (known3 === null || find2 === null || put === null || find2 === "") return value ?? null;
|
|
186991
|
+
const out = known3.split(find2).join(put);
|
|
186981
186992
|
return value instanceof Partial ? new Partial(out) : out;
|
|
186982
186993
|
}
|
|
186983
186994
|
case "take":
|
|
@@ -188815,8 +188826,537 @@ var init_arm = __esm({
|
|
|
188815
188826
|
}
|
|
188816
188827
|
});
|
|
188817
188828
|
|
|
188829
|
+
// ../../packages/diagrams/src/importers/asyncapi/document.ts
|
|
188830
|
+
function nodeOf2(value, depth = 0) {
|
|
188831
|
+
const at3 = { line: 1, column: 1 };
|
|
188832
|
+
if (depth > MAX_DEPTH13 || value === null || value === void 0) return { kind: "scalar", value: "", quoted: false, isNull: true, ...at3 };
|
|
188833
|
+
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) => nodeOf2(item, depth + 1)), ...at3 };
|
|
188834
|
+
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value: nodeOf2(entry2, depth + 1), ...at3 })), ...at3 };
|
|
188835
|
+
return { kind: "scalar", value: String(value), quoted: typeof value === "string", isNull: false, ...at3 };
|
|
188836
|
+
}
|
|
188837
|
+
function readDocument(text3) {
|
|
188838
|
+
if (/^\s*\{/.test(text3)) {
|
|
188839
|
+
try {
|
|
188840
|
+
return { root: nodeOf2(JSON.parse(text3)), problem: null };
|
|
188841
|
+
} catch (error62) {
|
|
188842
|
+
return { root: null, problem: { line: 1, column: 1, message: `The JSON cannot be read: ${error62 instanceof Error ? error62.message : "it is not valid"}.`, hint: "Fix the JSON, often a missing or extra comma or quote." } };
|
|
188843
|
+
}
|
|
188844
|
+
}
|
|
188845
|
+
const read = parseYaml(text3);
|
|
188846
|
+
if (read.error !== null) return { root: null, problem: { ...read.error, message: `The YAML cannot be read: ${read.error.message}` } };
|
|
188847
|
+
return { root: read.documents.find((document2) => document2.root !== null)?.root ?? null, problem: null };
|
|
188848
|
+
}
|
|
188849
|
+
function pointerPart(part) {
|
|
188850
|
+
const plain3 = part.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
188851
|
+
try {
|
|
188852
|
+
return decodeURIComponent(plain3);
|
|
188853
|
+
} catch {
|
|
188854
|
+
return plain3;
|
|
188855
|
+
}
|
|
188856
|
+
}
|
|
188857
|
+
function nameOfRef(ref) {
|
|
188858
|
+
const path = ref.slice(ref.indexOf("#") + 1);
|
|
188859
|
+
const last = path.split("/").filter((part) => part !== "").pop() ?? ref;
|
|
188860
|
+
return pointerPart(last);
|
|
188861
|
+
}
|
|
188862
|
+
function deref(root, node3) {
|
|
188863
|
+
let at3 = node3;
|
|
188864
|
+
for (let hop = 0; hop < MAX_HOPS; hop += 1) {
|
|
188865
|
+
const ref = refOf(at3);
|
|
188866
|
+
if (ref === null || !ref.startsWith("#/")) return at3;
|
|
188867
|
+
let target = root;
|
|
188868
|
+
for (const part of ref.slice(2).split("/")) target = get(target, pointerPart(part));
|
|
188869
|
+
if (target === void 0) return at3;
|
|
188870
|
+
at3 = target;
|
|
188871
|
+
}
|
|
188872
|
+
return at3;
|
|
188873
|
+
}
|
|
188874
|
+
var MAX_HOPS, MAX_DEPTH13, refOf;
|
|
188875
|
+
var init_document2 = __esm({
|
|
188876
|
+
"../../packages/diagrams/src/importers/asyncapi/document.ts"() {
|
|
188877
|
+
"use strict";
|
|
188878
|
+
init_yaml();
|
|
188879
|
+
MAX_HOPS = 10;
|
|
188880
|
+
MAX_DEPTH13 = 64;
|
|
188881
|
+
refOf = (node3) => {
|
|
188882
|
+
const ref = get(node3, "$ref");
|
|
188883
|
+
return ref?.kind === "scalar" ? ref.value : null;
|
|
188884
|
+
};
|
|
188885
|
+
}
|
|
188886
|
+
});
|
|
188887
|
+
|
|
188888
|
+
// ../../packages/diagrams/src/importers/asyncapi/spec.ts
|
|
188889
|
+
function messageName(root, node3, fallback) {
|
|
188890
|
+
const ref = refOf(node3);
|
|
188891
|
+
const message2 = deref(root, node3);
|
|
188892
|
+
return text(get(message2, "name")) ?? text(get(message2, "title")) ?? text(get(message2, "messageId")) ?? fallback ?? (ref === null ? null : nameOfRef(ref));
|
|
188893
|
+
}
|
|
188894
|
+
function messagesOf2(root, operation) {
|
|
188895
|
+
const message2 = get(operation, "message");
|
|
188896
|
+
const resolved2 = deref(root, message2);
|
|
188897
|
+
const choices = items(get(resolved2, "oneOf"));
|
|
188898
|
+
const list = choices.length > 0 ? choices : message2 === void 0 ? [] : [message2];
|
|
188899
|
+
return list.map((node3) => messageName(root, node3, null)).filter((name2) => name2 !== null);
|
|
188900
|
+
}
|
|
188901
|
+
function serversOf(root) {
|
|
188902
|
+
return entries(get(root, "servers")).map((entry2) => {
|
|
188903
|
+
const server = deref(root, entry2.value);
|
|
188904
|
+
const host = text(get(server, "host")) ?? text(get(server, "url"));
|
|
188905
|
+
return { name: entry2.key, protocol: (text(get(server, "protocol")) ?? "").toLowerCase(), host, line: entry2.line, column: entry2.column };
|
|
188906
|
+
});
|
|
188907
|
+
}
|
|
188908
|
+
function channelServers(root, channel) {
|
|
188909
|
+
return items(get(channel, "servers")).map((node3) => text(node3) ?? (refOf(node3) === null ? null : nameOfRef(refOf(node3) ?? ""))).filter((name2) => name2 !== null);
|
|
188910
|
+
}
|
|
188911
|
+
function readVersion2(root) {
|
|
188912
|
+
const channels = [];
|
|
188913
|
+
const operations = [];
|
|
188914
|
+
for (const entry2 of entries(get(root, "channels"))) {
|
|
188915
|
+
const channel = deref(root, entry2.value);
|
|
188916
|
+
channels.push({ id: entry2.key, address: entry2.key, description: text(get(channel, "description")), servers: channelServers(root, channel), line: entry2.line, column: entry2.column });
|
|
188917
|
+
for (const [key, direction] of [["subscribe", "send"], ["publish", "receive"]]) {
|
|
188918
|
+
const operation = get(channel, key);
|
|
188919
|
+
if (operation === void 0) continue;
|
|
188920
|
+
const at3 = channel?.kind === "map" ? channel.entries.find((candidate2) => candidate2.key === key) : void 0;
|
|
188921
|
+
operations.push({ id: text(get(operation, "operationId")) ?? `${key} ${entry2.key}`, channel: entry2.key, direction, messages: messagesOf2(root, operation), line: at3?.line ?? entry2.line, column: at3?.column ?? entry2.column });
|
|
188922
|
+
}
|
|
188923
|
+
}
|
|
188924
|
+
return { channels, operations, unresolved: [] };
|
|
188925
|
+
}
|
|
188926
|
+
function readVersion3(root) {
|
|
188927
|
+
const channels = [];
|
|
188928
|
+
const messagesOfChannel = /* @__PURE__ */ new Map();
|
|
188929
|
+
for (const entry2 of entries(get(root, "channels"))) {
|
|
188930
|
+
const channel = deref(root, entry2.value);
|
|
188931
|
+
channels.push({ id: entry2.key, address: text(get(channel, "address")) ?? entry2.key, description: text(get(channel, "description")) ?? text(get(channel, "summary")), servers: channelServers(root, channel), line: entry2.line, column: entry2.column });
|
|
188932
|
+
messagesOfChannel.set(
|
|
188933
|
+
entry2.key,
|
|
188934
|
+
entries(get(channel, "messages")).map((message2) => messageName(root, message2.value, message2.key)).filter((name2) => name2 !== null)
|
|
188935
|
+
);
|
|
188936
|
+
}
|
|
188937
|
+
const operations = [];
|
|
188938
|
+
const unresolved = [];
|
|
188939
|
+
for (const entry2 of entries(get(root, "operations"))) {
|
|
188940
|
+
const operation = deref(root, entry2.value);
|
|
188941
|
+
const action = text(get(operation, "action"));
|
|
188942
|
+
const ref = refOf(get(operation, "channel"));
|
|
188943
|
+
const channel = ref === null ? null : ref.startsWith("#/channels/") ? nameOfRef(ref) : null;
|
|
188944
|
+
if (channel === null || !messagesOfChannel.has(channel)) {
|
|
188945
|
+
unresolved.push({ name: ref ?? entry2.key, line: entry2.line, column: entry2.column });
|
|
188946
|
+
continue;
|
|
188947
|
+
}
|
|
188948
|
+
if (action !== "send" && action !== "receive") continue;
|
|
188949
|
+
const listed2 = items(get(operation, "messages")).map((node3) => {
|
|
188950
|
+
const target = refOf(node3);
|
|
188951
|
+
const key = target === null ? null : nameOfRef(target);
|
|
188952
|
+
return messageName(root, node3, null) ?? key;
|
|
188953
|
+
}).filter((name2) => name2 !== null);
|
|
188954
|
+
operations.push({ id: entry2.key, channel, direction: action, messages: listed2.length > 0 ? listed2 : messagesOfChannel.get(channel) ?? [], line: entry2.line, column: entry2.column });
|
|
188955
|
+
}
|
|
188956
|
+
return { channels, operations, unresolved };
|
|
188957
|
+
}
|
|
188958
|
+
function majorOf(root) {
|
|
188959
|
+
const version2 = text(get(root, "asyncapi"));
|
|
188960
|
+
if (version2 === null) return null;
|
|
188961
|
+
return version2.startsWith("2.") ? 2 : version2.startsWith("3.") ? 3 : null;
|
|
188962
|
+
}
|
|
188963
|
+
function readApplication(root, major) {
|
|
188964
|
+
const info = get(root, "info");
|
|
188965
|
+
const read = major === 2 ? readVersion2(root) : readVersion3(root);
|
|
188966
|
+
return { title: text(get(info, "title")) ?? "Application", version: text(get(root, "asyncapi")) ?? "", appVersion: text(get(info, "version")), major, servers: serversOf(root), ...read };
|
|
188967
|
+
}
|
|
188968
|
+
var init_spec = __esm({
|
|
188969
|
+
"../../packages/diagrams/src/importers/asyncapi/spec.ts"() {
|
|
188970
|
+
"use strict";
|
|
188971
|
+
init_yaml();
|
|
188972
|
+
init_document2();
|
|
188973
|
+
}
|
|
188974
|
+
});
|
|
188975
|
+
|
|
188976
|
+
// ../../packages/diagrams/src/importers/asyncapi/index.ts
|
|
188977
|
+
function familyOf2(protocol) {
|
|
188978
|
+
if (protocol.startsWith("kafka")) return "kafka";
|
|
188979
|
+
if (protocol.startsWith("amqp")) return "amqp";
|
|
188980
|
+
if (protocol.includes("mqtt")) return "mqtt";
|
|
188981
|
+
if (protocol === "wss") return "ws";
|
|
188982
|
+
if (protocol === "https") return "http";
|
|
188983
|
+
return protocol === "" ? "broker" : protocol;
|
|
188984
|
+
}
|
|
188985
|
+
function messagesLabel(messages) {
|
|
188986
|
+
const unique2 = [...new Set(messages.map((message2) => cleanText(message2)))];
|
|
188987
|
+
if (unique2.length === 0) return null;
|
|
188988
|
+
return unique2.length <= 2 ? unique2.join(", ") : `${unique2[0]} and ${unique2.length - 1} more`;
|
|
188989
|
+
}
|
|
188990
|
+
function readAsyncApi(text3, context) {
|
|
188991
|
+
const index2 = new LineIndex(text3);
|
|
188992
|
+
const files = context.files.map((file2, position) => ({ path: file2.path, start: file2.start, text: text3.slice(file2.start, context.files[position + 1]?.start ?? text3.length) }));
|
|
188993
|
+
const at3 = (file2, line3, column) => index2.span(file2.start + file2.text.split("\n").slice(0, line3 - 1).join("\n").length + (line3 > 1 ? 1 : 0) + column - 1);
|
|
188994
|
+
const applications = [];
|
|
188995
|
+
for (const file2 of files) {
|
|
188996
|
+
const read = readDocument(file2.text);
|
|
188997
|
+
const name2 = cleanText(file2.path, "The file");
|
|
188998
|
+
if (read.problem !== null || read.root === null) {
|
|
188999
|
+
const problem = read.problem ?? { line: 1, column: 1, message: "The file is empty.", hint: "Send an AsyncAPI document." };
|
|
189000
|
+
context.report.add(files.length === 1 ? DIAGNOSTIC_CODES.importUnreadable : DIAGNOSTIC_CODES.importSkipped, at3(file2, problem.line, problem.column), `${files.length === 1 ? "" : `${name2} is not drawn: `}${problem.message}`, problem.hint);
|
|
189001
|
+
if (files.length === 1) return null;
|
|
189002
|
+
continue;
|
|
189003
|
+
}
|
|
189004
|
+
const major = majorOf(read.root);
|
|
189005
|
+
if (major === null) {
|
|
189006
|
+
const said = read.root.kind === "map" && read.root.entries.some((entry2) => entry2.key === "asyncapi") ? "is of an AsyncAPI version this reader does not read" : "has no asyncapi: field, so it is not an AsyncAPI document";
|
|
189007
|
+
if (files.length > 1) context.report.add(DIAGNOSTIC_CODES.importSkipped, at3(file2, 1, 1), `${name2} ${said}, and is not drawn.`, "Send AsyncAPI 2.x or 3.x documents; convert a 1.x document with the AsyncAPI converter.");
|
|
189008
|
+
else context.report.add(DIAGNOSTIC_CODES.importNoShape, START, `The text ${said}.`, "Send an AsyncAPI 2.x or 3.x document, which starts with asyncapi: and a version.");
|
|
189009
|
+
continue;
|
|
189010
|
+
}
|
|
189011
|
+
applications.push({ app: readApplication(read.root, major), file: file2 });
|
|
189012
|
+
}
|
|
189013
|
+
if (applications.length === 0) {
|
|
189014
|
+
if (files.length > 1) context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "None of the files is an AsyncAPI document.", "Send AsyncAPI 2.x or 3.x documents, each starting with asyncapi: and a version.");
|
|
189015
|
+
return null;
|
|
189016
|
+
}
|
|
189017
|
+
const nodes = [];
|
|
189018
|
+
const groups = [];
|
|
189019
|
+
const edges = [];
|
|
189020
|
+
const arrows = /* @__PURE__ */ new Map();
|
|
189021
|
+
const channelBox = /* @__PURE__ */ new Map();
|
|
189022
|
+
const brokerHosts = /* @__PURE__ */ new Map();
|
|
189023
|
+
const brokerServers = /* @__PURE__ */ new Map();
|
|
189024
|
+
let operations = 0;
|
|
189025
|
+
for (const { app, file: file2 } of applications) {
|
|
189026
|
+
for (const problem of app.unresolved) context.report.add(DIAGNOSTIC_CODES.importUnresolved, at3(file2, problem.line, problem.column), `The operation names a channel the document does not hold: ${cleanText(problem.name)}, so no arrow is drawn for it.`, "Point channel at an entry of channels, such as $ref: '#/channels/orderPlaced'.");
|
|
189027
|
+
const appKey = `app:${app.title}`;
|
|
189028
|
+
if (!nodes.some((node3) => node3.key === appKey)) nodes.push({ key: appKey, type: "service", label: cleanText(app.title), sub: app.appVersion === null ? null : `Version ${cleanText(app.appVersion)}`, idHint: app.title.toLowerCase() });
|
|
189029
|
+
const serverFamily = new Map(app.servers.map((server) => [server.name, familyOf2(server.protocol)]));
|
|
189030
|
+
for (const server of app.servers) {
|
|
189031
|
+
const family = familyOf2(server.protocol);
|
|
189032
|
+
brokerServers.set(family, [...brokerServers.get(family) ?? [], server]);
|
|
189033
|
+
if (server.host !== null) brokerHosts.set(family, (brokerHosts.get(family) ?? /* @__PURE__ */ new Set()).add(server.host));
|
|
189034
|
+
}
|
|
189035
|
+
for (const channel of app.channels) {
|
|
189036
|
+
const families = new Set((channel.servers.length > 0 ? channel.servers : app.servers.map((server) => server.name)).map((name2) => serverFamily.get(name2)).filter((family2) => family2 !== void 0));
|
|
189037
|
+
const family = families.size === 1 ? [...families][0] : void 0;
|
|
189038
|
+
const key = `channel:${channel.address}`;
|
|
189039
|
+
const existing = channelBox.get(key);
|
|
189040
|
+
if (existing === void 0) {
|
|
189041
|
+
const box = { key, type: "queue", label: cleanText(channel.address), sub: channel.description === null ? null : cleanText(channel.description), group: family === void 0 ? null : `broker:${family}`, idHint: channel.address };
|
|
189042
|
+
channelBox.set(key, box);
|
|
189043
|
+
nodes.push(box);
|
|
189044
|
+
}
|
|
189045
|
+
}
|
|
189046
|
+
for (const operation of app.operations) {
|
|
189047
|
+
const channel = app.channels.find((candidate2) => candidate2.id === operation.channel);
|
|
189048
|
+
if (channel === void 0) continue;
|
|
189049
|
+
const channelKey = `channel:${channel.address}`;
|
|
189050
|
+
operations += 1;
|
|
189051
|
+
const [from, to] = operation.direction === "send" ? [appKey, channelKey] : [channelKey, appKey];
|
|
189052
|
+
const pair2 = `${from}\0${to}`;
|
|
189053
|
+
arrows.set(pair2, { from, to, messages: [...arrows.get(pair2)?.messages ?? [], ...operation.messages] });
|
|
189054
|
+
}
|
|
189055
|
+
}
|
|
189056
|
+
for (const arrow of arrows.values()) edges.push({ from: arrow.from, to: arrow.to, label: messagesLabel(arrow.messages) });
|
|
189057
|
+
const usedFamilies = new Set(nodes.map((node3) => node3.group).filter((group2) => group2 !== null && group2 !== void 0));
|
|
189058
|
+
for (const family of [...brokerServers.keys()]) {
|
|
189059
|
+
const key = `broker:${family}`;
|
|
189060
|
+
if (!usedFamilies.has(key)) continue;
|
|
189061
|
+
const broker = BROKERS[family];
|
|
189062
|
+
const hosts = [...brokerHosts.get(family) ?? []];
|
|
189063
|
+
const servers = brokerServers.get(family) ?? [];
|
|
189064
|
+
const named = servers.map((server) => iconForName(`${server.name} ${server.host ?? ""}`, "queue")).find((icon) => icon?.startsWith("simple:") === true) ?? null;
|
|
189065
|
+
const where = hosts.length === 0 ? null : hosts.length === 1 ? hosts[0] ?? null : `${hosts.length} hosts`;
|
|
189066
|
+
groups.push({ key, label: broker?.label ?? `${family.toUpperCase()} broker`, type: "messaging", icon: broker?.icon ?? named, sub: where === null ? null : cleanText(where), idHint: family });
|
|
189067
|
+
}
|
|
189068
|
+
const unused = [...brokerServers.entries()].filter(([family]) => !usedFamilies.has(`broker:${family}`)).flatMap(([, servers]) => servers);
|
|
189069
|
+
if (unused.length > 0) {
|
|
189070
|
+
const first = unused[0];
|
|
189071
|
+
const file2 = applications.find(({ app }) => app.servers.includes(first))?.file ?? files[0];
|
|
189072
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, at3(file2, first.line, first.column), `${countOf2(unused.length, "server")} carr${unused.length === 1 ? "ies" : "y"} no channel that is drawn in a frame, so ${unused.length === 1 ? "it is" : "they are"} not drawn: ${unused.slice(0, 3).map((server) => cleanText(server.name)).join(", ")}.`, "Name the servers of each channel with servers:, so each channel sits in the frame of its broker.");
|
|
189073
|
+
}
|
|
189074
|
+
const sends = (key) => edges.some((edge) => edge.from === key);
|
|
189075
|
+
const receives = (key) => edges.some((edge) => edge.to === key);
|
|
189076
|
+
const rank = (node3) => node3.type === "queue" ? 1 : sends(node3.key) && !receives(node3.key) ? 0 : !sends(node3.key) && receives(node3.key) ? 2 : 1;
|
|
189077
|
+
const ordered = [...nodes].sort((a, b) => rank(a) - rank(b));
|
|
189078
|
+
const one = applications.length === 1 ? applications[0]?.app : void 0;
|
|
189079
|
+
const channels = channelBox.size;
|
|
189080
|
+
return writeFlow(
|
|
189081
|
+
{
|
|
189082
|
+
title: context.title ?? (one === void 0 ? "Event flows" : cleanText(one.title)),
|
|
189083
|
+
desc: one === void 0 ? `${countOf2(applications.length, "application")} and the ${countOf2(channels, "channel")} where they meet: an arrow into a channel sends to it, an arrow out of one receives from it, labelled with the messages. Imported from AsyncAPI.` : `What ${cleanText(one.title)} sends and receives on ${countOf2(channels, "channel")}: an arrow into a channel sends to it, an arrow out of one receives from it, labelled with the messages. Imported from AsyncAPI ${cleanText(one.version)}.`,
|
|
189084
|
+
direction: "right",
|
|
189085
|
+
nodes: ordered,
|
|
189086
|
+
groups,
|
|
189087
|
+
edges,
|
|
189088
|
+
noun: "channels",
|
|
189089
|
+
advice: one === void 0 ? "Check that each channel has the same address in every file that uses it, so producers and consumers meet on one box." : "Import the AsyncAPI documents of the other applications with this one, as files, to see who sends and who receives on each channel.",
|
|
189090
|
+
coverage: { noun: "channels and operations", total: channels + operations, drawn: channels + operations, summarised: 0 }
|
|
189091
|
+
},
|
|
189092
|
+
context.report
|
|
189093
|
+
);
|
|
189094
|
+
}
|
|
189095
|
+
var BROKERS, asyncapiImporter;
|
|
189096
|
+
var init_asyncapi = __esm({
|
|
189097
|
+
"../../packages/diagrams/src/importers/asyncapi/index.ts"() {
|
|
189098
|
+
"use strict";
|
|
189099
|
+
init_core();
|
|
189100
|
+
init_shared2();
|
|
189101
|
+
init_document2();
|
|
189102
|
+
init_spec();
|
|
189103
|
+
BROKERS = {
|
|
189104
|
+
kafka: { label: "Kafka", icon: "simple:apachekafka" },
|
|
189105
|
+
amqp: { label: "AMQP broker", icon: null },
|
|
189106
|
+
mqtt: { label: "MQTT broker", icon: null },
|
|
189107
|
+
nats: { label: "NATS", icon: null },
|
|
189108
|
+
redis: { label: "Redis", icon: "simple:redis" },
|
|
189109
|
+
pulsar: { label: "Pulsar", icon: "simple:apachepulsar" },
|
|
189110
|
+
sns: { label: "Amazon SNS", icon: "aws:sns" },
|
|
189111
|
+
sqs: { label: "Amazon SQS", icon: "aws:sqs" },
|
|
189112
|
+
googlepubsub: { label: "Google Pub/Sub", icon: "gcp:pubsub" },
|
|
189113
|
+
ibmmq: { label: "IBM MQ", icon: null },
|
|
189114
|
+
jms: { label: "JMS broker", icon: null },
|
|
189115
|
+
solace: { label: "Solace", icon: null },
|
|
189116
|
+
stomp: { label: "STOMP broker", icon: null },
|
|
189117
|
+
ws: { label: "WebSocket", icon: null },
|
|
189118
|
+
http: { label: "HTTP", icon: null },
|
|
189119
|
+
anypointmq: { label: "Anypoint MQ", icon: null },
|
|
189120
|
+
mercure: { label: "Mercure", icon: null }
|
|
189121
|
+
};
|
|
189122
|
+
asyncapiImporter = { format: "asyncapi", kinds: ["flow"], joins: "\n", extensions: [".yaml", ".yml", ".json"], read: readAsyncApi };
|
|
189123
|
+
}
|
|
189124
|
+
});
|
|
189125
|
+
|
|
189126
|
+
// ../../packages/diagrams/src/importers/azure-pipelines/pipeline.ts
|
|
189127
|
+
function dependsOnOf2(node3) {
|
|
189128
|
+
const value = get(node3, "dependsOn");
|
|
189129
|
+
if (value === void 0) return null;
|
|
189130
|
+
return items(value).map((item) => text(item)).filter((name2) => name2 !== null && name2 !== "");
|
|
189131
|
+
}
|
|
189132
|
+
function stepLabel(step) {
|
|
189133
|
+
const named = text(get(step, "displayName")) ?? text(get(step, "name"));
|
|
189134
|
+
if (named !== null) return named;
|
|
189135
|
+
const task = text(get(step, "task"));
|
|
189136
|
+
if (task !== null) return task.split("@")[0] ?? task;
|
|
189137
|
+
const checkout = text(get(step, "checkout"));
|
|
189138
|
+
if (checkout !== null) return checkout === "none" ? "No checkout" : `Check out ${checkout}`;
|
|
189139
|
+
for (const key of ["script", "bash", "pwsh", "powershell"]) {
|
|
189140
|
+
const script = text(get(step, key));
|
|
189141
|
+
if (script === null) continue;
|
|
189142
|
+
const first = script.split("\n").map((line3) => line3.trim()).find((line3) => line3 !== "" && !line3.startsWith("#")) ?? "Run a script";
|
|
189143
|
+
if (first.length <= MAX_STEP_LABEL) return first;
|
|
189144
|
+
const cut = first.slice(0, MAX_STEP_LABEL);
|
|
189145
|
+
return cut.lastIndexOf(" ") > 12 ? cut.slice(0, cut.lastIndexOf(" ")) : cut;
|
|
189146
|
+
}
|
|
189147
|
+
for (const key of ["download", "publish", "getPackage", "restoreCache", "reviewApp"]) if (get(step, key) !== void 0) return `${key.charAt(0).toUpperCase()}${key.slice(1)} ${text(get(step, key)) ?? ""}`.trim();
|
|
189148
|
+
return "Step";
|
|
189149
|
+
}
|
|
189150
|
+
function stepsOf(list, templates) {
|
|
189151
|
+
const out = [];
|
|
189152
|
+
for (const step of items(list)) {
|
|
189153
|
+
const template = text(get(step, "template"));
|
|
189154
|
+
if (template !== null) templates.push({ path: template, line: step.line, column: step.column });
|
|
189155
|
+
else if (step.kind === "map") out.push({ label: cleanText(stepLabel(step), "Step"), line: step.line, column: step.column });
|
|
189156
|
+
}
|
|
189157
|
+
return out;
|
|
189158
|
+
}
|
|
189159
|
+
function poolOf(node3, fallback) {
|
|
189160
|
+
const pool = get(node3, "pool");
|
|
189161
|
+
if (pool === void 0) return fallback;
|
|
189162
|
+
return text(pool) ?? text(get(pool, "vmImage")) ?? text(get(pool, "name")) ?? fallback;
|
|
189163
|
+
}
|
|
189164
|
+
function deploymentSteps(job, templates) {
|
|
189165
|
+
const strategy = get(job, "strategy");
|
|
189166
|
+
return entries(strategy).flatMap((kind) => entries(kind.value).flatMap((hook) => (hook.key === "on" ? entries(hook.value).map((when) => when.value) : [hook.value]).flatMap((phase) => stepsOf(get(phase, "steps"), templates))));
|
|
189167
|
+
}
|
|
189168
|
+
function jobsOf(list, pool, templates) {
|
|
189169
|
+
const out = [];
|
|
189170
|
+
for (const job of items(list)) {
|
|
189171
|
+
const template = text(get(job, "template"));
|
|
189172
|
+
if (template !== null) {
|
|
189173
|
+
templates.push({ path: template, line: job.line, column: job.column });
|
|
189174
|
+
continue;
|
|
189175
|
+
}
|
|
189176
|
+
const deployment = text(get(job, "deployment"));
|
|
189177
|
+
const name2 = deployment ?? text(get(job, "job"));
|
|
189178
|
+
if (name2 === null) continue;
|
|
189179
|
+
const strategy = get(job, "strategy");
|
|
189180
|
+
const matrix = entries(get(strategy, "matrix")).length;
|
|
189181
|
+
const parallel = Number(text(get(strategy, "parallel")));
|
|
189182
|
+
const environment = get(job, "environment");
|
|
189183
|
+
out.push({
|
|
189184
|
+
name: name2,
|
|
189185
|
+
label: cleanText(text(get(job, "displayName")) ?? name2, name2),
|
|
189186
|
+
dependsOn: dependsOnOf2(job),
|
|
189187
|
+
conditional: get(job, "condition") !== void 0,
|
|
189188
|
+
environment: deployment === null ? null : text(environment) ?? text(get(environment, "name")),
|
|
189189
|
+
pool: poolOf(job, pool),
|
|
189190
|
+
runs: matrix > 1 ? matrix : Number.isInteger(parallel) && parallel > 1 ? parallel : 1,
|
|
189191
|
+
matrix: matrix > 1,
|
|
189192
|
+
steps: deployment === null ? stepsOf(get(job, "steps"), templates) : deploymentSteps(job, templates),
|
|
189193
|
+
line: job.line,
|
|
189194
|
+
column: job.column
|
|
189195
|
+
});
|
|
189196
|
+
}
|
|
189197
|
+
return out;
|
|
189198
|
+
}
|
|
189199
|
+
function readPipeline(root) {
|
|
189200
|
+
const templates = [];
|
|
189201
|
+
const extended2 = text(get(get(root, "extends"), "template"));
|
|
189202
|
+
if (extended2 !== null) {
|
|
189203
|
+
const at3 = root.kind === "map" ? root.entries.find((entry2) => entry2.key === "extends") : void 0;
|
|
189204
|
+
templates.push({ path: extended2, line: at3?.line ?? 1, column: at3?.column ?? 1 });
|
|
189205
|
+
}
|
|
189206
|
+
const pool = poolOf(root, null);
|
|
189207
|
+
if (get(root, "stages") !== void 0) {
|
|
189208
|
+
const stages = [];
|
|
189209
|
+
for (const stage of items(get(root, "stages"))) {
|
|
189210
|
+
const template = text(get(stage, "template"));
|
|
189211
|
+
if (template !== null) {
|
|
189212
|
+
templates.push({ path: template, line: stage.line, column: stage.column });
|
|
189213
|
+
continue;
|
|
189214
|
+
}
|
|
189215
|
+
const name2 = text(get(stage, "stage"));
|
|
189216
|
+
if (name2 === null) continue;
|
|
189217
|
+
stages.push({ name: name2, label: cleanText(text(get(stage, "displayName")) ?? name2, name2), dependsOn: dependsOnOf2(stage), conditional: get(stage, "condition") !== void 0, jobs: jobsOf(get(stage, "jobs"), poolOf(stage, pool), templates), line: stage.line, column: stage.column });
|
|
189218
|
+
}
|
|
189219
|
+
return { stages, shape: "stages", templates };
|
|
189220
|
+
}
|
|
189221
|
+
if (get(root, "jobs") !== void 0) return { stages: [{ name: "", label: "", dependsOn: [], conditional: false, jobs: jobsOf(get(root, "jobs"), pool, templates), line: 1, column: 1 }], shape: "jobs", templates };
|
|
189222
|
+
const steps = stepsOf(get(root, "steps"), templates);
|
|
189223
|
+
const job = { name: "Job", label: "Job", dependsOn: null, conditional: false, environment: null, pool, runs: 1, matrix: false, steps, line: 1, column: 1 };
|
|
189224
|
+
return { stages: steps.length === 0 ? [] : [{ name: "", label: "", dependsOn: [], conditional: false, jobs: [job], line: 1, column: 1 }], shape: "steps", templates };
|
|
189225
|
+
}
|
|
189226
|
+
var MAX_STEP_LABEL;
|
|
189227
|
+
var init_pipeline = __esm({
|
|
189228
|
+
"../../packages/diagrams/src/importers/azure-pipelines/pipeline.ts"() {
|
|
189229
|
+
"use strict";
|
|
189230
|
+
init_shared2();
|
|
189231
|
+
init_yaml();
|
|
189232
|
+
MAX_STEP_LABEL = 48;
|
|
189233
|
+
}
|
|
189234
|
+
});
|
|
189235
|
+
|
|
189236
|
+
// ../../packages/diagrams/src/importers/azure-pipelines/index.ts
|
|
189237
|
+
function subOf(job, stage) {
|
|
189238
|
+
const parts = [
|
|
189239
|
+
job.conditional || stage.conditional ? "when its condition holds" : null,
|
|
189240
|
+
job.runs > 1 ? `${job.runs} ${job.matrix ? "matrix" : "parallel"} runs` : null,
|
|
189241
|
+
job.environment === null ? null : `deploys to ${job.environment}`,
|
|
189242
|
+
job.pool,
|
|
189243
|
+
job.steps.length === 0 ? null : countOf2(job.steps.length, "step")
|
|
189244
|
+
].filter((part) => part !== null);
|
|
189245
|
+
return parts.length === 0 ? null : cleanText(parts.join(", "));
|
|
189246
|
+
}
|
|
189247
|
+
function readAzurePipelines(source, context) {
|
|
189248
|
+
const read = parseYaml(source);
|
|
189249
|
+
if (read.error !== null) {
|
|
189250
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
189251
|
+
return null;
|
|
189252
|
+
}
|
|
189253
|
+
const root = read.documents.find((document2) => document2.root?.kind === "map")?.root ?? null;
|
|
189254
|
+
const pipeline = root === null ? null : readPipeline(root);
|
|
189255
|
+
const firstTemplate = pipeline?.templates[0];
|
|
189256
|
+
if (pipeline !== null && firstTemplate !== void 0) {
|
|
189257
|
+
const paths = [...new Set(pipeline.templates.map((template) => cleanText(template.path)))];
|
|
189258
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, spanAt3(firstTemplate.line, firstTemplate.column), `${countOf2(paths.length, "template")} ${paths.length === 1 ? "is" : "are"} not fetched, so what ${paths.length === 1 ? "it adds is" : "they add is"} not drawn: ${paths.slice(0, 3).join(", ")}.`, "Import the template files too, or draw this file knowing their stages, jobs, and steps are missing.");
|
|
189259
|
+
}
|
|
189260
|
+
if (pipeline === null || pipeline.stages.every((stage) => stage.jobs.length === 0)) {
|
|
189261
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The file has no stages, jobs, or steps of its own.", "Send an azure-pipelines.yml with stages:, jobs:, or steps:.");
|
|
189262
|
+
return null;
|
|
189263
|
+
}
|
|
189264
|
+
const stages = pipeline.stages.filter((stage) => stage.jobs.length > 0);
|
|
189265
|
+
const nodes = [{ key: START_KEY, type: "terminal", label: "Pipeline starts" }];
|
|
189266
|
+
const groups = [];
|
|
189267
|
+
const edges = [];
|
|
189268
|
+
const unresolved = [];
|
|
189269
|
+
if (pipeline.shape === "steps") {
|
|
189270
|
+
const job = stages[0]?.jobs[0];
|
|
189271
|
+
job.steps.forEach((step, index2) => nodes.push({ key: `step:${index2}`, type: "step", label: step.label, idHint: `step_${index2 + 1}` }));
|
|
189272
|
+
job.steps.forEach((_step, index2) => edges.push({ from: index2 === 0 ? START_KEY : `step:${index2 - 1}`, to: `step:${index2}` }));
|
|
189273
|
+
return writeFlow(
|
|
189274
|
+
{
|
|
189275
|
+
title: context.title ?? "Azure pipeline",
|
|
189276
|
+
desc: `The ${countOf2(job.steps.length, "step")} of an Azure pipeline of one job${job.pool === null ? "" : ` on ${cleanText(job.pool)}`}, in order. Imported from Azure Pipelines.`,
|
|
189277
|
+
direction: "down",
|
|
189278
|
+
nodes,
|
|
189279
|
+
groups,
|
|
189280
|
+
edges,
|
|
189281
|
+
noun: "steps",
|
|
189282
|
+
coverage: { noun: "steps", total: job.steps.length, drawn: job.steps.length, summarised: 0 },
|
|
189283
|
+
advice: "Give each step a displayName, so the picture says what it does."
|
|
189284
|
+
},
|
|
189285
|
+
context.report
|
|
189286
|
+
);
|
|
189287
|
+
}
|
|
189288
|
+
const keyOf5 = (stage, job) => pipeline.shape === "jobs" ? `job:${job.name}` : `job:${stage.name}.${job.name}`;
|
|
189289
|
+
const stageNames = new Set(pipeline.stages.map((stage) => stage.name));
|
|
189290
|
+
for (const stage of stages) {
|
|
189291
|
+
if (pipeline.shape === "stages") groups.push({ key: `stage:${stage.name}`, label: stage.label, type: "ci-cd", idHint: `stage_${hintOf(stage.name)}` });
|
|
189292
|
+
for (const job of stage.jobs) nodes.push({ key: keyOf5(stage, job), type: "step", label: job.label, sub: subOf(job, stage), group: pipeline.shape === "stages" ? `stage:${stage.name}` : null, idHint: hintOf(job.name) });
|
|
189293
|
+
}
|
|
189294
|
+
const inStage = (stage, job) => (job.dependsOn ?? []).filter((name2) => stage.jobs.some((other) => other.name === name2));
|
|
189295
|
+
const firstJobs = (stage) => stage.jobs.filter((job) => inStage(stage, job).length === 0);
|
|
189296
|
+
const lastJobs = (stage) => stage.jobs.filter((job) => !stage.jobs.some((other) => inStage(stage, other).includes(job.name)));
|
|
189297
|
+
stages.forEach((stage, index2) => {
|
|
189298
|
+
const dashed = (job) => job.conditional || stage.conditional ? "-->" : void 0;
|
|
189299
|
+
const link2 = (from, job) => {
|
|
189300
|
+
const arrow = dashed(job);
|
|
189301
|
+
edges.push({ from, to: keyOf5(stage, job), ...arrow === void 0 ? {} : { arrow } });
|
|
189302
|
+
};
|
|
189303
|
+
const before = stage.dependsOn === null ? index2 === 0 ? [] : [stages[index2 - 1]] : stage.dependsOn.flatMap((name2) => {
|
|
189304
|
+
const found = stages.find((other) => other.name === name2);
|
|
189305
|
+
if (found === void 0 && !stageNames.has(name2)) unresolved.push({ name: `stage ${name2}`, line: stage.line, column: stage.column });
|
|
189306
|
+
return found === void 0 ? [] : [found];
|
|
189307
|
+
});
|
|
189308
|
+
for (const job of stage.jobs) {
|
|
189309
|
+
for (const name2 of job.dependsOn ?? []) {
|
|
189310
|
+
if (stage.jobs.some((other) => other.name === name2)) link2(keyOf5(stage, stage.jobs.find((other) => other.name === name2)), job);
|
|
189311
|
+
else unresolved.push({ name: `job ${name2}`, line: job.line, column: job.column });
|
|
189312
|
+
}
|
|
189313
|
+
}
|
|
189314
|
+
for (const job of firstJobs(stage)) {
|
|
189315
|
+
if (before.length === 0) link2(START_KEY, job);
|
|
189316
|
+
for (const previous of before) for (const last of lastJobs(previous)) link2(keyOf5(previous, last), job);
|
|
189317
|
+
}
|
|
189318
|
+
});
|
|
189319
|
+
const first = unresolved[0];
|
|
189320
|
+
if (first !== void 0) {
|
|
189321
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(first.line, first.column), `${countOf2(unresolved.length, "dependsOn")} name${unresolved.length === 1 ? "s" : ""} what the file does not hold, so no arrow is drawn for ${unresolved.length === 1 ? "it" : "them"}: ${unresolved.slice(0, 3).map((entry2) => cleanText(entry2.name)).join(", ")}.`, "Fix the name in dependsOn, or import the template that defines it.");
|
|
189322
|
+
}
|
|
189323
|
+
const jobs = stages.reduce((sum, stage) => sum + stage.jobs.length, 0);
|
|
189324
|
+
const deployments = stages.reduce((sum, stage) => sum + stage.jobs.filter((job) => job.environment !== null).length, 0);
|
|
189325
|
+
return writeFlow(
|
|
189326
|
+
{
|
|
189327
|
+
title: context.title ?? "Azure pipeline",
|
|
189328
|
+
desc: `${countOf2(jobs, "job")}${pipeline.shape === "stages" ? ` in ${countOf2(stages.length, "stage")}` : ""}${deployments === 0 ? "" : `, ${deployments} of which ${deployments === 1 ? "deploys" : "deploy"} to an environment`}, in the order dependsOn sets. A dashed arrow reaches a job that runs only when its condition holds. Imported from Azure Pipelines.`,
|
|
189329
|
+
direction: "down",
|
|
189330
|
+
nodes,
|
|
189331
|
+
groups,
|
|
189332
|
+
edges,
|
|
189333
|
+
noun: "jobs",
|
|
189334
|
+
capSpan: (key) => {
|
|
189335
|
+
const job = stages.flatMap((stage) => stage.jobs.map((entry2) => ({ key: keyOf5(stage, entry2), entry: entry2 }))).find((candidate2) => candidate2.key === key)?.entry;
|
|
189336
|
+
return spanAt3(job?.line ?? 1, job?.column ?? 1);
|
|
189337
|
+
},
|
|
189338
|
+
coverage: { noun: "jobs", total: jobs, drawn: jobs, summarised: 0 },
|
|
189339
|
+
advice: "Give each stage and job a displayName, so the picture says what it does."
|
|
189340
|
+
},
|
|
189341
|
+
context.report
|
|
189342
|
+
);
|
|
189343
|
+
}
|
|
189344
|
+
var hintOf, START_KEY, azurePipelinesImporter;
|
|
189345
|
+
var init_azure_pipelines = __esm({
|
|
189346
|
+
"../../packages/diagrams/src/importers/azure-pipelines/index.ts"() {
|
|
189347
|
+
"use strict";
|
|
189348
|
+
init_core();
|
|
189349
|
+
init_shared2();
|
|
189350
|
+
init_yaml();
|
|
189351
|
+
init_pipeline();
|
|
189352
|
+
hintOf = (name2) => name2.replace(/([a-z0-9])([A-Z][a-z])/g, "$1_$2").toLowerCase();
|
|
189353
|
+
START_KEY = "pipeline";
|
|
189354
|
+
azurePipelinesImporter = { format: "azure-pipelines", kinds: ["flow"], joins: null, extensions: [], read: readAzurePipelines };
|
|
189355
|
+
}
|
|
189356
|
+
});
|
|
189357
|
+
|
|
188818
189358
|
// ../../packages/diagrams/src/importers/backstage/entities.ts
|
|
188819
|
-
function
|
|
189359
|
+
function refOf2(written3, fallbackKind, namespace) {
|
|
188820
189360
|
const colon = written3.indexOf(":");
|
|
188821
189361
|
const kind = colon === -1 ? fallbackKind : written3.slice(0, colon).toLowerCase();
|
|
188822
189362
|
const rest = colon === -1 ? written3 : written3.slice(colon + 1);
|
|
@@ -188833,9 +189373,9 @@ function readEntity2(root) {
|
|
|
188833
189373
|
const spec = get(root, "spec");
|
|
188834
189374
|
const one = (key, fallback) => {
|
|
188835
189375
|
const value = text(get(spec, key));
|
|
188836
|
-
return value === null || value === "" ? null :
|
|
189376
|
+
return value === null || value === "" ? null : refOf2(value, fallback, namespace);
|
|
188837
189377
|
};
|
|
188838
|
-
const many = (key, fallback) => names5(get(spec, key)).map((value) =>
|
|
189378
|
+
const many = (key, fallback) => names5(get(spec, key)).map((value) => refOf2(value, fallback, namespace));
|
|
188839
189379
|
return {
|
|
188840
189380
|
kind,
|
|
188841
189381
|
ref: `${kind.toLowerCase()}:${namespace}/${name2}`,
|
|
@@ -188856,14 +189396,14 @@ function readEntity2(root) {
|
|
|
188856
189396
|
column: root.column
|
|
188857
189397
|
};
|
|
188858
189398
|
}
|
|
188859
|
-
var DRAWN_KINDS2, QUIET_KINDS2,
|
|
189399
|
+
var DRAWN_KINDS2, QUIET_KINDS2, nameOfRef2;
|
|
188860
189400
|
var init_entities = __esm({
|
|
188861
189401
|
"../../packages/diagrams/src/importers/backstage/entities.ts"() {
|
|
188862
189402
|
"use strict";
|
|
188863
189403
|
init_yaml();
|
|
188864
189404
|
DRAWN_KINDS2 = ["Domain", "System", "Component", "API", "Resource", "Group", "User"];
|
|
188865
189405
|
QUIET_KINDS2 = /* @__PURE__ */ new Set(["Location"]);
|
|
188866
|
-
|
|
189406
|
+
nameOfRef2 = (ref) => ref.slice(ref.lastIndexOf("/") + 1);
|
|
188867
189407
|
}
|
|
188868
189408
|
});
|
|
188869
189409
|
|
|
@@ -188877,7 +189417,7 @@ function brandOf(...texts) {
|
|
|
188877
189417
|
}
|
|
188878
189418
|
function boxOf3(entity, byOwner) {
|
|
188879
189419
|
const type = (entity.type ?? "").toLowerCase();
|
|
188880
|
-
const said = (words3) => cleanText([words3, entity.lifecycle === null || entity.lifecycle === "production" ? null : entity.lifecycle, byOwner || entity.owner === null ? null : `owned by ${
|
|
189420
|
+
const said = (words3) => cleanText([words3, entity.lifecycle === null || entity.lifecycle === "production" ? null : entity.lifecycle, byOwner || entity.owner === null ? null : `owned by ${nameOfRef2(entity.owner)}`].filter((part) => part !== null).join(", "));
|
|
188881
189421
|
const label = entity.title ?? entity.name;
|
|
188882
189422
|
if (entity.kind === "API") return { type: "gateway", label, sub: said(`${API_NAMES[type] ?? entity.type ?? ""} API`.trim()), icon: API_ICONS[type] ?? "lucide:plug", idHint: entity.name };
|
|
188883
189423
|
if (entity.kind === "Resource") {
|
|
@@ -188924,15 +189464,15 @@ function readBackstage(textIn, context) {
|
|
|
188924
189464
|
}
|
|
188925
189465
|
for (const entity of boxes2) if (entity.owner !== null && byRef.get(entity.owner)?.kind === "Group") frameOf3.set(entity.ref, entity.owner);
|
|
188926
189466
|
} else {
|
|
188927
|
-
for (const domain2 of entities.filter((entity) => entity.kind === "Domain")) groups.push({ key: domain2.ref, label: domain2.title ?? domain2.name, sub: cleanText(`Domain${domain2.owner === null ? "" : `, owned by ${
|
|
188928
|
-
for (const system of entities.filter((entity) => entity.kind === "System")) groups.push({ key: system.ref, label: system.title ?? system.name, sub: cleanText(`System${system.owner === null ? "" : `, owned by ${
|
|
189467
|
+
for (const domain2 of entities.filter((entity) => entity.kind === "Domain")) groups.push({ key: domain2.ref, label: domain2.title ?? domain2.name, sub: cleanText(`Domain${domain2.owner === null ? "" : `, owned by ${nameOfRef2(domain2.owner)}`}`), icon: "lucide:map", idHint: domain2.name });
|
|
189468
|
+
for (const system of entities.filter((entity) => entity.kind === "System")) groups.push({ key: system.ref, label: system.title ?? system.name, sub: cleanText(`System${system.owner === null ? "" : `, owned by ${nameOfRef2(system.owner)}`}`), icon: "lucide:boxes", parent: system.domain !== null && byRef.has(system.domain) ? system.domain : null, idHint: system.name });
|
|
188929
189469
|
for (const entity of boxes2) if (entity.system !== null && byRef.get(entity.system)?.kind === "System") frameOf3.set(entity.ref, entity.system);
|
|
188930
189470
|
}
|
|
188931
189471
|
const order = { Component: 0, API: 1, Resource: 2 };
|
|
188932
189472
|
const ordered = [...boxes2].sort((a, b) => order[a.kind] - order[b.kind]);
|
|
188933
189473
|
const nodes = ordered.map((entity) => {
|
|
188934
189474
|
const box = boxOf3(entity, byOwner);
|
|
188935
|
-
const system = byOwner && entity.system !== null ? `, in ${
|
|
189475
|
+
const system = byOwner && entity.system !== null ? `, in ${nameOfRef2(entity.system)}` : "";
|
|
188936
189476
|
return { key: entity.ref, ...box, sub: box.sub === null || box.sub === void 0 ? null : cleanText(`${box.sub}${system}`), group: frameOf3.get(entity.ref) ?? null };
|
|
188937
189477
|
});
|
|
188938
189478
|
const drawn = new Set(nodes.map((node3) => node3.key));
|
|
@@ -189225,14 +189765,14 @@ function templateItems(template, offsetOf) {
|
|
|
189225
189765
|
}
|
|
189226
189766
|
return { items: items2, empty };
|
|
189227
189767
|
}
|
|
189228
|
-
var
|
|
189768
|
+
var MAX_DEPTH14, PSEUDO, entryOf, scalarOf, itemsOf, subNames, Template;
|
|
189229
189769
|
var init_template = __esm({
|
|
189230
189770
|
"../../packages/diagrams/src/importers/cloudformation/template.ts"() {
|
|
189231
189771
|
"use strict";
|
|
189232
189772
|
init_attributes();
|
|
189233
189773
|
init_type_names();
|
|
189234
189774
|
init_value();
|
|
189235
|
-
|
|
189775
|
+
MAX_DEPTH14 = 16;
|
|
189236
189776
|
PSEUDO = {
|
|
189237
189777
|
"AWS::Region": "region",
|
|
189238
189778
|
"AWS::AccountId": "account",
|
|
@@ -189264,7 +189804,7 @@ var init_template = __esm({
|
|
|
189264
189804
|
conditionMemo = /* @__PURE__ */ new Map();
|
|
189265
189805
|
/** The value of a node as far as the template's defaults give it. */
|
|
189266
189806
|
evaluate(node3, depth = 0) {
|
|
189267
|
-
if (node3 === void 0 || depth >
|
|
189807
|
+
if (node3 === void 0 || depth > MAX_DEPTH14) return new Unknown("value");
|
|
189268
189808
|
const intrinsic = intrinsicOf(node3);
|
|
189269
189809
|
if (intrinsic !== null) return this.call(intrinsic, depth);
|
|
189270
189810
|
if (node3.kind === "scalar") return node3.isNull ? null : node3.value;
|
|
@@ -189372,7 +189912,7 @@ var init_template = __esm({
|
|
|
189372
189912
|
}
|
|
189373
189913
|
/** The resources a node names: `Ref`, `GetAtt`, and `${ }` of `Sub`, and only the branch an `If` takes when its condition is known. */
|
|
189374
189914
|
refs(node3, depth = 0) {
|
|
189375
|
-
if (node3 === void 0 || depth >
|
|
189915
|
+
if (node3 === void 0 || depth > MAX_DEPTH14) return [];
|
|
189376
189916
|
const intrinsic = intrinsicOf(node3);
|
|
189377
189917
|
if (intrinsic !== null) {
|
|
189378
189918
|
const argument = intrinsic.argument;
|
|
@@ -189409,7 +189949,7 @@ var init_template = __esm({
|
|
|
189409
189949
|
}
|
|
189410
189950
|
/** Every reference a node holds, by the keys that lead to it. */
|
|
189411
189951
|
refsByPath(node3, path, out, depth = 0) {
|
|
189412
|
-
if (node3 === void 0 || depth >
|
|
189952
|
+
if (node3 === void 0 || depth > MAX_DEPTH14) return;
|
|
189413
189953
|
if (intrinsicOf(node3) === null && node3.kind === "map") {
|
|
189414
189954
|
for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
|
|
189415
189955
|
return;
|
|
@@ -189426,17 +189966,17 @@ var init_template = __esm({
|
|
|
189426
189966
|
});
|
|
189427
189967
|
|
|
189428
189968
|
// ../../packages/diagrams/src/importers/cloudformation/index.ts
|
|
189429
|
-
function
|
|
189969
|
+
function nodeOf3(value, depth = 0) {
|
|
189430
189970
|
const at3 = { line: 1, column: 1 };
|
|
189431
189971
|
if (depth > 64 || value === null || value === void 0) return { kind: "scalar", value: "", quoted: false, isNull: true, ...at3 };
|
|
189432
|
-
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) =>
|
|
189433
|
-
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value:
|
|
189972
|
+
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) => nodeOf3(item, depth + 1)), ...at3 };
|
|
189973
|
+
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value: nodeOf3(entry2, depth + 1), ...at3 })), ...at3 };
|
|
189434
189974
|
return { kind: "scalar", value: String(value), quoted: typeof value === "string", isNull: false, ...at3 };
|
|
189435
189975
|
}
|
|
189436
189976
|
function readFile(text3) {
|
|
189437
189977
|
if (/^\s*\{/.test(text3)) {
|
|
189438
189978
|
try {
|
|
189439
|
-
return { root:
|
|
189979
|
+
return { root: nodeOf3(JSON.parse(text3)), problem: null };
|
|
189440
189980
|
} catch (error62) {
|
|
189441
189981
|
return { root: null, problem: { line: 1, column: 1, message: `The template is not JSON: ${error62 instanceof Error ? error62.message : "it cannot be read"}.`, hint: "Send the template as CloudFormation writes it, in JSON or YAML." } };
|
|
189442
189982
|
}
|
|
@@ -189669,7 +190209,7 @@ function readable(segment, stack) {
|
|
|
189669
190209
|
const at3 = stack.length >= 3 ? own2.indexOf(stack) : -1;
|
|
189670
190210
|
return (at3 > 0 ? own2.slice(0, at3) : own2) || segment;
|
|
189671
190211
|
}
|
|
189672
|
-
function frameModules2(tree, classes,
|
|
190212
|
+
function frameModules2(tree, classes, startOf4) {
|
|
189673
190213
|
const scopes = /* @__PURE__ */ new Map();
|
|
189674
190214
|
const used = /* @__PURE__ */ new Set();
|
|
189675
190215
|
const modules = [];
|
|
@@ -189684,7 +190224,7 @@ function frameModules2(tree, classes, startOf3) {
|
|
|
189684
190224
|
const kind = tree.frames.get(path) ?? "Construct";
|
|
189685
190225
|
const fqn = classes.get(path) ?? "";
|
|
189686
190226
|
const own2 = /^(?:aws-cdk-lib|@aws-cdk\/[^.]+)\./.test(fqn) && !/\.(?:Stack|NestedStack|Stage)$/.test(fqn) ? fqn.split(".").pop() ?? "" : "";
|
|
189687
|
-
modules.push({ scope, name: path, label: id, instance: null, source: own2, start:
|
|
190227
|
+
modules.push({ scope, name: path, label: id, instance: null, source: own2, start: startOf4(path), noun: kind });
|
|
189688
190228
|
}
|
|
189689
190229
|
return { modules, scopes };
|
|
189690
190230
|
}
|
|
@@ -189849,7 +190389,7 @@ function readCdk(joined2, context) {
|
|
|
189849
190389
|
}
|
|
189850
190390
|
let hops = 0;
|
|
189851
190391
|
const refsOf = (read, node3) => {
|
|
189852
|
-
if (node3 === void 0 || hops >=
|
|
190392
|
+
if (node3 === void 0 || hops >= MAX_HOPS2) return [];
|
|
189853
190393
|
hops += 1;
|
|
189854
190394
|
try {
|
|
189855
190395
|
return read.model.refs(node3).map((ref) => read.names.get(ref) ?? ref);
|
|
@@ -189915,12 +190455,12 @@ function readCdk(joined2, context) {
|
|
|
189915
190455
|
const maker = makers.get(item.name) ?? null;
|
|
189916
190456
|
if ((labelCount.get(item.label) ?? 0) > 1 && maker !== null && !item.label.startsWith(`${maker}_`)) items2[position] = { ...item, label: `${maker}_${item.label}` };
|
|
189917
190457
|
}
|
|
189918
|
-
const
|
|
190458
|
+
const startOf4 = (path) => {
|
|
189919
190459
|
const owner = reads.find((read) => read.template.stackPath === path) ?? reads.find((read) => read.template.topPath === path.split("/")[0]);
|
|
189920
190460
|
const at3 = owner === void 0 ? -1 : owner.template.file.text.indexOf(`"${path}/`);
|
|
189921
190461
|
return owner === void 0 ? 0 : owner.template.file.start + Math.max(0, at3);
|
|
189922
190462
|
};
|
|
189923
|
-
const { modules, scopes } = frameModules2(tree, assembly.classes,
|
|
190463
|
+
const { modules, scopes } = frameModules2(tree, assembly.classes, startOf4);
|
|
189924
190464
|
const scoped = items2.map((item) => {
|
|
189925
190465
|
const frames = placements.get(item.name) ?? [];
|
|
189926
190466
|
const innermost = frames[frames.length - 1];
|
|
@@ -189950,7 +190490,7 @@ function readCdk(joined2, context) {
|
|
|
189950
190490
|
framing: "construct"
|
|
189951
190491
|
});
|
|
189952
190492
|
}
|
|
189953
|
-
var LISTED9,
|
|
190493
|
+
var LISTED9, MAX_HOPS2, METADATA_TYPE, withoutHash, cdkImporter;
|
|
189954
190494
|
var init_cdk = __esm({
|
|
189955
190495
|
"../../packages/diagrams/src/importers/cdk/index.ts"() {
|
|
189956
190496
|
"use strict";
|
|
@@ -189964,7 +190504,7 @@ var init_cdk = __esm({
|
|
|
189964
190504
|
init_assembly();
|
|
189965
190505
|
init_constructs();
|
|
189966
190506
|
LISTED9 = 3;
|
|
189967
|
-
|
|
190507
|
+
MAX_HOPS2 = 8;
|
|
189968
190508
|
METADATA_TYPE = "AWS::CDK::Metadata";
|
|
189969
190509
|
withoutHash = (logical) => logical.replace(/[0-9A-F]{8}$/, "") || logical;
|
|
189970
190510
|
cdkImporter = { format: "cdk", kinds: ["flow"], joins: "\n", extensions: [".json", ".yaml", ".yml", ".out"], read: readCdk };
|
|
@@ -190119,17 +190659,17 @@ var init_services2 = __esm({
|
|
|
190119
190659
|
});
|
|
190120
190660
|
|
|
190121
190661
|
// ../../packages/diagrams/src/importers/compose/index.ts
|
|
190122
|
-
function
|
|
190662
|
+
function subOf2(service) {
|
|
190123
190663
|
const runs = service.image ?? (service.build === null ? null : `build ${service.build}`);
|
|
190124
190664
|
const ports = service.ports.length === 0 ? null : `${service.ports.length === 1 ? "port" : "ports"} ${service.ports.join(", ")}`;
|
|
190125
190665
|
const replicas = service.replicas === null || service.replicas === "1" ? null : `${service.replicas} replicas`;
|
|
190126
190666
|
const parts = [runs, ports, replicas].filter((part) => part !== null);
|
|
190127
190667
|
return parts.length === 0 ? null : parts.join(", ");
|
|
190128
190668
|
}
|
|
190129
|
-
function
|
|
190669
|
+
function nodeOf4(service, group2) {
|
|
190130
190670
|
const look = (service.image === null ? null : imageLook(service.image)) ?? imageLook(service.name);
|
|
190131
190671
|
const type = look?.type ?? "service";
|
|
190132
|
-
return { key: `service:${service.name}`, type, label: service.name, sub:
|
|
190672
|
+
return { key: `service:${service.name}`, type, label: service.name, sub: subOf2(service), icon: look?.icon ?? iconForName(service.name, type), group: group2, idHint: service.name };
|
|
190133
190673
|
}
|
|
190134
190674
|
function groupsOf(services, networks) {
|
|
190135
190675
|
const home = /* @__PURE__ */ new Map();
|
|
@@ -190187,7 +190727,7 @@ function readCompose(source, context) {
|
|
|
190187
190727
|
const mounted = new Set(services.flatMap((service) => service.volumes));
|
|
190188
190728
|
const volumes = declared(root, "volumes").filter((volume) => mounted.has(volume));
|
|
190189
190729
|
const nodes = [
|
|
190190
|
-
...services.map((service) =>
|
|
190730
|
+
...services.map((service) => nodeOf4(service, home.get(service.name) ?? null)),
|
|
190191
190731
|
...volumes.map((volume) => ({ key: `volume:${volume}`, type: "storage", label: volume, sub: "Named volume", idHint: `${volume}_volume` }))
|
|
190192
190732
|
];
|
|
190193
190733
|
const name2 = text(get(root, "name"));
|
|
@@ -191942,8 +192482,8 @@ function actionLabel(uses) {
|
|
|
191942
192482
|
}
|
|
191943
192483
|
function commandLabel(run3) {
|
|
191944
192484
|
const first = run3.split("\n").map((line3) => line3.trim()).find((line3) => line3 !== "" && !line3.startsWith("#")) ?? "Run a script";
|
|
191945
|
-
if (first.length <=
|
|
191946
|
-
const cut = first.slice(0,
|
|
192485
|
+
if (first.length <= MAX_STEP_LABEL2) return first;
|
|
192486
|
+
const cut = first.slice(0, MAX_STEP_LABEL2);
|
|
191947
192487
|
const space = cut.lastIndexOf(" ");
|
|
191948
192488
|
return space > 12 ? cut.slice(0, space) : cut;
|
|
191949
192489
|
}
|
|
@@ -192015,13 +192555,13 @@ function triggerOf(root) {
|
|
|
192015
192555
|
const short3 = `${words2.map((word2) => word2.short).join(" or ")}${more}`;
|
|
192016
192556
|
return { label: cleanText(`${short3.charAt(0).toUpperCase()}${short3.slice(1)}`), sentence: cleanText(`${words2.map((word2) => word2.long).join(" or ")}${more}`) };
|
|
192017
192557
|
}
|
|
192018
|
-
var
|
|
192558
|
+
var MAX_STEP_LABEL2, ACTION_ICONS, COMMAND_ICONS;
|
|
192019
192559
|
var init_workflow = __esm({
|
|
192020
192560
|
"../../packages/diagrams/src/importers/github-actions/workflow.ts"() {
|
|
192021
192561
|
"use strict";
|
|
192022
192562
|
init_shared2();
|
|
192023
192563
|
init_yaml();
|
|
192024
|
-
|
|
192564
|
+
MAX_STEP_LABEL2 = 48;
|
|
192025
192565
|
ACTION_ICONS = {
|
|
192026
192566
|
"actions/checkout": "lucide:git-branch",
|
|
192027
192567
|
"actions/setup-node": "simple:nodedotjs",
|
|
@@ -192111,31 +192651,31 @@ function readWorkflow(source, context) {
|
|
|
192111
192651
|
return null;
|
|
192112
192652
|
}
|
|
192113
192653
|
const ids = new Set(jobs.map((job) => job.id));
|
|
192114
|
-
const
|
|
192654
|
+
const resolved2 = jobs.map((job) => {
|
|
192115
192655
|
const missing = job.needs.filter((need) => !ids.has(need));
|
|
192116
192656
|
for (const need of missing) context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(job.line, job.column, job.id.length), `Job ${job.id} needs ${need}, which is not a job of this workflow.`, "Fix the name in needs:, or add the job.");
|
|
192117
192657
|
return missing.length === 0 ? job : { ...job, needs: job.needs.filter((need) => ids.has(need)) };
|
|
192118
192658
|
});
|
|
192119
|
-
const expanded = fitsSteps(
|
|
192120
|
-
const drawn = expanded ? stepBoxes(
|
|
192659
|
+
const expanded = fitsSteps(resolved2);
|
|
192660
|
+
const drawn = expanded ? stepBoxes(resolved2) : { ...jobBoxes(resolved2), groups: [] };
|
|
192121
192661
|
const trigger = triggerOf(root);
|
|
192122
192662
|
const firstOf = (job) => expanded ? job.steps.length === 0 ? `job:${job.id}` : `step:${job.id}:0` : `job:${job.id}`;
|
|
192123
|
-
const starts =
|
|
192663
|
+
const starts = resolved2.filter((job) => job.needs.length === 0).map((job) => ({ from: TRIGGER, to: firstOf(job) }));
|
|
192124
192664
|
const name2 = text(get(root, "name"));
|
|
192125
|
-
const depth = depthOf5(
|
|
192126
|
-
const steps =
|
|
192665
|
+
const depth = depthOf5(resolved2);
|
|
192666
|
+
const steps = resolved2.reduce((sum, job) => sum + job.steps.length, 0);
|
|
192127
192667
|
const coverage = expanded ? { noun: "steps", total: drawn.nodes.length, drawn: drawn.nodes.length, summarised: 0 } : { noun: "steps", total: steps, drawn: 0, summarised: steps };
|
|
192128
192668
|
return writeFlow(
|
|
192129
192669
|
{
|
|
192130
192670
|
title: context.title ?? name2 ?? "GitHub Actions workflow",
|
|
192131
|
-
desc: `${countOf2(
|
|
192671
|
+
desc: `${countOf2(resolved2.length, "job")}${expanded ? " and their steps" : ""} of ${name2 === null ? "a GitHub Actions workflow" : `the ${name2} workflow`}, started by ${trigger === null ? "its trigger" : trigger.sentence}, in the order their needs set, imported from GitHub Actions.`,
|
|
192132
192672
|
direction: expanded || depth > 4 ? "down" : "right",
|
|
192133
192673
|
nodes: [{ key: TRIGGER, type: "terminal", label: trigger?.label ?? "Workflow starts" }, ...drawn.nodes],
|
|
192134
192674
|
groups: drawn.groups,
|
|
192135
192675
|
edges: [...starts, ...drawn.edges],
|
|
192136
192676
|
noun: expanded ? "steps" : "jobs",
|
|
192137
192677
|
capSpan: (key) => {
|
|
192138
|
-
const job =
|
|
192678
|
+
const job = resolved2.find((candidate2) => key === `job:${candidate2.id}`);
|
|
192139
192679
|
return spanAt3(job?.line ?? 1, job?.column ?? 1);
|
|
192140
192680
|
},
|
|
192141
192681
|
coverage,
|
|
@@ -192159,6 +192699,213 @@ var init_github_actions = __esm({
|
|
|
192159
192699
|
}
|
|
192160
192700
|
});
|
|
192161
192701
|
|
|
192702
|
+
// ../../packages/diagrams/src/importers/gitlab-ci/pipeline.ts
|
|
192703
|
+
function resolved(name2, byName, missing, depth = 0) {
|
|
192704
|
+
const own2 = byName.get(name2);
|
|
192705
|
+
const out = /* @__PURE__ */ new Map();
|
|
192706
|
+
if (own2 === void 0 || depth > MAX_EXTENDS) return out;
|
|
192707
|
+
for (const parent of names5(get(own2, "extends"))) {
|
|
192708
|
+
if (!byName.has(parent)) {
|
|
192709
|
+
if (!missing.includes(parent)) missing.push(parent);
|
|
192710
|
+
continue;
|
|
192711
|
+
}
|
|
192712
|
+
for (const [key, value] of resolved(parent, byName, missing, depth + 1)) out.set(key, value);
|
|
192713
|
+
}
|
|
192714
|
+
for (const entry2 of entries(own2)) if (entry2.key !== "extends") out.set(entry2.key, entry2.value);
|
|
192715
|
+
return out;
|
|
192716
|
+
}
|
|
192717
|
+
function runsOf5(parallel) {
|
|
192718
|
+
const count3 = Number(text(parallel));
|
|
192719
|
+
if (Number.isInteger(count3) && count3 > 1) return { runs: count3, matrix: false };
|
|
192720
|
+
const matrix = items(get(parallel, "matrix"));
|
|
192721
|
+
if (matrix.length === 0) return { runs: 1, matrix: false };
|
|
192722
|
+
const runs = matrix.reduce((sum, entry2) => sum + entries(entry2).reduce((product, variable) => product * Math.max(1, items(variable.value).length), 1), 0);
|
|
192723
|
+
return { runs, matrix: true };
|
|
192724
|
+
}
|
|
192725
|
+
function startOf3(keys) {
|
|
192726
|
+
const when = text(keys.get("when"));
|
|
192727
|
+
if (when === "manual") return "manual";
|
|
192728
|
+
if (when === "delayed") return "delayed";
|
|
192729
|
+
if (when === "on_failure") return "on_failure";
|
|
192730
|
+
const rules = items(keys.get("rules"));
|
|
192731
|
+
if (rules.some((rule) => text(get(rule, "when")) === "manual")) return "manual";
|
|
192732
|
+
if (rules.length > 0) return "rules";
|
|
192733
|
+
if (keys.has("only") || keys.has("except")) return "only";
|
|
192734
|
+
return "always";
|
|
192735
|
+
}
|
|
192736
|
+
function triggerOf2(node3) {
|
|
192737
|
+
if (node3 === void 0) return null;
|
|
192738
|
+
const project2 = text(node3) ?? text(get(node3, "project"));
|
|
192739
|
+
if (project2 !== null) return { label: project2, child: false };
|
|
192740
|
+
const include = get(node3, "include");
|
|
192741
|
+
const file2 = text(include) ?? items(include).map((entry2) => text(entry2) ?? text(get(entry2, "local")) ?? text(get(entry2, "file")) ?? text(get(entry2, "template")) ?? text(get(entry2, "artifact"))).find((value) => value !== null) ?? null;
|
|
192742
|
+
return { label: file2 ?? "Child pipeline", child: true };
|
|
192743
|
+
}
|
|
192744
|
+
function includesOf(root) {
|
|
192745
|
+
const include = get(root, "include");
|
|
192746
|
+
return items(include).map((entry2) => {
|
|
192747
|
+
const said = text(entry2) ?? (text(get(entry2, "project")) === null ? null : `${text(get(entry2, "project"))}: ${names5(get(entry2, "file")).join(", ")}`) ?? text(get(entry2, "local")) ?? text(get(entry2, "remote")) ?? text(get(entry2, "template")) ?? text(get(entry2, "component")) ?? "an include";
|
|
192748
|
+
return { said: cleanText(said), line: entry2.line, column: entry2.column };
|
|
192749
|
+
});
|
|
192750
|
+
}
|
|
192751
|
+
function readPipeline2(root) {
|
|
192752
|
+
const byName = /* @__PURE__ */ new Map();
|
|
192753
|
+
for (const entry2 of entries(root)) if (entry2.value.kind === "map") byName.set(entry2.key, entry2.value);
|
|
192754
|
+
const written3 = names5(get(root, "stages"));
|
|
192755
|
+
const defaults = get(root, "default");
|
|
192756
|
+
const fallbackImage = text(get(defaults, "image")) ?? text(get(get(defaults, "image"), "name")) ?? text(get(root, "image")) ?? text(get(get(root, "image"), "name"));
|
|
192757
|
+
const jobs = [];
|
|
192758
|
+
for (const entry2 of entries(root)) {
|
|
192759
|
+
if (entry2.key.startsWith(".") || GLOBAL_KEYS.has(entry2.key) || entry2.value.kind !== "map") continue;
|
|
192760
|
+
const missing = [];
|
|
192761
|
+
const keys = resolved(entry2.key, byName, missing);
|
|
192762
|
+
const needsNode = keys.get("needs");
|
|
192763
|
+
const needs2 = needsNode === void 0 ? null : items(needsNode).map((need) => text(need) ?? (get(need, "pipeline") === void 0 && get(need, "project") === void 0 ? text(get(need, "job")) : null)).filter((need) => need !== null);
|
|
192764
|
+
const image = text(keys.get("image")) ?? text(get(keys.get("image"), "name")) ?? fallbackImage;
|
|
192765
|
+
const environment = text(keys.get("environment")) ?? text(get(keys.get("environment"), "name"));
|
|
192766
|
+
const allow = keys.get("allow_failure");
|
|
192767
|
+
jobs.push({
|
|
192768
|
+
name: entry2.key,
|
|
192769
|
+
stage: text(keys.get("stage")) ?? "test",
|
|
192770
|
+
needs: needs2,
|
|
192771
|
+
start: startOf3(keys),
|
|
192772
|
+
image: image === null ? null : image.split("/").pop() ?? image,
|
|
192773
|
+
...runsOf5(keys.get("parallel")),
|
|
192774
|
+
environment,
|
|
192775
|
+
trigger: triggerOf2(keys.get("trigger")),
|
|
192776
|
+
allowFailure: text(allow) === "true" || allow?.kind === "map",
|
|
192777
|
+
missingExtends: missing,
|
|
192778
|
+
line: entry2.line,
|
|
192779
|
+
column: entry2.column
|
|
192780
|
+
});
|
|
192781
|
+
}
|
|
192782
|
+
return { stages: written3.length > 0 ? written3 : [...DEFAULT_STAGES], stagesWritten: written3.length > 0, jobs, includes: includesOf(root) };
|
|
192783
|
+
}
|
|
192784
|
+
var DEFAULT_STAGES, GLOBAL_KEYS, MAX_EXTENDS;
|
|
192785
|
+
var init_pipeline2 = __esm({
|
|
192786
|
+
"../../packages/diagrams/src/importers/gitlab-ci/pipeline.ts"() {
|
|
192787
|
+
"use strict";
|
|
192788
|
+
init_shared2();
|
|
192789
|
+
init_yaml();
|
|
192790
|
+
DEFAULT_STAGES = [".pre", "build", "test", "deploy", ".post"];
|
|
192791
|
+
GLOBAL_KEYS = /* @__PURE__ */ new Set(["default", "include", "stages", "variables", "workflow", "image", "services", "cache", "before_script", "after_script", "types", "spec"]);
|
|
192792
|
+
MAX_EXTENDS = 11;
|
|
192793
|
+
}
|
|
192794
|
+
});
|
|
192795
|
+
|
|
192796
|
+
// ../../packages/diagrams/src/importers/gitlab-ci/index.ts
|
|
192797
|
+
function subOf3(job) {
|
|
192798
|
+
const parts = [
|
|
192799
|
+
START_WORDS[job.start],
|
|
192800
|
+
job.runs > 1 ? `${job.runs} ${job.matrix ? "matrix" : "parallel"} runs` : null,
|
|
192801
|
+
job.environment === null ? null : `deploys to ${job.environment}`,
|
|
192802
|
+
job.image,
|
|
192803
|
+
job.allowFailure ? "may fail" : null
|
|
192804
|
+
].filter((part) => part !== null);
|
|
192805
|
+
return parts.length === 0 ? null : cleanText(parts.join(", "));
|
|
192806
|
+
}
|
|
192807
|
+
function readGitlabCi(source, context) {
|
|
192808
|
+
const read = parseYaml(source);
|
|
192809
|
+
if (read.error !== null) {
|
|
192810
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
192811
|
+
return null;
|
|
192812
|
+
}
|
|
192813
|
+
const root = [...read.documents].reverse().find((document2) => document2.root?.kind === "map")?.root ?? null;
|
|
192814
|
+
const pipeline = root === null ? null : readPipeline2(root);
|
|
192815
|
+
if (pipeline === null || pipeline.jobs.length === 0) {
|
|
192816
|
+
const includes = pipeline?.includes.length ?? 0;
|
|
192817
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, includes > 0 ? "The file has no jobs of its own; they come from what it includes, which is not fetched." : "The file has no jobs.", includes > 0 ? "Import the included files, or a .gitlab-ci.yml with jobs." : "Send a .gitlab-ci.yml with at least one job, a key with a script or a trigger.");
|
|
192818
|
+
return null;
|
|
192819
|
+
}
|
|
192820
|
+
const firstInclude = pipeline.includes[0];
|
|
192821
|
+
if (firstInclude !== void 0) {
|
|
192822
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, spanAt3(firstInclude.line, firstInclude.column), `${countOf2(pipeline.includes.length, "include")} ${pipeline.includes.length === 1 ? "is" : "are"} not fetched, so the jobs ${pipeline.includes.length === 1 ? "it adds are" : "they add are"} not drawn: ${pipeline.includes.slice(0, 3).map((include) => include.said).join(", ")}.`, "Import the included files too, or draw this file alone knowing those jobs are missing.");
|
|
192823
|
+
}
|
|
192824
|
+
const names8 = new Set(pipeline.jobs.map((job) => job.name));
|
|
192825
|
+
const missingExtends = pipeline.jobs.filter((job) => job.missingExtends.length > 0);
|
|
192826
|
+
const firstMissing = missingExtends[0];
|
|
192827
|
+
if (firstMissing !== void 0) {
|
|
192828
|
+
const parents = [...new Set(missingExtends.flatMap((job) => job.missingExtends))];
|
|
192829
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(firstMissing.line, firstMissing.column, firstMissing.name.length), `${countOf2(missingExtends.length, "job")} extend${missingExtends.length === 1 ? "s" : ""} ${parents.length === 1 ? "a job" : "jobs"} the file does not hold, so what ${parents.length === 1 ? "it sets is" : "they set is"} not read: ${parents.slice(0, 3).map((name2) => cleanText(name2)).join(", ")}.`, "They often come from an include; import the file that defines them with this one.");
|
|
192830
|
+
}
|
|
192831
|
+
const stages = pipeline.stages.filter((stage) => pipeline.jobs.some((job) => job.stage === stage));
|
|
192832
|
+
const unknown2 = [...new Set(pipeline.jobs.map((job) => job.stage).filter((stage) => !pipeline.stages.includes(stage)))];
|
|
192833
|
+
const firstUnknown = pipeline.jobs.find((job) => unknown2.includes(job.stage));
|
|
192834
|
+
if (firstUnknown !== void 0) {
|
|
192835
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(firstUnknown.line, firstUnknown.column, firstUnknown.name.length), `${countOf2(unknown2.length, "stage")} ${unknown2.length === 1 ? "is" : "are"} used by jobs but not listed in stages, so ${unknown2.length === 1 ? "it is" : "they are"} drawn last: ${unknown2.slice(0, 3).map((stage) => cleanText(stage)).join(", ")}.`, "List every stage in stages:, in the order they run.");
|
|
192836
|
+
}
|
|
192837
|
+
const ordered = [...stages, ...unknown2];
|
|
192838
|
+
const jobsOf2 = (stage) => pipeline.jobs.filter((job) => job.stage === stage);
|
|
192839
|
+
const nodes = [{ key: START_KEY2, type: "terminal", label: "Pipeline starts" }];
|
|
192840
|
+
const groups = [];
|
|
192841
|
+
const edges = [];
|
|
192842
|
+
const unresolvedNeeds = [];
|
|
192843
|
+
for (const stage of ordered) {
|
|
192844
|
+
groups.push({ key: `stage:${stage}`, label: cleanText(stage), type: "ci-cd", idHint: `stage_${stage.replace(/^\./, "")}` });
|
|
192845
|
+
for (const job of jobsOf2(stage)) {
|
|
192846
|
+
nodes.push({ key: `job:${job.name}`, type: "step", label: cleanText(job.name), sub: subOf3(job), icon: job.image === null ? null : imageLook(job.image)?.icon ?? null, group: `stage:${stage}`, idHint: job.name });
|
|
192847
|
+
if (job.trigger !== null) {
|
|
192848
|
+
nodes.push({ key: `trigger:${job.name}`, type: "external", label: cleanText(job.trigger.label), sub: job.trigger.child ? "Child pipeline" : "Downstream pipeline", icon: "simple:gitlab", idHint: `${job.name}_pipeline` });
|
|
192849
|
+
edges.push({ from: `job:${job.name}`, to: `trigger:${job.name}`, label: "triggers" });
|
|
192850
|
+
}
|
|
192851
|
+
}
|
|
192852
|
+
}
|
|
192853
|
+
for (const job of pipeline.jobs) {
|
|
192854
|
+
const arrow = job.start === "always" ? void 0 : "-->";
|
|
192855
|
+
const into = (from) => {
|
|
192856
|
+
edges.push({ from, to: `job:${job.name}`, ...arrow === void 0 ? {} : { arrow } });
|
|
192857
|
+
};
|
|
192858
|
+
if (job.needs !== null) {
|
|
192859
|
+
for (const need of job.needs) {
|
|
192860
|
+
if (names8.has(need)) into(`job:${need}`);
|
|
192861
|
+
else unresolvedNeeds.push({ job, need });
|
|
192862
|
+
}
|
|
192863
|
+
if (job.needs.filter((need) => names8.has(need)).length === 0) into(START_KEY2);
|
|
192864
|
+
continue;
|
|
192865
|
+
}
|
|
192866
|
+
const before = ordered.slice(0, ordered.indexOf(job.stage)).reverse().find((stage) => jobsOf2(stage).length > 0);
|
|
192867
|
+
if (before === void 0) into(START_KEY2);
|
|
192868
|
+
else for (const previous of jobsOf2(before)) into(`job:${previous.name}`);
|
|
192869
|
+
}
|
|
192870
|
+
const firstNeed = unresolvedNeeds[0];
|
|
192871
|
+
if (firstNeed !== void 0) {
|
|
192872
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(firstNeed.job.line, firstNeed.job.column, firstNeed.job.name.length), `${countOf2(unresolvedNeeds.length, "need")} name${unresolvedNeeds.length === 1 ? "s a job" : " jobs"} the file does not hold, so no arrow is drawn for ${unresolvedNeeds.length === 1 ? "it" : "them"}: ${unresolvedNeeds.slice(0, 3).map((entry2) => `${cleanText(entry2.job.name)} needs ${cleanText(entry2.need)}`).join(", ")}.`, "Fix the name in needs:, or import the file that defines the job.");
|
|
192873
|
+
}
|
|
192874
|
+
const triggers = pipeline.jobs.filter((job) => job.trigger !== null).length;
|
|
192875
|
+
return writeFlow(
|
|
192876
|
+
{
|
|
192877
|
+
title: context.title ?? "GitLab CI/CD pipeline",
|
|
192878
|
+
desc: `${countOf2(pipeline.jobs.length, "job")} in ${countOf2(ordered.length, "stage")}${triggers === 0 ? "" : `, ${triggers} of which ${triggers === 1 ? "starts" : "start"} another pipeline`}, in the order they run: by needs, or stage after stage. A dashed arrow reaches a job that runs by hand or by its rules. Imported from GitLab CI/CD.`,
|
|
192879
|
+
// Stages run down the page: across, even three stages of a few jobs are wider than a column.
|
|
192880
|
+
direction: "down",
|
|
192881
|
+
nodes,
|
|
192882
|
+
groups,
|
|
192883
|
+
edges,
|
|
192884
|
+
noun: "jobs",
|
|
192885
|
+
capSpan: (key) => {
|
|
192886
|
+
const job = pipeline.jobs.find((candidate2) => key === `job:${candidate2.name}`);
|
|
192887
|
+
return spanAt3(job?.line ?? 1, job?.column ?? 1);
|
|
192888
|
+
},
|
|
192889
|
+
coverage: { noun: "jobs", total: pipeline.jobs.length, drawn: pipeline.jobs.length, summarised: 0 },
|
|
192890
|
+
advice: pipeline.stagesWritten ? "Add needs: to jobs that do not wait for a whole stage, so the picture shows what really runs in parallel." : "List the stages in stages:, so the picture shows them in the order they run."
|
|
192891
|
+
},
|
|
192892
|
+
context.report
|
|
192893
|
+
);
|
|
192894
|
+
}
|
|
192895
|
+
var START_KEY2, START_WORDS, gitlabCiImporter;
|
|
192896
|
+
var init_gitlab_ci = __esm({
|
|
192897
|
+
"../../packages/diagrams/src/importers/gitlab-ci/index.ts"() {
|
|
192898
|
+
"use strict";
|
|
192899
|
+
init_core();
|
|
192900
|
+
init_shared2();
|
|
192901
|
+
init_yaml();
|
|
192902
|
+
init_pipeline2();
|
|
192903
|
+
START_KEY2 = "pipeline";
|
|
192904
|
+
START_WORDS = { always: null, manual: "manual", rules: "when its rules match", only: "only on some refs", delayed: "delayed", on_failure: "on failure" };
|
|
192905
|
+
gitlabCiImporter = { format: "gitlab-ci", kinds: ["flow"], joins: null, extensions: [], read: readGitlabCi };
|
|
192906
|
+
}
|
|
192907
|
+
});
|
|
192908
|
+
|
|
192162
192909
|
// ../../packages/diagrams/src/importers/json/locate.ts
|
|
192163
192910
|
function stringEnd3(text3, start2) {
|
|
192164
192911
|
for (let index2 = start2 + 1; index2 < text3.length; index2 += 1) {
|
|
@@ -192483,7 +193230,7 @@ function withoutSchemaBodies(text3) {
|
|
|
192483
193230
|
}
|
|
192484
193231
|
return lines.join("\n");
|
|
192485
193232
|
}
|
|
192486
|
-
function
|
|
193233
|
+
function readDocument2(text3, report3) {
|
|
192487
193234
|
const index2 = new LineIndex(text3);
|
|
192488
193235
|
if (text3.trimStart().startsWith("{")) {
|
|
192489
193236
|
try {
|
|
@@ -192503,7 +193250,7 @@ function readDocument(text3, report3) {
|
|
|
192503
193250
|
return root === void 0 || root === null ? null : plain2(root);
|
|
192504
193251
|
}
|
|
192505
193252
|
var UNREAD_SECTIONS;
|
|
192506
|
-
var
|
|
193253
|
+
var init_document3 = __esm({
|
|
192507
193254
|
"../../packages/diagrams/src/importers/openapi/document.ts"() {
|
|
192508
193255
|
"use strict";
|
|
192509
193256
|
init_core();
|
|
@@ -192860,7 +193607,7 @@ var METHODS;
|
|
|
192860
193607
|
var init_operations = __esm({
|
|
192861
193608
|
"../../packages/diagrams/src/importers/openapi/operations.ts"() {
|
|
192862
193609
|
"use strict";
|
|
192863
|
-
|
|
193610
|
+
init_document3();
|
|
192864
193611
|
METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
|
|
192865
193612
|
}
|
|
192866
193613
|
});
|
|
@@ -192964,7 +193711,7 @@ function readOpenApi(text3, context) {
|
|
|
192964
193711
|
report3.add(DIAGNOSTIC_CODES.importNotFound, START, `An OpenAPI document has no "${asked}" view.`, 'Set options.view to "endpoints" for an access matrix, "map" for the endpoints by tag, or "sequence" for one operation.');
|
|
192965
193712
|
return null;
|
|
192966
193713
|
}
|
|
192967
|
-
const document2 =
|
|
193714
|
+
const document2 = readDocument2(text3, report3);
|
|
192968
193715
|
if (document2 === null) return null;
|
|
192969
193716
|
if (!isOpenApi3(document2)) {
|
|
192970
193717
|
report3.add(DIAGNOSTIC_CODES.importNoShape, START, "The document has no openapi: 3.x field, so it is not an OpenAPI 3 document.", "Send an OpenAPI 3.0 or 3.1 document. A Swagger 2.0 file can be converted with the swagger2openapi tool first.");
|
|
@@ -193011,7 +193758,7 @@ var init_openapi = __esm({
|
|
|
193011
193758
|
"use strict";
|
|
193012
193759
|
init_core();
|
|
193013
193760
|
init_shared2();
|
|
193014
|
-
|
|
193761
|
+
init_document3();
|
|
193015
193762
|
init_endpoints();
|
|
193016
193763
|
init_map();
|
|
193017
193764
|
init_operations();
|
|
@@ -193303,19 +194050,19 @@ function piecesOf4(value) {
|
|
|
193303
194050
|
}
|
|
193304
194051
|
return out;
|
|
193305
194052
|
}
|
|
193306
|
-
var
|
|
194053
|
+
var MAX_DEPTH15, Program;
|
|
193307
194054
|
var init_program = __esm({
|
|
193308
194055
|
"../../packages/diagrams/src/importers/pulumi/program.ts"() {
|
|
193309
194056
|
"use strict";
|
|
193310
194057
|
init_value();
|
|
193311
194058
|
init_yaml();
|
|
193312
194059
|
init_item();
|
|
193313
|
-
|
|
194060
|
+
MAX_DEPTH15 = 16;
|
|
193314
194061
|
Program = class {
|
|
193315
|
-
constructor(root, config2, stack,
|
|
194062
|
+
constructor(root, config2, stack, project2) {
|
|
193316
194063
|
this.config = config2;
|
|
193317
194064
|
this.stack = stack;
|
|
193318
|
-
this.project =
|
|
194065
|
+
this.project = project2;
|
|
193319
194066
|
this.resources = entries(get(root, "resources")).filter((entry2) => entry2.value.kind === "map").map((entry2) => ({ name: entry2.key, node: entry2.value, line: entry2.line, column: entry2.column }));
|
|
193320
194067
|
this.variables = new Map(entries(get(root, "variables")).map((entry2) => [entry2.key, entry2.value]));
|
|
193321
194068
|
const defaults = /* @__PURE__ */ new Map();
|
|
@@ -193338,7 +194085,7 @@ var init_program = __esm({
|
|
|
193338
194085
|
}
|
|
193339
194086
|
/** The value of a node as far as the program and the stack give it. */
|
|
193340
194087
|
evaluate(node3, depth = 0) {
|
|
193341
|
-
if (node3 === void 0 || depth >
|
|
194088
|
+
if (node3 === void 0 || depth > MAX_DEPTH15) return new Unknown("value");
|
|
193342
194089
|
if (node3.kind === "scalar") {
|
|
193343
194090
|
if (node3.isNull) return null;
|
|
193344
194091
|
if (!node3.value.includes("${")) return node3.value;
|
|
@@ -193423,7 +194170,7 @@ var init_program = __esm({
|
|
|
193423
194170
|
}
|
|
193424
194171
|
/** The resources a node names, through the variables it uses. */
|
|
193425
194172
|
refs(node3, depth = 0) {
|
|
193426
|
-
if (node3 === void 0 || depth >
|
|
194173
|
+
if (node3 === void 0 || depth > MAX_DEPTH15) return [];
|
|
193427
194174
|
if (node3.kind === "scalar") {
|
|
193428
194175
|
if (!node3.value.includes("${")) return [];
|
|
193429
194176
|
return piecesOf4(node3.value).flatMap((piece) => {
|
|
@@ -193446,7 +194193,7 @@ var init_program = __esm({
|
|
|
193446
194193
|
}
|
|
193447
194194
|
/** Every reference a node holds, by the keys that lead to it. */
|
|
193448
194195
|
refsByPath(node3, path, out, depth) {
|
|
193449
|
-
if (node3 === void 0 || depth >
|
|
194196
|
+
if (node3 === void 0 || depth > MAX_DEPTH15) return;
|
|
193450
194197
|
if (node3.kind === "map" && !(node3.entries.length === 1 && node3.entries[0]?.key.startsWith("fn::"))) {
|
|
193451
194198
|
for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
|
|
193452
194199
|
return;
|
|
@@ -194244,6 +194991,718 @@ var init_sql = __esm({
|
|
|
194244
194991
|
}
|
|
194245
194992
|
});
|
|
194246
194993
|
|
|
194994
|
+
// ../../packages/diagrams/src/importers/structurizr/tokens.ts
|
|
194995
|
+
function tokensOf(line3) {
|
|
194996
|
+
const tokens = [];
|
|
194997
|
+
let index2 = 0;
|
|
194998
|
+
while (index2 < line3.length) {
|
|
194999
|
+
const char = line3.charAt(index2);
|
|
195000
|
+
if (char === " " || char === " ") {
|
|
195001
|
+
index2 += 1;
|
|
195002
|
+
continue;
|
|
195003
|
+
}
|
|
195004
|
+
if (char === '"') {
|
|
195005
|
+
let value = "";
|
|
195006
|
+
let at3 = index2 + 1;
|
|
195007
|
+
for (; at3 < line3.length && line3.charAt(at3) !== '"'; at3 += 1) {
|
|
195008
|
+
if (line3.charAt(at3) === "\\" && at3 + 1 < line3.length) at3 += 1;
|
|
195009
|
+
value += line3.charAt(at3);
|
|
195010
|
+
}
|
|
195011
|
+
tokens.push({ text: value, quoted: true, column: index2 + 1 });
|
|
195012
|
+
index2 = at3 + 1;
|
|
195013
|
+
continue;
|
|
195014
|
+
}
|
|
195015
|
+
if (char === "#" || line3.startsWith("//", index2)) break;
|
|
195016
|
+
let end = index2;
|
|
195017
|
+
while (end < line3.length && !' "'.includes(line3.charAt(end))) end += 1;
|
|
195018
|
+
const word2 = line3.slice(index2, end);
|
|
195019
|
+
let start2 = 0;
|
|
195020
|
+
for (let at3 = 0; at3 < word2.length; at3 += 1) {
|
|
195021
|
+
const single = word2.charAt(at3) === "{" || word2.charAt(at3) === "}" || word2.charAt(at3) === "=";
|
|
195022
|
+
const arrow = word2.startsWith("->", at3);
|
|
195023
|
+
if (!single && !arrow) continue;
|
|
195024
|
+
if (at3 > start2) tokens.push({ text: word2.slice(start2, at3), quoted: false, column: index2 + start2 + 1 });
|
|
195025
|
+
const size = arrow ? 2 : 1;
|
|
195026
|
+
tokens.push({ text: word2.slice(at3, at3 + size), quoted: false, column: index2 + at3 + 1 });
|
|
195027
|
+
start2 = at3 + size;
|
|
195028
|
+
at3 += size - 1;
|
|
195029
|
+
}
|
|
195030
|
+
if (start2 < word2.length) tokens.push({ text: word2.slice(start2), quoted: false, column: index2 + start2 + 1 });
|
|
195031
|
+
index2 = end;
|
|
195032
|
+
}
|
|
195033
|
+
return tokens;
|
|
195034
|
+
}
|
|
195035
|
+
function statementsOf2(text3) {
|
|
195036
|
+
const lines = text3.split("\n");
|
|
195037
|
+
const out = [];
|
|
195038
|
+
let inComment = false;
|
|
195039
|
+
let pending = null;
|
|
195040
|
+
for (let index2 = 0; index2 < lines.length && out.length < MAX_STATEMENTS; index2 += 1) {
|
|
195041
|
+
let line3 = lines[index2] ?? "";
|
|
195042
|
+
if (inComment) {
|
|
195043
|
+
const close2 = line3.indexOf("*/");
|
|
195044
|
+
if (close2 === -1) continue;
|
|
195045
|
+
line3 = " ".repeat(close2 + 2) + line3.slice(close2 + 2);
|
|
195046
|
+
inComment = false;
|
|
195047
|
+
}
|
|
195048
|
+
const trimmed4 = line3.trim();
|
|
195049
|
+
if (trimmed4.startsWith("/*")) {
|
|
195050
|
+
const close2 = line3.indexOf("*/", line3.indexOf("/*") + 2);
|
|
195051
|
+
if (close2 === -1) {
|
|
195052
|
+
inComment = true;
|
|
195053
|
+
continue;
|
|
195054
|
+
}
|
|
195055
|
+
line3 = " ".repeat(close2 + 2) + line3.slice(close2 + 2);
|
|
195056
|
+
}
|
|
195057
|
+
if (line3.trimEnd().endsWith("\\")) {
|
|
195058
|
+
const head = line3.trimEnd().slice(0, -1);
|
|
195059
|
+
pending = pending === null ? { text: head, line: index2 + 1 } : { text: `${pending.text} ${head.trim()}`, line: pending.line };
|
|
195060
|
+
continue;
|
|
195061
|
+
}
|
|
195062
|
+
const whole2 = pending === null ? { text: line3, line: index2 + 1 } : { text: `${pending.text} ${line3.trim()}`, line: pending.line };
|
|
195063
|
+
pending = null;
|
|
195064
|
+
const tokens = tokensOf(whole2.text);
|
|
195065
|
+
if (tokens.length === 0) continue;
|
|
195066
|
+
const open2 = tokens.findIndex((token) => !token.quoted && token.text === "{");
|
|
195067
|
+
const last = tokens[tokens.length - 1];
|
|
195068
|
+
if (open2 !== -1 && open2 < tokens.length - 1 && last !== void 0 && !last.quoted && last.text === "}") {
|
|
195069
|
+
out.push({ tokens: tokens.slice(0, open2 + 1), line: whole2.line });
|
|
195070
|
+
if (open2 + 1 < tokens.length - 1) out.push({ tokens: tokens.slice(open2 + 1, -1), line: whole2.line });
|
|
195071
|
+
out.push({ tokens: [last], line: whole2.line });
|
|
195072
|
+
continue;
|
|
195073
|
+
}
|
|
195074
|
+
out.push({ tokens, line: whole2.line });
|
|
195075
|
+
}
|
|
195076
|
+
return out;
|
|
195077
|
+
}
|
|
195078
|
+
var MAX_STATEMENTS;
|
|
195079
|
+
var init_tokens4 = __esm({
|
|
195080
|
+
"../../packages/diagrams/src/importers/structurizr/tokens.ts"() {
|
|
195081
|
+
"use strict";
|
|
195082
|
+
MAX_STATEMENTS = 5e4;
|
|
195083
|
+
}
|
|
195084
|
+
});
|
|
195085
|
+
|
|
195086
|
+
// ../../packages/diagrams/src/importers/structurizr/dsl.ts
|
|
195087
|
+
function readDsl(text3) {
|
|
195088
|
+
const statements = statementsOf2(text3);
|
|
195089
|
+
const elements = [];
|
|
195090
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
195091
|
+
const groups = [];
|
|
195092
|
+
const relationships = [];
|
|
195093
|
+
const views = [];
|
|
195094
|
+
const cylinderTags = [];
|
|
195095
|
+
const skipped = [];
|
|
195096
|
+
const constants = /* @__PURE__ */ new Map();
|
|
195097
|
+
const stack = [];
|
|
195098
|
+
let hierarchical = false;
|
|
195099
|
+
let name2 = null;
|
|
195100
|
+
let description = null;
|
|
195101
|
+
const skip = (what, at3, hint2) => {
|
|
195102
|
+
if (!skipped.some((entry2) => entry2.what === what)) skipped.push({ what, line: at3.line, column: at3.column, hint: hint2 });
|
|
195103
|
+
};
|
|
195104
|
+
const expand2 = (value) => value.includes("${") ? value.replace(/\$\{([A-Za-z0-9_-]{1,64})\}/g, (whole2, key) => constants.get(key) ?? whole2) : value;
|
|
195105
|
+
const currentElement = () => {
|
|
195106
|
+
for (let index2 = stack.length - 1; index2 >= 0; index2 -= 1) {
|
|
195107
|
+
const frame = stack[index2];
|
|
195108
|
+
if (frame?.type === "element") return frame.key;
|
|
195109
|
+
}
|
|
195110
|
+
return null;
|
|
195111
|
+
};
|
|
195112
|
+
const currentGroup = () => {
|
|
195113
|
+
for (let index2 = stack.length - 1; index2 >= 0; index2 -= 1) {
|
|
195114
|
+
const frame = stack[index2];
|
|
195115
|
+
if (frame?.type === "group") return frame.key;
|
|
195116
|
+
if (frame?.type === "element") return null;
|
|
195117
|
+
}
|
|
195118
|
+
return null;
|
|
195119
|
+
};
|
|
195120
|
+
const resolve5 = (reference, scope) => {
|
|
195121
|
+
if (reference === "this") return scope;
|
|
195122
|
+
const lower = reference.toLowerCase();
|
|
195123
|
+
if (hierarchical) {
|
|
195124
|
+
for (let at3 = scope; at3 !== null; at3 = byKey.get(at3.toLowerCase())?.parent ?? null) {
|
|
195125
|
+
const found = byKey.get(`${at3.toLowerCase()}.${lower}`);
|
|
195126
|
+
if (found !== void 0) return found.key;
|
|
195127
|
+
}
|
|
195128
|
+
}
|
|
195129
|
+
return byKey.get(lower)?.key ?? null;
|
|
195130
|
+
};
|
|
195131
|
+
const addElement = (statement, identifier, kind, args) => {
|
|
195132
|
+
const parent = currentElement();
|
|
195133
|
+
const parentDraft = parent === null ? void 0 : byKey.get(parent.toLowerCase());
|
|
195134
|
+
const label = args[0]?.text ?? kind;
|
|
195135
|
+
const named = parentDraft === void 0 ? label : `${parentDraft.key}/${label}`;
|
|
195136
|
+
const key = identifier === null ? named : hierarchical && parentDraft !== void 0 ? `${parentDraft.key}.${identifier}` : identifier;
|
|
195137
|
+
const hasTech = kind === "container" || kind === "component";
|
|
195138
|
+
const tags = tagsOf2(args.slice(hasTech ? 3 : 2));
|
|
195139
|
+
const draft = {
|
|
195140
|
+
key,
|
|
195141
|
+
kind,
|
|
195142
|
+
name: label,
|
|
195143
|
+
description: args[1]?.text === "" ? null : args[1]?.text ?? null,
|
|
195144
|
+
technology: hasTech && args[2] !== void 0 && args[2].text !== "" ? args[2].text : null,
|
|
195145
|
+
tags,
|
|
195146
|
+
parent: parentDraft?.key ?? null,
|
|
195147
|
+
group: currentGroup(),
|
|
195148
|
+
external: tags.some((tag) => tag.toLowerCase() === "external"),
|
|
195149
|
+
line: statement.line,
|
|
195150
|
+
column: statement.tokens[0]?.column ?? 1
|
|
195151
|
+
};
|
|
195152
|
+
if (!byKey.has(key.toLowerCase())) {
|
|
195153
|
+
elements.push(draft);
|
|
195154
|
+
byKey.set(key.toLowerCase(), draft);
|
|
195155
|
+
}
|
|
195156
|
+
return { type: "element", key: byKey.get(key.toLowerCase())?.key ?? key };
|
|
195157
|
+
};
|
|
195158
|
+
const readModelStatement = (statement, words2) => {
|
|
195159
|
+
const first = words2[0];
|
|
195160
|
+
if (first === void 0) return { type: "skip" };
|
|
195161
|
+
const keyword = first.text.toLowerCase();
|
|
195162
|
+
const scope = currentElement();
|
|
195163
|
+
if (!first.quoted && keyword === "!identifiers") {
|
|
195164
|
+
hierarchical = words2[1]?.text.toLowerCase() === "hierarchical";
|
|
195165
|
+
return { type: "skip" };
|
|
195166
|
+
}
|
|
195167
|
+
if (!first.quoted && (keyword === "!element" || keyword === "!ref")) {
|
|
195168
|
+
const key = resolve5(words2[1]?.text ?? "", scope);
|
|
195169
|
+
if (key === null) {
|
|
195170
|
+
skip(`!element ${words2[1]?.text ?? ""}`, { line: statement.line, column: first.column }, "The element it extends is not in the files sent; send the workspace that defines it.");
|
|
195171
|
+
return { type: "skip" };
|
|
195172
|
+
}
|
|
195173
|
+
return { type: "element", key };
|
|
195174
|
+
}
|
|
195175
|
+
const assigned = words2[1]?.text === "=" && !words2[1].quoted;
|
|
195176
|
+
const rest = assigned ? words2.slice(2) : words2;
|
|
195177
|
+
const arrow = rest.findIndex((token) => !token.quoted && token.text === "->");
|
|
195178
|
+
if (arrow === 0 || arrow === 1) {
|
|
195179
|
+
const from = arrow === 0 ? "this" : rest[0]?.text ?? "";
|
|
195180
|
+
const to = rest[arrow + 1];
|
|
195181
|
+
if (to === void 0 || arrow === 0 && scope === null) {
|
|
195182
|
+
skip("A relationship with no source", { line: statement.line, column: first.column }, "Write the relationship as source -> destination, or inside the block of its source.");
|
|
195183
|
+
return { type: "skip" };
|
|
195184
|
+
}
|
|
195185
|
+
const args = rest.slice(arrow + 2);
|
|
195186
|
+
relationships.push({ from, to: to.text, scope, description: args[0]?.text === "" ? null : args[0]?.text ?? null, technology: args[1]?.text === "" ? null : args[1]?.text ?? null, tags: tagsOf2(args.slice(2)), line: statement.line, column: first.column });
|
|
195187
|
+
return { type: "relationship", index: relationships.length - 1 };
|
|
195188
|
+
}
|
|
195189
|
+
const word2 = (rest[0]?.text ?? "").toLowerCase();
|
|
195190
|
+
const kind = rest[0]?.quoted === true ? void 0 : ELEMENT_WORDS[word2];
|
|
195191
|
+
if (kind !== void 0) return addElement(statement, assigned ? first.text : null, kind, rest.slice(1));
|
|
195192
|
+
if (word2 === "group" || word2 === "enterprise") {
|
|
195193
|
+
const label = rest[1]?.text ?? (word2 === "enterprise" ? "Enterprise" : "Group");
|
|
195194
|
+
const parent = currentGroup();
|
|
195195
|
+
const key = parent !== null ? `${parent}/${label}` : scope !== null ? `${scope}/${label}` : label;
|
|
195196
|
+
if (!groups.some((group2) => group2.key === key)) groups.push({ key, name: label, parent, enterprise: word2 === "enterprise", line: statement.line });
|
|
195197
|
+
return { type: "group", key };
|
|
195198
|
+
}
|
|
195199
|
+
if (DEPLOYMENT_WORDS.has(word2)) {
|
|
195200
|
+
skip("Deployment environments", { line: statement.line, column: first.column }, "The picture shows the system context, container, or component level; a deployment view is not drawn.");
|
|
195201
|
+
return { type: "skip" };
|
|
195202
|
+
}
|
|
195203
|
+
if (word2 === "element") {
|
|
195204
|
+
skip("Custom elements", { line: statement.line, column: first.column }, "Only people, software systems, containers, and components are drawn.");
|
|
195205
|
+
return { type: "skip" };
|
|
195206
|
+
}
|
|
195207
|
+
if (scope !== null && (word2 === "description" || word2 === "technology" || word2 === "tags" || word2 === "tag")) {
|
|
195208
|
+
const draft = byKey.get(scope.toLowerCase());
|
|
195209
|
+
const value = rest[1]?.text ?? "";
|
|
195210
|
+
if (draft !== void 0 && word2 === "description") draft.description = value === "" ? null : value;
|
|
195211
|
+
if (draft !== void 0 && word2 === "technology") draft.technology = value === "" ? null : value;
|
|
195212
|
+
if (draft !== void 0 && (word2 === "tags" || word2 === "tag")) {
|
|
195213
|
+
draft.tags = [...draft.tags, ...tagsOf2(rest.slice(1))];
|
|
195214
|
+
draft.external ||= draft.tags.some((tag) => tag.toLowerCase() === "external");
|
|
195215
|
+
}
|
|
195216
|
+
return { type: "skip" };
|
|
195217
|
+
}
|
|
195218
|
+
if (scope !== null && word2 === "location") {
|
|
195219
|
+
const draft = byKey.get(scope.toLowerCase());
|
|
195220
|
+
if (draft !== void 0 && rest[1]?.text.toLowerCase() === "external") draft.external = true;
|
|
195221
|
+
return { type: "skip" };
|
|
195222
|
+
}
|
|
195223
|
+
if (word2 === "!include") skip(`!include ${rest[1]?.text ?? ""}`, { line: statement.line, column: first.column }, "Included files are not fetched; send the workspace with the included text in place.");
|
|
195224
|
+
return { type: "skip" };
|
|
195225
|
+
};
|
|
195226
|
+
for (const statement of statements) {
|
|
195227
|
+
const tokens = statement.tokens.map((token) => ({ ...token, text: expand2(token.text) }));
|
|
195228
|
+
const first = tokens[0];
|
|
195229
|
+
if (first === void 0) continue;
|
|
195230
|
+
if (!first.quoted && first.text === "}") {
|
|
195231
|
+
stack.pop();
|
|
195232
|
+
continue;
|
|
195233
|
+
}
|
|
195234
|
+
const last = tokens[tokens.length - 1];
|
|
195235
|
+
const opens = last !== void 0 && !last.quoted && last.text === "{";
|
|
195236
|
+
const words2 = opens ? tokens.slice(0, -1) : tokens;
|
|
195237
|
+
const keyword = first.quoted ? "" : first.text.toLowerCase();
|
|
195238
|
+
const frame = stack[stack.length - 1];
|
|
195239
|
+
let next = { type: "skip" };
|
|
195240
|
+
if (keyword === "!const" || keyword === "!constant" || keyword === "!var") {
|
|
195241
|
+
const key = words2[1]?.text;
|
|
195242
|
+
if (key !== void 0) constants.set(key, words2[2]?.text ?? "");
|
|
195243
|
+
} else if (frame === void 0) {
|
|
195244
|
+
if (keyword === "workspace") {
|
|
195245
|
+
if (words2[1]?.text.toLowerCase() === "extends" && !words2[1].quoted) skip("workspace extends", { line: statement.line, column: first.column }, "The workspace it extends is not fetched; send the base workspace, or one that holds the whole model.");
|
|
195246
|
+
else {
|
|
195247
|
+
name2 = words2[1]?.text ?? null;
|
|
195248
|
+
description = words2[2]?.text ?? null;
|
|
195249
|
+
}
|
|
195250
|
+
next = { type: "workspace" };
|
|
195251
|
+
}
|
|
195252
|
+
} else if (frame.type === "workspace") {
|
|
195253
|
+
if (keyword === "model") next = { type: "model" };
|
|
195254
|
+
else if (keyword === "views") next = { type: "views" };
|
|
195255
|
+
else if (keyword === "name") name2 = words2[1]?.text ?? name2;
|
|
195256
|
+
else if (keyword === "description") description = words2[1]?.text ?? description;
|
|
195257
|
+
else if (keyword === "!identifiers") hierarchical = words2[1]?.text.toLowerCase() === "hierarchical";
|
|
195258
|
+
else if (keyword === "!include") skip(`!include ${words2[1]?.text ?? ""}`, { line: statement.line, column: first.column }, "Included files are not fetched; send the workspace with the included text in place.");
|
|
195259
|
+
} else if (frame.type === "model" || frame.type === "element" || frame.type === "group") {
|
|
195260
|
+
next = readModelStatement(statement, words2);
|
|
195261
|
+
} else if (frame.type === "relationship") {
|
|
195262
|
+
const relationship = relationships[frame.index];
|
|
195263
|
+
if (relationship !== void 0 && (keyword === "tags" || keyword === "tag")) relationship.tags.push(...tagsOf2(words2.slice(1)));
|
|
195264
|
+
if (relationship !== void 0 && keyword === "description") relationship.description = words2[1]?.text ?? relationship.description;
|
|
195265
|
+
if (relationship !== void 0 && keyword === "technology") relationship.technology = words2[1]?.text ?? relationship.technology;
|
|
195266
|
+
} else if (frame.type === "views") {
|
|
195267
|
+
const level2 = VIEW_WORDS2[keyword];
|
|
195268
|
+
if (level2 !== void 0 && words2[1] !== void 0) {
|
|
195269
|
+
views.push({ level: level2, scope: words2[1].text, title: null, direction: null, line: statement.line, column: words2[1].column });
|
|
195270
|
+
next = { type: "view", index: views.length - 1 };
|
|
195271
|
+
} else if (keyword === "styles") next = { type: "styles" };
|
|
195272
|
+
} else if (frame.type === "view") {
|
|
195273
|
+
const view = views[frame.index];
|
|
195274
|
+
if (view !== void 0 && keyword === "title") view.title = words2[1]?.text ?? null;
|
|
195275
|
+
if (view !== void 0 && keyword === "autolayout") view.direction = /^(?:lr|rl)$/i.test(words2[1]?.text ?? "") ? "right" : "down";
|
|
195276
|
+
} else if (frame.type === "styles") {
|
|
195277
|
+
if (keyword === "element" && words2[1] !== void 0) next = { type: "style", tag: words2[1].text };
|
|
195278
|
+
} else if (frame.type === "style") {
|
|
195279
|
+
if (keyword === "shape" && words2[1]?.text.toLowerCase() === "cylinder") cylinderTags.push(frame.tag);
|
|
195280
|
+
}
|
|
195281
|
+
if (opens) stack.push(next);
|
|
195282
|
+
}
|
|
195283
|
+
const unresolved = [];
|
|
195284
|
+
const resolved2 = [];
|
|
195285
|
+
for (const relationship of relationships) {
|
|
195286
|
+
const from = resolve5(relationship.from, relationship.scope);
|
|
195287
|
+
const to = resolve5(relationship.to, relationship.scope);
|
|
195288
|
+
for (const [written3, key] of [[relationship.from, from], [relationship.to, to]]) if (key === null) unresolved.push({ name: written3, line: relationship.line, column: relationship.column });
|
|
195289
|
+
if (from !== null && to !== null) resolved2.push({ from, to, description: relationship.description, technology: relationship.technology, tags: relationship.tags, line: relationship.line, column: relationship.column });
|
|
195290
|
+
}
|
|
195291
|
+
const modelViews = [];
|
|
195292
|
+
for (const view of views) {
|
|
195293
|
+
const scope = resolve5(view.scope, null);
|
|
195294
|
+
if (scope === null) unresolved.push({ name: view.scope, line: view.line, column: view.column });
|
|
195295
|
+
else modelViews.push({ level: view.level, scope, title: view.title, direction: view.direction, line: view.line });
|
|
195296
|
+
}
|
|
195297
|
+
return { workspace: { name: name2, description, elements, relationships: resolved2, groups, views: modelViews, cylinderTags, skipped }, unresolved };
|
|
195298
|
+
}
|
|
195299
|
+
var ELEMENT_WORDS, VIEW_WORDS2, DEPLOYMENT_WORDS, tagsOf2;
|
|
195300
|
+
var init_dsl = __esm({
|
|
195301
|
+
"../../packages/diagrams/src/importers/structurizr/dsl.ts"() {
|
|
195302
|
+
"use strict";
|
|
195303
|
+
init_tokens4();
|
|
195304
|
+
ELEMENT_WORDS = { person: "person", softwaresystem: "system", container: "container", component: "component" };
|
|
195305
|
+
VIEW_WORDS2 = { systemcontext: "context", container: "container", component: "component" };
|
|
195306
|
+
DEPLOYMENT_WORDS = /* @__PURE__ */ new Set(["deploymentenvironment", "deploymentnode", "infrastructurenode", "softwaresysteminstance", "containerinstance", "deploymentgroup"]);
|
|
195307
|
+
tagsOf2 = (tokens) => tokens.flatMap((token) => token.text.split(",")).map((tag) => tag.trim()).filter((tag) => tag !== "");
|
|
195308
|
+
}
|
|
195309
|
+
});
|
|
195310
|
+
|
|
195311
|
+
// ../../packages/diagrams/src/importers/structurizr/json.ts
|
|
195312
|
+
function isWorkspaceJson(value) {
|
|
195313
|
+
return isObject4(value) && isObject4(value["model"]) && (Array.isArray(value["model"]["softwareSystems"]) || Array.isArray(value["model"]["people"]));
|
|
195314
|
+
}
|
|
195315
|
+
function readWorkspaceJson(json2) {
|
|
195316
|
+
const model = isObject4(json2["model"]) ? json2["model"] : {};
|
|
195317
|
+
const elements = [];
|
|
195318
|
+
const keyOfId = /* @__PURE__ */ new Map();
|
|
195319
|
+
const groups = [];
|
|
195320
|
+
const rawRelationships = [];
|
|
195321
|
+
const add2 = (entry2, kind, parent) => {
|
|
195322
|
+
const name2 = textOf7(entry2["name"]) ?? kind;
|
|
195323
|
+
const properties = isObject4(entry2["properties"]) ? entry2["properties"] : {};
|
|
195324
|
+
const identifier = textOf7(properties["structurizr.dsl.identifier"]);
|
|
195325
|
+
const tags = tagsOf3(entry2["tags"]);
|
|
195326
|
+
const group2 = textOf7(entry2["group"]);
|
|
195327
|
+
if (group2 !== null && !groups.some((existing) => existing.key === group2)) groups.push({ key: group2, name: group2, parent: null, enterprise: false, line: 1 });
|
|
195328
|
+
const element = {
|
|
195329
|
+
key: identifier ?? (parent === null ? name2 : `${parent.key}/${name2}`),
|
|
195330
|
+
kind,
|
|
195331
|
+
name: name2,
|
|
195332
|
+
description: textOf7(entry2["description"]),
|
|
195333
|
+
technology: kind === "container" || kind === "component" ? textOf7(entry2["technology"]) : null,
|
|
195334
|
+
tags,
|
|
195335
|
+
parent: parent?.key ?? null,
|
|
195336
|
+
group: group2,
|
|
195337
|
+
external: textOf7(entry2["location"])?.toLowerCase() === "external" || tags.some((tag) => tag.toLowerCase() === "external"),
|
|
195338
|
+
line: 1,
|
|
195339
|
+
column: 1
|
|
195340
|
+
};
|
|
195341
|
+
elements.push(element);
|
|
195342
|
+
const id = textOf7(entry2["id"]);
|
|
195343
|
+
if (id !== null) keyOfId.set(id, element.key);
|
|
195344
|
+
rawRelationships.push(...listOf4(entry2["relationships"]));
|
|
195345
|
+
return element;
|
|
195346
|
+
};
|
|
195347
|
+
for (const person of listOf4(model["people"])) add2(person, "person", null);
|
|
195348
|
+
for (const system of listOf4(model["softwareSystems"])) {
|
|
195349
|
+
const parent = add2(system, "system", null);
|
|
195350
|
+
for (const container of listOf4(system["containers"])) {
|
|
195351
|
+
const holder = add2(container, "container", parent);
|
|
195352
|
+
for (const component of listOf4(container["components"])) add2(component, "component", holder);
|
|
195353
|
+
}
|
|
195354
|
+
}
|
|
195355
|
+
const relationships = [];
|
|
195356
|
+
for (const relationship of rawRelationships) {
|
|
195357
|
+
if (relationship["linkedRelationshipId"] !== void 0) continue;
|
|
195358
|
+
const from = keyOfId.get(textOf7(relationship["sourceId"]) ?? "");
|
|
195359
|
+
const to = keyOfId.get(textOf7(relationship["destinationId"]) ?? "");
|
|
195360
|
+
if (from === void 0 || to === void 0) continue;
|
|
195361
|
+
relationships.push({ from, to, description: textOf7(relationship["description"]), technology: textOf7(relationship["technology"]), tags: tagsOf3(relationship["tags"]), line: 1, column: 1 });
|
|
195362
|
+
}
|
|
195363
|
+
const viewsJson = isObject4(json2["views"]) ? json2["views"] : {};
|
|
195364
|
+
const views = [];
|
|
195365
|
+
const lists = [
|
|
195366
|
+
["systemContextViews", "context", "softwareSystemId"],
|
|
195367
|
+
["containerViews", "container", "softwareSystemId"],
|
|
195368
|
+
["componentViews", "component", "containerId"]
|
|
195369
|
+
];
|
|
195370
|
+
for (const [list, level2, field] of lists) {
|
|
195371
|
+
for (const view of listOf4(viewsJson[list])) {
|
|
195372
|
+
const scope = keyOfId.get(textOf7(view[field]) ?? "");
|
|
195373
|
+
const rank = isObject4(view["automaticLayout"]) ? textOf7(view["automaticLayout"]["rankDirection"]) : null;
|
|
195374
|
+
if (scope !== void 0) views.push({ level: level2, scope, title: textOf7(view["title"]), direction: rank === null ? null : /^(?:LeftRight|RightLeft)$/i.test(rank) ? "right" : "down", line: 1 });
|
|
195375
|
+
}
|
|
195376
|
+
}
|
|
195377
|
+
const configuration = isObject4(viewsJson["configuration"]) ? viewsJson["configuration"] : {};
|
|
195378
|
+
const styles = isObject4(configuration["styles"]) ? configuration["styles"] : {};
|
|
195379
|
+
const cylinderTags = listOf4(styles["elements"]).filter((style) => textOf7(style["shape"])?.toLowerCase() === "cylinder").map((style) => textOf7(style["tag"]) ?? "").filter((tag) => tag !== "");
|
|
195380
|
+
return { name: textOf7(json2["name"]), description: textOf7(json2["description"]), elements, relationships, groups, views, cylinderTags, skipped: [] };
|
|
195381
|
+
}
|
|
195382
|
+
var isObject4, listOf4, textOf7, DEFAULT_TAGS, tagsOf3;
|
|
195383
|
+
var init_json2 = __esm({
|
|
195384
|
+
"../../packages/diagrams/src/importers/structurizr/json.ts"() {
|
|
195385
|
+
"use strict";
|
|
195386
|
+
isObject4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
195387
|
+
listOf4 = (value) => Array.isArray(value) ? value.filter(isObject4) : [];
|
|
195388
|
+
textOf7 = (value) => typeof value === "string" && value.trim() !== "" ? value : typeof value === "number" ? String(value) : null;
|
|
195389
|
+
DEFAULT_TAGS = /* @__PURE__ */ new Set(["element", "person", "software system", "container", "component", "relationship"]);
|
|
195390
|
+
tagsOf3 = (value) => (textOf7(value) ?? "").split(",").map((tag) => tag.trim()).filter((tag) => tag !== "" && !DEFAULT_TAGS.has(tag.toLowerCase()));
|
|
195391
|
+
}
|
|
195392
|
+
});
|
|
195393
|
+
|
|
195394
|
+
// ../../packages/diagrams/src/importers/structurizr/view.ts
|
|
195395
|
+
function find(workspace, name2) {
|
|
195396
|
+
const lower = name2.toLowerCase();
|
|
195397
|
+
return workspace.elements.find((element) => element.key.toLowerCase() === lower) ?? workspace.elements.find((element) => element.name.toLowerCase() === lower);
|
|
195398
|
+
}
|
|
195399
|
+
function chooseView(workspace, level2, root) {
|
|
195400
|
+
const named = root === null ? null : find(workspace, root) ?? null;
|
|
195401
|
+
if (root !== null && named === null) return { view: null, missing: root };
|
|
195402
|
+
const systems = workspace.elements.filter((element) => element.kind === "system");
|
|
195403
|
+
const withChildren = (kind) => workspace.elements.find((element) => element.kind === kind && childrenOf(workspace, element.key).length > 0);
|
|
195404
|
+
const systemOf = (element) => {
|
|
195405
|
+
let at3 = element;
|
|
195406
|
+
for (let depth = 0; at3.parent !== null && depth < 3; depth += 1) at3 = workspace.elements.find((candidate2) => candidate2.key === at3.parent) ?? at3;
|
|
195407
|
+
return at3;
|
|
195408
|
+
};
|
|
195409
|
+
if (level2 === null && named === null) {
|
|
195410
|
+
const defined2 = workspace.views[0];
|
|
195411
|
+
const scope = defined2 === void 0 ? void 0 : workspace.elements.find((element) => element.key === defined2.scope);
|
|
195412
|
+
if (defined2 !== void 0 && scope !== void 0) return { view: { level: defined2.level, scope, title: defined2.title, direction: defined2.direction }, missing: null };
|
|
195413
|
+
const system2 = withChildren("system");
|
|
195414
|
+
if (system2 !== void 0) return { view: { level: "container", scope: system2, title: null, direction: null }, missing: null };
|
|
195415
|
+
const first = systems[0];
|
|
195416
|
+
return { view: first === void 0 ? null : { level: "context", scope: first, title: null, direction: null }, missing: null };
|
|
195417
|
+
}
|
|
195418
|
+
const wanted2 = level2 ?? (named?.kind === "container" || named?.kind === "component" ? "component" : named !== null && childrenOf(workspace, named.key).length > 0 ? "container" : "context");
|
|
195419
|
+
const defined = (scope) => workspace.views.find((view) => view.level === wanted2 && view.scope === scope.key);
|
|
195420
|
+
if (wanted2 === "component") {
|
|
195421
|
+
const container = named === null ? withChildren("container") : named.kind === "component" ? workspace.elements.find((element) => element.key === named.parent) : named.kind === "container" ? named : childrenOf(workspace, named.key).find((child) => childrenOf(workspace, child.key).length > 0) ?? childrenOf(workspace, named.key)[0];
|
|
195422
|
+
return { view: container === void 0 ? null : { level: "component", scope: container, title: defined(container)?.title ?? null, direction: defined(container)?.direction ?? null }, missing: null };
|
|
195423
|
+
}
|
|
195424
|
+
const system = named === null ? wanted2 === "container" ? withChildren("system") ?? systems[0] : withChildren("system") ?? systems[0] : named.kind === "person" ? void 0 : systemOf(named);
|
|
195425
|
+
return { view: system === void 0 ? null : { level: wanted2, scope: system, title: defined(system)?.title ?? null, direction: defined(system)?.direction ?? null }, missing: null };
|
|
195426
|
+
}
|
|
195427
|
+
function hiddenWords(workspace, element) {
|
|
195428
|
+
const containers = childrenOf(workspace, element.key);
|
|
195429
|
+
const components = containers.flatMap((child) => childrenOf(workspace, child.key));
|
|
195430
|
+
const parts = [
|
|
195431
|
+
containers.length === 0 ? null : `${containers.length} ${element.kind === "container" ? containers.length === 1 ? "component" : "components" : containers.length === 1 ? "container" : "containers"}`,
|
|
195432
|
+
components.length === 0 ? null : `${components.length} ${components.length === 1 ? "component" : "components"}`
|
|
195433
|
+
].filter((part) => part !== null);
|
|
195434
|
+
return { count: containers.length + components.length, words: parts.join(" and ") };
|
|
195435
|
+
}
|
|
195436
|
+
function project(workspace, view) {
|
|
195437
|
+
const byKey = new Map(workspace.elements.map((element) => [element.key, element]));
|
|
195438
|
+
const ancestors = (element) => {
|
|
195439
|
+
const out = [];
|
|
195440
|
+
for (let at3 = element.parent === null ? void 0 : byKey.get(element.parent); at3 !== void 0 && out.length < 3; at3 = at3.parent === null ? void 0 : byKey.get(at3.parent)) out.push(at3);
|
|
195441
|
+
return out;
|
|
195442
|
+
};
|
|
195443
|
+
const within = (element, holder) => element.key === holder.key || ancestors(element).some((ancestor) => ancestor.key === holder.key);
|
|
195444
|
+
const top = (element) => ancestors(element).pop() ?? element;
|
|
195445
|
+
const scope = view.scope;
|
|
195446
|
+
const system = top(scope);
|
|
195447
|
+
const inner = view.level === "context" ? [scope] : childrenOf(workspace, scope.key);
|
|
195448
|
+
const innerKeys = new Set(inner.map((element) => element.key));
|
|
195449
|
+
const innerOf2 = (element) => [element, ...ancestors(element)].find((candidate2) => innerKeys.has(candidate2.key)) ?? null;
|
|
195450
|
+
const outerOf = (element) => {
|
|
195451
|
+
if (view.level === "component" && within(element, system) && !within(element, scope)) return [element, ...ancestors(element)].find((candidate2) => candidate2.kind === "container") ?? null;
|
|
195452
|
+
if (within(element, system)) return null;
|
|
195453
|
+
return top(element);
|
|
195454
|
+
};
|
|
195455
|
+
const shown = new Map(inner.map((element) => [element.key, element]));
|
|
195456
|
+
const lines = [];
|
|
195457
|
+
const seen = /* @__PURE__ */ new Set();
|
|
195458
|
+
for (const relationship of workspace.relationships) {
|
|
195459
|
+
const fromElement = byKey.get(relationship.from);
|
|
195460
|
+
const toElement = byKey.get(relationship.to);
|
|
195461
|
+
if (fromElement === void 0 || toElement === void 0) continue;
|
|
195462
|
+
const fromInner = innerOf2(fromElement);
|
|
195463
|
+
const toInner = innerOf2(toElement);
|
|
195464
|
+
if (fromInner === null && toInner === null) continue;
|
|
195465
|
+
const from = fromInner ?? outerOf(fromElement);
|
|
195466
|
+
const to = toInner ?? outerOf(toElement);
|
|
195467
|
+
if (from === null || to === null || from.key === to.key) continue;
|
|
195468
|
+
shown.set(from.key, from);
|
|
195469
|
+
shown.set(to.key, to);
|
|
195470
|
+
const pair2 = `${from.key}\0${to.key}`;
|
|
195471
|
+
if (seen.has(pair2)) continue;
|
|
195472
|
+
seen.add(pair2);
|
|
195473
|
+
lines.push({ from: from.key, to: to.key, relationship });
|
|
195474
|
+
}
|
|
195475
|
+
for (const relationship of workspace.relationships) {
|
|
195476
|
+
const fromElement = byKey.get(relationship.from);
|
|
195477
|
+
const toElement = byKey.get(relationship.to);
|
|
195478
|
+
if (fromElement === void 0 || toElement === void 0 || innerOf2(fromElement) !== null || innerOf2(toElement) !== null) continue;
|
|
195479
|
+
const from = outerOf(fromElement);
|
|
195480
|
+
const to = outerOf(toElement);
|
|
195481
|
+
if (from === null || to === null || from.key === to.key || !shown.has(from.key) || !shown.has(to.key)) continue;
|
|
195482
|
+
const pair2 = `${from.key}\0${to.key}`;
|
|
195483
|
+
if (seen.has(pair2)) continue;
|
|
195484
|
+
seen.add(pair2);
|
|
195485
|
+
lines.push({ from: from.key, to: to.key, relationship });
|
|
195486
|
+
}
|
|
195487
|
+
const boundaries = [];
|
|
195488
|
+
const groupBoundary = (groupKey, holder) => {
|
|
195489
|
+
const group2 = groupKey === null ? void 0 : workspace.groups.find((entry2) => entry2.key === groupKey);
|
|
195490
|
+
if (group2 === void 0) return holder;
|
|
195491
|
+
const parent = groupBoundary(group2.parent, holder);
|
|
195492
|
+
const key = `group:${group2.key}`;
|
|
195493
|
+
if (!boundaries.some((boundary) => boundary.key === key)) boundaries.push({ key, name: group2.name, kind: group2.enterprise ? "enterprise" : "group", parent, tech: null, element: null });
|
|
195494
|
+
return key;
|
|
195495
|
+
};
|
|
195496
|
+
let scopeBoundary = null;
|
|
195497
|
+
if (view.level === "component") {
|
|
195498
|
+
boundaries.push({ key: system.key, name: system.name, kind: "system", parent: groupBoundary(system.group, null), tech: null, element: system });
|
|
195499
|
+
boundaries.push({ key: scope.key, name: scope.name, kind: "container", parent: system.key, tech: scope.technology, element: scope });
|
|
195500
|
+
scopeBoundary = scope.key;
|
|
195501
|
+
} else if (view.level === "container") {
|
|
195502
|
+
boundaries.push({ key: scope.key, name: scope.name, kind: "system", parent: groupBoundary(scope.group, null), tech: null, element: scope });
|
|
195503
|
+
scopeBoundary = scope.key;
|
|
195504
|
+
}
|
|
195505
|
+
const enterprise = workspace.groups.some((group2) => group2.enterprise);
|
|
195506
|
+
const inEnterprise = (element) => {
|
|
195507
|
+
let group2 = workspace.groups.find((entry2) => entry2.key === top(element).group);
|
|
195508
|
+
for (let depth = 0; group2 !== void 0 && depth < workspace.groups.length; depth += 1) {
|
|
195509
|
+
if (group2.enterprise) return true;
|
|
195510
|
+
group2 = workspace.groups.find((entry2) => entry2.key === group2?.parent);
|
|
195511
|
+
}
|
|
195512
|
+
return false;
|
|
195513
|
+
};
|
|
195514
|
+
const order = (element) => innerKeys.has(element.key) ? 1 : element.kind === "person" ? 0 : 2;
|
|
195515
|
+
const placed = [...shown.values()].sort((a, b) => order(a) - order(b) || workspace.elements.indexOf(a) - workspace.elements.indexOf(b)).map((element) => {
|
|
195516
|
+
const holder = innerKeys.has(element.key) && view.level !== "context" ? scopeBoundary : view.level === "component" && within(element, system) ? system.key : null;
|
|
195517
|
+
const hidden = hiddenWords(workspace, element);
|
|
195518
|
+
return { element, boundary: groupBoundary(element.group, holder), external: element.external || element.kind === "system" && element.key !== system.key && (enterprise ? !inEnterprise(element) : true), hidden: hidden.count, hiddenWords: hidden.words };
|
|
195519
|
+
});
|
|
195520
|
+
const depthOf7 = (key) => {
|
|
195521
|
+
let depth = 0;
|
|
195522
|
+
for (let at3 = key; at3 !== null && depth <= boundaries.length; depth += 1) at3 = boundaries.find((boundary) => boundary.key === at3)?.parent ?? null;
|
|
195523
|
+
return depth;
|
|
195524
|
+
};
|
|
195525
|
+
const kept2 = (key) => {
|
|
195526
|
+
let at3 = key;
|
|
195527
|
+
while (at3 !== null && depthOf7(at3) > MAX_DEPTH16) at3 = boundaries.find((boundary) => boundary.key === at3)?.parent ?? null;
|
|
195528
|
+
return at3;
|
|
195529
|
+
};
|
|
195530
|
+
const elements = placed.map((entry2) => ({ ...entry2, boundary: kept2(entry2.boundary) }));
|
|
195531
|
+
const used = new Set(elements.map((entry2) => entry2.boundary));
|
|
195532
|
+
for (let changed = true, round2 = 0; changed && round2 <= boundaries.length; round2 += 1) {
|
|
195533
|
+
changed = false;
|
|
195534
|
+
for (const boundary of boundaries) if (used.has(boundary.key) && boundary.parent !== null && !used.has(boundary.parent)) {
|
|
195535
|
+
used.add(boundary.parent);
|
|
195536
|
+
changed = true;
|
|
195537
|
+
}
|
|
195538
|
+
}
|
|
195539
|
+
const shownBoundaries = boundaries.filter((boundary) => depthOf7(boundary.key) <= MAX_DEPTH16 && (boundary.element !== null || used.has(boundary.key)));
|
|
195540
|
+
const drawn = /* @__PURE__ */ new Set([...elements.map((entry2) => entry2.element.key), ...shownBoundaries.flatMap((boundary) => boundary.element === null ? [] : [boundary.element.key])]);
|
|
195541
|
+
const summarisedBy = (element) => ancestors(element).some((ancestor) => shown.has(ancestor.key));
|
|
195542
|
+
const summarised = workspace.elements.filter((element) => !drawn.has(element.key) && summarisedBy(element)).length;
|
|
195543
|
+
const omitted = workspace.elements.filter((element) => !drawn.has(element.key) && !summarisedBy(element));
|
|
195544
|
+
return { elements, boundaries: shownBoundaries, relationships: lines, summarised, omitted };
|
|
195545
|
+
}
|
|
195546
|
+
var MAX_DEPTH16, childrenOf;
|
|
195547
|
+
var init_view = __esm({
|
|
195548
|
+
"../../packages/diagrams/src/importers/structurizr/view.ts"() {
|
|
195549
|
+
"use strict";
|
|
195550
|
+
MAX_DEPTH16 = 4;
|
|
195551
|
+
childrenOf = (workspace, key) => workspace.elements.filter((element) => element.parent === key);
|
|
195552
|
+
}
|
|
195553
|
+
});
|
|
195554
|
+
|
|
195555
|
+
// ../../packages/diagrams/src/importers/structurizr/index.ts
|
|
195556
|
+
function isDatabase(element, workspace) {
|
|
195557
|
+
if (element.kind !== "container" && element.kind !== "component") return false;
|
|
195558
|
+
const tags = element.tags.map((tag) => tag.toLowerCase());
|
|
195559
|
+
return tags.includes("database") || workspace.cylinderTags.some((tag) => tags.includes(tag.toLowerCase())) || element.technology !== null && DATABASE_WORDS.test(element.technology);
|
|
195560
|
+
}
|
|
195561
|
+
function readWorkspace(text3, context) {
|
|
195562
|
+
if (/^\s*\{/.test(text3)) {
|
|
195563
|
+
let json2;
|
|
195564
|
+
try {
|
|
195565
|
+
json2 = JSON.parse(text3);
|
|
195566
|
+
} catch (error62) {
|
|
195567
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, START, `The text is not JSON: ${error62 instanceof Error ? error62.message : "it cannot be read"}.`, "Send the workspace as Structurizr exports it (workspace.json), or its DSL (workspace.dsl).");
|
|
195568
|
+
return null;
|
|
195569
|
+
}
|
|
195570
|
+
if (!isWorkspaceJson(json2)) {
|
|
195571
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The JSON has no model of people or software systems, so it is not a Structurizr workspace.", "Send workspace.json as Structurizr exports it, or the workspace DSL.");
|
|
195572
|
+
return null;
|
|
195573
|
+
}
|
|
195574
|
+
return { workspace: readWorkspaceJson(json2), unresolved: [] };
|
|
195575
|
+
}
|
|
195576
|
+
return readDsl(text3);
|
|
195577
|
+
}
|
|
195578
|
+
function writeC4(workspace, view, shown, title, desc) {
|
|
195579
|
+
const ids = new IdAllocator();
|
|
195580
|
+
const hint2 = (element) => element.key.includes("/") ? element.name : element.key.split(".").pop() ?? element.name;
|
|
195581
|
+
for (const boundary of shown.boundaries) if (boundary.element !== null) ids.idFor(`b:${boundary.key}`, hint2(boundary.element));
|
|
195582
|
+
for (const entry2 of shown.elements) ids.idFor(`e:${entry2.element.key}`, hint2(entry2.element));
|
|
195583
|
+
for (const boundary of shown.boundaries) if (boundary.element === null) ids.idFor(`b:${boundary.key}`, boundary.name.toLowerCase());
|
|
195584
|
+
const lines = new SourceLines();
|
|
195585
|
+
lines.add(`c4 ${quote(title)}${options2({ view: view.level, direction: view.direction, desc })}`);
|
|
195586
|
+
const elementLine2 = (entry2, depth) => {
|
|
195587
|
+
const { element } = entry2;
|
|
195588
|
+
const type = isDatabase(element, workspace) ? "db" : element.kind;
|
|
195589
|
+
const text3 = [element.description === null ? null : cleanText(element.description), entry2.hidden === 0 ? null : `Holds ${entry2.hiddenWords}.`].filter((part) => part !== null).join(" ");
|
|
195590
|
+
lines.add(`${type} ${ids.idFor(`e:${element.key}`)} ${quote(cleanText(element.name))}${options2({ tech: element.technology === null ? null : cleanText(element.technology), desc: text3, external: entry2.external ? "on" : null }, ["tech", "desc"])}`, depth);
|
|
195591
|
+
};
|
|
195592
|
+
const writeBoundary = (boundary, depth) => {
|
|
195593
|
+
lines.gap();
|
|
195594
|
+
lines.add(`boundary ${ids.idFor(`b:${boundary.key}`)} ${quote(cleanText(boundary.name))}${options2({ kind: boundary.kind, tech: boundary.tech === null ? null : cleanText(boundary.tech) }, ["tech"])} {`, depth);
|
|
195595
|
+
for (const entry2 of shown.elements) if (entry2.boundary === boundary.key) elementLine2(entry2, depth + 1);
|
|
195596
|
+
for (const child of shown.boundaries) if (child.parent === boundary.key) writeBoundary(child, depth + 1);
|
|
195597
|
+
lines.add("}", depth);
|
|
195598
|
+
};
|
|
195599
|
+
lines.gap();
|
|
195600
|
+
const people = shown.elements.filter((entry2) => entry2.boundary === null && entry2.element.kind === "person");
|
|
195601
|
+
for (const entry2 of people) elementLine2(entry2, 0);
|
|
195602
|
+
for (const boundary of shown.boundaries) if (boundary.parent === null) writeBoundary(boundary, 0);
|
|
195603
|
+
lines.gap();
|
|
195604
|
+
for (const entry2 of shown.elements) if (entry2.boundary === null && entry2.element.kind !== "person") elementLine2(entry2, 0);
|
|
195605
|
+
lines.gap();
|
|
195606
|
+
const kindOf3 = new Map(shown.elements.map((entry2) => [entry2.element.key, entry2.element.kind]));
|
|
195607
|
+
const ordered = [...shown.relationships].sort((a, b) => Number(kindOf3.get(a.from) !== "person") - Number(kindOf3.get(b.from) !== "person"));
|
|
195608
|
+
for (const line3 of ordered) {
|
|
195609
|
+
const { relationship } = line3;
|
|
195610
|
+
const async = relationship.tags.some((tag) => /^async(?:hronous)?$/i.test(tag));
|
|
195611
|
+
const label = relationship.description === null ? "" : ` : ${quote(cleanText(relationship.description))}${options2({ tech: relationship.technology === null ? null : cleanText(relationship.technology) }, ["tech"])}`;
|
|
195612
|
+
lines.add(`${ids.idFor(`e:${line3.from}`)} ${async ? "-->" : "->"} ${ids.idFor(`e:${line3.to}`)}${label}`);
|
|
195613
|
+
}
|
|
195614
|
+
return { source: lines.toString(), ids: { ...ids.mapped("b:"), ...ids.mapped("e:") }, links: shown.relationships.length };
|
|
195615
|
+
}
|
|
195616
|
+
function capped(shown, context) {
|
|
195617
|
+
const elements = shown.elements.slice(0, C4_BUDGET.maxElements);
|
|
195618
|
+
const keys = new Set(elements.map((entry2) => entry2.element.key));
|
|
195619
|
+
const relationships = shown.relationships.filter((line3) => keys.has(line3.from) && keys.has(line3.to)).slice(0, C4_BUDGET.maxRelationships);
|
|
195620
|
+
const leftElements = shown.elements.length - elements.length;
|
|
195621
|
+
const leftLines = shown.relationships.length - relationships.length;
|
|
195622
|
+
if (leftElements + leftLines > 0) {
|
|
195623
|
+
const first = shown.elements[C4_BUDGET.maxElements]?.element;
|
|
195624
|
+
context.report.add(
|
|
195625
|
+
DIAGNOSTIC_CODES.importDropped,
|
|
195626
|
+
first === void 0 ? START : spanAt3(first.line, first.column),
|
|
195627
|
+
`${[leftElements === 0 ? null : countOf2(leftElements, "element"), leftLines === 0 ? null : countOf2(leftLines, "relationship")].filter((part) => part !== null).join(" and ")} past what one C4 picture holds ${leftElements + leftLines === 1 ? "was" : "were"} left out.`,
|
|
195628
|
+
"Draw a smaller view: one container with options.view component, or one system with options.root."
|
|
195629
|
+
);
|
|
195630
|
+
}
|
|
195631
|
+
return { ...shown, elements, relationships, omitted: [...shown.omitted, ...shown.elements.slice(C4_BUDGET.maxElements).map((entry2) => entry2.element)] };
|
|
195632
|
+
}
|
|
195633
|
+
function readStructurizr(text3, context) {
|
|
195634
|
+
const read = readWorkspace(text3, context);
|
|
195635
|
+
if (read === null) return null;
|
|
195636
|
+
const { workspace, unresolved } = read;
|
|
195637
|
+
if (workspace.elements.length === 0) {
|
|
195638
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The workspace has no people, software systems, containers, or components.", 'Send a workspace with a model block, such as workspace { model { user = person "User" } }.');
|
|
195639
|
+
return null;
|
|
195640
|
+
}
|
|
195641
|
+
for (const skipped of workspace.skipped) context.report.add(DIAGNOSTIC_CODES.importSkipped, spanAt3(skipped.line, skipped.column), `${cleanText(skipped.what)} ${skipped.what.startsWith("!") || skipped.what.startsWith("workspace") ? "is" : "are"} not drawn.`, skipped.hint);
|
|
195642
|
+
const firstUnresolved = unresolved[0];
|
|
195643
|
+
if (firstUnresolved !== void 0) {
|
|
195644
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(firstUnresolved.line, firstUnresolved.column), `${countOf2(unresolved.length, "reference")} name${unresolved.length === 1 ? "s" : ""} no element of the model: ${[...new Set(unresolved.map((entry2) => entry2.name))].slice(0, 3).map((name2) => cleanText(name2)).join(", ")}.`, "Check the identifier; with !identifiers hierarchical, an element inside another is named by its path, such as shop.api.");
|
|
195645
|
+
}
|
|
195646
|
+
const requested = context.options.view;
|
|
195647
|
+
const level2 = requested !== void 0 && LEVELS.includes(requested) ? requested : null;
|
|
195648
|
+
const chosen = chooseView(workspace, level2, context.options.root ?? null);
|
|
195649
|
+
if (chosen.missing !== null) {
|
|
195650
|
+
context.report.add(DIAGNOSTIC_CODES.importNotFound, START, `No element of the workspace is named ${cleanText(chosen.missing)}.`, `Set options.root to the identifier or name of a software system or container, such as ${workspace.elements.find((element) => element.kind === "system")?.key ?? "shop"}.`);
|
|
195651
|
+
return null;
|
|
195652
|
+
}
|
|
195653
|
+
if (chosen.view === null) {
|
|
195654
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, level2 === "component" ? "No container of the workspace has components." : "The workspace has no software system to draw a view of.", "Add a softwareSystem to the model, or choose another level with options.view.");
|
|
195655
|
+
return null;
|
|
195656
|
+
}
|
|
195657
|
+
const view = chosen.view;
|
|
195658
|
+
const shown = capped(project(workspace, view), context);
|
|
195659
|
+
const omitted = shown.omitted;
|
|
195660
|
+
const firstOmitted = omitted[0];
|
|
195661
|
+
if (firstOmitted !== void 0) {
|
|
195662
|
+
context.report.add(
|
|
195663
|
+
DIAGNOSTIC_CODES.importSkipped,
|
|
195664
|
+
spanAt3(firstOmitted.line, firstOmitted.column),
|
|
195665
|
+
`${countOf2(omitted.length, "element")} ${omitted.length === 1 ? "is" : "are"} not in the ${LEVEL_WORDS[view.level].title} view of ${cleanText(view.scope.name)}: ${omitted.slice(0, 3).map((element) => cleanText(element.key)).join(", ")}.`,
|
|
195666
|
+
"An element is drawn when a relationship joins it to what the view is about. Choose another view with options.view (context, container, or component) and options.root."
|
|
195667
|
+
);
|
|
195668
|
+
}
|
|
195669
|
+
const scopeName = cleanText(view.scope.name);
|
|
195670
|
+
const title = context.title ?? (view.title === null ? `${scopeName}: ${LEVEL_WORDS[view.level].title}` : cleanText(view.title));
|
|
195671
|
+
const what = view.level === "context" ? `${scopeName} ${LEVEL_WORDS.context.sentence}` : `${LEVEL_WORDS[view.level].sentence} ${scopeName} and what they talk to`;
|
|
195672
|
+
const desc = `${what.charAt(0).toUpperCase()}${what.slice(1)}, imported from the Structurizr workspace${workspace.name === null ? "" : ` ${cleanText(workspace.name)}`}.`;
|
|
195673
|
+
const written3 = writeC4(workspace, view, shown, title, desc);
|
|
195674
|
+
const drawn = shown.elements.length + shown.boundaries.filter((boundary) => boundary.element !== null).length;
|
|
195675
|
+
const others = workspace.views.length > 1 ? ` The workspace defines ${countOf2(workspace.views.length, "view")}; draw another with options.view and options.root.` : "";
|
|
195676
|
+
return {
|
|
195677
|
+
kind: "c4",
|
|
195678
|
+
source: written3.source,
|
|
195679
|
+
stats: { items: shown.elements.length, links: written3.links, groups: shown.boundaries.length, dropped: omitted.length },
|
|
195680
|
+
advice: `Check that each element has a description and each relationship a technology, so the cards and lines say what they do.${others}`,
|
|
195681
|
+
coverage: { noun: "elements", total: workspace.elements.length, drawn, summarised: shown.summarised },
|
|
195682
|
+
ids: written3.ids
|
|
195683
|
+
};
|
|
195684
|
+
}
|
|
195685
|
+
var DATABASE_WORDS, LEVELS, LEVEL_WORDS, structurizrImporter;
|
|
195686
|
+
var init_structurizr = __esm({
|
|
195687
|
+
"../../packages/diagrams/src/importers/structurizr/index.ts"() {
|
|
195688
|
+
"use strict";
|
|
195689
|
+
init_core();
|
|
195690
|
+
init_limits();
|
|
195691
|
+
init_shared2();
|
|
195692
|
+
init_dsl();
|
|
195693
|
+
init_json2();
|
|
195694
|
+
init_view();
|
|
195695
|
+
DATABASE_WORDS = /\b(?:database|postgres(?:ql)?|mysql|mariadb|oracle|sql server|sqlite|mongodb|dynamodb|cassandra|cosmos ?db|couchdb|neo4j|elasticsearch|opensearch|clickhouse|snowflake|bigquery|redshift)\b/i;
|
|
195696
|
+
LEVELS = ["context", "container", "component"];
|
|
195697
|
+
LEVEL_WORDS = {
|
|
195698
|
+
context: { title: "system context", sentence: "and the people and systems around it" },
|
|
195699
|
+
container: { title: "containers", sentence: "the containers of" },
|
|
195700
|
+
component: { title: "components", sentence: "the components of" }
|
|
195701
|
+
};
|
|
195702
|
+
structurizrImporter = { format: "structurizr", kinds: ["c4"], joins: null, extensions: [".dsl", ".json"], read: readStructurizr };
|
|
195703
|
+
}
|
|
195704
|
+
});
|
|
195705
|
+
|
|
194247
195706
|
// ../../packages/diagrams/src/importers/terraform-plan/document.ts
|
|
194248
195707
|
function moduleOfAddress(address, type, mode) {
|
|
194249
195708
|
const own2 = `${mode === "data" ? "data." : ""}${type}.`;
|
|
@@ -194251,7 +195710,7 @@ function moduleOfAddress(address, type, mode) {
|
|
|
194251
195710
|
return at3 <= 0 ? "" : address.slice(0, at3 - 1);
|
|
194252
195711
|
}
|
|
194253
195712
|
function resourceOf3(raw, module) {
|
|
194254
|
-
if (!
|
|
195713
|
+
if (!isObject5(raw) || typeof raw["address"] !== "string" || typeof raw["type"] !== "string" || typeof raw["name"] !== "string") return null;
|
|
194255
195714
|
const mode = raw["mode"] === "data" ? "data" : "managed";
|
|
194256
195715
|
const index2 = typeof raw["index"] === "string" || typeof raw["index"] === "number" ? raw["index"] : null;
|
|
194257
195716
|
return {
|
|
@@ -194261,13 +195720,13 @@ function resourceOf3(raw, module) {
|
|
|
194261
195720
|
name: raw["name"],
|
|
194262
195721
|
index: index2,
|
|
194263
195722
|
module: module === "" ? moduleOfAddress(raw["address"], raw["type"], mode) : module,
|
|
194264
|
-
values:
|
|
194265
|
-
sensitive:
|
|
195723
|
+
values: isObject5(raw["values"]) ? raw["values"] : {},
|
|
195724
|
+
sensitive: isObject5(raw["sensitive_values"]) ? raw["sensitive_values"] : {},
|
|
194266
195725
|
dependsOn: strings2(raw["depends_on"])
|
|
194267
195726
|
};
|
|
194268
195727
|
}
|
|
194269
195728
|
function moduleResources(raw, depth = 0) {
|
|
194270
|
-
if (!
|
|
195729
|
+
if (!isObject5(raw) || depth > MAX_MODULE_DEPTH2) return [];
|
|
194271
195730
|
const address = typeof raw["address"] === "string" ? raw["address"] : "";
|
|
194272
195731
|
const own2 = (Array.isArray(raw["resources"]) ? raw["resources"] : []).map((entry2) => resourceOf3(entry2, address)).filter((entry2) => entry2 !== null);
|
|
194273
195732
|
const children = Array.isArray(raw["child_modules"]) ? raw["child_modules"].flatMap((child) => moduleResources(child, depth + 1)) : [];
|
|
@@ -194275,9 +195734,9 @@ function moduleResources(raw, depth = 0) {
|
|
|
194275
195734
|
}
|
|
194276
195735
|
function variablesOf(raw, sensitive) {
|
|
194277
195736
|
const out = /* @__PURE__ */ new Map();
|
|
194278
|
-
if (!
|
|
195737
|
+
if (!isObject5(raw)) return out;
|
|
194279
195738
|
for (const [name2, entry2] of Object.entries(raw)) {
|
|
194280
|
-
if (sensitive.has(name2) || !
|
|
195739
|
+
if (sensitive.has(name2) || !isObject5(entry2)) continue;
|
|
194281
195740
|
const value = entry2["value"];
|
|
194282
195741
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out.set(name2, String(value));
|
|
194283
195742
|
}
|
|
@@ -194286,28 +195745,28 @@ function variablesOf(raw, sensitive) {
|
|
|
194286
195745
|
function sensitiveVariables(configuration) {
|
|
194287
195746
|
const out = /* @__PURE__ */ new Set();
|
|
194288
195747
|
const root = configuration === null ? null : configuration["root_module"];
|
|
194289
|
-
const variables =
|
|
194290
|
-
for (const [name2, entry2] of Object.entries(variables)) if (
|
|
195748
|
+
const variables = isObject5(root) && isObject5(root["variables"]) ? root["variables"] : {};
|
|
195749
|
+
for (const [name2, entry2] of Object.entries(variables)) if (isObject5(entry2) && entry2["sensitive"] === true) out.add(name2);
|
|
194291
195750
|
return out;
|
|
194292
195751
|
}
|
|
194293
195752
|
function changesOf(raw) {
|
|
194294
195753
|
const out = /* @__PURE__ */ new Map();
|
|
194295
195754
|
if (!Array.isArray(raw)) return out;
|
|
194296
195755
|
for (const entry2 of raw) {
|
|
194297
|
-
if (!
|
|
195756
|
+
if (!isObject5(entry2) || typeof entry2["address"] !== "string" || !isObject5(entry2["change"])) continue;
|
|
194298
195757
|
const change = entry2["change"];
|
|
194299
|
-
out.set(entry2["address"], { actions: strings2(change["actions"]), previous: typeof entry2["previous_address"] === "string" ? entry2["previous_address"] : null, before:
|
|
195758
|
+
out.set(entry2["address"], { actions: strings2(change["actions"]), previous: typeof entry2["previous_address"] === "string" ? entry2["previous_address"] : null, before: isObject5(change["before"]) ? change["before"] : null });
|
|
194300
195759
|
}
|
|
194301
195760
|
return out;
|
|
194302
195761
|
}
|
|
194303
195762
|
function readPlanDocument(json2) {
|
|
194304
|
-
if (!
|
|
194305
|
-
const configuration =
|
|
194306
|
-
const providers = configuration !== null &&
|
|
195763
|
+
if (!isObject5(json2)) return null;
|
|
195764
|
+
const configuration = isObject5(json2["configuration"]) ? json2["configuration"] : null;
|
|
195765
|
+
const providers = configuration !== null && isObject5(configuration["provider_config"]) ? configuration["provider_config"] : {};
|
|
194307
195766
|
const variables = variablesOf(json2["variables"], sensitiveVariables(configuration));
|
|
194308
|
-
if (
|
|
194309
|
-
const planned =
|
|
194310
|
-
const prior =
|
|
195767
|
+
if (isObject5(json2["planned_values"]) || Array.isArray(json2["resource_changes"])) {
|
|
195768
|
+
const planned = isObject5(json2["planned_values"]) ? moduleResources(json2["planned_values"]["root_module"]) : [];
|
|
195769
|
+
const prior = isObject5(json2["prior_state"]) && isObject5(json2["prior_state"]["values"]) ? moduleResources(json2["prior_state"]["values"]["root_module"]) : [];
|
|
194311
195770
|
const changes = changesOf(json2["resource_changes"]);
|
|
194312
195771
|
const kept2 = new Set(planned.map((resource) => resource.address));
|
|
194313
195772
|
const data = prior.filter((resource) => resource.mode === "data" && !kept2.has(resource.address));
|
|
@@ -194320,11 +195779,11 @@ function readPlanDocument(json2) {
|
|
|
194320
195779
|
}
|
|
194321
195780
|
const drift = /* @__PURE__ */ new Set();
|
|
194322
195781
|
if (Array.isArray(json2["resource_drift"])) {
|
|
194323
|
-
for (const entry2 of json2["resource_drift"]) if (
|
|
195782
|
+
for (const entry2 of json2["resource_drift"]) if (isObject5(entry2) && typeof entry2["address"] === "string") drift.add(entry2["address"]);
|
|
194324
195783
|
}
|
|
194325
195784
|
return { kind: "plan", resources: [...planned, ...data], destroyed, changes, drift, configuration, providers, variables };
|
|
194326
195785
|
}
|
|
194327
|
-
if (
|
|
195786
|
+
if (isObject5(json2["values"]) && isObject5(json2["values"]["root_module"])) {
|
|
194328
195787
|
return { kind: "state", resources: moduleResources(json2["values"]["root_module"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration, providers, variables };
|
|
194329
195788
|
}
|
|
194330
195789
|
if (Array.isArray(json2["resources"]) && typeof json2["version"] === "number") return { kind: "state", resources: rawStateResources(json2["resources"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration: null, providers: {}, variables: /* @__PURE__ */ new Map() };
|
|
@@ -194333,12 +195792,12 @@ function readPlanDocument(json2) {
|
|
|
194333
195792
|
function rawStateResources(raw) {
|
|
194334
195793
|
const out = [];
|
|
194335
195794
|
for (const block of raw) {
|
|
194336
|
-
if (!
|
|
195795
|
+
if (!isObject5(block) || typeof block["type"] !== "string" || typeof block["name"] !== "string" || !Array.isArray(block["instances"])) continue;
|
|
194337
195796
|
const module = typeof block["module"] === "string" ? block["module"] : "";
|
|
194338
195797
|
const mode = block["mode"] === "data" ? "data" : "managed";
|
|
194339
195798
|
const base = `${module === "" ? "" : `${module}.`}${mode === "data" ? "data." : ""}${block["type"]}.${block["name"]}`;
|
|
194340
195799
|
for (const instance of block["instances"]) {
|
|
194341
|
-
if (!
|
|
195800
|
+
if (!isObject5(instance)) continue;
|
|
194342
195801
|
const key = instance["index_key"];
|
|
194343
195802
|
const index2 = typeof key === "string" || typeof key === "number" ? key : null;
|
|
194344
195803
|
const address = `${base}${index2 === null ? "" : typeof index2 === "number" ? `[${index2}]` : `[${JSON.stringify(index2)}]`}`;
|
|
@@ -194346,20 +195805,20 @@ function rawStateResources(raw) {
|
|
|
194346
195805
|
if (Array.isArray(instance["sensitive_attributes"])) {
|
|
194347
195806
|
for (const path of instance["sensitive_attributes"]) {
|
|
194348
195807
|
const first = Array.isArray(path) ? path[0] : null;
|
|
194349
|
-
if (
|
|
195808
|
+
if (isObject5(first) && typeof first["value"] === "string") sensitive[first["value"]] = true;
|
|
194350
195809
|
}
|
|
194351
195810
|
}
|
|
194352
|
-
out.push({ address, mode, type: block["type"], name: block["name"], index: index2, module, values:
|
|
195811
|
+
out.push({ address, mode, type: block["type"], name: block["name"], index: index2, module, values: isObject5(instance["attributes"]) ? instance["attributes"] : {}, sensitive, dependsOn: strings2(instance["dependencies"]) });
|
|
194353
195812
|
}
|
|
194354
195813
|
}
|
|
194355
195814
|
return out;
|
|
194356
195815
|
}
|
|
194357
|
-
var MAX_MODULE_DEPTH2,
|
|
194358
|
-
var
|
|
195816
|
+
var MAX_MODULE_DEPTH2, isObject5, strings2, destroys;
|
|
195817
|
+
var init_document4 = __esm({
|
|
194359
195818
|
"../../packages/diagrams/src/importers/terraform-plan/document.ts"() {
|
|
194360
195819
|
"use strict";
|
|
194361
195820
|
MAX_MODULE_DEPTH2 = 16;
|
|
194362
|
-
|
|
195821
|
+
isObject5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
194363
195822
|
strings2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
194364
195823
|
destroys = (change) => change !== void 0 && change.actions.length === 1 && change.actions[0] === "delete";
|
|
194365
195824
|
}
|
|
@@ -194367,14 +195826,14 @@ var init_document3 = __esm({
|
|
|
194367
195826
|
|
|
194368
195827
|
// ../../packages/diagrams/src/importers/terraform-plan/references.ts
|
|
194369
195828
|
function attributesOf3(expressions, depth = 0) {
|
|
194370
|
-
if (!
|
|
195829
|
+
if (!isObject5(expressions) || depth > MAX_NESTING) return [];
|
|
194371
195830
|
const out = [];
|
|
194372
195831
|
for (const [name2, value] of Object.entries(expressions)) {
|
|
194373
|
-
if (
|
|
195832
|
+
if (isObject5(value) && ("references" in value || "constant_value" in value)) {
|
|
194374
195833
|
const refs = strings3(value["references"]);
|
|
194375
195834
|
out.push({ name: name2, refs: refs.filter((ref) => !SAME_INSTANCE.has(ref)), paired: refs.some((ref) => SAME_INSTANCE.has(ref)) });
|
|
194376
195835
|
} else if (Array.isArray(value)) for (const block of value) out.push(...attributesOf3(block, depth + 1));
|
|
194377
|
-
else if (
|
|
195836
|
+
else if (isObject5(value)) out.push(...attributesOf3(value, depth + 1));
|
|
194378
195837
|
}
|
|
194379
195838
|
return out;
|
|
194380
195839
|
}
|
|
@@ -194399,13 +195858,13 @@ function parentOf3(module) {
|
|
|
194399
195858
|
const at3 = module.lastIndexOf(".module.");
|
|
194400
195859
|
return at3 === -1 ? "" : module.slice(0, at3);
|
|
194401
195860
|
}
|
|
194402
|
-
var
|
|
195861
|
+
var MAX_DEPTH17, MAX_NESTING, TYPE2, SAME_INSTANCE, strings3, Configuration;
|
|
194403
195862
|
var init_references2 = __esm({
|
|
194404
195863
|
"../../packages/diagrams/src/importers/terraform-plan/references.ts"() {
|
|
194405
195864
|
"use strict";
|
|
194406
195865
|
init_address();
|
|
194407
|
-
|
|
194408
|
-
|
|
195866
|
+
init_document4();
|
|
195867
|
+
MAX_DEPTH17 = 8;
|
|
194409
195868
|
MAX_NESTING = 8;
|
|
194410
195869
|
TYPE2 = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
|
|
194411
195870
|
SAME_INSTANCE = /* @__PURE__ */ new Set(["each.key", "each.value", "count.index"]);
|
|
@@ -194421,11 +195880,11 @@ var init_references2 = __esm({
|
|
|
194421
195880
|
moduleAt(address) {
|
|
194422
195881
|
let module = this.root;
|
|
194423
195882
|
for (const call of callsOf2(address)) {
|
|
194424
|
-
const calls =
|
|
195883
|
+
const calls = isObject5(module) && isObject5(module["module_calls"]) ? module["module_calls"] : null;
|
|
194425
195884
|
const entry2 = calls === null ? null : calls[call.name];
|
|
194426
|
-
module =
|
|
195885
|
+
module = isObject5(entry2) ? entry2["module"] : null;
|
|
194427
195886
|
}
|
|
194428
|
-
return
|
|
195887
|
+
return isObject5(module) ? module : null;
|
|
194429
195888
|
}
|
|
194430
195889
|
/** The call of a module instance, as its parent's configuration writes it: its source, version, and the values it passes. */
|
|
194431
195890
|
callAt(address) {
|
|
@@ -194433,20 +195892,20 @@ var init_references2 = __esm({
|
|
|
194433
195892
|
const last = calls[calls.length - 1];
|
|
194434
195893
|
if (last === void 0) return null;
|
|
194435
195894
|
const parent = this.moduleAt(parentOf3(address));
|
|
194436
|
-
const entry2 = parent !== null &&
|
|
194437
|
-
return
|
|
195895
|
+
const entry2 = parent !== null && isObject5(parent["module_calls"]) ? parent["module_calls"][last.name] : null;
|
|
195896
|
+
return isObject5(entry2) ? entry2 : null;
|
|
194438
195897
|
}
|
|
194439
195898
|
/** The configured block of a resource, by the module instance it is in and its address inside the module. */
|
|
194440
195899
|
resourceAt(module, local2) {
|
|
194441
195900
|
const config2 = this.moduleAt(module);
|
|
194442
195901
|
const list = config2 !== null && Array.isArray(config2["resources"]) ? config2["resources"] : [];
|
|
194443
|
-
const found = list.find((entry2) =>
|
|
195902
|
+
const found = list.find((entry2) => isObject5(entry2) && entry2["address"] === local2);
|
|
194444
195903
|
if (found === void 0) return null;
|
|
194445
195904
|
return { attributes: attributesOf3(found["expressions"]), dependsOn: strings3(found["depends_on"]), providerKey: typeof found["provider_config_key"] === "string" ? found["provider_config_key"] : null };
|
|
194446
195905
|
}
|
|
194447
195906
|
/** What a reference written in a module instance names, followed through module outputs and the variables its call passes. */
|
|
194448
195907
|
resolve(ref, module, depth = 0) {
|
|
194449
|
-
if (depth >
|
|
195908
|
+
if (depth > MAX_DEPTH17) return [];
|
|
194450
195909
|
const steps = references(ref)[0] ?? [];
|
|
194451
195910
|
const [first, second, third, fourth] = steps;
|
|
194452
195911
|
const name2 = (step) => step?.kind === "name" ? step.text : null;
|
|
@@ -194471,9 +195930,9 @@ var init_references2 = __esm({
|
|
|
194471
195930
|
const out = [];
|
|
194472
195931
|
for (const instance of chosen) {
|
|
194473
195932
|
const config2 = this.moduleAt(instance);
|
|
194474
|
-
const outputs = config2 !== null &&
|
|
195933
|
+
const outputs = config2 !== null && isObject5(config2["outputs"]) ? config2["outputs"] : {};
|
|
194475
195934
|
const entry2 = outputs[output2];
|
|
194476
|
-
const expression2 =
|
|
195935
|
+
const expression2 = isObject5(entry2) && isObject5(entry2["expression"]) ? entry2["expression"] : null;
|
|
194477
195936
|
for (const inner of strings3(expression2?.["references"])) out.push(...this.resolve(inner, instance, depth + 1));
|
|
194478
195937
|
}
|
|
194479
195938
|
return out;
|
|
@@ -194482,9 +195941,9 @@ var init_references2 = __esm({
|
|
|
194482
195941
|
variable(module, variable, depth) {
|
|
194483
195942
|
if (module === "") return [{ kind: "var", name: variable }];
|
|
194484
195943
|
const call = this.callAt(module);
|
|
194485
|
-
const expressions = call !== null &&
|
|
195944
|
+
const expressions = call !== null && isObject5(call["expressions"]) ? call["expressions"] : {};
|
|
194486
195945
|
const passed = expressions[variable];
|
|
194487
|
-
const refs =
|
|
195946
|
+
const refs = isObject5(passed) ? strings3(passed["references"]).filter((ref) => !SAME_INSTANCE.has(ref)) : [];
|
|
194488
195947
|
return refs.flatMap((ref) => this.resolve(ref, parentOf3(module), depth + 1));
|
|
194489
195948
|
}
|
|
194490
195949
|
};
|
|
@@ -194493,7 +195952,7 @@ var init_references2 = __esm({
|
|
|
194493
195952
|
|
|
194494
195953
|
// ../../packages/diagrams/src/importers/terraform-plan/resources.ts
|
|
194495
195954
|
function rawOf(value) {
|
|
194496
|
-
if (
|
|
195955
|
+
if (isObject5(value)) {
|
|
194497
195956
|
const entries2 = Object.entries(value).filter((entry2) => typeof entry2[1] === "string");
|
|
194498
195957
|
return `{ ${entries2.map(([key, entry2]) => `${key} = ${JSON.stringify(entry2)}`).join(", ")} }`;
|
|
194499
195958
|
}
|
|
@@ -194507,7 +195966,7 @@ function valuesOf2(resource) {
|
|
|
194507
195966
|
}
|
|
194508
195967
|
const tags = resource.values["tags"];
|
|
194509
195968
|
const hidden = resource.sensitive["tags"];
|
|
194510
|
-
if (
|
|
195969
|
+
if (isObject5(tags) && typeof tags["Name"] === "string" && !(isObject5(hidden) && hidden["Name"] === true) && hidden !== true) out.set("tags.Name", tags["Name"]);
|
|
194511
195970
|
return out;
|
|
194512
195971
|
}
|
|
194513
195972
|
function blockOf2(resource, values, start2) {
|
|
@@ -194525,7 +195984,7 @@ function stringsOf(values, sensitive) {
|
|
|
194525
195984
|
if (out.length >= MAX_VALUES || depth > MAX_VALUE_DEPTH || hidden === true) return;
|
|
194526
195985
|
if (typeof value === "string") out.push({ name: name2, value });
|
|
194527
195986
|
else if (Array.isArray(value)) value.forEach((item, index2) => walk(item, name2, Array.isArray(hidden) ? hidden[index2] : void 0, depth + 1));
|
|
194528
|
-
else if (
|
|
195987
|
+
else if (isObject5(value)) for (const [key, entry2] of Object.entries(value)) walk(entry2, key, isObject5(hidden) ? hidden[key] : void 0, depth + 1);
|
|
194529
195988
|
};
|
|
194530
195989
|
for (const [name2, value] of Object.entries(values)) if (!OWN_IDS.has(name2) && !SKIPPED2.has(name2) && name2 !== "tags") walk(value, name2, sensitive[name2], 0);
|
|
194531
195990
|
return out;
|
|
@@ -194546,7 +196005,7 @@ function planResources(document2, text3) {
|
|
|
194546
196005
|
if (byBase.has(same)) alias.set(baseOf(resource), same);
|
|
194547
196006
|
}
|
|
194548
196007
|
const instances = [...new Set(all.map((resource) => resource.module).filter((module) => module !== "").flatMap((module) => callsOf2(module).map((_call, index2, calls) => calls.slice(0, index2 + 1).map((call) => `module.${call.name}${call.suffix}`).join("."))))];
|
|
194549
|
-
const configuration = new Configuration(document2.configuration === null ? null :
|
|
196008
|
+
const configuration = new Configuration(document2.configuration === null ? null : isObject5(document2.configuration["root_module"]) ? document2.configuration["root_module"] : null, instances);
|
|
194550
196009
|
const expand2 = (target, own2, paired) => {
|
|
194551
196010
|
if (target.kind !== "item") return [];
|
|
194552
196011
|
const base = alias.get(target.address) ?? target.address;
|
|
@@ -194688,7 +196147,7 @@ var init_resources2 = __esm({
|
|
|
194688
196147
|
init_generic();
|
|
194689
196148
|
init_graph4();
|
|
194690
196149
|
init_resources();
|
|
194691
|
-
|
|
196150
|
+
init_document4();
|
|
194692
196151
|
init_references2();
|
|
194693
196152
|
MAX_VALUE_DEPTH = 6;
|
|
194694
196153
|
MAX_VALUES = 400;
|
|
@@ -194719,19 +196178,19 @@ function importedOf(json2) {
|
|
|
194719
196178
|
const out = /* @__PURE__ */ new Set();
|
|
194720
196179
|
const changes = json2["resource_changes"];
|
|
194721
196180
|
if (Array.isArray(changes)) {
|
|
194722
|
-
for (const entry2 of changes) if (
|
|
196181
|
+
for (const entry2 of changes) if (isObject5(entry2) && isObject5(entry2["change"]) && entry2["change"]["importing"] !== void 0 && typeof entry2["address"] === "string") out.add(entry2["address"]);
|
|
194723
196182
|
}
|
|
194724
196183
|
return out;
|
|
194725
196184
|
}
|
|
194726
196185
|
function accountsOf(document2, types) {
|
|
194727
196186
|
const out = /* @__PURE__ */ new Map();
|
|
194728
196187
|
for (const entry2 of Object.values(document2.providers)) {
|
|
194729
|
-
if (!
|
|
196188
|
+
if (!isObject5(entry2) || typeof entry2["name"] !== "string") continue;
|
|
194730
196189
|
const cloud = providerOf2(`${entry2["name"]}_x`);
|
|
194731
196190
|
if (cloud === null || out.get(cloud) !== void 0) continue;
|
|
194732
|
-
const expressions =
|
|
194733
|
-
const
|
|
194734
|
-
out.set(cloud, cloud === "gcp" && typeof
|
|
196191
|
+
const expressions = isObject5(entry2["expressions"]) ? entry2["expressions"] : {};
|
|
196192
|
+
const project2 = isObject5(expressions["project"]) ? expressions["project"]["constant_value"] : void 0;
|
|
196193
|
+
out.set(cloud, cloud === "gcp" && typeof project2 === "string" ? project2 : null);
|
|
194735
196194
|
}
|
|
194736
196195
|
for (const type of types) {
|
|
194737
196196
|
const cloud = providerOf2(type);
|
|
@@ -194743,9 +196202,9 @@ function regionsOf2(document2) {
|
|
|
194743
196202
|
const out = /* @__PURE__ */ new Map();
|
|
194744
196203
|
const byProvider = /* @__PURE__ */ new Map();
|
|
194745
196204
|
for (const [key, entry2] of Object.entries(document2.providers)) {
|
|
194746
|
-
if (!
|
|
194747
|
-
const expressions =
|
|
194748
|
-
const region =
|
|
196205
|
+
if (!isObject5(entry2) || typeof entry2["name"] !== "string" || key.includes(":")) continue;
|
|
196206
|
+
const expressions = isObject5(entry2["expressions"]) ? entry2["expressions"] : {};
|
|
196207
|
+
const region = isObject5(expressions["region"]) ? expressions["region"]["constant_value"] : void 0;
|
|
194749
196208
|
if (typeof region !== "string" || region === "") continue;
|
|
194750
196209
|
out.set(key, region);
|
|
194751
196210
|
byProvider.set(entry2["name"], /* @__PURE__ */ new Set([...byProvider.get(entry2["name"]) ?? [], region]));
|
|
@@ -194778,7 +196237,7 @@ function readTerraformPlan(text3, context) {
|
|
|
194778
196237
|
return null;
|
|
194779
196238
|
}
|
|
194780
196239
|
const document2 = readPlanDocument(json2);
|
|
194781
|
-
if (document2 === null || !
|
|
196240
|
+
if (document2 === null || !isObject5(json2)) {
|
|
194782
196241
|
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The JSON is neither a plan (planned_values and resource_changes) nor a state (values.root_module).", "Run terraform plan -out=plan.out, then send the output of terraform show -json plan.out; or send terraform show -json for the state.");
|
|
194783
196242
|
return null;
|
|
194784
196243
|
}
|
|
@@ -194846,7 +196305,7 @@ var init_terraform_plan = __esm({
|
|
|
194846
196305
|
init_labels();
|
|
194847
196306
|
init_resources();
|
|
194848
196307
|
init_values2();
|
|
194849
|
-
|
|
196308
|
+
init_document4();
|
|
194850
196309
|
init_resources2();
|
|
194851
196310
|
CHANGES = {
|
|
194852
196311
|
create: { tone: "green", word: "create", said: "one marked + is created", mark: "create" },
|
|
@@ -195162,6 +196621,8 @@ var init_registry4 = __esm({
|
|
|
195162
196621
|
"../../packages/diagrams/src/importers/registry.ts"() {
|
|
195163
196622
|
"use strict";
|
|
195164
196623
|
init_arm();
|
|
196624
|
+
init_asyncapi();
|
|
196625
|
+
init_azure_pipelines();
|
|
195165
196626
|
init_backstage();
|
|
195166
196627
|
init_bicep();
|
|
195167
196628
|
init_cdk();
|
|
@@ -195172,6 +196633,7 @@ var init_registry4 = __esm({
|
|
|
195172
196633
|
init_git_log();
|
|
195173
196634
|
init_helm();
|
|
195174
196635
|
init_github_actions();
|
|
196636
|
+
init_gitlab_ci();
|
|
195175
196637
|
init_json();
|
|
195176
196638
|
init_kubernetes();
|
|
195177
196639
|
init_kustomize();
|
|
@@ -195179,6 +196641,7 @@ var init_registry4 = __esm({
|
|
|
195179
196641
|
init_prisma();
|
|
195180
196642
|
init_pulumi();
|
|
195181
196643
|
init_sql();
|
|
196644
|
+
init_structurizr();
|
|
195182
196645
|
init_terraform();
|
|
195183
196646
|
init_terraform_plan();
|
|
195184
196647
|
init_tree5();
|
|
@@ -195199,7 +196662,11 @@ var init_registry4 = __esm({
|
|
|
195199
196662
|
helm: helmImporter,
|
|
195200
196663
|
kustomize: kustomizeImporter,
|
|
195201
196664
|
backstage: backstageImporter,
|
|
196665
|
+
structurizr: structurizrImporter,
|
|
196666
|
+
asyncapi: asyncapiImporter,
|
|
195202
196667
|
"github-actions": githubActionsImporter,
|
|
196668
|
+
"gitlab-ci": gitlabCiImporter,
|
|
196669
|
+
"azure-pipelines": azurePipelinesImporter,
|
|
195203
196670
|
csv: csvImporter,
|
|
195204
196671
|
json: jsonImporter,
|
|
195205
196672
|
tree: treeImporter,
|
|
@@ -197086,7 +198553,7 @@ function wordsOf5(text3) {
|
|
|
197086
198553
|
function cleanLabel2(text3) {
|
|
197087
198554
|
return text3.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[`*_~"\\]/g, "").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
|
|
197088
198555
|
}
|
|
197089
|
-
function
|
|
198556
|
+
function stepLabel2(text3) {
|
|
197090
198557
|
const clean = cleanLabel2(text3).replace(/[.;]$/, "");
|
|
197091
198558
|
const capital2 = `${clean.charAt(0).toUpperCase()}${clean.slice(1)}`;
|
|
197092
198559
|
if (capital2.length <= ONE_LINE) return { label: capital2, sub: null };
|
|
@@ -197097,7 +198564,7 @@ function stepLabel(text3) {
|
|
|
197097
198564
|
return { label: capital2, sub: null };
|
|
197098
198565
|
}
|
|
197099
198566
|
function stepText2(text3) {
|
|
197100
|
-
const { label, sub } =
|
|
198567
|
+
const { label, sub } = stepLabel2(text3);
|
|
197101
198568
|
return sub === null ? `"${label}"` : `"${label}" sub="${sub}"`;
|
|
197102
198569
|
}
|
|
197103
198570
|
function withDescription(source, description) {
|
|
@@ -197969,7 +199436,7 @@ function partType(name2) {
|
|
|
197969
199436
|
function linkedFlow(material, title) {
|
|
197970
199437
|
const ids = idMaker("part");
|
|
197971
199438
|
const nodes = /* @__PURE__ */ new Map();
|
|
197972
|
-
const
|
|
199439
|
+
const nodeOf5 = (label) => {
|
|
197973
199440
|
const key = label.toLowerCase();
|
|
197974
199441
|
const known3 = nodes.get(key);
|
|
197975
199442
|
if (known3 !== void 0 && /^[a-z]/.test(known3.label) && /^[A-Z]/.test(label)) known3.label = label;
|
|
@@ -197978,7 +199445,7 @@ function linkedFlow(material, title) {
|
|
|
197978
199445
|
nodes.set(key, node3);
|
|
197979
199446
|
return node3.id;
|
|
197980
199447
|
};
|
|
197981
|
-
const links = material.relations.slice(0, MOST * 2).map((relation2) => ({ from:
|
|
199448
|
+
const links = material.relations.slice(0, MOST * 2).map((relation2) => ({ from: nodeOf5(relation2.from), to: nodeOf5(relation2.to), verb: relation2.verb }));
|
|
197982
199449
|
const edges = links.map((link2) => `${link2.from} -> ${link2.to} : ${quoted4(link2.verb)}`);
|
|
197983
199450
|
return sourceOf(`flow ${quoted4(title)} direction=${directionFor(longestChain2(links))}`, [
|
|
197984
199451
|
...[...nodes.values()].map((node3) => `node ${node3.id} ${partType(node3.label)} ${quoted4(node3.label)}${iconOption(node3.label)}`),
|
|
@@ -197998,7 +199465,7 @@ function longestChain2(links) {
|
|
|
197998
199465
|
};
|
|
197999
199466
|
return Math.max(0, ...links.map((link2) => walk(link2.from, /* @__PURE__ */ new Set([link2.from]))));
|
|
198000
199467
|
}
|
|
198001
|
-
function
|
|
199468
|
+
function stepsOf2(material) {
|
|
198002
199469
|
const pairs = material.labelled.filter((line3) => cleanLabel2(line3.text) !== "");
|
|
198003
199470
|
const repeated = new Set(pairs.map((line3) => line3.label.toLowerCase())).size < pairs.length;
|
|
198004
199471
|
if (pairs.length >= 2 && repeated || pairs.length >= 3) return pairs.slice(0, MOST).map((pair2) => ({ label: pair2.label, text: pair2.text }));
|
|
@@ -198109,7 +199576,7 @@ var init_systems = __esm({
|
|
|
198109
199576
|
},
|
|
198110
199577
|
swimlane: (material, title) => {
|
|
198111
199578
|
const ids = idMaker("step");
|
|
198112
|
-
const steps =
|
|
199579
|
+
const steps = stepsOf2(material);
|
|
198113
199580
|
const laneNames = distinctLabels(steps.map((step) => step.label)).slice(0, 6);
|
|
198114
199581
|
const placed = steps.map((step) => ({ lane: laneNames.findIndex((name2) => name2.toLowerCase() === cleanLabel2(step.label).toLowerCase()), label: cleanLabel2(step.text) })).filter((step) => step.lane >= 0).map((step) => ({ ...step, id: ids(step.label) }));
|
|
198115
199582
|
const begin = ids("Start");
|
|
@@ -198889,7 +200356,7 @@ var init_draw_for_view = __esm({
|
|
|
198889
200356
|
});
|
|
198890
200357
|
|
|
198891
200358
|
// ../../packages/diagrams/src/view/index.ts
|
|
198892
|
-
var
|
|
200359
|
+
var init_view2 = __esm({
|
|
198893
200360
|
"../../packages/diagrams/src/view/index.ts"() {
|
|
198894
200361
|
"use strict";
|
|
198895
200362
|
init_fragment();
|
|
@@ -198974,7 +200441,7 @@ var init_view_link = __esm({
|
|
|
198974
200441
|
init_constants();
|
|
198975
200442
|
init_apply_defaults();
|
|
198976
200443
|
init_schema4();
|
|
198977
|
-
|
|
200444
|
+
init_view2();
|
|
198978
200445
|
SOURCE_OF = {
|
|
198979
200446
|
draw_diagram: (args, answer) => answer["valid"] === true ? args["source"] : null,
|
|
198980
200447
|
draw_from_pattern: (_args, answer) => answer["valid"] === true ? answer["source"] : null,
|
|
@@ -199379,7 +200846,7 @@ var init_server_info = __esm({
|
|
|
199379
200846
|
`Draws ${joinWords(kindNouns(), "and")} diagrams from a small line-oriented text language.`,
|
|
199380
200847
|
"Prefer the workflow tools: each does the work of several single tools in one call.",
|
|
199381
200848
|
"When you are unsure which kind of diagram fits, call suggest_diagram with the request in plain words and any data: it ranks the kinds and gives a starter that parses; for a whole document, plan_document_diagrams returns the sections a picture would help, each with a starter.",
|
|
199382
|
-
"When the diagram should come from a file the person has (SQL, Prisma, or Drizzle models, an OpenAPI document, Terraform, Bicep, ARM, Pulumi, CloudFormation, or the CDK, docker-compose, Kubernetes manifests, Helm, Kustomize, a Backstage catalog, a GitHub Actions workflow, CSV or JSON data, a folder listing, or a git log), call import_source with its text and format: it builds the whole diagram from the file in one call, and its diagnostics say what was left out get_diagram_syntax with topic import-formats says what each format reads.",
|
|
200849
|
+
"When the diagram should come from a file the person has (SQL, Prisma, or Drizzle models, an OpenAPI document, Terraform, Bicep, ARM, Pulumi, CloudFormation, or the CDK, docker-compose, Kubernetes manifests, Helm, Kustomize, a Backstage catalog, a Structurizr workspace, AsyncAPI documents, a GitHub Actions workflow, a GitLab CI/CD or Azure Pipelines pipeline, CSV or JSON data, a folder listing, or a git log), call import_source with its text and format: it builds the whole diagram from the file in one call, and its diagnostics say what was left out get_diagram_syntax with topic import-formats says what each format reads.",
|
|
199383
200850
|
"For a request to draw a common architecture, such as a three-tier network, a serverless API, a container platform, or a queue with workers, call find_pattern first with the request in plain words; when a pattern fits, call draw_from_pattern with its id, a provider flavour (neutral, aws, azure, or gcp), and slot values that rename its parts, or get_pattern to read and edit its source, and when nothing fits, write the diagram from scratch with draw_diagram.",
|
|
199384
200851
|
"Call get_diagram_syntax once with no kind to read the shared language, and again with kind set to the kind you draw for its statements, limits, and example.",
|
|
199385
200852
|
'Write the source and call draw_diagram: it returns every error with line, column, and hint and draws nothing until the source is valid, so fix every error and call again; once valid it returns the warnings, an outline to check the meaning, and the SVG for light and dark. The pictures are most of the answer and you cannot look at them, so pass svg "never" to check a diagram, and draw only when you will save, show, or publish the pictures; when a drawing is too big to read in one answer the SVG is left out, picturesOmitted says so, and svg "always" forces it.',
|
|
@@ -199763,7 +201230,7 @@ var init_create_server = __esm({
|
|
|
199763
201230
|
"use strict";
|
|
199764
201231
|
init_dist();
|
|
199765
201232
|
init_tools();
|
|
199766
|
-
|
|
201233
|
+
init_view2();
|
|
199767
201234
|
init_activity();
|
|
199768
201235
|
init_audit();
|
|
199769
201236
|
init_engine_runner();
|
|
@@ -200227,7 +201694,7 @@ var VIEWER_URL_VARIABLE;
|
|
|
200227
201694
|
var init_viewer_address = __esm({
|
|
200228
201695
|
"src/viewer-address.ts"() {
|
|
200229
201696
|
"use strict";
|
|
200230
|
-
|
|
201697
|
+
init_view2();
|
|
200231
201698
|
VIEWER_URL_VARIABLE = "PLOTWORK_VIEWER_URL";
|
|
200232
201699
|
}
|
|
200233
201700
|
});
|