@buun_group/plotwork-mcp 0.1.0-beta.6 → 0.1.0-beta.8
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 +2347 -344
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.8" };
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
|
|
@@ -160,6 +160,71 @@ var init_flow_node_types = __esm({
|
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
+
// ../../packages/diagrams/src/constants/auto-group-types.ts
|
|
164
|
+
var AUTO_GROUP_TYPES, REGION_CODE, AZURE_REGION_NAMES;
|
|
165
|
+
var init_auto_group_types = __esm({
|
|
166
|
+
"../../packages/diagrams/src/constants/auto-group-types.ts"() {
|
|
167
|
+
"use strict";
|
|
168
|
+
AUTO_GROUP_TYPES = {
|
|
169
|
+
network: { ends: ["vpc", "vnet", "network", "virtual network", "private network", "virtual private cloud", "vcn"] },
|
|
170
|
+
subnet: { ends: ["subnet", "subnets"] },
|
|
171
|
+
"public-subnet": { ends: ["public subnet", "public subnets"] },
|
|
172
|
+
"private-subnet": { ends: ["private subnet", "private subnets"] },
|
|
173
|
+
environment: { ends: ["environment", "env"], whole: ["production", "prod", "staging", "dev", "development", "qa", "uat"] },
|
|
174
|
+
"ci-cd": {
|
|
175
|
+
ends: ["ci", "ci cd", "cicd", "ci pipeline", "ci cd pipeline", "build pipeline", "release pipeline", "deploy pipeline", "deployment pipeline", "delivery pipeline"],
|
|
176
|
+
whole: ["pipeline", "pipelines"]
|
|
177
|
+
},
|
|
178
|
+
messaging: { ends: ["kafka", "kafka cluster", "queue", "queues", "message queue", "message queues", "event bus", "message bus", "messaging", "event streaming", "service bus", "pub sub", "pubsub"] },
|
|
179
|
+
cluster: { ends: ["kubernetes", "k8s", "kubernetes cluster", "k8s cluster", "eks cluster", "aks cluster", "gke cluster", "container cluster"], whole: ["cluster"] },
|
|
180
|
+
region: { ends: ["region"] },
|
|
181
|
+
account: { ends: ["aws account"] },
|
|
182
|
+
"data-tier": { ends: ["data", "data tier", "database tier", "data layer", "database layer", "databases", "data stores", "data store", "storage tier", "persistence", "persistence layer"] },
|
|
183
|
+
security: { ends: ["security", "iam", "security services"] },
|
|
184
|
+
observability: { ends: ["monitoring", "observability", "logging", "telemetry"] }
|
|
185
|
+
};
|
|
186
|
+
REGION_CODE = /^(?:(?:us|eu|ap|sa|ca|me|af|il|mx)-[a-z]+-\d|(?:us|europe|asia|australia|southamerica|northamerica|me|africa)-[a-z]+\d)$/;
|
|
187
|
+
AZURE_REGION_NAMES = /* @__PURE__ */ new Set([
|
|
188
|
+
"eastus",
|
|
189
|
+
"eastus2",
|
|
190
|
+
"westus",
|
|
191
|
+
"westus2",
|
|
192
|
+
"westus3",
|
|
193
|
+
"centralus",
|
|
194
|
+
"northcentralus",
|
|
195
|
+
"southcentralus",
|
|
196
|
+
"westcentralus",
|
|
197
|
+
"canadacentral",
|
|
198
|
+
"canadaeast",
|
|
199
|
+
"brazilsouth",
|
|
200
|
+
"northeurope",
|
|
201
|
+
"westeurope",
|
|
202
|
+
"uksouth",
|
|
203
|
+
"ukwest",
|
|
204
|
+
"francecentral",
|
|
205
|
+
"germanywestcentral",
|
|
206
|
+
"swedencentral",
|
|
207
|
+
"switzerlandnorth",
|
|
208
|
+
"norwayeast",
|
|
209
|
+
"polandcentral",
|
|
210
|
+
"italynorth",
|
|
211
|
+
"eastasia",
|
|
212
|
+
"southeastasia",
|
|
213
|
+
"japaneast",
|
|
214
|
+
"japanwest",
|
|
215
|
+
"koreacentral",
|
|
216
|
+
"centralindia",
|
|
217
|
+
"southindia",
|
|
218
|
+
"australiaeast",
|
|
219
|
+
"australiasoutheast",
|
|
220
|
+
"uaenorth",
|
|
221
|
+
"southafricanorth",
|
|
222
|
+
"qatarcentral",
|
|
223
|
+
"israelcentral"
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
163
228
|
// ../../packages/diagrams/src/constants/group-types.ts
|
|
164
229
|
function groupTypeIcon(type, provider, canUse = () => true) {
|
|
165
230
|
const spec = GROUP_TYPE_SPECS[type];
|
|
@@ -386,7 +451,7 @@ var init_auto_icons = __esm({
|
|
|
386
451
|
ICON_MODE_SPEC = {
|
|
387
452
|
key: "icons",
|
|
388
453
|
values: ICON_MODES.join(", "),
|
|
389
|
-
meaning: 'auto (the default): an item with no icon= gets the icon its label, else its sub= or tech=, names for certain: a brand ("Postgres"), a cloud product ("Amazon S3"), or in some kinds a role ("Email"). A name that is also an everyday word ("Vault") stays plain. icon=none keeps one item plain; off keeps all plain.',
|
|
454
|
+
meaning: 'auto (the default): an item with no icon= gets the icon its label, else its sub= or tech=, names for certain: a brand ("Postgres"), a cloud product ("Amazon S3"), or in some kinds a role ("Email"). A name that is also an everyday word ("Vault") stays plain. icon=none keeps one item plain; off keeps all plain, with flow edge labels, and stops a flow group taking its type from its name.',
|
|
390
455
|
example: 'flow "Checkout" icons=off'
|
|
391
456
|
};
|
|
392
457
|
PLAIN_WORD_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -643,7 +708,7 @@ var init_view_links = __esm({
|
|
|
643
708
|
};
|
|
644
709
|
CLI_RELEASE = {
|
|
645
710
|
packageName: "@buun_group/plotwork",
|
|
646
|
-
version: "0.1.0-beta.
|
|
711
|
+
version: "0.1.0-beta.9",
|
|
647
712
|
onNpm: true
|
|
648
713
|
};
|
|
649
714
|
}
|
|
@@ -662,7 +727,7 @@ var init_mcp_release = __esm({
|
|
|
662
727
|
"use strict";
|
|
663
728
|
MCP_RELEASE = {
|
|
664
729
|
packageName: "@buun_group/plotwork-mcp",
|
|
665
|
-
version: "0.1.0-beta.
|
|
730
|
+
version: "0.1.0-beta.6"
|
|
666
731
|
};
|
|
667
732
|
}
|
|
668
733
|
});
|
|
@@ -3500,6 +3565,195 @@ var init_label_icons = __esm({
|
|
|
3500
3565
|
}
|
|
3501
3566
|
});
|
|
3502
3567
|
|
|
3568
|
+
// ../../packages/diagrams/src/constants/label-vocabulary.ts
|
|
3569
|
+
var EDGE_STYLES, LABEL_VERB_PHRASES, LABEL_VERB_MAX_WORDS, NOT_VERB_PHRASES, STYLE_STEPS;
|
|
3570
|
+
var init_label_vocabulary = __esm({
|
|
3571
|
+
"../../packages/diagrams/src/constants/label-vocabulary.ts"() {
|
|
3572
|
+
"use strict";
|
|
3573
|
+
EDGE_STYLES = {
|
|
3574
|
+
/** Reads stored data: a query, a select. */
|
|
3575
|
+
reads: { icon: "lucide:eye", role: "data" },
|
|
3576
|
+
/** Reads its settings, such as a Kubernetes ConfigMap; not stored data, so no role. */
|
|
3577
|
+
"reads-settings": { icon: "lucide:eye", role: null },
|
|
3578
|
+
/** Writes stored data: an insert, an update. */
|
|
3579
|
+
writes: { icon: "lucide:square-pen", role: "data" },
|
|
3580
|
+
/** Reads and writes a store the file names without saying which: a database, a bucket, a cache. */
|
|
3581
|
+
stores: { icon: "lucide:database", role: "data" },
|
|
3582
|
+
/** Mounts a volume or a claim. */
|
|
3583
|
+
mounts: { icon: "lucide:hard-drive", role: "data" },
|
|
3584
|
+
/** Sends, publishes, produces, or emits a message it does not wait for. */
|
|
3585
|
+
sends: { icon: "lucide:send", role: "async" },
|
|
3586
|
+
/** Receives, consumes, or subscribes to messages. */
|
|
3587
|
+
receives: { icon: "lucide:inbox", role: "async" },
|
|
3588
|
+
/** Calls or requests and waits for the answer. */
|
|
3589
|
+
calls: { icon: "lucide:arrow-right-left", role: null },
|
|
3590
|
+
/** Routes outside traffic: a host, a path, a public address, a DNS name. */
|
|
3591
|
+
routes: { icon: "lucide:globe", role: null },
|
|
3592
|
+
/** Needs another thing to be there first. */
|
|
3593
|
+
"depends-on": { icon: "lucide:link", role: null },
|
|
3594
|
+
/** Provides an API. */
|
|
3595
|
+
provides: { icon: "lucide:plug", role: null },
|
|
3596
|
+
/** Consumes an API. */
|
|
3597
|
+
consumes: { icon: "lucide:plug-zap", role: null },
|
|
3598
|
+
/** Starts another thing: a function on an event, a downstream pipeline. */
|
|
3599
|
+
triggers: { icon: "lucide:zap", role: null },
|
|
3600
|
+
/** Deploys to an environment. */
|
|
3601
|
+
deploys: { icon: "lucide:rocket", role: null },
|
|
3602
|
+
/** Grants a role, assumes one, or authenticates. */
|
|
3603
|
+
grants: { icon: "lucide:key-round", role: "identity" },
|
|
3604
|
+
/** Uses a credential: a secret, a password, a key. */
|
|
3605
|
+
secret: { icon: "lucide:key-round", role: "identity" },
|
|
3606
|
+
/** Reaches another over a private network: a private endpoint, VPC peering, VNet integration. */
|
|
3607
|
+
private: { icon: "lucide:lock", role: "private" },
|
|
3608
|
+
/** Is guarded by a firewall or a security group. */
|
|
3609
|
+
filters: { icon: "lucide:shield", role: null },
|
|
3610
|
+
/** Sends logs or telemetry. */
|
|
3611
|
+
reports: { icon: "lucide:activity", role: null },
|
|
3612
|
+
/** Pulls container images. */
|
|
3613
|
+
pulls: { icon: "lucide:download", role: null },
|
|
3614
|
+
/** Builds on a base, such as a Kustomize overlay on its base. */
|
|
3615
|
+
"builds-on": { icon: "lucide:layers", role: null },
|
|
3616
|
+
/** Includes a component. */
|
|
3617
|
+
includes: { icon: "lucide:package", role: null },
|
|
3618
|
+
/** Patches what another file holds. */
|
|
3619
|
+
patches: { icon: "lucide:replace", role: null }
|
|
3620
|
+
};
|
|
3621
|
+
LABEL_VERB_PHRASES = {
|
|
3622
|
+
reads: ["reads", "read", "reading", "reads from", "read from", "queries", "query", "querying", "looks up", "look up", "selects", "select from", "loads from", "fetches from"],
|
|
3623
|
+
writes: [
|
|
3624
|
+
"writes",
|
|
3625
|
+
"write",
|
|
3626
|
+
"writing",
|
|
3627
|
+
"writes to",
|
|
3628
|
+
"write to",
|
|
3629
|
+
"inserts",
|
|
3630
|
+
"insert",
|
|
3631
|
+
"inserts into",
|
|
3632
|
+
"updates",
|
|
3633
|
+
"update",
|
|
3634
|
+
"saves",
|
|
3635
|
+
"save",
|
|
3636
|
+
"saves to",
|
|
3637
|
+
"persists",
|
|
3638
|
+
"persist",
|
|
3639
|
+
"persists to",
|
|
3640
|
+
"deletes",
|
|
3641
|
+
"delete",
|
|
3642
|
+
"deletes from",
|
|
3643
|
+
"uploads",
|
|
3644
|
+
"upload",
|
|
3645
|
+
"uploads to",
|
|
3646
|
+
"upload to"
|
|
3647
|
+
],
|
|
3648
|
+
stores: ["stores", "store", "stores in", "store in", "caches", "caches in", "reads and writes", "reads writes", "read write", "read and write"],
|
|
3649
|
+
mounts: ["mounts", "mount"],
|
|
3650
|
+
sends: [
|
|
3651
|
+
"sends",
|
|
3652
|
+
"send",
|
|
3653
|
+
"sends to",
|
|
3654
|
+
"publishes",
|
|
3655
|
+
"publish",
|
|
3656
|
+
"publishes to",
|
|
3657
|
+
"publish to",
|
|
3658
|
+
"emits",
|
|
3659
|
+
"emit",
|
|
3660
|
+
"produces",
|
|
3661
|
+
"produce",
|
|
3662
|
+
"produces to",
|
|
3663
|
+
"enqueues",
|
|
3664
|
+
"enqueue",
|
|
3665
|
+
"pushes to",
|
|
3666
|
+
"notifies",
|
|
3667
|
+
"notify",
|
|
3668
|
+
"fires"
|
|
3669
|
+
],
|
|
3670
|
+
receives: ["receives", "receive", "consumes", "consume", "consumes from", "subscribes", "subscribes to", "subscribe to", "listens to", "listens on", "polls", "dequeues"],
|
|
3671
|
+
calls: ["calls", "call", "invokes", "invoke", "requests", "request", "fetches", "fetch", "queries api", "http", "https", "grpc", "rest", "graphql"],
|
|
3672
|
+
routes: ["routes", "routes to", "route to", "forwards", "forwards to", "forward to", "proxies", "proxies to", "redirects to", "load balances"],
|
|
3673
|
+
"depends-on": ["depends on", "depend on", "requires", "needs"],
|
|
3674
|
+
provides: ["provides", "exposes", "serves"],
|
|
3675
|
+
triggers: ["triggers", "trigger", "starts", "kicks off", "schedules", "wakes"],
|
|
3676
|
+
deploys: ["deploys", "deploy", "deploys to", "deploy to", "releases to", "ships to", "promotes to", "rolls out", "rolls out to"],
|
|
3677
|
+
grants: [
|
|
3678
|
+
"authenticates",
|
|
3679
|
+
"authenticate",
|
|
3680
|
+
"authenticates with",
|
|
3681
|
+
"authenticates against",
|
|
3682
|
+
"authorizes",
|
|
3683
|
+
"authorize",
|
|
3684
|
+
"authorises",
|
|
3685
|
+
"authorise",
|
|
3686
|
+
"signs in",
|
|
3687
|
+
"sign in",
|
|
3688
|
+
"signs in with",
|
|
3689
|
+
"logs in",
|
|
3690
|
+
"log in",
|
|
3691
|
+
"logs in with",
|
|
3692
|
+
"grants",
|
|
3693
|
+
"grant",
|
|
3694
|
+
"assumes role",
|
|
3695
|
+
"issues token",
|
|
3696
|
+
"issues tokens",
|
|
3697
|
+
"verifies token",
|
|
3698
|
+
"verify token",
|
|
3699
|
+
"validates token",
|
|
3700
|
+
"validate token",
|
|
3701
|
+
"logs out",
|
|
3702
|
+
"log out",
|
|
3703
|
+
"signs out",
|
|
3704
|
+
"sign out"
|
|
3705
|
+
],
|
|
3706
|
+
secret: ["reads secret", "reads secrets", "read secret", "read secrets", "read credentials", "fetches secret", "fetches secrets", "reads credentials", "gets secret", "gets secrets"],
|
|
3707
|
+
reports: [
|
|
3708
|
+
"reports",
|
|
3709
|
+
"reports to",
|
|
3710
|
+
"logs",
|
|
3711
|
+
"logs to",
|
|
3712
|
+
"metrics",
|
|
3713
|
+
"telemetry",
|
|
3714
|
+
"traces",
|
|
3715
|
+
"logs and metrics",
|
|
3716
|
+
"sends logs",
|
|
3717
|
+
"sends logs to",
|
|
3718
|
+
"sends metrics",
|
|
3719
|
+
"sends metrics to",
|
|
3720
|
+
"sends telemetry",
|
|
3721
|
+
"sends traces",
|
|
3722
|
+
"ships logs",
|
|
3723
|
+
"ships logs to",
|
|
3724
|
+
"exports metrics",
|
|
3725
|
+
"exports traces",
|
|
3726
|
+
"emits metrics",
|
|
3727
|
+
"emits logs"
|
|
3728
|
+
],
|
|
3729
|
+
pulls: ["pulls image", "pulls images", "pulls images from", "pulls image from"]
|
|
3730
|
+
};
|
|
3731
|
+
LABEL_VERB_MAX_WORDS = 5;
|
|
3732
|
+
NOT_VERB_PHRASES = [
|
|
3733
|
+
"read replica",
|
|
3734
|
+
"read replicas",
|
|
3735
|
+
"read model",
|
|
3736
|
+
"read only",
|
|
3737
|
+
"write model",
|
|
3738
|
+
"write ahead",
|
|
3739
|
+
"request id",
|
|
3740
|
+
"request body",
|
|
3741
|
+
"call center",
|
|
3742
|
+
"call centre",
|
|
3743
|
+
"update available",
|
|
3744
|
+
"query string",
|
|
3745
|
+
"query params"
|
|
3746
|
+
];
|
|
3747
|
+
STYLE_STEPS = [
|
|
3748
|
+
'Label each arrow with a verb, such as "reads", "writes orders", "publishes OrderPlaced", "calls", "deploys to", or "authenticates": the label then draws the icon of that relationship (verbIcons). icon= picks another icon; icon=none keeps the label plain.',
|
|
3749
|
+
"Add role= to the arrows whose line means something: role=data for reads and writes of stored data, role=async for messages nobody waits for, role=identity for sign-in and credentials, role=private for private network links. The line takes the role's colour and the legend names it; warning W500 lists the arrows to mark.",
|
|
3750
|
+
'Give every group a type= (network, subnet, environment, data-tier, messaging, cluster, ci-cd, observability, and the rest), so its frame, tone, and icon follow. A group named plainly, such as "VPC", "Production", "Kafka", or "Monitoring", gets its type by itself; type=none keeps it plain.',
|
|
3751
|
+
'Name each node after the product it is ("Postgres", "Redis", "Amazon S3") so it draws the mark, and choose the node type that says what it is.',
|
|
3752
|
+
"Keep labels to two to four words; the picture carries the rest."
|
|
3753
|
+
];
|
|
3754
|
+
}
|
|
3755
|
+
});
|
|
3756
|
+
|
|
3503
3757
|
// ../../packages/diagrams/src/constants/status-icons.ts
|
|
3504
3758
|
var STATUS_ICON_SPECS;
|
|
3505
3759
|
var init_status_icons = __esm({
|
|
@@ -3548,6 +3802,7 @@ var init_constants = __esm({
|
|
|
3548
3802
|
init_directions();
|
|
3549
3803
|
init_word_list();
|
|
3550
3804
|
init_flow_node_types();
|
|
3805
|
+
init_auto_group_types();
|
|
3551
3806
|
init_group_types();
|
|
3552
3807
|
init_overlays();
|
|
3553
3808
|
init_node_change();
|
|
@@ -3576,6 +3831,7 @@ var init_constants = __esm({
|
|
|
3576
3831
|
init_icon_concepts();
|
|
3577
3832
|
init_icon_sets();
|
|
3578
3833
|
init_label_icons();
|
|
3834
|
+
init_label_vocabulary();
|
|
3579
3835
|
init_status_icons();
|
|
3580
3836
|
init_tones();
|
|
3581
3837
|
}
|
|
@@ -3644,7 +3900,7 @@ function formatDiagnostic(diagnostic, source) {
|
|
|
3644
3900
|
if (diagnostic.hint !== null) parts.push(`hint: ${diagnostic.hint}`);
|
|
3645
3901
|
return parts.join("\n");
|
|
3646
3902
|
}
|
|
3647
|
-
var DIAGNOSTIC_CODES;
|
|
3903
|
+
var DIAGNOSTIC_CODES, STYLE_HINT_CODES;
|
|
3648
3904
|
var init_diagnostics = __esm({
|
|
3649
3905
|
"../../packages/diagrams/src/core/diagnostics.ts"() {
|
|
3650
3906
|
"use strict";
|
|
@@ -3677,6 +3933,9 @@ var init_diagnostics = __esm({
|
|
|
3677
3933
|
suggestIcon: "W204",
|
|
3678
3934
|
suggestGroupType: "W205",
|
|
3679
3935
|
overlayCovers: "W206",
|
|
3936
|
+
// Style suggestions. W5xx says how a valid diagram would look more finished; like W204 and W205 it is a suggestion, not a problem
|
|
3937
|
+
// (`isStyleHint`), so a check that fails on warnings passes it.
|
|
3938
|
+
suggestLineRole: "W500",
|
|
3680
3939
|
// Mermaid import. M1xx stops a conversion; M2xx reports something dropped or changed and never stops it.
|
|
3681
3940
|
// They point into the Mermaid source that was submitted, not into the Plotwork source.
|
|
3682
3941
|
mermaidNotDiagram: "M100",
|
|
@@ -3853,6 +4112,7 @@ var init_diagnostics = __esm({
|
|
|
3853
4112
|
overrideRefused: "S202",
|
|
3854
4113
|
overridesMissing: "S203"
|
|
3855
4114
|
};
|
|
4115
|
+
STYLE_HINT_CODES = /* @__PURE__ */ new Set([DIAGNOSTIC_CODES.suggestIcon, DIAGNOSTIC_CODES.suggestGroupType, DIAGNOSTIC_CODES.suggestLineRole]);
|
|
3856
4116
|
}
|
|
3857
4117
|
});
|
|
3858
4118
|
|
|
@@ -4023,13 +4283,13 @@ function indexOf(set2) {
|
|
|
4023
4283
|
const known3 = indexes.get(set2);
|
|
4024
4284
|
if (known3 !== void 0) return known3;
|
|
4025
4285
|
const byName = /* @__PURE__ */ new Map();
|
|
4026
|
-
const
|
|
4286
|
+
const phrases2 = /* @__PURE__ */ new Map();
|
|
4027
4287
|
for (const icon of set2.icons) {
|
|
4028
4288
|
if (byName.has(icon.name)) continue;
|
|
4029
4289
|
byName.set(icon.name, definitionOf(icon));
|
|
4030
|
-
|
|
4290
|
+
phrases2.set(icon.name, new Set([normalizePhrase(icon.name), ...icon.aliases.map(normalizePhrase)].filter(Boolean)));
|
|
4031
4291
|
}
|
|
4032
|
-
const index2 = { byName, phrases };
|
|
4292
|
+
const index2 = { byName, phrases: phrases2 };
|
|
4033
4293
|
indexes.set(set2, index2);
|
|
4034
4294
|
return index2;
|
|
4035
4295
|
}
|
|
@@ -6697,9 +6957,9 @@ function cloudPhrases(generic) {
|
|
|
6697
6957
|
const ref = `${set2}:${spec.name}`;
|
|
6698
6958
|
const bases = [normalizePhrase(spec.name), ...(spec.aliases ?? []).map(normalizePhrase)];
|
|
6699
6959
|
const title = normalizePhrase(spec.title);
|
|
6700
|
-
const
|
|
6701
|
-
for (const providerName2 of providerNames) for (const base of bases)
|
|
6702
|
-
for (const phrase2 of
|
|
6960
|
+
const phrases2 = /* @__PURE__ */ new Set([title, ...bases]);
|
|
6961
|
+
for (const providerName2 of providerNames) for (const base of bases) phrases2.add(`${providerName2} ${base}`);
|
|
6962
|
+
for (const phrase2 of phrases2) {
|
|
6703
6963
|
if (spec.vendor !== void 0 && claimed.has(phrase2)) continue;
|
|
6704
6964
|
const isScoped = spec.scopeToProvider === true && phrase2 !== title && !providerNames.some((providerName2) => phrase2.startsWith(`${providerName2} `));
|
|
6705
6965
|
out.push({ phrase: phrase2, words: phrase2.split(" ").length, ref, set: set2, isGeneric: generic.has(phrase2) || isScoped, isBrand: false });
|
|
@@ -6712,8 +6972,8 @@ function cloudPhrases(generic) {
|
|
|
6712
6972
|
function brandPhrases() {
|
|
6713
6973
|
return listSetNames("simple").flatMap((name2) => {
|
|
6714
6974
|
const ref = `simple:${name2}`;
|
|
6715
|
-
const
|
|
6716
|
-
return [...
|
|
6975
|
+
const phrases2 = /* @__PURE__ */ new Set([normalizePhrase(name2), ...(ICON_ALIASES[ref] ?? []).map(normalizePhrase), ...(findIcon(ref)?.aliases ?? []).map(normalizePhrase)]);
|
|
6976
|
+
return [...phrases2].map((phrase2) => ({ phrase: phrase2, words: phrase2.split(" ").length, ref, set: "simple", isGeneric: false, isBrand: true }));
|
|
6717
6977
|
});
|
|
6718
6978
|
}
|
|
6719
6979
|
function listProductPhrases() {
|
|
@@ -6800,7 +7060,7 @@ function indexIcon(ref) {
|
|
|
6800
7060
|
const glyph = glyphNameOf(ref);
|
|
6801
7061
|
const plainNames = [normalizePhrase(name2), ...(ICON_ALIASES[ref] ?? []).map(normalizePhrase)];
|
|
6802
7062
|
const aliases = (icon?.aliases ?? []).map(normalizePhrase);
|
|
6803
|
-
const
|
|
7063
|
+
const phrases2 = /* @__PURE__ */ new Set([...plainNames, ...aliases]);
|
|
6804
7064
|
const kindPhrases = /* @__PURE__ */ new Set();
|
|
6805
7065
|
const providerKindPhrases = /* @__PURE__ */ new Set();
|
|
6806
7066
|
const titleWords = /* @__PURE__ */ new Set();
|
|
@@ -6809,11 +7069,11 @@ function indexIcon(ref) {
|
|
|
6809
7069
|
for (const word2 of normalizePhrase(spec.title).split(" ")) titleWords.add(word2);
|
|
6810
7070
|
for (const base of [...plainNames, ...aliases, normalizePhrase(spec.title)]) stems.add(stemPhrase(base));
|
|
6811
7071
|
const provider = CLOUD_PROVIDER_SPECS[cloudSet];
|
|
6812
|
-
|
|
6813
|
-
if (spec.kind === "provider") for (const providerName2 of provider.names)
|
|
7072
|
+
phrases2.add(normalizePhrase(spec.title));
|
|
7073
|
+
if (spec.kind === "provider") for (const providerName2 of provider.names) phrases2.add(providerName2);
|
|
6814
7074
|
const kindPhraseList = CLOUD_KIND_SPECS[spec.kind].phrases.map(normalizePhrase);
|
|
6815
7075
|
for (const providerName2 of provider.names) {
|
|
6816
|
-
for (const base of [...plainNames, ...aliases])
|
|
7076
|
+
for (const base of [...plainNames, ...aliases]) phrases2.add(`${providerName2} ${base}`);
|
|
6817
7077
|
for (const kindPhrase of kindPhraseList) providerKindPhrases.add(`${providerName2} ${kindPhrase}`);
|
|
6818
7078
|
}
|
|
6819
7079
|
for (const kindPhrase of kindPhraseList) kindPhrases.add(kindPhrase);
|
|
@@ -6822,8 +7082,8 @@ function indexIcon(ref) {
|
|
|
6822
7082
|
ref,
|
|
6823
7083
|
tags: (icon?.tags ?? []).map((tag) => tag.toLowerCase()),
|
|
6824
7084
|
concept: glyph === null ? void 0 : CONCEPTS_BY_GLYPH.get(glyph),
|
|
6825
|
-
phrases,
|
|
6826
|
-
haystack: ` ${[...
|
|
7085
|
+
phrases: phrases2,
|
|
7086
|
+
haystack: ` ${[...phrases2].join(" | ")} `,
|
|
6827
7087
|
stems,
|
|
6828
7088
|
titleWords,
|
|
6829
7089
|
isVendorOnly: spec?.vendor !== void 0,
|
|
@@ -6944,7 +7204,11 @@ var init_guide = __esm({
|
|
|
6944
7204
|
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
7205
|
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
7206
|
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." },
|
|
7207
|
+
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." },
|
|
7208
|
+
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
7209
|
"github-actions": { reads: "A GitHub Actions workflow file.", draws: "flow of the trigger, the jobs in needs order, and their steps", options: "none." },
|
|
7210
|
+
"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." },
|
|
7211
|
+
"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
7212
|
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
7213
|
json: { reads: "Records, rows, a name to number object, or nested objects of numbers.", draws: "the same charts as csv", options: "chart." },
|
|
6950
7214
|
tree: { reads: "tree output, a list of paths, or an indented outline.", draws: "tree", options: "none." },
|
|
@@ -6958,8 +7222,8 @@ var IMPORT_FORMATS, IMPORT_VIEWS, IMPORT_CHARTS, IMPORT_GROUP_BY, NO_STATS;
|
|
|
6958
7222
|
var init_types2 = __esm({
|
|
6959
7223
|
"../../packages/diagrams/src/importers/types.ts"() {
|
|
6960
7224
|
"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"];
|
|
7225
|
+
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"];
|
|
7226
|
+
IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline", "context", "container", "component"];
|
|
6963
7227
|
IMPORT_CHARTS = ["auto", "xychart", "pie", "sankey", "treemap", "matrix"];
|
|
6964
7228
|
IMPORT_GROUP_BY = ["module", "network", "file", "owner"];
|
|
6965
7229
|
NO_STATS = { items: 0, links: 0, groups: 0, dropped: 0 };
|
|
@@ -7023,7 +7287,8 @@ var init_looks = __esm({
|
|
|
7023
7287
|
system: { caption: "Software System", frame: "dashed", icon: null },
|
|
7024
7288
|
container: { caption: "Container", frame: "dashed", icon: null },
|
|
7025
7289
|
enterprise: { caption: "Enterprise", frame: "dashed", icon: null },
|
|
7026
|
-
deployment: { caption: "Deployment Node", frame: "solid", icon: "lucide:server" }
|
|
7290
|
+
deployment: { caption: "Deployment Node", frame: "solid", icon: "lucide:server" },
|
|
7291
|
+
group: { caption: "Group", frame: "dashed", icon: null }
|
|
7027
7292
|
};
|
|
7028
7293
|
}
|
|
7029
7294
|
});
|
|
@@ -102504,13 +102769,13 @@ var init_stretch = __esm({
|
|
|
102504
102769
|
function tryRoutes(scene, changes) {
|
|
102505
102770
|
const old = changes.map(({ edge }) => ({ edge, points: edge.points, label: edge.label, hits: intrusions(scene, edge, edge.points, edge.label) }));
|
|
102506
102771
|
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 +
|
|
102772
|
+
const runsOf6 = (edge) => scene.edges.reduce((sum, other) => other === edge ? sum : sum + sharedRuns(edge.points, other.points), 0);
|
|
102773
|
+
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
102774
|
for (const change of changes) {
|
|
102510
102775
|
change.edge.points = change.points;
|
|
102511
102776
|
change.edge.label = change.label;
|
|
102512
102777
|
}
|
|
102513
|
-
const after = changes.reduce((sum, { edge }) => ({ crossings: sum.crossings + crossingsOf2(edge), runs: sum.runs +
|
|
102778
|
+
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
102779
|
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
102780
|
if (isClean) return true;
|
|
102516
102781
|
for (const { edge, points, label } of old) {
|
|
@@ -105226,7 +105491,7 @@ var init_words = __esm({
|
|
|
105226
105491
|
C4_VIEWS = ["context", "container", "component", "deployment", "dynamic"];
|
|
105227
105492
|
DEFAULT_VIEW = "container";
|
|
105228
105493
|
C4_ELEMENT_WORDS = ["person", "system", "container", "component", "db"];
|
|
105229
|
-
C4_BOUNDARY_KINDS = ["system", "container", "enterprise", "deployment"];
|
|
105494
|
+
C4_BOUNDARY_KINDS = ["system", "container", "enterprise", "deployment", "group"];
|
|
105230
105495
|
DEFAULT_BOUNDARY_KIND = "system";
|
|
105231
105496
|
C4_HEADER_OPTIONS = ["view", "direction", "desc", "icons"];
|
|
105232
105497
|
C4_ELEMENT_OPTIONS = ["desc", "tech", "external", "icon", "tone"];
|
|
@@ -105351,7 +105616,7 @@ function resolveRelationships(state) {
|
|
|
105351
105616
|
const elementIds = new Set(state.elements.map((element) => element.id));
|
|
105352
105617
|
const boundaryIds = new Set(state.boundaries.map((boundary) => boundary.id));
|
|
105353
105618
|
const names8 = [...elementIds];
|
|
105354
|
-
const
|
|
105619
|
+
const resolved2 = [];
|
|
105355
105620
|
let suggested = 0;
|
|
105356
105621
|
for (const pending of state.pending) {
|
|
105357
105622
|
const missing = [pending.from, pending.to].filter((end) => !elementIds.has(end.text));
|
|
@@ -105362,19 +105627,19 @@ function resolveRelationships(state) {
|
|
|
105362
105627
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, message2, spanOf2(end), `${guess}Declare it first with: container ${end.text} "Name"`));
|
|
105363
105628
|
}
|
|
105364
105629
|
if (missing.length > 0) continue;
|
|
105365
|
-
|
|
105366
|
-
id: toEdgeId(
|
|
105630
|
+
resolved2.push({
|
|
105631
|
+
id: toEdgeId(resolved2.length),
|
|
105367
105632
|
from: toNodeId(pending.from.text),
|
|
105368
105633
|
to: toNodeId(pending.to.text),
|
|
105369
105634
|
label: pending.label,
|
|
105370
105635
|
tech: pending.tech,
|
|
105371
105636
|
line: pending.arrow.line,
|
|
105372
105637
|
heads: pending.arrow.heads,
|
|
105373
|
-
...state.view === "dynamic" ? { step: DEFAULT_FIRST_STEP +
|
|
105638
|
+
...state.view === "dynamic" ? { step: DEFAULT_FIRST_STEP + resolved2.length } : {},
|
|
105374
105639
|
at: pending.at
|
|
105375
105640
|
});
|
|
105376
105641
|
}
|
|
105377
|
-
return
|
|
105642
|
+
return resolved2;
|
|
105378
105643
|
}
|
|
105379
105644
|
function dispatch(line3, state, scopes) {
|
|
105380
105645
|
const cursor = new TokenCursor(line3.tokens);
|
|
@@ -106393,7 +106658,7 @@ function c4Vocabulary() {
|
|
|
106393
106658
|
example: 'container api "API Application" tech="Spring Boot" desc="Serves the banking data as JSON."'
|
|
106394
106659
|
},
|
|
106395
106660
|
{
|
|
106396
|
-
syntax: 'boundary <id> "Name" kind=system|container|enterprise|deployment tech="<technology>" {',
|
|
106661
|
+
syntax: 'boundary <id> "Name" kind=system|container|enterprise|deployment|group tech="<technology>" {',
|
|
106397
106662
|
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
106663
|
example: 'boundary bank "Internet Banking System" kind=system {'
|
|
106399
106664
|
},
|
|
@@ -108974,15 +109239,15 @@ function resolveRelation(pending, state, ids, known3, index2) {
|
|
|
108974
109239
|
}
|
|
108975
109240
|
function resolveNotes(state) {
|
|
108976
109241
|
const ids = state.classes.map((node3) => node3.id);
|
|
108977
|
-
const
|
|
109242
|
+
const resolved2 = [];
|
|
108978
109243
|
for (const note of state.notes) {
|
|
108979
109244
|
if (note.target !== null && !ids.includes(note.target.text)) {
|
|
108980
109245
|
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
109246
|
continue;
|
|
108982
109247
|
}
|
|
108983
|
-
|
|
109248
|
+
resolved2.push({ id: `note${resolved2.length}`, text: note.text, target: note.target === null ? null : toNodeId(note.target.text), at: note.at });
|
|
108984
109249
|
}
|
|
108985
|
-
return
|
|
109250
|
+
return resolved2;
|
|
108986
109251
|
}
|
|
108987
109252
|
function parseClass(lines, report3) {
|
|
108988
109253
|
const state = {
|
|
@@ -109017,8 +109282,8 @@ function parseClass(lines, report3) {
|
|
|
109017
109282
|
const ids = state.classes.map((node3) => node3.id);
|
|
109018
109283
|
const known3 = new Set(ids);
|
|
109019
109284
|
for (const pending of state.relations) {
|
|
109020
|
-
const
|
|
109021
|
-
if (
|
|
109285
|
+
const resolved2 = resolveRelation(pending, state, ids, known3, relations.length);
|
|
109286
|
+
if (resolved2 !== null) relations.push(resolved2);
|
|
109022
109287
|
}
|
|
109023
109288
|
return {
|
|
109024
109289
|
kind: "class",
|
|
@@ -110253,9 +110518,39 @@ var init_flow_outline = __esm({
|
|
|
110253
110518
|
}
|
|
110254
110519
|
});
|
|
110255
110520
|
|
|
110521
|
+
// ../../packages/diagrams/src/parse/label-icon.ts
|
|
110522
|
+
function verbPhrases() {
|
|
110523
|
+
phrases ??= Object.entries(LABEL_VERB_PHRASES).flatMap(([verb, words2]) => (words2 ?? []).map((phrase2) => [phrase2, verb])).sort((a, b) => b[0].split(" ").length - a[0].split(" ").length || b[0].length - a[0].length);
|
|
110524
|
+
return phrases;
|
|
110525
|
+
}
|
|
110526
|
+
function startsWithWords(text3, phrase2) {
|
|
110527
|
+
return text3 === phrase2 || text3.startsWith(`${phrase2} `);
|
|
110528
|
+
}
|
|
110529
|
+
function verbNamedBy(label) {
|
|
110530
|
+
const text3 = normalizePhrase(label);
|
|
110531
|
+
if (text3 === "" || text3.split(" ").length > LABEL_VERB_MAX_WORDS) return null;
|
|
110532
|
+
if (NOT_VERB_PHRASES.some((phrase2) => startsWithWords(text3, phrase2))) return null;
|
|
110533
|
+
const found = verbPhrases().find(([phrase2]) => startsWithWords(text3, phrase2));
|
|
110534
|
+
return found === void 0 ? null : found[1];
|
|
110535
|
+
}
|
|
110536
|
+
function labelIconFor(label) {
|
|
110537
|
+
const word2 = label.trim().toLowerCase();
|
|
110538
|
+
if (Object.hasOwn(LABEL_ICON_DEFAULTS, word2)) return LABEL_ICON_DEFAULTS[word2] ?? null;
|
|
110539
|
+
const verb = verbNamedBy(label);
|
|
110540
|
+
return verb === null ? null : EDGE_STYLES[verb].icon;
|
|
110541
|
+
}
|
|
110542
|
+
var phrases;
|
|
110543
|
+
var init_label_icon = __esm({
|
|
110544
|
+
"../../packages/diagrams/src/parse/label-icon.ts"() {
|
|
110545
|
+
"use strict";
|
|
110546
|
+
init_constants();
|
|
110547
|
+
init_phrase();
|
|
110548
|
+
}
|
|
110549
|
+
});
|
|
110550
|
+
|
|
110256
110551
|
// ../../packages/diagrams/src/parse/group-options.ts
|
|
110257
110552
|
function resolveGroupType(option, state) {
|
|
110258
|
-
if (option === void 0) return null;
|
|
110553
|
+
if (option === void 0 || option.value === PLAIN_GROUP_TYPE) return null;
|
|
110259
110554
|
const type = GROUP_TYPES.find((candidate2) => candidate2 === option.value);
|
|
110260
110555
|
if (type !== void 0) return type;
|
|
110261
110556
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownGroupType, `Unknown group type "${option.value}"`, option.valueToken, didYouMean(option.value, GROUP_TYPES)));
|
|
@@ -110268,8 +110563,29 @@ function resolveProvider(option, state) {
|
|
|
110268
110563
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownProvider, `Unknown provider "${option.value}"`, option.valueToken, providerHint(option.value)));
|
|
110269
110564
|
return null;
|
|
110270
110565
|
}
|
|
110271
|
-
function
|
|
110272
|
-
|
|
110566
|
+
function wordsOf2(phrase2) {
|
|
110567
|
+
return phrase2.split(" ").length;
|
|
110568
|
+
}
|
|
110569
|
+
function longestOtherReading(normalized, type) {
|
|
110570
|
+
const lengths = GROUP_TYPES.filter((other) => other !== type).flatMap((other) => GROUP_TYPE_SPECS[other].phrases.filter((phrase2) => ` ${normalized} `.includes(` ${phrase2} `)).map(wordsOf2));
|
|
110571
|
+
return Math.max(0, ...lengths);
|
|
110572
|
+
}
|
|
110573
|
+
function autoGroupType(label) {
|
|
110574
|
+
const trimmed4 = label.trim().toLowerCase();
|
|
110575
|
+
if (REGION_CODE.test(trimmed4) || AZURE_REGION_NAMES.has(trimmed4)) return "region";
|
|
110576
|
+
const normalized = normalizePhrase(label);
|
|
110577
|
+
let best = null;
|
|
110578
|
+
for (const [type, phrases2] of Object.entries(AUTO_GROUP_TYPES)) {
|
|
110579
|
+
const fits = [...(phrases2?.ends ?? []).filter((phrase2) => normalized === phrase2 || normalized.endsWith(` ${phrase2}`)), ...(phrases2?.whole ?? []).filter((phrase2) => normalized === phrase2)];
|
|
110580
|
+
for (const phrase2 of fits) if (best === null || wordsOf2(phrase2) > best.words) best = { type, words: wordsOf2(phrase2) };
|
|
110581
|
+
}
|
|
110582
|
+
return best === null || longestOtherReading(normalized, best.type) > best.words ? null : best.type;
|
|
110583
|
+
}
|
|
110584
|
+
function resolveGroupLook(options3, parent, state, label = null) {
|
|
110585
|
+
const typeOption = findOption(options3, "type");
|
|
110586
|
+
const isPlain = typeOption?.value === PLAIN_GROUP_TYPE;
|
|
110587
|
+
const named = typeOption === void 0 && label !== null && !iconsAreOff(state) ? autoGroupType(label) : null;
|
|
110588
|
+
const type = named ?? resolveGroupType(typeOption, state);
|
|
110273
110589
|
const inherited = parent === null ? state.provider : state.groups.find((group2) => group2.id === parent)?.provider ?? state.provider;
|
|
110274
110590
|
const provider = resolveProvider(findOption(options3, "provider"), state) ?? inherited;
|
|
110275
110591
|
const spec = type === null ? null : GROUP_TYPE_SPECS[type];
|
|
@@ -110278,19 +110594,24 @@ function resolveGroupLook(options3, parent, state) {
|
|
|
110278
110594
|
provider,
|
|
110279
110595
|
tone: resolveTone(findOption(options3, "tone"), spec?.tone ?? GROUP_DEFAULTS.tone, state),
|
|
110280
110596
|
icon: resolveIcon(findOption(options3, "icon"), type === null ? GROUP_DEFAULTS.icon : groupIcon(type, provider), state),
|
|
110281
|
-
frame: spec?.frame ?? GROUP_DEFAULTS.frame
|
|
110597
|
+
frame: spec?.frame ?? GROUP_DEFAULTS.frame,
|
|
110598
|
+
...isPlain ? { isPlain: true } : {}
|
|
110282
110599
|
};
|
|
110283
110600
|
}
|
|
110601
|
+
var PLAIN_GROUP_TYPE;
|
|
110284
110602
|
var init_group_options = __esm({
|
|
110285
110603
|
"../../packages/diagrams/src/parse/group-options.ts"() {
|
|
110286
110604
|
"use strict";
|
|
110287
110605
|
init_constants();
|
|
110288
110606
|
init_core();
|
|
110289
110607
|
init_icons();
|
|
110608
|
+
init_phrase();
|
|
110609
|
+
init_auto_icon();
|
|
110290
110610
|
init_icon_hint();
|
|
110291
110611
|
init_options();
|
|
110292
110612
|
init_statement_helpers();
|
|
110293
110613
|
init_suggest();
|
|
110614
|
+
PLAIN_GROUP_TYPE = "none";
|
|
110294
110615
|
}
|
|
110295
110616
|
});
|
|
110296
110617
|
|
|
@@ -110533,7 +110854,7 @@ function parseGroupStatement(cursor, state, line3, parent) {
|
|
|
110533
110854
|
state.groups.push({
|
|
110534
110855
|
id: groupId,
|
|
110535
110856
|
label,
|
|
110536
|
-
...resolveGroupLook(options3, parent, state),
|
|
110857
|
+
...resolveGroupLook(options3, parent, state, label),
|
|
110537
110858
|
parent,
|
|
110538
110859
|
sub: findOption(options3, "sub")?.value ?? null,
|
|
110539
110860
|
stack: resolveStack(findOption(options3, "stack"), state, true),
|
|
@@ -110560,12 +110881,12 @@ function parseEdgeStatement(cursor, state, line3) {
|
|
|
110560
110881
|
if (iconOption2 !== void 0 && label === null) {
|
|
110561
110882
|
state.report.push(errorAt(DIAGNOSTIC_CODES.syntax, "An edge icon needs a label", iconOption2.keyToken, 'Write: a -> b : "label" icon=status:success'));
|
|
110562
110883
|
}
|
|
110563
|
-
const icon = resolveIcon(iconOption2, label === null ? null :
|
|
110884
|
+
const icon = resolveIcon(iconOption2, label === null || iconsAreOff(state) ? null : labelIconFor(label), state);
|
|
110564
110885
|
rejectTrailing(cursor, state, "Write one edge per line; chains like a -> b -> c are not supported.");
|
|
110565
110886
|
const spec = ARROW_SPECS[arrow.text];
|
|
110566
110887
|
const motion = readLineMotion(options3, state.motion, spec.heads, from, state.report);
|
|
110567
110888
|
const role = readLineRole(findOption(options3, "role"), state.report);
|
|
110568
|
-
state.edges.push({ from: from.text, to: to.text, fromToken: from, toToken: to, label, icon, line: spec.line, heads: spec.heads, ...motion, ...role === void 0 ? {} : { role } });
|
|
110889
|
+
state.edges.push({ from: from.text, to: to.text, fromToken: from, toToken: to, label, icon, ...iconOption2 === void 0 ? {} : { hasOwnIcon: true }, line: spec.line, heads: spec.heads, ...motion, ...role === void 0 ? {} : { role } });
|
|
110569
110890
|
}
|
|
110570
110891
|
function parseOverlayStatement(cursor, state, line3, parent) {
|
|
110571
110892
|
cursor.next();
|
|
@@ -110606,6 +110927,7 @@ var init_flow_statements = __esm({
|
|
|
110606
110927
|
init_constants();
|
|
110607
110928
|
init_core();
|
|
110608
110929
|
init_auto_icon();
|
|
110930
|
+
init_label_icon();
|
|
110609
110931
|
init_group_options();
|
|
110610
110932
|
init_line_motion();
|
|
110611
110933
|
init_line_role();
|
|
@@ -110654,7 +110976,7 @@ function isRefused(member, at3, overlay, seen, state, parents) {
|
|
|
110654
110976
|
function resolveOverlays(state) {
|
|
110655
110977
|
const parents = parentsOf2(state);
|
|
110656
110978
|
const claimedBy = /* @__PURE__ */ new Map();
|
|
110657
|
-
const
|
|
110979
|
+
const resolved2 = [];
|
|
110658
110980
|
for (const overlay of state.overlays) {
|
|
110659
110981
|
const seen = /* @__PURE__ */ new Set();
|
|
110660
110982
|
let isSound = true;
|
|
@@ -110678,9 +111000,9 @@ function resolveOverlays(state) {
|
|
|
110678
111000
|
if (!isSound) continue;
|
|
110679
111001
|
for (const member of overlay.members) claimedBy.set(member, overlay.id);
|
|
110680
111002
|
const { memberAt: _memberAt, ...rest } = overlay;
|
|
110681
|
-
|
|
111003
|
+
resolved2.push(rest);
|
|
110682
111004
|
}
|
|
110683
|
-
return
|
|
111005
|
+
return resolved2;
|
|
110684
111006
|
}
|
|
110685
111007
|
var init_overlay_resolve = __esm({
|
|
110686
111008
|
"../../packages/diagrams/src/parse/overlay-resolve.ts"() {
|
|
@@ -110734,7 +111056,7 @@ function closeScope3(line3, state, scopes) {
|
|
|
110734
111056
|
function resolveEdges(state) {
|
|
110735
111057
|
const nodeIds = state.nodes.map((node3) => node3.id);
|
|
110736
111058
|
const known3 = new Set(nodeIds);
|
|
110737
|
-
const
|
|
111059
|
+
const resolved2 = [];
|
|
110738
111060
|
for (const edge of state.edges) {
|
|
110739
111061
|
const missing = [
|
|
110740
111062
|
{ id: edge.from, token: edge.fromToken },
|
|
@@ -110746,12 +111068,13 @@ function resolveEdges(state) {
|
|
|
110746
111068
|
state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown node "${end.id}"`, end.token, hint2));
|
|
110747
111069
|
}
|
|
110748
111070
|
if (missing.length === 0) {
|
|
110749
|
-
|
|
110750
|
-
id: toEdgeId(
|
|
111071
|
+
resolved2.push({
|
|
111072
|
+
id: toEdgeId(resolved2.length),
|
|
110751
111073
|
from: toNodeId(edge.from),
|
|
110752
111074
|
to: toNodeId(edge.to),
|
|
110753
111075
|
label: edge.label,
|
|
110754
111076
|
icon: edge.icon,
|
|
111077
|
+
...edge.hasOwnIcon === void 0 ? {} : { hasOwnIcon: edge.hasOwnIcon },
|
|
110755
111078
|
line: edge.line,
|
|
110756
111079
|
heads: edge.heads,
|
|
110757
111080
|
...edge.isAnimated === void 0 ? {} : { isAnimated: edge.isAnimated },
|
|
@@ -110760,7 +111083,7 @@ function resolveEdges(state) {
|
|
|
110760
111083
|
});
|
|
110761
111084
|
}
|
|
110762
111085
|
}
|
|
110763
|
-
return
|
|
111086
|
+
return resolved2;
|
|
110764
111087
|
}
|
|
110765
111088
|
function parseFlow(lines, report3) {
|
|
110766
111089
|
const state = {
|
|
@@ -111154,7 +111477,7 @@ function typesNamedBy(label) {
|
|
|
111154
111477
|
function suggestGroupTypes(diagram) {
|
|
111155
111478
|
const warnings = [];
|
|
111156
111479
|
for (const group2 of diagram.groups) {
|
|
111157
|
-
if (group2.type !== null) continue;
|
|
111480
|
+
if (group2.type !== null || group2.isPlain === true) continue;
|
|
111158
111481
|
const types = typesNamedBy(group2.label);
|
|
111159
111482
|
const [type] = types;
|
|
111160
111483
|
if (types.length !== 1 || type === void 0) continue;
|
|
@@ -111172,7 +111495,6 @@ function suggestGroupTypes(diagram) {
|
|
|
111172
111495
|
}
|
|
111173
111496
|
return warnings;
|
|
111174
111497
|
}
|
|
111175
|
-
var REGION_CODE;
|
|
111176
111498
|
var init_suggest_group_types = __esm({
|
|
111177
111499
|
"../../packages/diagrams/src/lint/suggest-group-types.ts"() {
|
|
111178
111500
|
"use strict";
|
|
@@ -111180,7 +111502,53 @@ var init_suggest_group_types = __esm({
|
|
|
111180
111502
|
init_core();
|
|
111181
111503
|
init_icons();
|
|
111182
111504
|
init_suggest_icons();
|
|
111183
|
-
|
|
111505
|
+
}
|
|
111506
|
+
});
|
|
111507
|
+
|
|
111508
|
+
// ../../packages/diagrams/src/lint/suggest-line-roles.ts
|
|
111509
|
+
function nameOf(edge) {
|
|
111510
|
+
return `${edge.from} -> ${edge.to}`;
|
|
111511
|
+
}
|
|
111512
|
+
function suggestLineRoles(diagram) {
|
|
111513
|
+
const byRole = /* @__PURE__ */ new Map();
|
|
111514
|
+
for (const edge of diagram.edges) {
|
|
111515
|
+
if (edge.role !== void 0 || edge.hasOwnIcon === true || edge.label === null) continue;
|
|
111516
|
+
const verb = verbNamedBy(edge.label);
|
|
111517
|
+
const role = verb === null ? null : EDGE_STYLES[verb].role;
|
|
111518
|
+
if (role !== null) byRole.set(role, [...byRole.get(role) ?? [], edge]);
|
|
111519
|
+
}
|
|
111520
|
+
return LINE_ROLES.flatMap((role) => {
|
|
111521
|
+
const edges = byRole.get(role) ?? [];
|
|
111522
|
+
if (edges.length === 0) return [];
|
|
111523
|
+
const named = edges.slice(0, NAMED_ARROWS).map(nameOf).join(", ");
|
|
111524
|
+
const rest = edges.length > NAMED_ARROWS ? ` and ${edges.length - NAMED_ARROWS} more` : "";
|
|
111525
|
+
const doing = edges.length === 1 ? `1 arrow ${ROLE_DOING[role].one}` : `${edges.length} arrows ${ROLE_DOING[role].many}`;
|
|
111526
|
+
const spec = LINE_ROLE_SPECS[role];
|
|
111527
|
+
return [
|
|
111528
|
+
warningAt(
|
|
111529
|
+
DIAGNOSTIC_CODES.suggestLineRole,
|
|
111530
|
+
`${doing} (${named}${rest}) with no role=`,
|
|
111531
|
+
HEADER,
|
|
111532
|
+
edges.length === 1 ? `Add role=${role} to it, which draws the line ${spec.tone} and names it ${spec.legend} in the legend.` : `Add role=${role} to each, which draws the lines ${spec.tone} and names them ${spec.legend} in the legend.`
|
|
111533
|
+
)
|
|
111534
|
+
];
|
|
111535
|
+
});
|
|
111536
|
+
}
|
|
111537
|
+
var ROLE_DOING, NAMED_ARROWS;
|
|
111538
|
+
var init_suggest_line_roles = __esm({
|
|
111539
|
+
"../../packages/diagrams/src/lint/suggest-line-roles.ts"() {
|
|
111540
|
+
"use strict";
|
|
111541
|
+
init_constants();
|
|
111542
|
+
init_core();
|
|
111543
|
+
init_label_icon();
|
|
111544
|
+
init_general_warnings();
|
|
111545
|
+
ROLE_DOING = {
|
|
111546
|
+
data: { one: "reads or writes stored data", many: "read or write stored data" },
|
|
111547
|
+
async: { one: "sends or receives a message that is not waited for", many: "send or receive messages that are not waited for" },
|
|
111548
|
+
identity: { one: "signs in or carries a credential", many: "sign in or carry credentials" },
|
|
111549
|
+
private: { one: "crosses a private network", many: "cross a private network" }
|
|
111550
|
+
};
|
|
111551
|
+
NAMED_ARROWS = 4;
|
|
111184
111552
|
}
|
|
111185
111553
|
});
|
|
111186
111554
|
|
|
@@ -111221,7 +111589,7 @@ function lintFlow(diagram, measure) {
|
|
|
111221
111589
|
shortenedWarning(shortenedIds3(diagram)),
|
|
111222
111590
|
widthWarning(measure.size, "Use direction=down, shorten labels, or split the diagram.")
|
|
111223
111591
|
]);
|
|
111224
|
-
return [...general, ...overlayWarnings(diagram, measure.overlayCovers), ...suggestGroupTypes(diagram), ...suggestIcons(diagram)];
|
|
111592
|
+
return [...general, ...overlayWarnings(diagram, measure.overlayCovers), ...suggestGroupTypes(diagram), ...suggestIcons(diagram), ...suggestLineRoles(diagram)];
|
|
111225
111593
|
}
|
|
111226
111594
|
var init_lint3 = __esm({
|
|
111227
111595
|
"../../packages/diagrams/src/kinds/flow/lint.ts"() {
|
|
@@ -111235,6 +111603,7 @@ var init_lint3 = __esm({
|
|
|
111235
111603
|
init_overlay_warnings();
|
|
111236
111604
|
init_suggest_group_types();
|
|
111237
111605
|
init_suggest_icons();
|
|
111606
|
+
init_suggest_line_roles();
|
|
111238
111607
|
}
|
|
111239
111608
|
});
|
|
111240
111609
|
|
|
@@ -112649,19 +113018,19 @@ function resolve(declaration) {
|
|
|
112649
113018
|
if (fill !== null && tone === null) leftOut.unshift(`fill ${fill} has no tone`);
|
|
112650
113019
|
return { tone, fill, leftOut };
|
|
112651
113020
|
}
|
|
112652
|
-
function report2(state, declaration,
|
|
113021
|
+
function report2(state, declaration, resolved2, subject, isApplied) {
|
|
112653
113022
|
const { reporter } = state.ctx;
|
|
112654
|
-
const leftOut = [...
|
|
112655
|
-
if (
|
|
113023
|
+
const leftOut = [...resolved2.leftOut];
|
|
113024
|
+
if (resolved2.tone !== null && resolved2.fill !== null && isApplied) {
|
|
112656
113025
|
reporter.add(
|
|
112657
113026
|
DIAGNOSTIC_CODES.mermaidMappedToNearest,
|
|
112658
113027
|
declaration.span,
|
|
112659
|
-
`The fill ${
|
|
113028
|
+
`The fill ${resolved2.fill} of ${subject} became the tone ${resolved2.tone}.`,
|
|
112660
113029
|
"Check that the tone says what it means. The theme draws it in light and dark.",
|
|
112661
113030
|
"fill-tone"
|
|
112662
113031
|
);
|
|
112663
|
-
} else if (
|
|
112664
|
-
leftOut.unshift(`fill ${
|
|
113032
|
+
} else if (resolved2.tone !== null && resolved2.fill !== null) {
|
|
113033
|
+
leftOut.unshift(`fill ${resolved2.fill} has no node or subgraph to colour`);
|
|
112665
113034
|
}
|
|
112666
113035
|
if (leftOut.length > 0) reporter.dropped("styleLeftOut", declaration.span, leftOut.join(", "));
|
|
112667
113036
|
}
|
|
@@ -112669,9 +113038,9 @@ function applyStyles(state) {
|
|
|
112669
113038
|
const { builder, ctx } = state;
|
|
112670
113039
|
const classTones = /* @__PURE__ */ new Map();
|
|
112671
113040
|
for (const declaration of state.classDefs) {
|
|
112672
|
-
const
|
|
112673
|
-
if (
|
|
112674
|
-
report2(state, declaration,
|
|
113041
|
+
const resolved2 = resolve(declaration);
|
|
113042
|
+
if (resolved2.tone !== null) for (const name2 of declaration.targets) classTones.set(name2, resolved2.tone);
|
|
113043
|
+
report2(state, declaration, resolved2, `the class ${declaration.targets.map((name2) => `"${name2}"`).join(", ")}`, resolved2.tone !== null);
|
|
112675
113044
|
}
|
|
112676
113045
|
for (const node3 of builder.nodes) {
|
|
112677
113046
|
for (const name2 of node3.classes) {
|
|
@@ -112680,9 +113049,9 @@ function applyStyles(state) {
|
|
|
112680
113049
|
}
|
|
112681
113050
|
}
|
|
112682
113051
|
for (const declaration of state.styles) {
|
|
112683
|
-
const
|
|
112684
|
-
const applied =
|
|
112685
|
-
report2(state, declaration,
|
|
113052
|
+
const resolved2 = resolve(declaration);
|
|
113053
|
+
const applied = resolved2.tone === null ? [] : declaration.targets.filter((target) => builder.setTone(target, resolved2.tone));
|
|
113054
|
+
report2(state, declaration, resolved2, `the style of ${declaration.targets.map((target) => `"${target}"`).join(", ")}`, applied.length > 0);
|
|
112686
113055
|
}
|
|
112687
113056
|
for (const use of state.classUses) {
|
|
112688
113057
|
if (!classTones.has(use.name)) ctx.reporter.dropped("classAssign", use.span, use.name);
|
|
@@ -112830,7 +113199,7 @@ function matches(rule, words2) {
|
|
|
112830
113199
|
return rule.whole.includes(whole2) || rule.last.includes(last) || words2.some((word2) => rule.product.includes(word2));
|
|
112831
113200
|
}
|
|
112832
113201
|
function keywordType(label) {
|
|
112833
|
-
const words2 =
|
|
113202
|
+
const words2 = wordsOf3(label);
|
|
112834
113203
|
if (words2.length === 0 || words2.length > KEYWORD_MAX_WORDS) return null;
|
|
112835
113204
|
const found = new Set(KEYWORD_RULES.filter((rule) => matches(rule, words2)).map((rule) => rule.type));
|
|
112836
113205
|
const [only] = [...found];
|
|
@@ -112842,7 +113211,7 @@ function statusCodeTone(label) {
|
|
|
112842
113211
|
return family === "4" || family === "5" ? "red" : null;
|
|
112843
113212
|
}
|
|
112844
113213
|
function productType(text3) {
|
|
112845
|
-
const words2 =
|
|
113214
|
+
const words2 = wordsOf3(text3);
|
|
112846
113215
|
if (words2.length === 0 || words2.length > KEYWORD_MAX_WORDS) return null;
|
|
112847
113216
|
const found = new Set(KEYWORD_RULES.filter((rule) => words2.some((word2) => rule.product.includes(word2))).map((rule) => rule.type));
|
|
112848
113217
|
const [only] = [...found];
|
|
@@ -112879,7 +113248,7 @@ function inferNodeIcon(node3, type) {
|
|
|
112879
113248
|
if (NOT_PRODUCT_TYPES2.has(type) || FLOW_NODE_TYPE_DEFAULTS[type].shape === "pill") return null;
|
|
112880
113249
|
return brandMarkNamedBy(node3.label) ?? (node3.sub === null ? null : brandMarkNamedBy(node3.sub));
|
|
112881
113250
|
}
|
|
112882
|
-
var
|
|
113251
|
+
var wordsOf3, STATUS_CODE, NOT_PRODUCT_TYPES2;
|
|
112883
113252
|
var init_infer = __esm({
|
|
112884
113253
|
"../../packages/diagrams/src/import/infer.ts"() {
|
|
112885
113254
|
"use strict";
|
|
@@ -112887,7 +113256,7 @@ var init_infer = __esm({
|
|
|
112887
113256
|
init_icons();
|
|
112888
113257
|
init_suggest_icons();
|
|
112889
113258
|
init_mapping();
|
|
112890
|
-
|
|
113259
|
+
wordsOf3 = (label) => label.toLowerCase().split(/[^a-z0-9]+/).filter((word2) => word2 !== "");
|
|
112891
113260
|
STATUS_CODE = /^(?:(?:return|returns|respond|respond with|response|http)\s+)?(?:http\s+)?([2-5])\d\d(?:\s|$)/i;
|
|
112892
113261
|
NOT_PRODUCT_TYPES2 = /* @__PURE__ */ new Set(["decision", "terminal", "step"]);
|
|
112893
113262
|
}
|
|
@@ -114278,7 +114647,7 @@ function resolveWindows(ir, calendar, ctx) {
|
|
|
114278
114647
|
if (target === void 0) return fail2(task, `${what} "${key}", which is not a task of this chart.`, hint2);
|
|
114279
114648
|
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
114649
|
};
|
|
114281
|
-
const
|
|
114650
|
+
const startOf4 = (task, index2) => {
|
|
114282
114651
|
if (task.start.kind === "date") return task.start.day;
|
|
114283
114652
|
if (task.start.kind === "previous") {
|
|
114284
114653
|
const previous = ir.tasks[index2 - 1];
|
|
@@ -114289,7 +114658,7 @@ function resolveWindows(ir, calendar, ctx) {
|
|
|
114289
114658
|
return ends.length === 0 || ends.includes(null) ? null : Math.max(...ends.map((day) => day ?? 0));
|
|
114290
114659
|
};
|
|
114291
114660
|
const place2 = (task, index2) => {
|
|
114292
|
-
const wanted2 =
|
|
114661
|
+
const wanted2 = startOf4(task, index2);
|
|
114293
114662
|
if (wanted2 === null) return null;
|
|
114294
114663
|
const start2 = task.start.kind === "date" || !calendar.isActive ? wanted2 : nextWorkingDay(calendar, wanted2);
|
|
114295
114664
|
const { end } = task;
|
|
@@ -116339,7 +116708,7 @@ function summarizeGit(diagram) {
|
|
|
116339
116708
|
const counts = `${countOf(diagram.commits.length, "commit")} on ${countOf(diagram.branches.length, "branch", "branches")}${optionalCount(merges, "merge")}${optionalCount(picks2, "cherry-pick")}${optionalCount(tags, "tag")}`;
|
|
116340
116709
|
return `${title}: ${counts}.${description}`;
|
|
116341
116710
|
}
|
|
116342
|
-
function
|
|
116711
|
+
function nameOf2(commit) {
|
|
116343
116712
|
return commit.message === null ? `commit ${commit.index + 1}` : `"${commit.message}"`;
|
|
116344
116713
|
}
|
|
116345
116714
|
function describeCommit(commit, diagram) {
|
|
@@ -116353,7 +116722,7 @@ function describeCommit(commit, diagram) {
|
|
|
116353
116722
|
return `merge of ${commit.mergedBranch ?? "a branch"} into ${commit.branch}${message2}${nothing2}${kind}${id}${tags}`;
|
|
116354
116723
|
}
|
|
116355
116724
|
if (commit.origin === "cherry-pick") {
|
|
116356
|
-
const of = source === void 0 ? "a commit" : `${source.id ??
|
|
116725
|
+
const of = source === void 0 ? "a commit" : `${source.id ?? nameOf2(source)}${source.message === null ? "" : ` ("${source.message}")`}`;
|
|
116357
116726
|
const own2 = commit.message !== null && commit.message !== source?.message ? `, message "${commit.message}"` : "";
|
|
116358
116727
|
return `cherry-pick of ${of}${own2}${kind}${id}${tags}`;
|
|
116359
116728
|
}
|
|
@@ -116362,7 +116731,7 @@ function describeCommit(commit, diagram) {
|
|
|
116362
116731
|
function describeBranch(branch, diagram) {
|
|
116363
116732
|
const parent = branch.forkedFrom === null ? void 0 : diagram.commits[branch.forkedFrom];
|
|
116364
116733
|
if (parent === void 0 || branch.parentBranch === null) return `${branch.name} is the default branch`;
|
|
116365
|
-
return `${branch.name} was made from ${branch.parentBranch} at ${
|
|
116734
|
+
return `${branch.name} was made from ${branch.parentBranch} at ${nameOf2(parent)}`;
|
|
116366
116735
|
}
|
|
116367
116736
|
function outlineGit(diagram) {
|
|
116368
116737
|
const lines = [summarizeGit(diagram), "Branches, in lane order:"];
|
|
@@ -117191,7 +117560,7 @@ var init_check2 = __esm({
|
|
|
117191
117560
|
});
|
|
117192
117561
|
|
|
117193
117562
|
// ../../packages/diagrams/src/kinds/journey/layout-columns.ts
|
|
117194
|
-
function
|
|
117563
|
+
function wordsOf4(text3, role) {
|
|
117195
117564
|
const widths = (text3 ?? "").split(/\s+/).filter(Boolean).map((word2) => measureRole(word2, role));
|
|
117196
117565
|
return { widths, space: measureRole(" ", role), longest: widths.reduce((most, width) => Math.max(most, width), 0) };
|
|
117197
117566
|
}
|
|
@@ -117231,7 +117600,7 @@ function candidates(needed) {
|
|
|
117231
117600
|
}
|
|
117232
117601
|
function chooseColumn(sections, hasTabs) {
|
|
117233
117602
|
const tasks = sections.flatMap((section) => section.tasks);
|
|
117234
|
-
const words2 = tasks.map((task) => ({ label:
|
|
117603
|
+
const words2 = tasks.map((task) => ({ label: wordsOf4(task.label, "label"), sub: wordsOf4(task.sub, "sub") }));
|
|
117235
117604
|
const longest = words2.reduce((most, item) => Math.max(most, item.label.longest, item.sub.longest), 0);
|
|
117236
117605
|
const widths = candidates(longest + card.paddingX * 2);
|
|
117237
117606
|
const isClean = (column) => {
|
|
@@ -117540,11 +117909,11 @@ function assignTones(chosen) {
|
|
|
117540
117909
|
return given2;
|
|
117541
117910
|
});
|
|
117542
117911
|
}
|
|
117543
|
-
function
|
|
117912
|
+
function wordsOf5(name2) {
|
|
117544
117913
|
return (name2.match(WORD) ?? []).map((word2) => [...word2]);
|
|
117545
117914
|
}
|
|
117546
117915
|
function initialsCandidates(name2) {
|
|
117547
|
-
const words2 =
|
|
117916
|
+
const words2 = wordsOf5(name2);
|
|
117548
117917
|
const first = words2[0] ?? [];
|
|
117549
117918
|
if (first.length === 0) return [[...name2.trim()][0]?.toUpperCase() ?? "?"];
|
|
117550
117919
|
const upper = (chars) => chars.join("").toUpperCase();
|
|
@@ -119178,7 +119547,7 @@ function outlineLayers(diagram) {
|
|
|
119178
119547
|
...diagram.links.map((link2) => `- ${describeLink(link2, labels2)}`)
|
|
119179
119548
|
];
|
|
119180
119549
|
}
|
|
119181
|
-
var STYLE_WORDS,
|
|
119550
|
+
var STYLE_WORDS, nameOf3, listOf;
|
|
119182
119551
|
var init_outline6 = __esm({
|
|
119183
119552
|
"../../packages/diagrams/src/kinds/layers/outline.ts"() {
|
|
119184
119553
|
"use strict";
|
|
@@ -119186,8 +119555,8 @@ var init_outline6 = __esm({
|
|
|
119186
119555
|
init_check3();
|
|
119187
119556
|
init_text3();
|
|
119188
119557
|
STYLE_WORDS = { solid: "", dashed: ", optional or indirect", dotted: ", asynchronous" };
|
|
119189
|
-
|
|
119190
|
-
listOf = (blocks2) => blocks2.length === 0 ? "no blocks." : `${blocks2.map(
|
|
119558
|
+
nameOf3 = (block) => block.sub === null ? oneLine2(block.label) : `${oneLine2(block.label)} (${oneLine2(block.sub)})`;
|
|
119559
|
+
listOf = (blocks2) => blocks2.length === 0 ? "no blocks." : `${blocks2.map(nameOf3).join(", ")}.`;
|
|
119191
119560
|
}
|
|
119192
119561
|
});
|
|
119193
119562
|
|
|
@@ -119403,7 +119772,7 @@ function close(line3, state) {
|
|
|
119403
119772
|
function resolveLinks(state) {
|
|
119404
119773
|
const ids = state.layers.flatMap((layer2) => layer2.blocks.map((block) => block.id));
|
|
119405
119774
|
const inAside = new Set(state.asides.flatMap((aside) => aside.blocks.map((block) => block.id)));
|
|
119406
|
-
const
|
|
119775
|
+
const resolved2 = [];
|
|
119407
119776
|
for (const link2 of state.links) {
|
|
119408
119777
|
const missing = [link2.from, link2.to].filter((end) => !ids.includes(end.text));
|
|
119409
119778
|
for (const end of missing) {
|
|
@@ -119412,9 +119781,9 @@ function resolveLinks(state) {
|
|
|
119412
119781
|
}
|
|
119413
119782
|
if (missing.length > 0) continue;
|
|
119414
119783
|
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
|
|
119784
|
+
else resolved2.push({ from: link2.from.text, to: link2.to.text, label: link2.label, line: link2.line, heads: link2.heads });
|
|
119416
119785
|
}
|
|
119417
|
-
return
|
|
119786
|
+
return resolved2;
|
|
119418
119787
|
}
|
|
119419
119788
|
function parseLayers(lines, report3) {
|
|
119420
119789
|
const state = { title: null, description: null, direction: "down", showCounts: false, layers: [], asides: [], links: [], open: [], declared: /* @__PURE__ */ new Map(), report: report3 };
|
|
@@ -125659,21 +126028,21 @@ var init_marks2 = __esm({
|
|
|
125659
126028
|
});
|
|
125660
126029
|
|
|
125661
126030
|
// ../../packages/diagrams/src/kinds/sankey/node-content.ts
|
|
125662
|
-
function
|
|
126031
|
+
function nameOf4(node3) {
|
|
125663
126032
|
const name2 = oneLine6(node3.label);
|
|
125664
126033
|
const chars = [...name2];
|
|
125665
126034
|
return chars.length > MAX_NAME_CHARS ? { text: chars.slice(0, MAX_NAME_CHARS).join(""), isClipped: true } : { text: name2, isClipped: false };
|
|
125666
126035
|
}
|
|
125667
126036
|
function wantedWidth(node3, valueText) {
|
|
125668
|
-
const text3 = Math.max(measureRole(
|
|
126037
|
+
const text3 = Math.max(measureRole(nameOf4(node3).text, "label"), valueText === null ? 0 : measureRole(valueText, "sub"));
|
|
125669
126038
|
return Math.ceil(2 * SANKEY_METRICS.padX + (node3.icon === null ? 0 : SANKEY_METRICS.chipSize + SANKEY_METRICS.chipGap) + text3);
|
|
125670
126039
|
}
|
|
125671
126040
|
function floorWidth(node3, valueText) {
|
|
125672
|
-
const longest =
|
|
126041
|
+
const longest = nameOf4(node3).text.split(" ").reduce((most, word2) => Math.max(most, measureRole(word2, "label")), 0);
|
|
125673
126042
|
return Math.ceil(2 * SANKEY_METRICS.padX + (node3.icon === null ? 0 : SANKEY_METRICS.chipSize + SANKEY_METRICS.chipGap) + Math.max(longest, valueText === null ? 0 : measureRole(valueText, "sub")));
|
|
125674
126043
|
}
|
|
125675
126044
|
function fitNode(node3, valueText, width) {
|
|
125676
|
-
const name2 =
|
|
126045
|
+
const name2 = nameOf4(node3);
|
|
125677
126046
|
const hasChip = node3.icon !== null;
|
|
125678
126047
|
const textWidth3 = width - 2 * SANKEY_METRICS.padX - (hasChip ? SANKEY_METRICS.chipSize + SANKEY_METRICS.chipGap : 0);
|
|
125679
126048
|
const fitted = fitText(name2.text, "label", textWidth3, textWidth3, SANKEY_METRICS.maxLabelLines);
|
|
@@ -127198,14 +127567,14 @@ function resolveEnd(token, tables, report3) {
|
|
|
127198
127567
|
return { table: table2, column: columnName2 };
|
|
127199
127568
|
}
|
|
127200
127569
|
function resolveRelations(state) {
|
|
127201
|
-
const
|
|
127570
|
+
const resolved2 = [];
|
|
127202
127571
|
for (const pending of state.relations) {
|
|
127203
127572
|
const from = resolveEnd(pending.from, state.tables, state.report);
|
|
127204
127573
|
const to = resolveEnd(pending.to, state.tables, state.report);
|
|
127205
127574
|
if (from === null || to === null) continue;
|
|
127206
127575
|
const fromColumn = from.table.columns.find((column) => column.name === from.column);
|
|
127207
|
-
|
|
127208
|
-
id: toEdgeId(
|
|
127576
|
+
resolved2.push({
|
|
127577
|
+
id: toEdgeId(resolved2.length),
|
|
127209
127578
|
fromTable: toTableId(from.table.id),
|
|
127210
127579
|
fromColumn: from.column,
|
|
127211
127580
|
toTable: toTableId(to.table.id),
|
|
@@ -127214,7 +127583,7 @@ function resolveRelations(state) {
|
|
|
127214
127583
|
cardinality: fromColumn?.isPrimaryKey === true || fromColumn?.isUnique === true ? "one-to-one" : "many-to-one"
|
|
127215
127584
|
});
|
|
127216
127585
|
}
|
|
127217
|
-
return
|
|
127586
|
+
return resolved2;
|
|
127218
127587
|
}
|
|
127219
127588
|
function parseSchema(lines, report3) {
|
|
127220
127589
|
const state = { title: null, description: null, tables: [], relations: [], openTable: null, declared: /* @__PURE__ */ new Map(), report: report3 };
|
|
@@ -130819,7 +131188,7 @@ function planState(ir, ctx) {
|
|
|
130819
131188
|
origin: node3.span.line
|
|
130820
131189
|
}));
|
|
130821
131190
|
const kindOf3 = new Map(real.map((node3) => [node3.key, node3.kind]));
|
|
130822
|
-
const
|
|
131191
|
+
const nameOf11 = (key) => {
|
|
130823
131192
|
const marker = ir.nodes.find((node3) => node3.key === key);
|
|
130824
131193
|
return marker !== void 0 && (marker.kind === "start" || marker.kind === "end") ? `the ${marker.kind} marker` : `"${key}"`;
|
|
130825
131194
|
};
|
|
@@ -130842,7 +131211,7 @@ function planState(ir, ctx) {
|
|
|
130842
131211
|
}
|
|
130843
131212
|
const isNested = transition.from !== transition.to && (lineageOf2(transition.to, parentKeys).includes(transition.from) || lineageOf2(transition.from, parentKeys).includes(transition.to));
|
|
130844
131213
|
if (isNested) {
|
|
130845
|
-
reporter.add(DIAGNOSTIC_CODES.mermaidDroppedMeaning, span, `Dropped a transition between ${
|
|
131214
|
+
reporter.add(DIAGNOSTIC_CODES.mermaidDroppedMeaning, span, `Dropped a transition between ${nameOf11(transition.from)} and ${nameOf11(transition.to)}, because one is inside the other. A transition cannot join a state to one inside it.`, "Start the transition from a state inside the composite state, or from its own start marker.", "nested-transition");
|
|
130846
131215
|
continue;
|
|
130847
131216
|
}
|
|
130848
131217
|
const { composite, region } = transition.scope;
|
|
@@ -130907,7 +131276,7 @@ function summarizeState(diagram) {
|
|
|
130907
131276
|
const description = diagram.meta.description === null ? "" : ` ${diagram.meta.description}`;
|
|
130908
131277
|
return `${title}: ${counts}.${description}`;
|
|
130909
131278
|
}
|
|
130910
|
-
function
|
|
131279
|
+
function nameOf5(diagram, node3) {
|
|
130911
131280
|
const holder = node3.parent === null ? void 0 : diagram.states.find((candidate2) => candidate2.id === node3.parent);
|
|
130912
131281
|
const scope = holder === void 0 ? "" : ` of ${holder.label}${node3.region === null ? "" : regionSuffix(diagram, holder.id, node3.region)}`;
|
|
130913
131282
|
if (node3.kind === "start" || node3.kind === "end") return `${KIND_NAMES[node3.kind]}${scope}`;
|
|
@@ -130922,7 +131291,7 @@ function regionSuffix(diagram, parent, index2) {
|
|
|
130922
131291
|
}
|
|
130923
131292
|
function nodeLine2(diagram, node3) {
|
|
130924
131293
|
const detail = node3.description.length === 0 ? "" : ` (${node3.description.join("; ")})`;
|
|
130925
|
-
const name2 =
|
|
131294
|
+
const name2 = nameOf5(diagram, node3);
|
|
130926
131295
|
if (node3.kind === "state") return `${name2}${detail}, state`;
|
|
130927
131296
|
if (node3.kind === "composite") return `${name2}${detail}, composite state`;
|
|
130928
131297
|
if (node3.kind === "choice") return `${name2}, choice`;
|
|
@@ -130933,7 +131302,7 @@ function nodeLine2(diagram, node3) {
|
|
|
130933
131302
|
function transitionLine(diagram, transition) {
|
|
130934
131303
|
const name2 = (id) => {
|
|
130935
131304
|
const node3 = diagram.states.find((candidate2) => candidate2.id === id);
|
|
130936
|
-
return node3 === void 0 ? id :
|
|
131305
|
+
return node3 === void 0 ? id : nameOf5(diagram, node3);
|
|
130937
131306
|
};
|
|
130938
131307
|
const on = transition.event === null ? "" : ` on ${transition.event}`;
|
|
130939
131308
|
const guard = transition.guard === null ? "" : `, if ${transition.guard}`;
|
|
@@ -130965,7 +131334,7 @@ function outlineState(diagram) {
|
|
|
130965
131334
|
lines.push("Notes:");
|
|
130966
131335
|
for (const note of diagram.notes) {
|
|
130967
131336
|
const target = diagram.states.find((node3) => node3.id === note.target);
|
|
130968
|
-
lines.push(`- On ${target === void 0 ? note.target :
|
|
131337
|
+
lines.push(`- On ${target === void 0 ? note.target : nameOf5(diagram, target)}: ${note.text}`);
|
|
130969
131338
|
}
|
|
130970
131339
|
}
|
|
130971
131340
|
return lines;
|
|
@@ -131287,7 +131656,7 @@ function lineage(id, byId) {
|
|
|
131287
131656
|
}
|
|
131288
131657
|
function resolveTransitions(state, byId) {
|
|
131289
131658
|
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
|
|
131659
|
+
const resolved2 = [];
|
|
131291
131660
|
let suggested = 0;
|
|
131292
131661
|
for (const pending of state.transitions) {
|
|
131293
131662
|
const missing = [
|
|
@@ -131310,9 +131679,9 @@ function resolveTransitions(state, byId) {
|
|
|
131310
131679
|
continue;
|
|
131311
131680
|
}
|
|
131312
131681
|
const parts = pending.label === null ? { event: null, guard: null, action: null } : splitLabel(pending.label);
|
|
131313
|
-
|
|
131682
|
+
resolved2.push({ id: `t${resolved2.length}`, from: pending.from, to: pending.to, label: pending.label, ...parts, at: pending.at });
|
|
131314
131683
|
}
|
|
131315
|
-
return
|
|
131684
|
+
return resolved2;
|
|
131316
131685
|
}
|
|
131317
131686
|
function resolveNotes2(state, byId) {
|
|
131318
131687
|
const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice").map((node3) => node3.id);
|
|
@@ -132593,7 +132962,7 @@ function parseFlow2(cursor, p, line3) {
|
|
|
132593
132962
|
}
|
|
132594
132963
|
function resolveFlows(p) {
|
|
132595
132964
|
const names8 = p.items.map((item) => item.id);
|
|
132596
|
-
const
|
|
132965
|
+
const resolved2 = [];
|
|
132597
132966
|
let suggested = 0;
|
|
132598
132967
|
for (const pending of p.pending) {
|
|
132599
132968
|
const missing = [pending.from, pending.to].filter((end) => !names8.includes(end.text));
|
|
@@ -132608,9 +132977,9 @@ function resolveFlows(p) {
|
|
|
132608
132977
|
continue;
|
|
132609
132978
|
}
|
|
132610
132979
|
const parts = pending.label === null ? { event: null, guard: null, action: null } : splitLabel(pending.label);
|
|
132611
|
-
|
|
132980
|
+
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
132981
|
}
|
|
132613
|
-
return
|
|
132982
|
+
return resolved2;
|
|
132614
132983
|
}
|
|
132615
132984
|
function dispatch11(line3, p, scope) {
|
|
132616
132985
|
const cursor = new TokenCursor(line3.tokens);
|
|
@@ -138992,7 +139361,7 @@ api --> email : "Sends email using" tech="SMTP"
|
|
|
138992
139361
|
email --> customer : "Sends emails to"
|
|
138993
139362
|
` },
|
|
138994
139363
|
{ kind: "class", title: "Notification service", source: 'class "Notification service" desc="A notifier queues messages and delivers each one through a channel. Channels are interchangeable, so a new one needs no change to the notifier."\n\nclass Notifier stereotype="service" {\n "-queue: Queue<Message>"\n "+send(m: Message): void"\n "+retry(): int"\n}\n\nclass Message {\n "+id: uuid"\n "+body: String"\n "+priority: Priority"\n}\n\nclass Priority type=enum {\n "LOW"\n "NORMAL"\n "URGENT"\n}\n\nclass Template "Template<T>" type=abstract {\n "+render(data: T): String" abstract\n "+named(n: String): Template" static\n}\n\npackage channels "Channels" {\n class Channel type=interface {\n "+deliver(m: Message): Ack"\n }\n class Email "EmailChannel" {\n "-host: String"\n "+deliver(m: Message): Ack"\n }\n class Sms "SmsChannel" {\n "-gateway: String"\n "+deliver(m: Message): Ack"\n }\n}\n\nNotifier "1" owns "*" Message : "queues"\nNotifier "1" has "1..*" Channel : "delivers through"\nNotifier --> Template : "renders with"\nMessage --> Priority\nEmail implements Channel\nSms implements Channel\n\nnote on Message : "Kept until every channel has confirmed delivery."\n' },
|
|
138995
|
-
{ kind: "flow", title: "Login request", source: 'flow "Login request" desc="A user signs in through an API that checks credentials in a database."\n\nnode user person "User"\nnode api service "Auth API" sub="Validates credentials"\n\ngroup data "Data"
|
|
139364
|
+
{ kind: "flow", title: "Login request", source: 'flow "Login request" desc="A user signs in through an API that checks credentials in a database and keeps the session in a cache."\n\nnode user person "User"\nnode api service "Auth API" sub="Validates credentials"\n\ngroup data "Data" {\n node db database "PostgreSQL" sub="Password hashes"\n node cache cache "Redis" sub="Sessions"\n}\n\nuser -> api : "signs in" role=identity\napi -> db : "looks up user" role=data\ndb --> api : "row"\napi -> cache : "stores session" role=data\n' },
|
|
138996
139365
|
{ kind: "gantt", title: "Product launch plan", source: 'gantt "Product launch plan" start=2026-01-05 unit=week today=2026-02-11 weekends=skip holidays=2026-04-03 desc="A fourteen week plan from research to launch, with design and build running side by side."\n\nsection "Discover" {\n task research "User research" start=2026-01-05 duration=2w status=done\n task brief "Product brief" after=research duration=1w status=done\n}\n\nsection "Design" tone=violet {\n task ux "UX flows" after=brief duration=2w status=done\n task ui "Visual design" after=ux duration=3w status=active\n task ds "Design system" after=brief duration=4w status=active\n}\n\nsection "Build" tone=aqua {\n task api "API and data model" after=brief duration=5w status=active\n task web "Web app" after=ui,api duration=4w status=critical\n task mobile "Mobile app" after=ui,api duration=4w\n milestone beta "Beta ready" after=web\n}\n\nsection "Launch" tone=orange {\n task docs "Help center" after=ui duration=3w\n task qa "Testing and fixes" after=web,mobile duration=2w status=critical\n milestone ga "Public launch" after=qa status=critical\n}\n' },
|
|
138997
139366
|
{ kind: "git", title: "Release and hotfix", source: 'git "Release and hotfix" desc="A feature is merged into develop, develop is released as v1.0, and a hotfix is tagged and picked back."\n\ncommit "Initial commit"\nbranch develop order=2\ncommit "Set up CI"\nbranch "feature/search" from=develop\ncommit "Add search box"\ncommit "Index the docs"\ncheckout develop\nmerge "feature/search" "Add search"\ncheckout main\nmerge develop "Release 1.0" tag="v1.0" type=highlight\nbranch hotfix order=1\ncommit "Fix null check" id=fix\ncheckout main\nmerge hotfix tag="v1.0.1"\ncheckout develop\ncherry-pick fix\ncommit "Revert flaky test" type=reverse\n' },
|
|
138998
139367
|
{ kind: "journey", title: "Checkout experience", source: 'journey "Checkout experience" desc="How a shopper feels from finding a product to holding the parcel, and who is involved at each step."\n\nactor "Customer" tone=blue\nactor "Support agent" tone=violet\nactor "Bank"\nactor "Courier"\n\nsection "Browse" {\n task "Find a product" score=5 actors="Customer"\n task "Compare prices" score=3 actors="Customer, Support agent" sub="Asks about delivery"\n}\n\nsection "Pay" {\n task "Enter card details" score=2 actors="Customer"\n task "Confirm with the bank" score=1 actors="Customer, Bank"\n task "Get a receipt" score=4 actors="Customer"\n}\n\nsection "Deliver" {\n task "Track the parcel" score=4 actors="Customer, Courier"\n task "Receive it" score=5 actors="Customer, Courier"\n}\n' },
|
|
@@ -139050,7 +139419,7 @@ ship -> delivered : "arrived"
|
|
|
139050
139419
|
{ kind: "treemap", title: "Monthly cloud spend", source: 'treemap "Monthly cloud spend" unit="$" better=down desc="Where the monthly cloud bill goes, by service, with the change since last month. A rise in cost is drawn red."\n\ngroup "Compute" icon=lucide:cpu {\n item "EC2" 18400 icon=aws:ec2 delta="8%"\n item "Fargate" 6800 icon=aws:fargate delta="21%"\n item "Lambda" 4200 icon=aws:lambda delta="-12%"\n item "EKS" 3100 icon=aws:eks\n}\n\ngroup "Data" icon=lucide:database {\n item "RDS" 9600 icon=aws:rds delta="4%"\n item "S3" 5200 icon=aws:s3 delta="-3%"\n item "DynamoDB" 3900 icon=aws:dynamodb\n item "OpenSearch" 3400 icon=aws:opensearch\n item "ElastiCache" 2800\n}\n\ngroup "Network" icon=lucide:globe {\n item "Data transfer" 4800 delta="15%"\n item "NAT gateway" 3300 icon=aws:nat-gateway\n item "CloudFront" 2200 icon=aws:cloudfront delta="-6%"\n item "Load balancers" 1900 icon=aws:elb\n}\n\ngroup "Operations" icon=lucide:activity {\n item "CloudWatch" 4600 icon=aws:cloudwatch\n item "Support plan" 3200\n group "Security" icon=lucide:shield {\n item "GuardDuty" 2400 icon=aws:guardduty\n item "WAF" 1900 icon=aws:waf\n }\n}\n' },
|
|
139051
139420
|
{ kind: "xychart", title: "API latency against the SLO", source: 'xychart "API latency against the SLO" desc="Weekly p50 and p95 latency of the checkout API against its 400 ms objective: p95 crossed the line after release 2.3 and came back under it after the cache fix."\n\nx "Week" ["W1" "W2" "W3" "W4" "W5" "W6" "W7" "W8"]\ny "Latency" unit="ms" min=0 max=500\n\nbar "p95" [310 330 345 420 455 440 350 335]\nline "p50" [120 125 128 160 170 165 135 130]\n\nthreshold "SLO 400 ms" 400 tone=red\n\nnote "Release 2.3" at="W4"\nnote "Cache fix" at="W7"\n' }
|
|
139052
139421
|
];
|
|
139053
|
-
ARCHITECTURE_EXAMPLE = { kind: "flow", title: "Web application on a cloud", source: 'flow "Web application on a cloud" provider=azure direction=down desc="Visitors load a single-page app from storage through a content delivery network and sign in through an identity service. The app calls an API on an application plan, which stores uploads, reads a database, and hands slow work to a queue that a background worker drains. A pipeline builds and deploys the API, and a monitoring service collects telemetry."\n\nnode visitors client "Visitors" sub="Browsers"\n\ngroup edge "Edge" type=edge {\n node cdn gateway "Content delivery" icon=azure:cdn\n}\n\ngroup sign-in "Sign-in" type=identity-boundary {\n node idp identity "Identity service" icon=azure:entra-id\n}\n\ngroup files "Storage" type=storage-account {\n node site storage "Web app files" icon=azure:blob-storage stack=simple:react,simple:typescript\n node uploads storage "Uploads" icon=azure:blob-storage\n}\n\ngroup plan "Application plan" type=service-plan {\n node api service "Orders API" icon=azure:app-service stack=simple:nodedotjs\n}\n\ngroup messaging "Messaging" type=messaging {\n node jobs queue "Job queue" icon=azure:service-bus\n}\n\nnode worker function "Background worker" icon=azure:functions stack=simple:nodedotjs\nnode db database "Database" icon=azure:sql-database\n\ngroup delivery "Delivery pipeline" type=ci-cd {\n node repo step "Source code" icon=lucide:git-branch\n node build step "Build pipeline" icon=azure:devops\n}\n\ngroup monitoring "Monitoring" type=observability {\n node telemetry service "Metrics and logs" icon=azure:monitor\n}\n\nvisitors -> cdn : "HTTPS"\nvisitors -> idp : "sign in"\ncdn -> site\ncdn -> api : "API calls"\napi -> uploads : "store files"\napi -> jobs : "enqueue"\njobs ..> worker : "event"\nworker -> db : "writes"\napi -> db : "reads"\nrepo -> build\nbuild ..> api : "deploys image"\napi ..> telemetry : "telemetry"\n' };
|
|
139422
|
+
ARCHITECTURE_EXAMPLE = { kind: "flow", title: "Web application on a cloud", source: 'flow "Web application on a cloud" provider=azure direction=down desc="Visitors load a single-page app from storage through a content delivery network and sign in through an identity service. The app calls an API on an application plan, which stores uploads, reads a database, and hands slow work to a queue that a background worker drains. A pipeline builds and deploys the API, and a monitoring service collects telemetry."\n\nnode visitors client "Visitors" sub="Browsers"\n\ngroup edge "Edge" type=edge {\n node cdn gateway "Content delivery" icon=azure:cdn\n}\n\ngroup sign-in "Sign-in" type=identity-boundary {\n node idp identity "Identity service" icon=azure:entra-id\n}\n\ngroup files "Storage" type=storage-account {\n node site storage "Web app files" icon=azure:blob-storage stack=simple:react,simple:typescript\n node uploads storage "Uploads" icon=azure:blob-storage\n}\n\ngroup plan "Application plan" type=service-plan {\n node api service "Orders API" icon=azure:app-service stack=simple:nodedotjs\n}\n\ngroup messaging "Messaging" type=messaging {\n node jobs queue "Job queue" icon=azure:service-bus\n}\n\nnode worker function "Background worker" icon=azure:functions stack=simple:nodedotjs\nnode db database "Database" icon=azure:sql-database\n\ngroup delivery "Delivery pipeline" type=ci-cd {\n node repo step "Source code" icon=lucide:git-branch\n node build step "Build pipeline" icon=azure:devops\n}\n\ngroup monitoring "Monitoring" type=observability {\n node telemetry service "Metrics and logs" icon=azure:monitor\n}\n\nvisitors -> cdn : "HTTPS"\nvisitors -> idp : "sign in" role=identity\ncdn -> site\ncdn -> api : "API calls"\napi -> uploads : "store files" role=data\napi -> jobs : "enqueue" role=async\njobs ..> worker : "event"\nworker -> db : "writes" role=data\napi -> db : "reads" role=data\nrepo -> build\nbuild ..> api : "deploys image"\napi ..> telemetry : "telemetry"\n' };
|
|
139054
139423
|
}
|
|
139055
139424
|
});
|
|
139056
139425
|
|
|
@@ -139102,6 +139471,8 @@ function buildVocabulary() {
|
|
|
139102
139471
|
},
|
|
139103
139472
|
lineOptions: LINE_OPTION_SPECS.map((spec) => ({ ...spec })),
|
|
139104
139473
|
labelIcons: Object.entries(LABEL_ICON_DEFAULTS).map(([label, icon]) => ({ label, icon })),
|
|
139474
|
+
verbIcons: Object.entries(LABEL_VERB_PHRASES).map(([verb, words2]) => ({ icon: EDGE_STYLES[verb].icon, words: [...words2 ?? []] })),
|
|
139475
|
+
style: [...STYLE_STEPS],
|
|
139105
139476
|
autoIcons: { ...ICON_MODE_SPEC },
|
|
139106
139477
|
roleIcons: roleIconTable(),
|
|
139107
139478
|
statusIcons: Object.entries(STATUS_ICON_SPECS).map(([name2, spec]) => ({ ref: `status:${name2}`, tone: spec.tone, meaning: spec.meaning })),
|
|
@@ -139210,6 +139581,8 @@ var init_build_vocabulary = __esm({
|
|
|
139210
139581
|
arrows: ["overview", "flow", "sequence"],
|
|
139211
139582
|
lineOptions: ["overview", "flow", "sequence"],
|
|
139212
139583
|
labelIcons: ["overview", "flow"],
|
|
139584
|
+
verbIcons: ["flow"],
|
|
139585
|
+
style: ["overview", "flow"],
|
|
139213
139586
|
autoIcons: AUTO_ICON_KINDS,
|
|
139214
139587
|
roleIcons: ["flow", "c4", "layers", "mindmap", "swimlane"],
|
|
139215
139588
|
blockTypes: ["overview", "sequence"],
|
|
@@ -139830,7 +140203,7 @@ function descendantsOf(scan, index2) {
|
|
|
139830
140203
|
});
|
|
139831
140204
|
return inside;
|
|
139832
140205
|
}
|
|
139833
|
-
function
|
|
140206
|
+
function nameOf6(element) {
|
|
139834
140207
|
if (element.role === "edge") return `${element.from ?? ""} ${element.arrow ?? ""} ${element.to ?? ""}`;
|
|
139835
140208
|
return element.id ?? (element.label === null ? element.rest : `"${element.label}"`);
|
|
139836
140209
|
}
|
|
@@ -139854,7 +140227,7 @@ function subjectOf(element) {
|
|
|
139854
140227
|
function renamedName(element, rename2) {
|
|
139855
140228
|
if (element.role === "edge") return `${rename2(element.from ?? "")} -> ${rename2(element.to ?? "")}`;
|
|
139856
140229
|
if (element.role === "header") return "header";
|
|
139857
|
-
return element.id === null ?
|
|
140230
|
+
return element.id === null ? nameOf6(element) : rename2(element.id);
|
|
139858
140231
|
}
|
|
139859
140232
|
function entriesOf3(source, rename2) {
|
|
139860
140233
|
const { elements } = scanSource(source);
|
|
@@ -143355,7 +143728,7 @@ var init_schemas = __esm({
|
|
|
143355
143728
|
}
|
|
143356
143729
|
return propValues;
|
|
143357
143730
|
});
|
|
143358
|
-
const
|
|
143731
|
+
const isObject6 = isObject;
|
|
143359
143732
|
const catchall = def.catchall;
|
|
143360
143733
|
let value;
|
|
143361
143734
|
const memo3 = globalConfig.memoizer;
|
|
@@ -143363,7 +143736,7 @@ var init_schemas = __esm({
|
|
|
143363
143736
|
inst._zod.parse = (payload, ctx) => {
|
|
143364
143737
|
value ?? (value = _normalized.value);
|
|
143365
143738
|
const input2 = payload.value;
|
|
143366
|
-
if (!
|
|
143739
|
+
if (!isObject6(input2)) {
|
|
143367
143740
|
payload.issues.push({
|
|
143368
143741
|
expected: "object",
|
|
143369
143742
|
code: "invalid_type",
|
|
@@ -143499,7 +143872,7 @@ var init_schemas = __esm({
|
|
|
143499
143872
|
return doc.compile();
|
|
143500
143873
|
};
|
|
143501
143874
|
let fastpass;
|
|
143502
|
-
const
|
|
143875
|
+
const isObject6 = isObject;
|
|
143503
143876
|
const jit = !globalConfig.jitless;
|
|
143504
143877
|
const allowsEval2 = allowsEval;
|
|
143505
143878
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -143508,7 +143881,7 @@ var init_schemas = __esm({
|
|
|
143508
143881
|
inst._zod.parse = (payload, ctx) => {
|
|
143509
143882
|
value ?? (value = _normalized.value);
|
|
143510
143883
|
const input2 = payload.value;
|
|
143511
|
-
if (!
|
|
143884
|
+
if (!isObject6(input2)) {
|
|
143512
143885
|
payload.issues.push({
|
|
143513
143886
|
expected: "object",
|
|
143514
143887
|
code: "invalid_type",
|
|
@@ -159272,8 +159645,8 @@ function convertBaseSchema(schema, ctx) {
|
|
|
159272
159645
|
});
|
|
159273
159646
|
}
|
|
159274
159647
|
ctx.processing.add(refPath);
|
|
159275
|
-
const
|
|
159276
|
-
const zodSchema2 = convertSchema(
|
|
159648
|
+
const resolved2 = resolveRef(refPath, ctx);
|
|
159649
|
+
const zodSchema2 = convertSchema(resolved2, ctx);
|
|
159277
159650
|
ctx.refs.set(refPath, zodSchema2);
|
|
159278
159651
|
ctx.processing.delete(refPath);
|
|
159279
159652
|
return zodSchema2;
|
|
@@ -161646,9 +162019,9 @@ async function runSync(document2, settings, ops, cache, limit) {
|
|
|
161646
162019
|
const render = async (written3, id) => {
|
|
161647
162020
|
const source = applyDefaults(written3, settings.defaults).source;
|
|
161648
162021
|
if (calls.length >= limit) {
|
|
161649
|
-
const
|
|
161650
|
-
calls.push({ id, source, detail: null, capped });
|
|
161651
|
-
return { diagnostics:
|
|
162022
|
+
const capped2 = calls.length >= settings.countLimit ? "count" : "bytes";
|
|
162023
|
+
calls.push({ id, source, detail: null, capped: capped2 });
|
|
162024
|
+
return { diagnostics: capped2 === "count" ? CAPPED_BY_COUNT : CAPPED_BY_BYTES };
|
|
161652
162025
|
}
|
|
161653
162026
|
const key = `${id}\0${source}`;
|
|
161654
162027
|
let detail = cache.get(key);
|
|
@@ -171949,9 +172322,9 @@ var init_ajvProvider_CEoC_sr = __esm({
|
|
|
171949
172322
|
}
|
|
171950
172323
|
function resolve5(baseURI, relativeURI, options3) {
|
|
171951
172324
|
const schemelessOptions = options3 ? Object.assign({ scheme: "null" }, options3) : { scheme: "null" };
|
|
171952
|
-
const
|
|
172325
|
+
const resolved2 = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
171953
172326
|
schemelessOptions.skipEscape = true;
|
|
171954
|
-
return serialize(
|
|
172327
|
+
return serialize(resolved2, schemelessOptions);
|
|
171955
172328
|
}
|
|
171956
172329
|
function resolveComponent(base, relative, options3, skipNormalization) {
|
|
171957
172330
|
const target = {};
|
|
@@ -178123,7 +178496,7 @@ var init_sources = __esm({
|
|
|
178123
178496
|
tags: external_exports.array(external_exports.string().min(1).max(200)).max(200).optional().describe("openapi: the tags to read."),
|
|
178124
178497
|
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
178498
|
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.")
|
|
178499
|
+
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
178500
|
}).meta({ id: "SourceOptions", description: "The reader options of one source, as import_source takes them." });
|
|
178128
178501
|
SourcePublishSchema = external_exports.strictObject({
|
|
178129
178502
|
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 +178512,7 @@ var init_sources = __esm({
|
|
|
178139
178512
|
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
178513
|
format: external_exports.enum(IMPORT_FORMATS).describe("The format of the files, as import_source reads them."),
|
|
178141
178514
|
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."),
|
|
178515
|
+
view: external_exports.enum(IMPORT_VIEWS).optional().describe("openapi: endpoints, map, or sequence; git-log: git or timeline; structurizr: context, container, or component."),
|
|
178143
178516
|
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
178517
|
options: SourceOptionsSchema.optional(),
|
|
178145
178518
|
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."),
|
|
@@ -178582,6 +178955,8 @@ var init_vocabulary18 = __esm({
|
|
|
178582
178955
|
group: GroupSchema.describe("How a flow group looks and what it accepts; its corner tab shows its icon and name."),
|
|
178583
178956
|
lineOptions: external_exports.array(LineOptionSchema).describe("Options that animate a line (animate=on makes dashes travel toward the arrowhead) or number the steps of a flow or sequence (numbered=on, start=, and step= on a line). All are off by default."),
|
|
178584
178957
|
labelIcons: external_exports.array(LabelIconSchema).describe("Edge labels that get a tick or cross automatically; icon=none on the edge removes it."),
|
|
178958
|
+
verbIcons: external_exports.array(external_exports.object({ icon: external_exports.string().describe("The icon drawn in the label."), words: external_exports.array(external_exports.string()).describe('Phrases that draw it: the whole label, or its first words followed by what is acted on ("reads orders").') })).describe("The icons a flow edge label draws when it names a relationship with a verb. icon= on the edge wins, icon=none removes it, and icons=off on the header turns them all off."),
|
|
178959
|
+
style: external_exports.array(external_exports.string()).describe("How to make a flow diagram look finished: verbs on arrows, role= on lines that mean something, typed groups, product names."),
|
|
178585
178960
|
autoIcons: AutoIconsSchema.describe("Items with no icon= get the icon their label names for certain (a brand, a cloud product, a common role). icon=none keeps one item plain; icons=off on the header keeps them all plain."),
|
|
178586
178961
|
roleIcons: external_exports.array(external_exports.object({ icon: external_exports.string().describe("The icon drawn."), words: external_exports.array(external_exports.string()).describe("Whole words of a label of three words or fewer that draw it.") })).describe("The plain icons for common roles, drawn on flow and sequence service and external items, C4 elements, layers blocks, mind map topics, and swimlane lanes. The last role word of the label wins."),
|
|
178587
178962
|
statusIcons: external_exports.array(StatusIconSchema).describe("Colored status and outcome icons: a green check, a red X, and so on."),
|
|
@@ -179201,7 +179576,7 @@ function finding(level2, code, message2, at3, hint2) {
|
|
|
179201
179576
|
function appliesTo(rule, kind) {
|
|
179202
179577
|
return rule.kinds === void 0 || rule.kinds.includes(kind);
|
|
179203
179578
|
}
|
|
179204
|
-
function
|
|
179579
|
+
function nameOf7(subject) {
|
|
179205
179580
|
return subject.id === null || subject.id === subject.label ? `"${subject.label}"` : `${subject.id} ("${subject.label}")`;
|
|
179206
179581
|
}
|
|
179207
179582
|
function iconAccepted(icon, choices) {
|
|
@@ -179228,7 +179603,7 @@ function iconFindings(rule, subjects, level2, places) {
|
|
|
179228
179603
|
const drawn = subject.icon === null ? "draws no icon" : `draws ${subject.icon}`;
|
|
179229
179604
|
const [first] = rule.use;
|
|
179230
179605
|
const choices = rule.use.length === 1 ? `icon=${first ?? ""}` : `icon= with one of ${rule.use.join(", ")}`;
|
|
179231
|
-
return [finding(rule.level ?? level2, DIAGNOSTIC_CODES.ruleIcon, `${
|
|
179606
|
+
return [finding(rule.level ?? level2, DIAGNOSTIC_CODES.ruleIcon, `${nameOf7(subject)} matches /${rule.label}/ and ${drawn}`, places.of(subject), rule.hint ?? `Give it ${choices}.`)];
|
|
179232
179607
|
});
|
|
179233
179608
|
}
|
|
179234
179609
|
function toneFindings(rule, subjects, level2, places) {
|
|
@@ -179238,7 +179613,7 @@ function toneFindings(rule, subjects, level2, places) {
|
|
|
179238
179613
|
if (!broken) return [];
|
|
179239
179614
|
const of = rule.types === void 0 ? "a node" : `a ${subject.type}`;
|
|
179240
179615
|
const fix = rule.allow !== void 0 ? `Use tone=${rule.allow.join(" or tone=")}.` : `Use a tone other than ${(rule.forbid ?? []).join(", ")}.`;
|
|
179241
|
-
return [finding(rule.level ?? level2, DIAGNOSTIC_CODES.ruleTone, `${
|
|
179616
|
+
return [finding(rule.level ?? level2, DIAGNOSTIC_CODES.ruleTone, `${nameOf7(subject)} is ${subject.tone}, a tone the team does not use for ${of}`, places.of(subject), rule.hint ?? fix)];
|
|
179242
179617
|
});
|
|
179243
179618
|
}
|
|
179244
179619
|
function diagramFindings(diagram, rules, count3, level2, places) {
|
|
@@ -179531,9 +179906,9 @@ users -> ingress : "HTTPS"
|
|
|
179531
179906
|
ingress -> web
|
|
179532
179907
|
ingress -> api
|
|
179533
179908
|
ingress -> admin
|
|
179534
|
-
api -> config : "reads"
|
|
179909
|
+
api -> config : "reads" icon=lucide:eye
|
|
179535
179910
|
web ..> monitor : "metrics"
|
|
179536
|
-
api -> secrets : "reads"`;
|
|
179911
|
+
api -> secrets : "reads secrets" role=identity`;
|
|
179537
179912
|
NEUTRAL2 = `flow "{{title}}" direction=down desc="{{description}}"
|
|
179538
179913
|
|
|
179539
179914
|
group delivery "{{pipeline}}" type=ci-cd {
|
|
@@ -179839,8 +180214,8 @@ bus ..> processor : "all events"
|
|
|
179839
180214
|
bus ..> notifier : "alerts"
|
|
179840
180215
|
bus ..> dlq : "after retries"
|
|
179841
180216
|
archiver -> archive : "archive"
|
|
179842
|
-
processor -> db : "write"
|
|
179843
|
-
notifier ..> mail : "send"`;
|
|
180217
|
+
processor -> db : "write" role=data
|
|
180218
|
+
notifier ..> mail : "send" role=async`;
|
|
179844
180219
|
NEUTRAL5 = `flow "{{title}}" direction=down desc="{{description}}"
|
|
179845
180220
|
|
|
179846
180221
|
group producers "{{producers}}" type=app-tier {
|
|
@@ -180068,7 +180443,7 @@ var init_microservices_gateway = __esm({
|
|
|
180068
180443
|
{ id: "billing-database", default: "Billing database", meaning: "The database that only the billing service reads and writes." }
|
|
180069
180444
|
];
|
|
180070
180445
|
EDGES6 = `clients -> gateway : "HTTPS"
|
|
180071
|
-
gateway -> idp : "verify token"
|
|
180446
|
+
gateway -> idp : "verify token" role=identity
|
|
180072
180447
|
gateway -> catalog : "{{catalog-path}}"
|
|
180073
180448
|
gateway -> booking : "{{booking-path}}"
|
|
180074
180449
|
catalog -> catalog-db
|
|
@@ -180218,12 +180593,12 @@ var init_queue_worker = __esm({
|
|
|
180218
180593
|
{ id: "alarm", default: "Queue depth alarm", meaning: "The alarm that fires when too many jobs wait in the queue." }
|
|
180219
180594
|
];
|
|
180220
180595
|
EDGES7 = `client -> api : "{{submit}}"
|
|
180221
|
-
api ..> queue : "enqueue job"
|
|
180596
|
+
api ..> queue : "enqueue job" role=async
|
|
180222
180597
|
queue ..> w1
|
|
180223
180598
|
queue ..> w2
|
|
180224
180599
|
queue ..> w3
|
|
180225
180600
|
queue ..> alarm
|
|
180226
|
-
w2 -> db : "write result"
|
|
180601
|
+
w2 -> db : "write result" role=data
|
|
180227
180602
|
w3 ..> dlq : "after {{retries}} tries"`;
|
|
180228
180603
|
OVERLAY = 'overlay pool "{{pool}}" type=scale-group members=w1,w2,w3';
|
|
180229
180604
|
NEUTRAL9 = `flow "{{title}}" direction=down desc="{{description}}"
|
|
@@ -180320,9 +180695,9 @@ var init_serverless_api = __esm({
|
|
|
180320
180695
|
gateway -> create : "POST {{path}}"
|
|
180321
180696
|
gateway -> list : "GET {{path}}"
|
|
180322
180697
|
gateway -> get : "GET {{path}}/id"
|
|
180323
|
-
gateway -> auth : "verify token"
|
|
180324
|
-
create -> bucket : "upload"
|
|
180325
|
-
create -> db : "write"
|
|
180698
|
+
gateway -> auth : "verify token" role=identity
|
|
180699
|
+
create -> bucket : "upload" role=data
|
|
180700
|
+
create -> db : "write" role=data
|
|
180326
180701
|
list -> db
|
|
180327
180702
|
get -> db
|
|
180328
180703
|
get ..> monitor : "logs and metrics"`;
|
|
@@ -180516,7 +180891,7 @@ dns -> cdn
|
|
|
180516
180891
|
cert -> cdn
|
|
180517
180892
|
publish ..> cdn
|
|
180518
180893
|
cdn -> bucket : "fetch files"
|
|
180519
|
-
publish -> bucket : "upload"`;
|
|
180894
|
+
publish -> bucket : "upload" role=data`;
|
|
180520
180895
|
NEUTRAL12 = `flow "{{title}}" direction=down desc="{{description}}"
|
|
180521
180896
|
|
|
180522
180897
|
group pipeline "{{pipeline}}" type=ci-cd {
|
|
@@ -180900,14 +181275,14 @@ var init_web_app_on_cloud = __esm({
|
|
|
180900
181275
|
{ id: "telemetry", default: "Metrics and logs", meaning: "The service that collects what the API reports." }
|
|
180901
181276
|
];
|
|
180902
181277
|
EDGES11 = `visitors -> cdn : "HTTPS"
|
|
180903
|
-
visitors -> idp : "sign in"
|
|
181278
|
+
visitors -> idp : "sign in" role=identity
|
|
180904
181279
|
cdn -> site
|
|
180905
181280
|
cdn -> api : "API calls"
|
|
180906
|
-
api -> uploads : "store files"
|
|
180907
|
-
api -> jobs : "enqueue"
|
|
181281
|
+
api -> uploads : "store files" role=data
|
|
181282
|
+
api -> jobs : "enqueue" role=async
|
|
180908
181283
|
jobs ..> worker : "event"
|
|
180909
|
-
worker -> db : "writes"
|
|
180910
|
-
api -> db : "reads"
|
|
181284
|
+
worker -> db : "writes" role=data
|
|
181285
|
+
api -> db : "reads" role=data
|
|
180911
181286
|
repo -> build
|
|
180912
181287
|
build ..> api : "deploys image"
|
|
180913
181288
|
api ..> telemetry : "telemetry"`;
|
|
@@ -181191,6 +181566,14 @@ var init_direction = __esm({
|
|
|
181191
181566
|
}
|
|
181192
181567
|
});
|
|
181193
181568
|
|
|
181569
|
+
// ../../packages/diagrams/src/importers/shared/edge-style.ts
|
|
181570
|
+
var init_edge_style = __esm({
|
|
181571
|
+
"../../packages/diagrams/src/importers/shared/edge-style.ts"() {
|
|
181572
|
+
"use strict";
|
|
181573
|
+
init_constants();
|
|
181574
|
+
}
|
|
181575
|
+
});
|
|
181576
|
+
|
|
181194
181577
|
// ../../packages/diagrams/src/importers/shared/icons.ts
|
|
181195
181578
|
function known2(ref) {
|
|
181196
181579
|
return ref !== null && isKnownIcon(ref) ? ref : null;
|
|
@@ -181683,7 +182066,7 @@ function writeOneFlow(draft, report3) {
|
|
|
181683
182066
|
const children = (parent) => groups.filter((group2) => parentOf4(group2) === parent);
|
|
181684
182067
|
const writeGroup = (group2, depth) => {
|
|
181685
182068
|
lines.gap();
|
|
181686
|
-
lines.add(`group ${ids.idFor(`group:${group2.key}`)} ${quote(group2.label)}${options2({ type: group2.type ?? namedType(group2.label), icon: known2(group2.icon ?? null), sub: group2.sub ?? null, tone: group2.tone ?? null })} {`, depth);
|
|
182069
|
+
lines.add(`group ${ids.idFor(`group:${group2.key}`)} ${quote(group2.label)}${options2({ type: group2.type ?? namedType(group2.label) ?? group2.otherwise ?? null, icon: known2(group2.icon ?? null), sub: group2.sub ?? null, tone: group2.tone ?? null })} {`, depth);
|
|
181687
182070
|
for (const node3 of kept2) if ((node3.group ?? null) === group2.key) nodeLine4(node3, depth + 1);
|
|
181688
182071
|
for (const child of children(group2.key)) writeGroup(child, depth + 1);
|
|
181689
182072
|
lines.add("}", depth);
|
|
@@ -181693,16 +182076,24 @@ function writeOneFlow(draft, report3) {
|
|
|
181693
182076
|
for (const node3 of kept2) if (node3.group === void 0 || node3.group === null || !groupKeys.has(node3.group)) nodeLine4(node3, 0);
|
|
181694
182077
|
for (const group2 of children(null)) writeGroup(group2, 0);
|
|
181695
182078
|
const written3 = /* @__PURE__ */ new Set();
|
|
181696
|
-
|
|
181697
|
-
lines.gap();
|
|
182079
|
+
const drawn = [];
|
|
181698
182080
|
for (const edge of draft.edges) {
|
|
181699
182081
|
const pair2 = `${edge.from}\0${edge.to}`;
|
|
181700
182082
|
if (edge.from === edge.to || !keptKeys.has(edge.from) || !keptKeys.has(edge.to) || written3.has(pair2)) continue;
|
|
181701
182083
|
written3.add(pair2);
|
|
181702
|
-
|
|
181703
|
-
|
|
181704
|
-
|
|
182084
|
+
drawn.push(edge);
|
|
182085
|
+
}
|
|
182086
|
+
const roleOf3 = (edge) => edge.verb === void 0 || edge.verb === null ? null : EDGE_STYLES[edge.verb].role;
|
|
182087
|
+
const roles = new Set(drawn.map(roleOf3));
|
|
182088
|
+
const colour = roles.size > 1;
|
|
182089
|
+
lines.gap();
|
|
182090
|
+
for (const edge of drawn) {
|
|
182091
|
+
const hasLabel = edge.label !== void 0 && edge.label !== null && edge.label !== "";
|
|
182092
|
+
const label = hasLabel ? ` : ${quote(edge.label ?? "")}` : "";
|
|
182093
|
+
const style = edge.verb === void 0 || edge.verb === null ? null : EDGE_STYLES[edge.verb];
|
|
182094
|
+
lines.add(`${ids.idFor(`node:${edge.from}`)} ${edge.arrow ?? "->"} ${ids.idFor(`node:${edge.to}`)}${label}${options2({ icon: hasLabel ? known2(style?.icon ?? null) : null, role: colour ? style?.role ?? null : null })}`);
|
|
181705
182095
|
}
|
|
182096
|
+
const links = drawn.length;
|
|
181706
182097
|
const coverage = draft.coverage ?? { noun: draft.noun, total: draft.nodes.length, drawn: kept2.length, summarised: 0 };
|
|
181707
182098
|
const named = { ...ids.mapped("group:"), ...ids.mapped("node:") };
|
|
181708
182099
|
return { kind: "flow", source: lines.toString(), stats: { items: kept2.length, links, groups: groups.length, dropped: left.length }, advice: draft.advice ?? null, coverage, ids: named };
|
|
@@ -181714,6 +182105,7 @@ var init_flow2 = __esm({
|
|
|
181714
182105
|
init_core();
|
|
181715
182106
|
init_lint21();
|
|
181716
182107
|
init_suggest_icons();
|
|
182108
|
+
init_edge_style();
|
|
181717
182109
|
init_icons3();
|
|
181718
182110
|
init_reporter2();
|
|
181719
182111
|
init_split_flow();
|
|
@@ -182085,6 +182477,7 @@ var init_shared2 = __esm({
|
|
|
182085
182477
|
"../../packages/diagrams/src/importers/shared/index.ts"() {
|
|
182086
182478
|
"use strict";
|
|
182087
182479
|
init_direction();
|
|
182480
|
+
init_edge_style();
|
|
182088
182481
|
init_flow2();
|
|
182089
182482
|
init_split_flow();
|
|
182090
182483
|
init_icons3();
|
|
@@ -182672,7 +183065,7 @@ function drawCharts(files, context, index2) {
|
|
|
182672
183065
|
const edges = [];
|
|
182673
183066
|
const repositories = new Set(charts.flatMap((chart) => chart.dependencies.map((dependency) => dependency.repository)).filter((repository) => repository !== null && repository !== "" && !repository.startsWith("file://")));
|
|
182674
183067
|
const framed = repositories.size > 1;
|
|
182675
|
-
const groups = framed ? [...repositories].sort().map((repository) => ({ key: `repository:${repository}`, label: repositoryLabel(repository), sub: "Chart repository", icon: "simple:helm", idHint: repositoryLabel(repository).split("/").pop() ?? "repository" })) : [];
|
|
183068
|
+
const groups = framed ? [...repositories].sort().map((repository) => ({ key: `repository:${repository}`, label: repositoryLabel(repository), sub: "Chart repository", type: "external-systems", icon: "simple:helm", idHint: repositoryLabel(repository).split("/").pop() ?? "repository" })) : [];
|
|
182676
183069
|
for (const chart of charts) {
|
|
182677
183070
|
const look = imageLook(chart.name);
|
|
182678
183071
|
nodes.push({ key: chartKey(chart), type: look?.type ?? "service", label: chart.name, sub: cleanText([[chart.library ? "Library chart" : "Chart", chart.version].filter((part) => part !== null).join(" "), chart.appVersion === null ? null : `app ${chart.appVersion}`].filter((part) => part !== null).join(", ")), icon: look?.icon ?? "simple:helm", idHint: chart.name });
|
|
@@ -182690,7 +183083,7 @@ function drawCharts(files, context, index2) {
|
|
|
182690
183083
|
nodes.push({ key, type: look?.type ?? "service", label: shown, sub: cleanText([shown === dependency.name ? "Chart" : `Chart ${dependency.name}`, off ? "off in values" : dependency.condition !== null && setting !== "true" ? "optional" : null].filter((part) => part !== null).join(", ")), icon: look?.icon ?? iconForName(dependency.name, look?.type ?? "service") ?? "simple:helm", group: repository, idHint: shown });
|
|
182691
183084
|
}
|
|
182692
183085
|
const version2 = chart.locked.get(dependency.name) ?? dependency.version;
|
|
182693
|
-
edges.push({ from: chartKey(chart), to: key, label: version2, ...off ? { arrow: "-->" } : {} });
|
|
183086
|
+
edges.push({ from: chartKey(chart), to: key, label: version2, verb: "depends-on", ...off ? { arrow: "-->" } : {} });
|
|
182694
183087
|
}
|
|
182695
183088
|
}
|
|
182696
183089
|
const root = charts[0];
|
|
@@ -182906,7 +183299,7 @@ function edgesOf(drawn, folded, context) {
|
|
|
182906
183299
|
const from = keyOf(manifest.kind, manifest.namespace, manifest.name);
|
|
182907
183300
|
for (const route of manifest.routes) {
|
|
182908
183301
|
const service = keyOf("Service", manifest.namespace, route.service);
|
|
182909
|
-
if (has("Service", manifest.namespace, route.service)) edges.push({ from, to: folded.get(service) ?? service, label: route.label });
|
|
183302
|
+
if (has("Service", manifest.namespace, route.service)) edges.push({ from, to: folded.get(service) ?? service, label: route.label, verb: "routes" });
|
|
182910
183303
|
else unresolved(manifest, `Service ${route.service}`);
|
|
182911
183304
|
}
|
|
182912
183305
|
if (manifest.kind === "Service" && !folded.has(from)) {
|
|
@@ -182924,7 +183317,7 @@ function edgesOf(drawn, folded, context) {
|
|
|
182924
183317
|
}
|
|
182925
183318
|
}
|
|
182926
183319
|
for (const use of manifest.uses) {
|
|
182927
|
-
if (has(use.kind, manifest.namespace, use.name)) edges.push({ from, to: keyOf(use.kind, manifest.namespace, use.name), arrow: use.kind === "PersistentVolumeClaim" ? "->" : "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads" });
|
|
183320
|
+
if (has(use.kind, manifest.namespace, use.name)) edges.push({ from, to: keyOf(use.kind, manifest.namespace, use.name), arrow: use.kind === "PersistentVolumeClaim" ? "->" : "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads", verb: use.kind === "PersistentVolumeClaim" ? "mounts" : use.kind === "Secret" ? "secret" : "reads-settings" });
|
|
182928
183321
|
else unresolved(manifest, `${use.kind} ${use.name}`);
|
|
182929
183322
|
}
|
|
182930
183323
|
}
|
|
@@ -182966,13 +183359,13 @@ function drawManifests(documents, context, framing) {
|
|
|
182966
183359
|
const ordered = [...drawn].sort((a, b) => (LOOKS[a.kind]?.rank ?? 2) - (LOOKS[b.kind]?.rank ?? 2));
|
|
182967
183360
|
const namespaces = [...new Set(ordered.map((manifest) => manifest.namespace))];
|
|
182968
183361
|
const grouped = namespaces.length > 1;
|
|
182969
|
-
const groups = grouped ? namespaces.map((namespace) => ({ key: `ns:${namespace}`, label: namespace, type: namespaceType(namespace), sub: "Namespace", idHint: `ns_${namespace}` })) : [];
|
|
183362
|
+
const groups = grouped ? namespaces.map((namespace) => ({ key: `ns:${namespace}`, label: namespace, type: namespaceType(namespace), otherwise: "resource-group", tone: namespaceType(namespace) === null ? "violet" : null, sub: "Namespace", idHint: `ns_${namespace}` })) : [];
|
|
182970
183363
|
const framed = /* @__PURE__ */ new Map();
|
|
182971
183364
|
for (const manifest of framing === null ? [] : ordered) {
|
|
182972
183365
|
let parent = grouped ? `ns:${manifest.namespace}` : null;
|
|
182973
183366
|
for (const frame of framing?.framesOf(manifest) ?? []) {
|
|
182974
183367
|
const key = grouped ? `${manifest.namespace}/${frame.key}` : frame.key;
|
|
182975
|
-
if (!groups.some((group2) => group2.key === key)) groups.push({ key, label: frame.label, sub: frame.sub, icon: frame.icon, parent, idHint: frame.idHint });
|
|
183368
|
+
if (!groups.some((group2) => group2.key === key)) groups.push({ key, label: frame.label, sub: frame.sub, icon: frame.icon, otherwise: frame.type, tone: frame.tone ?? null, parent, idHint: frame.idHint });
|
|
182976
183369
|
parent = key;
|
|
182977
183370
|
}
|
|
182978
183371
|
if (parent !== null) framed.set(manifest, parent);
|
|
@@ -183130,18 +183523,18 @@ function drawFolder(files, context, index2) {
|
|
|
183130
183523
|
for (const entry2 of ordered) {
|
|
183131
183524
|
const role = roleOf3(entry2);
|
|
183132
183525
|
const frame = `frame:${entry2.folder}`;
|
|
183133
|
-
groups.push({ key: frame, label: entry2.folder.slice(common.length) || baseName2(entry2.folder) || "kustomization", sub: role, icon: "lucide:layers", idHint: entry2.folder.slice(common.length) || baseName2(entry2.folder) || "root" });
|
|
183526
|
+
groups.push({ key: frame, label: entry2.folder.slice(common.length) || baseName2(entry2.folder) || "kustomization", sub: role, ...role === "Overlay" ? { type: "environment" } : { otherwise: "resource-group" }, icon: "lucide:layers", idHint: entry2.folder.slice(common.length) || baseName2(entry2.folder) || "root" });
|
|
183134
183527
|
nodes.push({ key: own2(entry2), type: "service", label: baseName2(entry2.folder) || "kustomization", sub: cleanText(entry2.details.length === 0 ? "kustomization.yaml" : entry2.details.slice(0, 4).join(", ")), icon: "lucide:layers", group: frame, idHint: `${baseName2(entry2.folder) || "kustomization"}_kustomization` });
|
|
183135
183528
|
for (const resource of entry2.resources) {
|
|
183136
183529
|
if (isRemote(resource)) {
|
|
183137
183530
|
nodes.push({ key: `remote:${resource}`, type: "service", label: cleanText(resource.replace(/^https?:\/\//, "").replace(/\?.*$/, "").split("/").slice(-2).join("/")), sub: "Remote resource", icon: "lucide:globe", group: frame, idHint: "remote" });
|
|
183138
|
-
edges.push({ from: own2(entry2), to: `remote:${resource}`, label: "builds on" });
|
|
183531
|
+
edges.push({ from: own2(entry2), to: `remote:${resource}`, label: "builds on", verb: "builds-on" });
|
|
183139
183532
|
continue;
|
|
183140
183533
|
}
|
|
183141
183534
|
const path = resolvePath(entry2.folder, resource);
|
|
183142
183535
|
const inner = path === null ? void 0 : byFolder.get(path);
|
|
183143
183536
|
if (inner !== void 0) {
|
|
183144
|
-
edges.push({ from: own2(entry2), to: own2(inner), label: "builds on" });
|
|
183537
|
+
edges.push({ from: own2(entry2), to: own2(inner), label: "builds on", verb: "builds-on" });
|
|
183145
183538
|
continue;
|
|
183146
183539
|
}
|
|
183147
183540
|
const found = path === null ? void 0 : objects.get(path);
|
|
@@ -183155,7 +183548,7 @@ function drawFolder(files, context, index2) {
|
|
|
183155
183548
|
}
|
|
183156
183549
|
for (const component of entry2.components) {
|
|
183157
183550
|
const inner = byFolder.get(resolvePath(entry2.folder, component) ?? "\0");
|
|
183158
|
-
if (inner !== void 0) edges.push({ from: own2(entry2), to: own2(inner), label: "includes" });
|
|
183551
|
+
if (inner !== void 0) edges.push({ from: own2(entry2), to: own2(inner), label: "includes", verb: "includes" });
|
|
183159
183552
|
else missing.push(`${entry2.folder === "" ? "" : `${entry2.folder}/`}${component}`);
|
|
183160
183553
|
}
|
|
183161
183554
|
for (const generator of entry2.generators) {
|
|
@@ -183170,16 +183563,16 @@ function drawFolder(files, context, index2) {
|
|
|
183170
183563
|
const key = `patch:${entry2.folder}/${patch.path ?? `${kind ?? "any"}/${name2 ?? "any"}`}`;
|
|
183171
183564
|
nodes.push({ key, type: "service", label: patch.path === null ? `${kind ?? "object"} ${name2 ?? ""}`.trim() : baseName2(patch.path), sub: cleanText(`Patch${kind === null ? "" : ` of ${kind}${name2 === null ? "" : ` ${name2}`}`}`), icon: "lucide:file-code", group: frame, idHint: `${baseName2(patch.path ?? "patch").replace(/\.ya?ml$/, "")}_patch` });
|
|
183172
183565
|
const target = kind === null && name2 === null ? null : fileOf2(entry2, kind, name2) ?? [...objects].find(([, inside]) => inside.some((object2) => (kind === null || object2.kind === kind) && (name2 === null || object2.name === name2)))?.[0] ?? null;
|
|
183173
|
-
if (target !== null) edges.push({ from: key, to: `file:${target}`, label: "patches" });
|
|
183566
|
+
if (target !== null) edges.push({ from: key, to: `file:${target}`, label: "patches", verb: "patches" });
|
|
183174
183567
|
}
|
|
183175
183568
|
}
|
|
183176
183569
|
const drawnFiles = [...objects].filter(([path]) => nodes.some((node3) => node3.key === `file:${path}`));
|
|
183177
183570
|
for (const [path, manifests] of drawnFiles) {
|
|
183178
183571
|
for (const manifest of manifests) {
|
|
183179
183572
|
for (const use of manifest.uses) {
|
|
183180
|
-
for (const node3 of nodes) if (node3.key.startsWith("generator:") && node3.key.endsWith(`/${use.kind}/${use.name}`)) edges.push({ from: `file:${path}`, to: node3.key, arrow: "-->", label: "reads" });
|
|
183573
|
+
for (const node3 of nodes) if (node3.key.startsWith("generator:") && node3.key.endsWith(`/${use.kind}/${use.name}`)) edges.push({ from: `file:${path}`, to: node3.key, arrow: "-->", label: "reads", verb: use.kind === "Secret" ? "secret" : "reads-settings" });
|
|
183181
183574
|
const holder = drawnFiles.find(([, others]) => others.some((other) => other.kind === use.kind && other.name === use.name));
|
|
183182
|
-
if (holder !== void 0 && holder[0] !== path) edges.push({ from: `file:${path}`, to: `file:${holder[0]}`, arrow: "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads" });
|
|
183575
|
+
if (holder !== void 0 && holder[0] !== path) edges.push({ from: `file:${path}`, to: `file:${holder[0]}`, arrow: "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads", verb: use.kind === "PersistentVolumeClaim" ? "mounts" : use.kind === "Secret" ? "secret" : "reads-settings" });
|
|
183183
183576
|
}
|
|
183184
183577
|
for (const [other, inside] of drawnFiles) {
|
|
183185
183578
|
if (other === path) continue;
|
|
@@ -183291,6 +183684,8 @@ var init_detect = __esm({
|
|
|
183291
183684
|
{ format: "cdk", test: (text3) => /"?aws:cdk:path"?\s*:/.test(text3) || /"artifacts"\s*:/.test(text3) && /"aws:cloudformation:stack"/.test(text3) },
|
|
183292
183685
|
{ 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
183686
|
{ format: "backstage", test: (text3) => /^apiVersion\s*:\s*["']?backstage\.io\//m.test(text3) },
|
|
183687
|
+
{ format: "asyncapi", test: (text3) => /^\s*["']?asyncapi["']?\s*:\s*["']?[23]\./m.test(text3) },
|
|
183688
|
+
{ 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
183689
|
// A kustomization, or what kustomize build makes of one: a generated ConfigMap or Secret whose name ends in its hash.
|
|
183295
183690
|
{ 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
183691
|
{ 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 +183701,13 @@ var init_detect = __esm({
|
|
|
183306
183701
|
NAMES = [
|
|
183307
183702
|
{ format: "compose", words: /\b(?:docker[- ]compose|compose (?:file|yaml|yml|stack))\b/i },
|
|
183308
183703
|
{ format: "backstage", words: /\b(?:backstage|catalog-info(?:\.yaml)?|software catalog)\b/i },
|
|
183704
|
+
{ format: "asyncapi", words: /\b(?:asyncapi|async api)\b/i },
|
|
183705
|
+
{ format: "structurizr", words: /\b(?:structurizr|workspace\.dsl|c4 (?:model|workspace))\b/i },
|
|
183309
183706
|
{ format: "kustomize", words: /\b(?:kustomize|kustomization(?:\.yaml)?)\b/i },
|
|
183310
183707
|
{ format: "helm", words: /\b(?:helm (?:charts?|template|release)|chart\.yaml)\b/i },
|
|
183311
183708
|
{ format: "kubernetes", words: /\b(?:kubernetes|k8s)\b/i },
|
|
183709
|
+
{ format: "gitlab-ci", words: /(?:\.gitlab-ci\.ya?ml\b|\bgitlab(?:[- ]ci| pipelines?| ci\/cd)\b)/i },
|
|
183710
|
+
{ format: "azure-pipelines", words: /(?:\bazure-pipelines\.ya?ml\b|\bazure (?:devops )?pipelines?\b)/i },
|
|
183312
183711
|
{ format: "github-actions", words: /\b(?:github actions?|workflow (?:file|yaml|yml)|ci workflow)\b/i },
|
|
183313
183712
|
{ format: "terraform-plan", words: /\b(?:terraform|tofu) (?:plan|state|show -json)\b|\bplan\.json\b/i },
|
|
183314
183713
|
{ format: "terraform", words: /\b(?:terraform|opentofu|hcl|\.tf files?)\b/i },
|
|
@@ -183326,7 +183725,7 @@ var init_detect = __esm({
|
|
|
183326
183725
|
{ format: "json", words: /\bjson (?:data|file|records|export)\b/i },
|
|
183327
183726
|
{ format: "tree", words: /\b(?:tree output|folder (?:structure|tree|listing)|directory (?:tree|listing))\b/i }
|
|
183328
183727
|
];
|
|
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"]);
|
|
183728
|
+
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
183729
|
}
|
|
183331
183730
|
});
|
|
183332
183731
|
|
|
@@ -183638,8 +184037,8 @@ function rawValue(resource, name2) {
|
|
|
183638
184037
|
return resource.block.attributes.find((attribute2) => attribute2.name === name2)?.raw ?? null;
|
|
183639
184038
|
}
|
|
183640
184039
|
function tagName(resource) {
|
|
183641
|
-
const
|
|
183642
|
-
if (
|
|
184040
|
+
const resolved2 = resource.values.get("tags.Name");
|
|
184041
|
+
if (resolved2 !== void 0 && !resolved2.includes("{")) return resolved2;
|
|
183643
184042
|
const tags = rawValue(resource, "tags");
|
|
183644
184043
|
if (tags === null) return null;
|
|
183645
184044
|
const match = /\bName\s*=\s*"((?:[^"\\$\n]|\\.)*)"/.exec(tags);
|
|
@@ -184323,7 +184722,7 @@ function bundleArrows(nodes, groups, edges, ownBox, joinPairs = true) {
|
|
|
184323
184722
|
if (sources.length < BUNDLE_AT) continue;
|
|
184324
184723
|
if (sources.length < FEW && (!joinPairs || !HOSTS2.has(typeOf.get(frame) ?? "") || (pairs.get(frame) ?? 0) < 2 || sources.some((edge) => !edges.some((other) => !joinable.has(other) && (other.from === edge.from || other.to === edge.from))))) continue;
|
|
184325
184724
|
for (const edge of sources) joined2.add(edge);
|
|
184326
|
-
replacements.set(first, { from: own2.key, to: first.to, label: `${first.label ?? ""} (${sources.length})
|
|
184725
|
+
replacements.set(first, { from: own2.key, to: first.to, label: `${first.label ?? ""} (${sources.length})`, verb: first.verb ?? null });
|
|
184327
184726
|
}
|
|
184328
184727
|
const out = [];
|
|
184329
184728
|
const written3 = /* @__PURE__ */ new Set();
|
|
@@ -184335,7 +184734,7 @@ function bundleArrows(nodes, groups, edges, ownBox, joinPairs = true) {
|
|
|
184335
184734
|
if (written3.has(pair2)) {
|
|
184336
184735
|
const index2 = out.findIndex((candidate2) => `${candidate2.from}\0${candidate2.to}` === pair2);
|
|
184337
184736
|
const before = out[index2];
|
|
184338
|
-
out[index2] = { ...before, label: [before.label, next.label].filter((label) => label !== null && label !== void 0 && label !== "").join(", ") };
|
|
184737
|
+
out[index2] = { ...before, label: [before.label, next.label].filter((label) => label !== null && label !== void 0 && label !== "").join(", "), verb: before.verb === next.verb ? before.verb ?? null : null };
|
|
184339
184738
|
continue;
|
|
184340
184739
|
}
|
|
184341
184740
|
written3.add(pair2);
|
|
@@ -184858,6 +185257,10 @@ function stackArrows(plan) {
|
|
|
184858
185257
|
}
|
|
184859
185258
|
return { arrows, unjoined };
|
|
184860
185259
|
}
|
|
185260
|
+
function verbOf(arrow) {
|
|
185261
|
+
if (arrow.grant || arrow.order !== true && POLICY_KEY.test(arrow.via)) return "grants";
|
|
185262
|
+
return LABEL_VERBS[arrow.label ?? ""] ?? null;
|
|
185263
|
+
}
|
|
184861
185264
|
function joinArrows(arrows) {
|
|
184862
185265
|
const joined2 = new Set(arrows.filter((arrow) => arrow.order !== true).flatMap((arrow) => [`${arrow.from}\0${arrow.to}`, `${arrow.to}\0${arrow.from}`]));
|
|
184863
185266
|
const byPair = /* @__PURE__ */ new Map();
|
|
@@ -184869,10 +185272,12 @@ function joinArrows(arrows) {
|
|
|
184869
185272
|
const grantWords = grants.length === 0 ? [] : grants.length === 1 ? [grants[0]?.label ?? "role"] : [`${grants.length} roles`];
|
|
184870
185273
|
const words2 = [...grantWords, ...others];
|
|
184871
185274
|
const label = words2.length === 0 ? null : words2.length <= MAX_LABELS2 ? words2.join(", ") : `${group2.length} links`;
|
|
184872
|
-
|
|
185275
|
+
const verbs = new Set(group2.map(verbOf));
|
|
185276
|
+
const verb = verbs.size === 1 ? [...verbs][0] ?? null : null;
|
|
185277
|
+
return { from: first.from, to: first.to, label, verb, ...group2.every((arrow) => arrow.order === true) ? { arrow: "-->" } : {} };
|
|
184873
185278
|
});
|
|
184874
185279
|
}
|
|
184875
|
-
var ORDER_LABEL, INBOUND, QUIET, ATTRIBUTE_LABELS, TYPE_LABELS, VAGUE_ATTRIBUTES, MAX_LABELS2;
|
|
185280
|
+
var ORDER_LABEL, INBOUND, QUIET, ATTRIBUTE_LABELS, TYPE_LABELS, VAGUE_ATTRIBUTES, LABEL_VERBS, POLICY_KEY, MAX_LABELS2;
|
|
184876
185281
|
var init_edges2 = __esm({
|
|
184877
185282
|
"../../packages/diagrams/src/importers/terraform/edges.ts"() {
|
|
184878
185283
|
"use strict";
|
|
@@ -184933,6 +185338,34 @@ var init_edges2 = __esm({
|
|
|
184933
185338
|
service: "calls"
|
|
184934
185339
|
};
|
|
184935
185340
|
VAGUE_ATTRIBUTES = /* @__PURE__ */ new Set(["value", "values", "config", "configuration", "settings", "properties", "body", "content", "input", "inputs", "parameters", "source", "data"]);
|
|
185341
|
+
LABEL_VERBS = {
|
|
185342
|
+
identity: "grants",
|
|
185343
|
+
role: "grants",
|
|
185344
|
+
policy: "grants",
|
|
185345
|
+
grants: "grants",
|
|
185346
|
+
"grants on": "grants",
|
|
185347
|
+
principal: "grants",
|
|
185348
|
+
data: "stores",
|
|
185349
|
+
storage: "stores",
|
|
185350
|
+
cache: "stores",
|
|
185351
|
+
secret: "secret",
|
|
185352
|
+
secrets: "secret",
|
|
185353
|
+
password: "secret",
|
|
185354
|
+
messages: "sends",
|
|
185355
|
+
"dead letters": "sends",
|
|
185356
|
+
triggers: "triggers",
|
|
185357
|
+
logs: "reports",
|
|
185358
|
+
"logs to": "reports",
|
|
185359
|
+
telemetry: "reports",
|
|
185360
|
+
images: "pulls",
|
|
185361
|
+
"private link": "private",
|
|
185362
|
+
"VNet integration": "private",
|
|
185363
|
+
"public IP": "routes",
|
|
185364
|
+
firewall: "filters",
|
|
185365
|
+
calls: "calls",
|
|
185366
|
+
[ORDER_LABEL]: "depends-on"
|
|
185367
|
+
};
|
|
185368
|
+
POLICY_KEY = /(?:^|\.)[a-z0-9_]*polic(?:y|ies)[a-z0-9_]*\./;
|
|
184936
185369
|
MAX_LABELS2 = 2;
|
|
184937
185370
|
}
|
|
184938
185371
|
});
|
|
@@ -185196,7 +185629,7 @@ function picture(plan, context, groupType) {
|
|
|
185196
185629
|
if (shape === "container") {
|
|
185197
185630
|
const frame = containerFrame(resource.key);
|
|
185198
185631
|
const parent = byFile ? parentOf4(frame, resource) : plan.parents.get(frame) ?? null;
|
|
185199
|
-
groups.push({ key: frame, label: box.label, type:
|
|
185632
|
+
groups.push({ key: frame, label: box.label, type: HOLDER_TYPES[box.type] ?? "resource-group", icon: box.icon ?? null, sub: null, parent, idHint: `${resource.name}_group` });
|
|
185200
185633
|
const product = role.role === "node" ? productOf2(resource, plan) : box.label;
|
|
185201
185634
|
nodes.push({ ...box, label: box.label === product ? box.label : product, sub: box.label === product ? box.sub ?? null : withParts(literalDetails(resource), multiplicity(resource), resource.kind === "data" && !plan.compatible ? "existing" : null), group: frame });
|
|
185202
185635
|
} else {
|
|
@@ -185216,7 +185649,7 @@ function picture(plan, context, groupType) {
|
|
|
185216
185649
|
for (const [key, module] of plan.modules) {
|
|
185217
185650
|
const source = module.source.replace(/^(?:\.\.?\/)+/, "");
|
|
185218
185651
|
const label = `${humanize(module.name)}${module.instance === null ? "" : ` ${module.instance}`}`;
|
|
185219
|
-
groups.push({ key, label, type: null, icon: moduleIcon(module.name, module.source, stackProvider(plan)) ?? "lucide:package", sub: cleanText(`${module.noun ?? "Module"} ${source}`), parent: plan.parents.get(key) ?? null, idHint: `${module.name}${module.instance === null ? "" : `_${module.instance}`}` });
|
|
185652
|
+
groups.push({ key, label, type: null, otherwise: "resource-group", icon: moduleIcon(module.name, module.source, stackProvider(plan)) ?? "lucide:package", sub: cleanText(`${module.noun ?? "Module"} ${source}`), parent: plan.parents.get(key) ?? null, idHint: `${module.name}${module.instance === null ? "" : `_${module.instance}`}` });
|
|
185220
185653
|
}
|
|
185221
185654
|
const holding = /* @__PURE__ */ new Set();
|
|
185222
185655
|
for (const node3 of nodes) for (const key of [node3.group ?? "", ...plan.ancestors(node3.group ?? "")]) holding.add(key);
|
|
@@ -185258,7 +185691,7 @@ function withoutIdleBoxes(nodes, groups, edges) {
|
|
|
185258
185691
|
const framed = groups.map((group2) => {
|
|
185259
185692
|
const box = idle.get(group2.key);
|
|
185260
185693
|
if (box === void 0) return group2;
|
|
185261
|
-
const said = group2.label.includes(box.label) || group2.type !== null && group2.type !== void 0 ? null : box.label;
|
|
185694
|
+
const said = group2.label.includes(box.label) || group2.type !== null && group2.type !== void 0 && group2.key !== containerFrame(box.key) ? null : box.label;
|
|
185262
185695
|
return { ...group2, sub: withParts(group2.sub ?? null, said, box.sub ?? null) };
|
|
185263
185696
|
});
|
|
185264
185697
|
return { nodes: kept2, groups: framed };
|
|
@@ -185282,7 +185715,7 @@ function literalDetails(resource) {
|
|
|
185282
185715
|
const values = names8.map((name2) => literal2(resource, name2)).filter((value) => value !== null && value !== "");
|
|
185283
185716
|
return values.length === 0 ? null : values.join(" ");
|
|
185284
185717
|
}
|
|
185285
|
-
var ACCOUNT_NAMES;
|
|
185718
|
+
var ACCOUNT_NAMES, HOLDER_TYPES;
|
|
185286
185719
|
var init_picture = __esm({
|
|
185287
185720
|
"../../packages/diagrams/src/importers/terraform/picture.ts"() {
|
|
185288
185721
|
"use strict";
|
|
@@ -185295,6 +185728,17 @@ var init_picture = __esm({
|
|
|
185295
185728
|
init_plan9();
|
|
185296
185729
|
init_resources();
|
|
185297
185730
|
ACCOUNT_NAMES = { aws: "AWS account", azure: "Azure subscription", gcp: "Google Cloud project" };
|
|
185731
|
+
HOLDER_TYPES = {
|
|
185732
|
+
database: "data-tier",
|
|
185733
|
+
cache: "data-tier",
|
|
185734
|
+
storage: "storage-account",
|
|
185735
|
+
queue: "messaging",
|
|
185736
|
+
secret: "security",
|
|
185737
|
+
identity: "identity-boundary",
|
|
185738
|
+
service: "app-tier",
|
|
185739
|
+
function: "app-tier",
|
|
185740
|
+
gateway: "edge"
|
|
185741
|
+
};
|
|
185298
185742
|
}
|
|
185299
185743
|
});
|
|
185300
185744
|
|
|
@@ -186358,13 +186802,13 @@ function expression(value, depth) {
|
|
|
186358
186802
|
}
|
|
186359
186803
|
function body5(object2, depth, lines) {
|
|
186360
186804
|
for (const [key, value] of Object.entries(object2)) {
|
|
186361
|
-
const
|
|
186805
|
+
const isObject6 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
|
|
186362
186806
|
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 (
|
|
186807
|
+
else if (isObject6(value)) {
|
|
186364
186808
|
lines.push(`${keyOf2(key)} {`);
|
|
186365
186809
|
body5(value, depth + 1, lines);
|
|
186366
186810
|
lines.push("}");
|
|
186367
|
-
} else if (Array.isArray(value) && value.length > 0 && value.every(
|
|
186811
|
+
} else if (Array.isArray(value) && value.length > 0 && value.every(isObject6)) {
|
|
186368
186812
|
for (const item of value) {
|
|
186369
186813
|
lines.push(`${keyOf2(key)} {`);
|
|
186370
186814
|
body5(item, depth + 1, lines);
|
|
@@ -186975,9 +187419,9 @@ var init_evaluate = __esm({
|
|
|
186975
187419
|
}
|
|
186976
187420
|
case "replace": {
|
|
186977
187421
|
const [value, search, replacement] = args();
|
|
186978
|
-
const [known3,
|
|
186979
|
-
if (known3 === null ||
|
|
186980
|
-
const out = known3.split(
|
|
187422
|
+
const [known3, find2, put] = [value instanceof Partial ? value.name : text3(value), text3(search), text3(replacement)];
|
|
187423
|
+
if (known3 === null || find2 === null || put === null || find2 === "") return value ?? null;
|
|
187424
|
+
const out = known3.split(find2).join(put);
|
|
186981
187425
|
return value instanceof Partial ? new Partial(out) : out;
|
|
186982
187426
|
}
|
|
186983
187427
|
case "take":
|
|
@@ -187351,7 +187795,7 @@ function chainOf(expr) {
|
|
|
187351
187795
|
}
|
|
187352
187796
|
return { base: current, steps };
|
|
187353
187797
|
}
|
|
187354
|
-
function
|
|
187798
|
+
function nameOf8(slot, evaluator) {
|
|
187355
187799
|
const named = bodyObject(slot.declaration.value)?.entries.find((entry2) => entry2.key === "name")?.value;
|
|
187356
187800
|
return named === void 0 ? null : textOf5(evaluator.evaluate(named, slot.env));
|
|
187357
187801
|
}
|
|
@@ -187366,15 +187810,15 @@ var init_slots2 = __esm({
|
|
|
187366
187810
|
|
|
187367
187811
|
// ../../packages/diagrams/src/importers/bicep/items.ts
|
|
187368
187812
|
function withoutReadCopies(items2) {
|
|
187369
|
-
const
|
|
187813
|
+
const nameOf11 = (item) => item.attributes.find((attribute2) => attribute2.name === "name")?.value ?? null;
|
|
187370
187814
|
const made = /* @__PURE__ */ new Map();
|
|
187371
187815
|
for (const item of items2) {
|
|
187372
|
-
const name2 =
|
|
187816
|
+
const name2 = nameOf11(item);
|
|
187373
187817
|
if (!item.existing && name2 !== null) made.set(`${item.type}\0${name2}`, item.name);
|
|
187374
187818
|
}
|
|
187375
187819
|
const alias = /* @__PURE__ */ new Map();
|
|
187376
187820
|
for (const item of items2) {
|
|
187377
|
-
const name2 =
|
|
187821
|
+
const name2 = nameOf11(item);
|
|
187378
187822
|
const real = name2 === null ? void 0 : made.get(`${item.type}\0${name2}`);
|
|
187379
187823
|
if (item.existing && real !== void 0) alias.set(item.name, real);
|
|
187380
187824
|
}
|
|
@@ -187467,18 +187911,18 @@ var init_items3 = __esm({
|
|
|
187467
187911
|
}
|
|
187468
187912
|
/** The resource a child names as its parent by the start of its name (`vnet-shop` of `vnet-shop/app`), when the stack declares it. */
|
|
187469
187913
|
parentByName(slot) {
|
|
187470
|
-
const name2 =
|
|
187914
|
+
const name2 = nameOf8(slot, this.evaluator);
|
|
187471
187915
|
const segments = slot.armType.split("/");
|
|
187472
187916
|
if (name2 === null || !name2.includes("/") || segments.length < 3) return null;
|
|
187473
187917
|
const parentType = segments.slice(0, -1).join("/").toLowerCase();
|
|
187474
187918
|
const parentName = name2.slice(0, name2.lastIndexOf("/"));
|
|
187475
|
-
for (const list of this.slots.values()) for (const candidate2 of list) if (candidate2.armType.toLowerCase() === parentType &&
|
|
187919
|
+
for (const list of this.slots.values()) for (const candidate2 of list) if (candidate2.armType.toLowerCase() === parentType && nameOf8(candidate2, this.evaluator) === parentName) return candidate2.transparent ? candidate2.holder?.name ?? null : candidate2.name;
|
|
187476
187920
|
if (/\/(?:blob|queue|table|file)services$/.test(parentType) && segments.length >= 4) return this.declared(segments.slice(0, -2).join("/"), parentName.slice(0, parentName.lastIndexOf("/")));
|
|
187477
187921
|
return null;
|
|
187478
187922
|
}
|
|
187479
187923
|
/** The item of a type and a name the deployment declares, or null. */
|
|
187480
187924
|
declared(type, name2) {
|
|
187481
|
-
for (const list of this.slots.values()) for (const candidate2 of list) if (candidate2.armType.toLowerCase() === type.toLowerCase() &&
|
|
187925
|
+
for (const list of this.slots.values()) for (const candidate2 of list) if (candidate2.armType.toLowerCase() === type.toLowerCase() && nameOf8(candidate2, this.evaluator) === name2) return candidate2.name;
|
|
187482
187926
|
return null;
|
|
187483
187927
|
}
|
|
187484
187928
|
/** The item that stands for a name: a storage service's account, since the service itself is not drawn. */
|
|
@@ -187719,9 +188163,9 @@ var init_references = __esm({
|
|
|
187719
188163
|
if (type !== null && last !== null && last !== void 0) {
|
|
187720
188164
|
for (const list of this.slots.values()) {
|
|
187721
188165
|
for (const slot of list) {
|
|
187722
|
-
const own2 =
|
|
188166
|
+
const own2 = nameOf8(slot, this.evaluator);
|
|
187723
188167
|
if (slot.armType.toLowerCase() === type && (own2 === last || own2 === names8.join("/"))) return [slot.name];
|
|
187724
|
-
if (type === `${slot.armType.toLowerCase()}/subnets` &&
|
|
188168
|
+
if (type === `${slot.armType.toLowerCase()}/subnets` && nameOf8(slot, this.evaluator) === names8[names8.length - 2]) {
|
|
187725
188169
|
const subnet = slot.subnets.find((entry2) => entry2.display === last || entry2.label === last);
|
|
187726
188170
|
if (subnet !== void 0) return [subnet.name];
|
|
187727
188171
|
}
|
|
@@ -188815,8 +189259,626 @@ var init_arm = __esm({
|
|
|
188815
189259
|
}
|
|
188816
189260
|
});
|
|
188817
189261
|
|
|
189262
|
+
// ../../packages/diagrams/src/importers/asyncapi/document.ts
|
|
189263
|
+
function nodeOf2(value, depth = 0) {
|
|
189264
|
+
const at3 = { line: 1, column: 1 };
|
|
189265
|
+
if (depth > MAX_DEPTH13 || value === null || value === void 0) return { kind: "scalar", value: "", quoted: false, isNull: true, ...at3 };
|
|
189266
|
+
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) => nodeOf2(item, depth + 1)), ...at3 };
|
|
189267
|
+
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value: nodeOf2(entry2, depth + 1), ...at3 })), ...at3 };
|
|
189268
|
+
return { kind: "scalar", value: String(value), quoted: typeof value === "string", isNull: false, ...at3 };
|
|
189269
|
+
}
|
|
189270
|
+
function readDocument(text3) {
|
|
189271
|
+
if (/^\s*\{/.test(text3)) {
|
|
189272
|
+
try {
|
|
189273
|
+
return { root: nodeOf2(JSON.parse(text3)), problem: null };
|
|
189274
|
+
} catch (error62) {
|
|
189275
|
+
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." } };
|
|
189276
|
+
}
|
|
189277
|
+
}
|
|
189278
|
+
const read = parseYaml(text3);
|
|
189279
|
+
if (read.error !== null) return { root: null, problem: { ...read.error, message: `The YAML cannot be read: ${read.error.message}` } };
|
|
189280
|
+
return { root: read.documents.find((document2) => document2.root !== null)?.root ?? null, problem: null };
|
|
189281
|
+
}
|
|
189282
|
+
function pointerPart(part) {
|
|
189283
|
+
const plain3 = part.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
189284
|
+
try {
|
|
189285
|
+
return decodeURIComponent(plain3);
|
|
189286
|
+
} catch {
|
|
189287
|
+
return plain3;
|
|
189288
|
+
}
|
|
189289
|
+
}
|
|
189290
|
+
function nameOfRef(ref) {
|
|
189291
|
+
const path = ref.slice(ref.indexOf("#") + 1);
|
|
189292
|
+
const last = path.split("/").filter((part) => part !== "").pop() ?? ref;
|
|
189293
|
+
return pointerPart(last);
|
|
189294
|
+
}
|
|
189295
|
+
function deref(root, node3) {
|
|
189296
|
+
let at3 = node3;
|
|
189297
|
+
for (let hop = 0; hop < MAX_HOPS; hop += 1) {
|
|
189298
|
+
const ref = refOf(at3);
|
|
189299
|
+
if (ref === null || !ref.startsWith("#/")) return at3;
|
|
189300
|
+
let target = root;
|
|
189301
|
+
for (const part of ref.slice(2).split("/")) target = get(target, pointerPart(part));
|
|
189302
|
+
if (target === void 0) return at3;
|
|
189303
|
+
at3 = target;
|
|
189304
|
+
}
|
|
189305
|
+
return at3;
|
|
189306
|
+
}
|
|
189307
|
+
var MAX_HOPS, MAX_DEPTH13, refOf;
|
|
189308
|
+
var init_document2 = __esm({
|
|
189309
|
+
"../../packages/diagrams/src/importers/asyncapi/document.ts"() {
|
|
189310
|
+
"use strict";
|
|
189311
|
+
init_yaml();
|
|
189312
|
+
MAX_HOPS = 10;
|
|
189313
|
+
MAX_DEPTH13 = 64;
|
|
189314
|
+
refOf = (node3) => {
|
|
189315
|
+
const ref = get(node3, "$ref");
|
|
189316
|
+
return ref?.kind === "scalar" ? ref.value : null;
|
|
189317
|
+
};
|
|
189318
|
+
}
|
|
189319
|
+
});
|
|
189320
|
+
|
|
189321
|
+
// ../../packages/diagrams/src/importers/asyncapi/layers.ts
|
|
189322
|
+
function adjacency(keys, arrows, reverse) {
|
|
189323
|
+
const next = new Map(keys.map((key) => [key, []]));
|
|
189324
|
+
for (const arrow of arrows) next.get(reverse ? arrow.to : arrow.from)?.push(reverse ? arrow.from : arrow.to);
|
|
189325
|
+
return next;
|
|
189326
|
+
}
|
|
189327
|
+
function finishOrder(start2, next, seen, finished2) {
|
|
189328
|
+
const stack = [{ key: start2, index: 0 }];
|
|
189329
|
+
seen.add(start2);
|
|
189330
|
+
while (stack.length > 0) {
|
|
189331
|
+
const top = stack[stack.length - 1];
|
|
189332
|
+
const following = next.get(top.key) ?? [];
|
|
189333
|
+
if (top.index < following.length) {
|
|
189334
|
+
const key = following[top.index];
|
|
189335
|
+
top.index += 1;
|
|
189336
|
+
if (!seen.has(key)) {
|
|
189337
|
+
seen.add(key);
|
|
189338
|
+
stack.push({ key, index: 0 });
|
|
189339
|
+
}
|
|
189340
|
+
} else {
|
|
189341
|
+
finished2.push(top.key);
|
|
189342
|
+
stack.pop();
|
|
189343
|
+
}
|
|
189344
|
+
}
|
|
189345
|
+
}
|
|
189346
|
+
function layersOf(keys, arrows) {
|
|
189347
|
+
const forward = adjacency(keys, arrows, false);
|
|
189348
|
+
const backward = adjacency(keys, arrows, true);
|
|
189349
|
+
const finished2 = [];
|
|
189350
|
+
const seen = /* @__PURE__ */ new Set();
|
|
189351
|
+
for (const key of keys) if (!seen.has(key)) finishOrder(key, forward, seen, finished2);
|
|
189352
|
+
const component = /* @__PURE__ */ new Map();
|
|
189353
|
+
const members2 = [];
|
|
189354
|
+
const assigned = /* @__PURE__ */ new Set();
|
|
189355
|
+
for (const key of [...finished2].reverse()) {
|
|
189356
|
+
if (assigned.has(key)) continue;
|
|
189357
|
+
const found = [];
|
|
189358
|
+
finishOrder(key, backward, assigned, found);
|
|
189359
|
+
for (const member of found) component.set(member, members2.length);
|
|
189360
|
+
members2.push(found);
|
|
189361
|
+
}
|
|
189362
|
+
const looped = new Set(members2.filter((group2) => group2.length > 1).flat());
|
|
189363
|
+
for (const arrow of arrows) if (arrow.from === arrow.to) looped.add(arrow.from);
|
|
189364
|
+
const step = new Array(members2.length).fill(0);
|
|
189365
|
+
const fed = /* @__PURE__ */ new Set();
|
|
189366
|
+
for (let index2 = 0; index2 < members2.length; index2 += 1) {
|
|
189367
|
+
for (const key of members2[index2] ?? []) {
|
|
189368
|
+
for (const to of forward.get(key) ?? []) {
|
|
189369
|
+
const target = component.get(to);
|
|
189370
|
+
if (target === index2) continue;
|
|
189371
|
+
step[target] = Math.max(step[target], step[index2] + 1);
|
|
189372
|
+
fed.add(target);
|
|
189373
|
+
}
|
|
189374
|
+
}
|
|
189375
|
+
}
|
|
189376
|
+
for (let index2 = members2.length - 1; index2 >= 0; index2 -= 1) {
|
|
189377
|
+
if (fed.has(index2)) continue;
|
|
189378
|
+
const targets = (members2[index2] ?? []).flatMap((key) => forward.get(key) ?? []).map((to) => component.get(to)).filter((target) => target !== index2);
|
|
189379
|
+
if (targets.length > 0) step[index2] = Math.min(...targets.map((target) => step[target])) - 1;
|
|
189380
|
+
}
|
|
189381
|
+
return { layer: new Map(keys.map((key) => [key, step[component.get(key)]])), looped };
|
|
189382
|
+
}
|
|
189383
|
+
var init_layers2 = __esm({
|
|
189384
|
+
"../../packages/diagrams/src/importers/asyncapi/layers.ts"() {
|
|
189385
|
+
"use strict";
|
|
189386
|
+
}
|
|
189387
|
+
});
|
|
189388
|
+
|
|
189389
|
+
// ../../packages/diagrams/src/importers/asyncapi/spec.ts
|
|
189390
|
+
function messageName(root, node3, fallback) {
|
|
189391
|
+
const ref = refOf(node3);
|
|
189392
|
+
const message2 = deref(root, node3);
|
|
189393
|
+
return text(get(message2, "name")) ?? text(get(message2, "title")) ?? text(get(message2, "messageId")) ?? fallback ?? (ref === null ? null : nameOfRef(ref));
|
|
189394
|
+
}
|
|
189395
|
+
function messagesOf2(root, operation) {
|
|
189396
|
+
const message2 = get(operation, "message");
|
|
189397
|
+
const resolved2 = deref(root, message2);
|
|
189398
|
+
const choices = items(get(resolved2, "oneOf"));
|
|
189399
|
+
const list = choices.length > 0 ? choices : message2 === void 0 ? [] : [message2];
|
|
189400
|
+
return list.map((node3) => messageName(root, node3, null)).filter((name2) => name2 !== null);
|
|
189401
|
+
}
|
|
189402
|
+
function serversOf(root) {
|
|
189403
|
+
return entries(get(root, "servers")).map((entry2) => {
|
|
189404
|
+
const server = deref(root, entry2.value);
|
|
189405
|
+
const host = text(get(server, "host")) ?? text(get(server, "url"));
|
|
189406
|
+
return { name: entry2.key, protocol: (text(get(server, "protocol")) ?? "").toLowerCase(), host, line: entry2.line, column: entry2.column };
|
|
189407
|
+
});
|
|
189408
|
+
}
|
|
189409
|
+
function channelServers(root, channel) {
|
|
189410
|
+
return items(get(channel, "servers")).map((node3) => text(node3) ?? (refOf(node3) === null ? null : nameOfRef(refOf(node3) ?? ""))).filter((name2) => name2 !== null);
|
|
189411
|
+
}
|
|
189412
|
+
function readVersion2(root) {
|
|
189413
|
+
const channels = [];
|
|
189414
|
+
const operations = [];
|
|
189415
|
+
for (const entry2 of entries(get(root, "channels"))) {
|
|
189416
|
+
const channel = deref(root, entry2.value);
|
|
189417
|
+
channels.push({ id: entry2.key, address: entry2.key, description: text(get(channel, "description")), servers: channelServers(root, channel), line: entry2.line, column: entry2.column });
|
|
189418
|
+
for (const [key, direction] of [["subscribe", "send"], ["publish", "receive"]]) {
|
|
189419
|
+
const operation = get(channel, key);
|
|
189420
|
+
if (operation === void 0) continue;
|
|
189421
|
+
const at3 = channel?.kind === "map" ? channel.entries.find((candidate2) => candidate2.key === key) : void 0;
|
|
189422
|
+
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 });
|
|
189423
|
+
}
|
|
189424
|
+
}
|
|
189425
|
+
return { channels, operations, unresolved: [] };
|
|
189426
|
+
}
|
|
189427
|
+
function readVersion3(root) {
|
|
189428
|
+
const channels = [];
|
|
189429
|
+
const messagesOfChannel = /* @__PURE__ */ new Map();
|
|
189430
|
+
for (const entry2 of entries(get(root, "channels"))) {
|
|
189431
|
+
const channel = deref(root, entry2.value);
|
|
189432
|
+
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 });
|
|
189433
|
+
messagesOfChannel.set(
|
|
189434
|
+
entry2.key,
|
|
189435
|
+
entries(get(channel, "messages")).map((message2) => messageName(root, message2.value, message2.key)).filter((name2) => name2 !== null)
|
|
189436
|
+
);
|
|
189437
|
+
}
|
|
189438
|
+
const operations = [];
|
|
189439
|
+
const unresolved = [];
|
|
189440
|
+
for (const entry2 of entries(get(root, "operations"))) {
|
|
189441
|
+
const operation = deref(root, entry2.value);
|
|
189442
|
+
const action = text(get(operation, "action"));
|
|
189443
|
+
const ref = refOf(get(operation, "channel"));
|
|
189444
|
+
const channel = ref === null ? null : ref.startsWith("#/channels/") ? nameOfRef(ref) : null;
|
|
189445
|
+
if (channel === null || !messagesOfChannel.has(channel)) {
|
|
189446
|
+
unresolved.push({ name: ref ?? entry2.key, line: entry2.line, column: entry2.column });
|
|
189447
|
+
continue;
|
|
189448
|
+
}
|
|
189449
|
+
if (action !== "send" && action !== "receive") continue;
|
|
189450
|
+
const listed2 = items(get(operation, "messages")).map((node3) => {
|
|
189451
|
+
const target = refOf(node3);
|
|
189452
|
+
const key = target === null ? null : nameOfRef(target);
|
|
189453
|
+
return messageName(root, node3, null) ?? key;
|
|
189454
|
+
}).filter((name2) => name2 !== null);
|
|
189455
|
+
operations.push({ id: entry2.key, channel, direction: action, messages: listed2.length > 0 ? listed2 : messagesOfChannel.get(channel) ?? [], line: entry2.line, column: entry2.column });
|
|
189456
|
+
}
|
|
189457
|
+
return { channels, operations, unresolved };
|
|
189458
|
+
}
|
|
189459
|
+
function majorOf(root) {
|
|
189460
|
+
const version2 = text(get(root, "asyncapi"));
|
|
189461
|
+
if (version2 === null) return null;
|
|
189462
|
+
return version2.startsWith("2.") ? 2 : version2.startsWith("3.") ? 3 : null;
|
|
189463
|
+
}
|
|
189464
|
+
function readApplication(root, major) {
|
|
189465
|
+
const info = get(root, "info");
|
|
189466
|
+
const read = major === 2 ? readVersion2(root) : readVersion3(root);
|
|
189467
|
+
return { title: text(get(info, "title")) ?? "Application", version: text(get(root, "asyncapi")) ?? "", appVersion: text(get(info, "version")), major, servers: serversOf(root), ...read };
|
|
189468
|
+
}
|
|
189469
|
+
var init_spec = __esm({
|
|
189470
|
+
"../../packages/diagrams/src/importers/asyncapi/spec.ts"() {
|
|
189471
|
+
"use strict";
|
|
189472
|
+
init_yaml();
|
|
189473
|
+
init_document2();
|
|
189474
|
+
}
|
|
189475
|
+
});
|
|
189476
|
+
|
|
189477
|
+
// ../../packages/diagrams/src/importers/asyncapi/index.ts
|
|
189478
|
+
function familyOf2(protocol) {
|
|
189479
|
+
if (protocol.startsWith("kafka")) return "kafka";
|
|
189480
|
+
if (protocol.startsWith("amqp")) return "amqp";
|
|
189481
|
+
if (protocol.includes("mqtt")) return "mqtt";
|
|
189482
|
+
if (protocol === "wss") return "ws";
|
|
189483
|
+
if (protocol === "https") return "http";
|
|
189484
|
+
return protocol === "" ? "broker" : protocol;
|
|
189485
|
+
}
|
|
189486
|
+
function messagesLabel(messages) {
|
|
189487
|
+
const unique2 = [...new Set(messages.map((message2) => cleanText(message2)))];
|
|
189488
|
+
if (unique2.length === 0) return null;
|
|
189489
|
+
return unique2.length <= 2 ? unique2.join(", ") : `${unique2[0]} and ${unique2.length - 1} more`;
|
|
189490
|
+
}
|
|
189491
|
+
function readAsyncApi(text3, context) {
|
|
189492
|
+
const index2 = new LineIndex(text3);
|
|
189493
|
+
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) }));
|
|
189494
|
+
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);
|
|
189495
|
+
const applications = [];
|
|
189496
|
+
for (const file2 of files) {
|
|
189497
|
+
const read = readDocument(file2.text);
|
|
189498
|
+
const name2 = cleanText(file2.path, "The file");
|
|
189499
|
+
if (read.problem !== null || read.root === null) {
|
|
189500
|
+
const problem = read.problem ?? { line: 1, column: 1, message: "The file is empty.", hint: "Send an AsyncAPI document." };
|
|
189501
|
+
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);
|
|
189502
|
+
if (files.length === 1) return null;
|
|
189503
|
+
continue;
|
|
189504
|
+
}
|
|
189505
|
+
const major = majorOf(read.root);
|
|
189506
|
+
if (major === null) {
|
|
189507
|
+
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";
|
|
189508
|
+
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.");
|
|
189509
|
+
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.");
|
|
189510
|
+
continue;
|
|
189511
|
+
}
|
|
189512
|
+
applications.push({ app: readApplication(read.root, major), file: file2 });
|
|
189513
|
+
}
|
|
189514
|
+
if (applications.length === 0) {
|
|
189515
|
+
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.");
|
|
189516
|
+
return null;
|
|
189517
|
+
}
|
|
189518
|
+
const nodes = [];
|
|
189519
|
+
const groups = [];
|
|
189520
|
+
const edges = [];
|
|
189521
|
+
const arrows = /* @__PURE__ */ new Map();
|
|
189522
|
+
const channelBox = /* @__PURE__ */ new Map();
|
|
189523
|
+
const channelFamily = /* @__PURE__ */ new Map();
|
|
189524
|
+
const brokerHosts = /* @__PURE__ */ new Map();
|
|
189525
|
+
const brokerServers = /* @__PURE__ */ new Map();
|
|
189526
|
+
let operations = 0;
|
|
189527
|
+
for (const { app, file: file2 } of applications) {
|
|
189528
|
+
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'.");
|
|
189529
|
+
const appKey = `app:${app.title}`;
|
|
189530
|
+
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() });
|
|
189531
|
+
const serverFamily = new Map(app.servers.map((server) => [server.name, familyOf2(server.protocol)]));
|
|
189532
|
+
for (const server of app.servers) {
|
|
189533
|
+
const family = familyOf2(server.protocol);
|
|
189534
|
+
brokerServers.set(family, [...brokerServers.get(family) ?? [], server]);
|
|
189535
|
+
if (server.host !== null) brokerHosts.set(family, (brokerHosts.get(family) ?? /* @__PURE__ */ new Set()).add(server.host));
|
|
189536
|
+
}
|
|
189537
|
+
for (const channel of app.channels) {
|
|
189538
|
+
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));
|
|
189539
|
+
const family = families.size === 1 ? [...families][0] : void 0;
|
|
189540
|
+
const key = `channel:${channel.address}`;
|
|
189541
|
+
const existing = channelBox.get(key);
|
|
189542
|
+
if (existing === void 0) {
|
|
189543
|
+
const box = { key, type: "queue", label: cleanText(channel.address), sub: channel.description === null ? null : cleanText(channel.description), group: null, idHint: channel.address };
|
|
189544
|
+
channelBox.set(key, box);
|
|
189545
|
+
if (family !== void 0) channelFamily.set(key, family);
|
|
189546
|
+
nodes.push(box);
|
|
189547
|
+
}
|
|
189548
|
+
}
|
|
189549
|
+
for (const operation of app.operations) {
|
|
189550
|
+
const channel = app.channels.find((candidate2) => candidate2.id === operation.channel);
|
|
189551
|
+
if (channel === void 0) continue;
|
|
189552
|
+
const channelKey = `channel:${channel.address}`;
|
|
189553
|
+
operations += 1;
|
|
189554
|
+
const [from, to] = operation.direction === "send" ? [appKey, channelKey] : [channelKey, appKey];
|
|
189555
|
+
const pair2 = `${from}\0${to}`;
|
|
189556
|
+
arrows.set(pair2, { from, to, messages: [...arrows.get(pair2)?.messages ?? [], ...operation.messages] });
|
|
189557
|
+
}
|
|
189558
|
+
}
|
|
189559
|
+
for (const arrow of arrows.values()) edges.push({ from: arrow.from, to: arrow.to, label: messagesLabel(arrow.messages), verb: arrow.from.startsWith("channel:") ? "receives" : "sends" });
|
|
189560
|
+
const { layer: layer2, looped } = layersOf(
|
|
189561
|
+
nodes.map((node3) => node3.key),
|
|
189562
|
+
edges
|
|
189563
|
+
);
|
|
189564
|
+
const brokerIcon = (family) => BROKERS[family]?.icon ?? (brokerServers.get(family) ?? []).map((server) => iconForName(`${server.name} ${server.host ?? ""}`, "queue")).find((icon) => icon?.startsWith("simple:") === true) ?? null;
|
|
189565
|
+
const frameSteps = /* @__PURE__ */ new Map();
|
|
189566
|
+
const frameKey = (family, step) => {
|
|
189567
|
+
const index3 = (frameSteps.get(family) ?? []).indexOf(step);
|
|
189568
|
+
return index3 === 0 ? `broker:${family}` : `broker:${family}:${index3 + 1}`;
|
|
189569
|
+
};
|
|
189570
|
+
const placed = nodes.map((node3) => {
|
|
189571
|
+
const family = channelFamily.get(node3.key);
|
|
189572
|
+
if (family === void 0) return node3;
|
|
189573
|
+
if (looped.has(node3.key)) return { ...node3, icon: brokerIcon(family) };
|
|
189574
|
+
const step = layer2.get(node3.key) ?? 0;
|
|
189575
|
+
const steps = frameSteps.get(family) ?? [];
|
|
189576
|
+
if (!steps.includes(step)) frameSteps.set(family, [...steps, step]);
|
|
189577
|
+
return { ...node3, group: frameKey(family, step) };
|
|
189578
|
+
});
|
|
189579
|
+
const usedFamilies = new Set(channelFamily.values());
|
|
189580
|
+
for (const family of [...brokerServers.keys()]) {
|
|
189581
|
+
const broker = BROKERS[family];
|
|
189582
|
+
const hosts = [...brokerHosts.get(family) ?? []];
|
|
189583
|
+
const where = hosts.length === 0 ? null : hosts.length === 1 ? hosts[0] ?? null : `${hosts.length} hosts`;
|
|
189584
|
+
const steps = [...frameSteps.get(family) ?? []].sort((a, b) => a - b);
|
|
189585
|
+
for (const step of steps) {
|
|
189586
|
+
groups.push({ key: frameKey(family, step), label: broker?.label ?? `${family.toUpperCase()} broker`, type: "messaging", icon: brokerIcon(family), sub: where === null || step !== steps[0] ? null : cleanText(where), idHint: family });
|
|
189587
|
+
}
|
|
189588
|
+
}
|
|
189589
|
+
const unused = [...brokerServers.entries()].filter(([family]) => !usedFamilies.has(family)).flatMap(([, servers]) => servers);
|
|
189590
|
+
if (unused.length > 0) {
|
|
189591
|
+
const first = unused[0];
|
|
189592
|
+
const file2 = applications.find(({ app }) => app.servers.includes(first))?.file ?? files[0];
|
|
189593
|
+
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.");
|
|
189594
|
+
}
|
|
189595
|
+
const sends = (key) => edges.some((edge) => edge.from === key);
|
|
189596
|
+
const receives = (key) => edges.some((edge) => edge.to === key);
|
|
189597
|
+
const rank = (node3) => node3.type === "queue" ? 1 : sends(node3.key) && !receives(node3.key) ? 0 : !sends(node3.key) && receives(node3.key) ? 2 : 1;
|
|
189598
|
+
const ordered = [...placed].sort((a, b) => rank(a) - rank(b));
|
|
189599
|
+
const one = applications.length === 1 ? applications[0]?.app : void 0;
|
|
189600
|
+
const channels = channelBox.size;
|
|
189601
|
+
return writeFlow(
|
|
189602
|
+
{
|
|
189603
|
+
title: context.title ?? (one === void 0 ? "Event flows" : cleanText(one.title)),
|
|
189604
|
+
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)}.`,
|
|
189605
|
+
direction: "down",
|
|
189606
|
+
nodes: ordered,
|
|
189607
|
+
groups,
|
|
189608
|
+
edges,
|
|
189609
|
+
noun: "channels",
|
|
189610
|
+
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.",
|
|
189611
|
+
coverage: { noun: "channels and operations", total: channels + operations, drawn: channels + operations, summarised: 0 }
|
|
189612
|
+
},
|
|
189613
|
+
context.report
|
|
189614
|
+
);
|
|
189615
|
+
}
|
|
189616
|
+
var BROKERS, asyncapiImporter;
|
|
189617
|
+
var init_asyncapi = __esm({
|
|
189618
|
+
"../../packages/diagrams/src/importers/asyncapi/index.ts"() {
|
|
189619
|
+
"use strict";
|
|
189620
|
+
init_core();
|
|
189621
|
+
init_shared2();
|
|
189622
|
+
init_document2();
|
|
189623
|
+
init_layers2();
|
|
189624
|
+
init_spec();
|
|
189625
|
+
BROKERS = {
|
|
189626
|
+
kafka: { label: "Kafka", icon: "simple:apachekafka" },
|
|
189627
|
+
amqp: { label: "AMQP broker", icon: null },
|
|
189628
|
+
mqtt: { label: "MQTT broker", icon: null },
|
|
189629
|
+
nats: { label: "NATS", icon: null },
|
|
189630
|
+
redis: { label: "Redis", icon: "simple:redis" },
|
|
189631
|
+
pulsar: { label: "Pulsar", icon: "simple:apachepulsar" },
|
|
189632
|
+
sns: { label: "Amazon SNS", icon: "aws:sns" },
|
|
189633
|
+
sqs: { label: "Amazon SQS", icon: "aws:sqs" },
|
|
189634
|
+
googlepubsub: { label: "Google Pub/Sub", icon: "gcp:pubsub" },
|
|
189635
|
+
ibmmq: { label: "IBM MQ", icon: null },
|
|
189636
|
+
jms: { label: "JMS broker", icon: null },
|
|
189637
|
+
solace: { label: "Solace", icon: null },
|
|
189638
|
+
stomp: { label: "STOMP broker", icon: null },
|
|
189639
|
+
ws: { label: "WebSocket", icon: null },
|
|
189640
|
+
http: { label: "HTTP", icon: null },
|
|
189641
|
+
anypointmq: { label: "Anypoint MQ", icon: null },
|
|
189642
|
+
mercure: { label: "Mercure", icon: null }
|
|
189643
|
+
};
|
|
189644
|
+
asyncapiImporter = { format: "asyncapi", kinds: ["flow"], joins: "\n", extensions: [".yaml", ".yml", ".json"], read: readAsyncApi };
|
|
189645
|
+
}
|
|
189646
|
+
});
|
|
189647
|
+
|
|
189648
|
+
// ../../packages/diagrams/src/importers/azure-pipelines/pipeline.ts
|
|
189649
|
+
function dependsOnOf2(node3) {
|
|
189650
|
+
const value = get(node3, "dependsOn");
|
|
189651
|
+
if (value === void 0) return null;
|
|
189652
|
+
return items(value).map((item) => text(item)).filter((name2) => name2 !== null && name2 !== "");
|
|
189653
|
+
}
|
|
189654
|
+
function stepLabel(step) {
|
|
189655
|
+
const named = text(get(step, "displayName")) ?? text(get(step, "name"));
|
|
189656
|
+
if (named !== null) return named;
|
|
189657
|
+
const task = text(get(step, "task"));
|
|
189658
|
+
if (task !== null) return task.split("@")[0] ?? task;
|
|
189659
|
+
const checkout = text(get(step, "checkout"));
|
|
189660
|
+
if (checkout !== null) return checkout === "none" ? "No checkout" : `Check out ${checkout}`;
|
|
189661
|
+
for (const key of ["script", "bash", "pwsh", "powershell"]) {
|
|
189662
|
+
const script = text(get(step, key));
|
|
189663
|
+
if (script === null) continue;
|
|
189664
|
+
const first = script.split("\n").map((line3) => line3.trim()).find((line3) => line3 !== "" && !line3.startsWith("#")) ?? "Run a script";
|
|
189665
|
+
if (first.length <= MAX_STEP_LABEL) return first;
|
|
189666
|
+
const cut = first.slice(0, MAX_STEP_LABEL);
|
|
189667
|
+
return cut.lastIndexOf(" ") > 12 ? cut.slice(0, cut.lastIndexOf(" ")) : cut;
|
|
189668
|
+
}
|
|
189669
|
+
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();
|
|
189670
|
+
return "Step";
|
|
189671
|
+
}
|
|
189672
|
+
function stepsOf(list, templates) {
|
|
189673
|
+
const out = [];
|
|
189674
|
+
for (const step of items(list)) {
|
|
189675
|
+
const template = text(get(step, "template"));
|
|
189676
|
+
if (template !== null) templates.push({ path: template, line: step.line, column: step.column });
|
|
189677
|
+
else if (step.kind === "map") out.push({ label: cleanText(stepLabel(step), "Step"), line: step.line, column: step.column });
|
|
189678
|
+
}
|
|
189679
|
+
return out;
|
|
189680
|
+
}
|
|
189681
|
+
function poolOf(node3, fallback) {
|
|
189682
|
+
const pool = get(node3, "pool");
|
|
189683
|
+
if (pool === void 0) return fallback;
|
|
189684
|
+
return text(pool) ?? text(get(pool, "vmImage")) ?? text(get(pool, "name")) ?? fallback;
|
|
189685
|
+
}
|
|
189686
|
+
function deploymentSteps(job, templates) {
|
|
189687
|
+
const strategy = get(job, "strategy");
|
|
189688
|
+
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))));
|
|
189689
|
+
}
|
|
189690
|
+
function jobsOf(list, pool, templates) {
|
|
189691
|
+
const out = [];
|
|
189692
|
+
for (const job of items(list)) {
|
|
189693
|
+
const template = text(get(job, "template"));
|
|
189694
|
+
if (template !== null) {
|
|
189695
|
+
templates.push({ path: template, line: job.line, column: job.column });
|
|
189696
|
+
continue;
|
|
189697
|
+
}
|
|
189698
|
+
const deployment = text(get(job, "deployment"));
|
|
189699
|
+
const name2 = deployment ?? text(get(job, "job"));
|
|
189700
|
+
if (name2 === null) continue;
|
|
189701
|
+
const strategy = get(job, "strategy");
|
|
189702
|
+
const matrix = entries(get(strategy, "matrix")).length;
|
|
189703
|
+
const parallel = Number(text(get(strategy, "parallel")));
|
|
189704
|
+
const environment = get(job, "environment");
|
|
189705
|
+
out.push({
|
|
189706
|
+
name: name2,
|
|
189707
|
+
label: cleanText(text(get(job, "displayName")) ?? name2, name2),
|
|
189708
|
+
dependsOn: dependsOnOf2(job),
|
|
189709
|
+
conditional: get(job, "condition") !== void 0,
|
|
189710
|
+
environment: deployment === null ? null : text(environment) ?? text(get(environment, "name")),
|
|
189711
|
+
pool: poolOf(job, pool),
|
|
189712
|
+
runs: matrix > 1 ? matrix : Number.isInteger(parallel) && parallel > 1 ? parallel : 1,
|
|
189713
|
+
matrix: matrix > 1,
|
|
189714
|
+
steps: deployment === null ? stepsOf(get(job, "steps"), templates) : deploymentSteps(job, templates),
|
|
189715
|
+
line: job.line,
|
|
189716
|
+
column: job.column
|
|
189717
|
+
});
|
|
189718
|
+
}
|
|
189719
|
+
return out;
|
|
189720
|
+
}
|
|
189721
|
+
function readPipeline(root) {
|
|
189722
|
+
const templates = [];
|
|
189723
|
+
const extended2 = text(get(get(root, "extends"), "template"));
|
|
189724
|
+
if (extended2 !== null) {
|
|
189725
|
+
const at3 = root.kind === "map" ? root.entries.find((entry2) => entry2.key === "extends") : void 0;
|
|
189726
|
+
templates.push({ path: extended2, line: at3?.line ?? 1, column: at3?.column ?? 1 });
|
|
189727
|
+
}
|
|
189728
|
+
const pool = poolOf(root, null);
|
|
189729
|
+
if (get(root, "stages") !== void 0) {
|
|
189730
|
+
const stages = [];
|
|
189731
|
+
for (const stage of items(get(root, "stages"))) {
|
|
189732
|
+
const template = text(get(stage, "template"));
|
|
189733
|
+
if (template !== null) {
|
|
189734
|
+
templates.push({ path: template, line: stage.line, column: stage.column });
|
|
189735
|
+
continue;
|
|
189736
|
+
}
|
|
189737
|
+
const name2 = text(get(stage, "stage"));
|
|
189738
|
+
if (name2 === null) continue;
|
|
189739
|
+
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 });
|
|
189740
|
+
}
|
|
189741
|
+
return { stages, shape: "stages", templates };
|
|
189742
|
+
}
|
|
189743
|
+
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 };
|
|
189744
|
+
const steps = stepsOf(get(root, "steps"), templates);
|
|
189745
|
+
const job = { name: "Job", label: "Job", dependsOn: null, conditional: false, environment: null, pool, runs: 1, matrix: false, steps, line: 1, column: 1 };
|
|
189746
|
+
return { stages: steps.length === 0 ? [] : [{ name: "", label: "", dependsOn: [], conditional: false, jobs: [job], line: 1, column: 1 }], shape: "steps", templates };
|
|
189747
|
+
}
|
|
189748
|
+
var MAX_STEP_LABEL;
|
|
189749
|
+
var init_pipeline = __esm({
|
|
189750
|
+
"../../packages/diagrams/src/importers/azure-pipelines/pipeline.ts"() {
|
|
189751
|
+
"use strict";
|
|
189752
|
+
init_shared2();
|
|
189753
|
+
init_yaml();
|
|
189754
|
+
MAX_STEP_LABEL = 48;
|
|
189755
|
+
}
|
|
189756
|
+
});
|
|
189757
|
+
|
|
189758
|
+
// ../../packages/diagrams/src/importers/azure-pipelines/index.ts
|
|
189759
|
+
function subOf(job, stage) {
|
|
189760
|
+
const parts = [
|
|
189761
|
+
job.conditional || stage.conditional ? "when its condition holds" : null,
|
|
189762
|
+
job.runs > 1 ? `${job.runs} ${job.matrix ? "matrix" : "parallel"} runs` : null,
|
|
189763
|
+
job.environment === null ? null : `deploys to ${job.environment}`,
|
|
189764
|
+
job.pool,
|
|
189765
|
+
job.steps.length === 0 ? null : countOf2(job.steps.length, "step")
|
|
189766
|
+
].filter((part) => part !== null);
|
|
189767
|
+
return parts.length === 0 ? null : cleanText(parts.join(", "));
|
|
189768
|
+
}
|
|
189769
|
+
function readAzurePipelines(source, context) {
|
|
189770
|
+
const read = parseYaml(source);
|
|
189771
|
+
if (read.error !== null) {
|
|
189772
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
189773
|
+
return null;
|
|
189774
|
+
}
|
|
189775
|
+
const root = read.documents.find((document2) => document2.root?.kind === "map")?.root ?? null;
|
|
189776
|
+
const pipeline = root === null ? null : readPipeline(root);
|
|
189777
|
+
const firstTemplate = pipeline?.templates[0];
|
|
189778
|
+
if (pipeline !== null && firstTemplate !== void 0) {
|
|
189779
|
+
const paths = [...new Set(pipeline.templates.map((template) => cleanText(template.path)))];
|
|
189780
|
+
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.");
|
|
189781
|
+
}
|
|
189782
|
+
if (pipeline === null || pipeline.stages.every((stage) => stage.jobs.length === 0)) {
|
|
189783
|
+
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:.");
|
|
189784
|
+
return null;
|
|
189785
|
+
}
|
|
189786
|
+
const stages = pipeline.stages.filter((stage) => stage.jobs.length > 0);
|
|
189787
|
+
const nodes = [{ key: START_KEY, type: "terminal", label: "Pipeline starts" }];
|
|
189788
|
+
const groups = [];
|
|
189789
|
+
const edges = [];
|
|
189790
|
+
const unresolved = [];
|
|
189791
|
+
if (pipeline.shape === "steps") {
|
|
189792
|
+
const job = stages[0]?.jobs[0];
|
|
189793
|
+
job.steps.forEach((step, index2) => nodes.push({ key: `step:${index2}`, type: "step", label: step.label, idHint: `step_${index2 + 1}` }));
|
|
189794
|
+
job.steps.forEach((_step, index2) => edges.push({ from: index2 === 0 ? START_KEY : `step:${index2 - 1}`, to: `step:${index2}` }));
|
|
189795
|
+
return writeFlow(
|
|
189796
|
+
{
|
|
189797
|
+
title: context.title ?? "Azure pipeline",
|
|
189798
|
+
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.`,
|
|
189799
|
+
direction: "down",
|
|
189800
|
+
nodes,
|
|
189801
|
+
groups,
|
|
189802
|
+
edges,
|
|
189803
|
+
noun: "steps",
|
|
189804
|
+
coverage: { noun: "steps", total: job.steps.length, drawn: job.steps.length, summarised: 0 },
|
|
189805
|
+
advice: "Give each step a displayName, so the picture says what it does."
|
|
189806
|
+
},
|
|
189807
|
+
context.report
|
|
189808
|
+
);
|
|
189809
|
+
}
|
|
189810
|
+
const keyOf5 = (stage, job) => pipeline.shape === "jobs" ? `job:${job.name}` : `job:${stage.name}.${job.name}`;
|
|
189811
|
+
const stageNames = new Set(pipeline.stages.map((stage) => stage.name));
|
|
189812
|
+
for (const stage of stages) {
|
|
189813
|
+
if (pipeline.shape === "stages") groups.push({ key: `stage:${stage.name}`, label: stage.label, type: "ci-cd", idHint: `stage_${hintOf(stage.name)}` });
|
|
189814
|
+
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) });
|
|
189815
|
+
}
|
|
189816
|
+
const inStage = (stage, job) => (job.dependsOn ?? []).filter((name2) => stage.jobs.some((other) => other.name === name2));
|
|
189817
|
+
const firstJobs = (stage) => stage.jobs.filter((job) => inStage(stage, job).length === 0);
|
|
189818
|
+
const lastJobs = (stage) => stage.jobs.filter((job) => !stage.jobs.some((other) => inStage(stage, other).includes(job.name)));
|
|
189819
|
+
stages.forEach((stage, index2) => {
|
|
189820
|
+
const dashed = (job) => job.conditional || stage.conditional ? "-->" : void 0;
|
|
189821
|
+
const link2 = (from, job) => {
|
|
189822
|
+
const arrow = dashed(job);
|
|
189823
|
+
edges.push({ from, to: keyOf5(stage, job), ...arrow === void 0 ? {} : { arrow } });
|
|
189824
|
+
};
|
|
189825
|
+
const before = stage.dependsOn === null ? index2 === 0 ? [] : [stages[index2 - 1]] : stage.dependsOn.flatMap((name2) => {
|
|
189826
|
+
const found = stages.find((other) => other.name === name2);
|
|
189827
|
+
if (found === void 0 && !stageNames.has(name2)) unresolved.push({ name: `stage ${name2}`, line: stage.line, column: stage.column });
|
|
189828
|
+
return found === void 0 ? [] : [found];
|
|
189829
|
+
});
|
|
189830
|
+
for (const job of stage.jobs) {
|
|
189831
|
+
for (const name2 of job.dependsOn ?? []) {
|
|
189832
|
+
if (stage.jobs.some((other) => other.name === name2)) link2(keyOf5(stage, stage.jobs.find((other) => other.name === name2)), job);
|
|
189833
|
+
else unresolved.push({ name: `job ${name2}`, line: job.line, column: job.column });
|
|
189834
|
+
}
|
|
189835
|
+
}
|
|
189836
|
+
for (const job of firstJobs(stage)) {
|
|
189837
|
+
if (before.length === 0) link2(START_KEY, job);
|
|
189838
|
+
for (const previous of before) for (const last of lastJobs(previous)) link2(keyOf5(previous, last), job);
|
|
189839
|
+
}
|
|
189840
|
+
});
|
|
189841
|
+
const first = unresolved[0];
|
|
189842
|
+
if (first !== void 0) {
|
|
189843
|
+
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.");
|
|
189844
|
+
}
|
|
189845
|
+
const jobs = stages.reduce((sum, stage) => sum + stage.jobs.length, 0);
|
|
189846
|
+
const deployments = stages.reduce((sum, stage) => sum + stage.jobs.filter((job) => job.environment !== null).length, 0);
|
|
189847
|
+
return writeFlow(
|
|
189848
|
+
{
|
|
189849
|
+
title: context.title ?? "Azure pipeline",
|
|
189850
|
+
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.`,
|
|
189851
|
+
direction: "down",
|
|
189852
|
+
nodes,
|
|
189853
|
+
groups,
|
|
189854
|
+
edges,
|
|
189855
|
+
noun: "jobs",
|
|
189856
|
+
capSpan: (key) => {
|
|
189857
|
+
const job = stages.flatMap((stage) => stage.jobs.map((entry2) => ({ key: keyOf5(stage, entry2), entry: entry2 }))).find((candidate2) => candidate2.key === key)?.entry;
|
|
189858
|
+
return spanAt3(job?.line ?? 1, job?.column ?? 1);
|
|
189859
|
+
},
|
|
189860
|
+
coverage: { noun: "jobs", total: jobs, drawn: jobs, summarised: 0 },
|
|
189861
|
+
advice: "Give each stage and job a displayName, so the picture says what it does."
|
|
189862
|
+
},
|
|
189863
|
+
context.report
|
|
189864
|
+
);
|
|
189865
|
+
}
|
|
189866
|
+
var hintOf, START_KEY, azurePipelinesImporter;
|
|
189867
|
+
var init_azure_pipelines = __esm({
|
|
189868
|
+
"../../packages/diagrams/src/importers/azure-pipelines/index.ts"() {
|
|
189869
|
+
"use strict";
|
|
189870
|
+
init_core();
|
|
189871
|
+
init_shared2();
|
|
189872
|
+
init_yaml();
|
|
189873
|
+
init_pipeline();
|
|
189874
|
+
hintOf = (name2) => name2.replace(/([a-z0-9])([A-Z][a-z])/g, "$1_$2").toLowerCase();
|
|
189875
|
+
START_KEY = "pipeline";
|
|
189876
|
+
azurePipelinesImporter = { format: "azure-pipelines", kinds: ["flow"], joins: null, extensions: [], read: readAzurePipelines };
|
|
189877
|
+
}
|
|
189878
|
+
});
|
|
189879
|
+
|
|
188818
189880
|
// ../../packages/diagrams/src/importers/backstage/entities.ts
|
|
188819
|
-
function
|
|
189881
|
+
function refOf2(written3, fallbackKind, namespace) {
|
|
188820
189882
|
const colon = written3.indexOf(":");
|
|
188821
189883
|
const kind = colon === -1 ? fallbackKind : written3.slice(0, colon).toLowerCase();
|
|
188822
189884
|
const rest = colon === -1 ? written3 : written3.slice(colon + 1);
|
|
@@ -188833,9 +189895,9 @@ function readEntity2(root) {
|
|
|
188833
189895
|
const spec = get(root, "spec");
|
|
188834
189896
|
const one = (key, fallback) => {
|
|
188835
189897
|
const value = text(get(spec, key));
|
|
188836
|
-
return value === null || value === "" ? null :
|
|
189898
|
+
return value === null || value === "" ? null : refOf2(value, fallback, namespace);
|
|
188837
189899
|
};
|
|
188838
|
-
const many = (key, fallback) => names5(get(spec, key)).map((value) =>
|
|
189900
|
+
const many = (key, fallback) => names5(get(spec, key)).map((value) => refOf2(value, fallback, namespace));
|
|
188839
189901
|
return {
|
|
188840
189902
|
kind,
|
|
188841
189903
|
ref: `${kind.toLowerCase()}:${namespace}/${name2}`,
|
|
@@ -188856,14 +189918,14 @@ function readEntity2(root) {
|
|
|
188856
189918
|
column: root.column
|
|
188857
189919
|
};
|
|
188858
189920
|
}
|
|
188859
|
-
var DRAWN_KINDS2, QUIET_KINDS2,
|
|
189921
|
+
var DRAWN_KINDS2, QUIET_KINDS2, nameOfRef2;
|
|
188860
189922
|
var init_entities = __esm({
|
|
188861
189923
|
"../../packages/diagrams/src/importers/backstage/entities.ts"() {
|
|
188862
189924
|
"use strict";
|
|
188863
189925
|
init_yaml();
|
|
188864
189926
|
DRAWN_KINDS2 = ["Domain", "System", "Component", "API", "Resource", "Group", "User"];
|
|
188865
189927
|
QUIET_KINDS2 = /* @__PURE__ */ new Set(["Location"]);
|
|
188866
|
-
|
|
189928
|
+
nameOfRef2 = (ref) => ref.slice(ref.lastIndexOf("/") + 1);
|
|
188867
189929
|
}
|
|
188868
189930
|
});
|
|
188869
189931
|
|
|
@@ -188877,7 +189939,7 @@ function brandOf(...texts) {
|
|
|
188877
189939
|
}
|
|
188878
189940
|
function boxOf3(entity, byOwner) {
|
|
188879
189941
|
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 ${
|
|
189942
|
+
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
189943
|
const label = entity.title ?? entity.name;
|
|
188882
189944
|
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
189945
|
if (entity.kind === "Resource") {
|
|
@@ -188920,37 +189982,37 @@ function readBackstage(textIn, context) {
|
|
|
188920
189982
|
for (const group2 of entities.filter((entity) => entity.kind === "Group")) {
|
|
188921
189983
|
const members2 = entities.filter((entity) => entity.kind === "User" && entity.memberOf.includes(group2.ref)).map((user) => user.title ?? user.name);
|
|
188922
189984
|
const said = members2.length === 0 ? null : members2.length <= 2 ? members2.join(", ") : countOf2(members2.length, "member");
|
|
188923
|
-
groups.push({ key: group2.ref, label: group2.title ?? group2.name, sub: cleanText(["Group", group2.type, said].filter((part) => part !== null).join(", ")), icon: "lucide:users", parent: group2.parent !== null && byRef.has(group2.parent) ? group2.parent : null, idHint: group2.name });
|
|
189985
|
+
groups.push({ key: group2.ref, label: group2.title ?? group2.name, sub: cleanText(["Group", group2.type, said].filter((part) => part !== null).join(", ")), type: "identity-boundary", icon: "lucide:users", parent: group2.parent !== null && byRef.has(group2.parent) ? group2.parent : null, idHint: group2.name });
|
|
188924
189986
|
}
|
|
188925
189987
|
for (const entity of boxes2) if (entity.owner !== null && byRef.get(entity.owner)?.kind === "Group") frameOf3.set(entity.ref, entity.owner);
|
|
188926
189988
|
} 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 ${
|
|
189989
|
+
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)}`}`), type: "resource-group", tone: "blue", icon: "lucide:map", idHint: domain2.name });
|
|
189990
|
+
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)}`}`), type: "app-tier", icon: "lucide:boxes", parent: system.domain !== null && byRef.has(system.domain) ? system.domain : null, idHint: system.name });
|
|
188929
189991
|
for (const entity of boxes2) if (entity.system !== null && byRef.get(entity.system)?.kind === "System") frameOf3.set(entity.ref, entity.system);
|
|
188930
189992
|
}
|
|
188931
189993
|
const order = { Component: 0, API: 1, Resource: 2 };
|
|
188932
189994
|
const ordered = [...boxes2].sort((a, b) => order[a.kind] - order[b.kind]);
|
|
188933
189995
|
const nodes = ordered.map((entity) => {
|
|
188934
189996
|
const box = boxOf3(entity, byOwner);
|
|
188935
|
-
const system = byOwner && entity.system !== null ? `, in ${
|
|
189997
|
+
const system = byOwner && entity.system !== null ? `, in ${nameOfRef2(entity.system)}` : "";
|
|
188936
189998
|
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
189999
|
});
|
|
188938
190000
|
const drawn = new Set(nodes.map((node3) => node3.key));
|
|
188939
190001
|
const edges = [];
|
|
188940
190002
|
const unknown2 = /* @__PURE__ */ new Set();
|
|
188941
|
-
const link2 = (from, to, label, arrow) => {
|
|
190003
|
+
const link2 = (from, to, label, verb, arrow) => {
|
|
188942
190004
|
if (!drawn.has(to)) {
|
|
188943
190005
|
if (!byRef.has(to)) unknown2.add(to);
|
|
188944
190006
|
return;
|
|
188945
190007
|
}
|
|
188946
|
-
edges.push({ from, to, label, ...arrow === void 0 ? {} : { arrow } });
|
|
190008
|
+
edges.push({ from, to, label, verb, ...arrow === void 0 ? {} : { arrow } });
|
|
188947
190009
|
};
|
|
188948
190010
|
for (const entity of ordered) {
|
|
188949
|
-
for (const api of entity.providesApis) link2(entity.ref, api, "provides");
|
|
188950
|
-
for (const api of entity.consumesApis) link2(entity.ref, api, "consumes");
|
|
188951
|
-
for (const target of entity.dependsOn) link2(entity.ref, target, "depends on");
|
|
188952
|
-
for (const source of entity.dependencyOf) if (drawn.has(source)) link2(source, entity.ref, "depends on");
|
|
188953
|
-
if (entity.kind === "Component" && entity.parent !== null) link2(entity.ref, entity.parent, "part of", "-->");
|
|
190011
|
+
for (const api of entity.providesApis) link2(entity.ref, api, "provides", "provides");
|
|
190012
|
+
for (const api of entity.consumesApis) link2(entity.ref, api, "consumes", "consumes");
|
|
190013
|
+
for (const target of entity.dependsOn) link2(entity.ref, target, "depends on", "depends-on");
|
|
190014
|
+
for (const source of entity.dependencyOf) if (drawn.has(source)) link2(source, entity.ref, "depends on", "depends-on");
|
|
190015
|
+
if (entity.kind === "Component" && entity.parent !== null) link2(entity.ref, entity.parent, "part of", null, "-->");
|
|
188954
190016
|
}
|
|
188955
190017
|
if (unknown2.size > 0) {
|
|
188956
190018
|
context.report.add(DIAGNOSTIC_CODES.importUnresolved, START, `${countOf2(unknown2.size, "relation")} name${unknown2.size === 1 ? "s an entity" : " entities"} the files do not describe, so no arrow is drawn: ${[...unknown2].slice(0, 3).join(", ")}.`, "Send the catalog-info.yaml files that describe them, or check that each reference names its kind, such as resource:orders-db.");
|
|
@@ -189225,14 +190287,14 @@ function templateItems(template, offsetOf) {
|
|
|
189225
190287
|
}
|
|
189226
190288
|
return { items: items2, empty };
|
|
189227
190289
|
}
|
|
189228
|
-
var
|
|
190290
|
+
var MAX_DEPTH14, PSEUDO, entryOf, scalarOf, itemsOf, subNames, Template;
|
|
189229
190291
|
var init_template = __esm({
|
|
189230
190292
|
"../../packages/diagrams/src/importers/cloudformation/template.ts"() {
|
|
189231
190293
|
"use strict";
|
|
189232
190294
|
init_attributes();
|
|
189233
190295
|
init_type_names();
|
|
189234
190296
|
init_value();
|
|
189235
|
-
|
|
190297
|
+
MAX_DEPTH14 = 16;
|
|
189236
190298
|
PSEUDO = {
|
|
189237
190299
|
"AWS::Region": "region",
|
|
189238
190300
|
"AWS::AccountId": "account",
|
|
@@ -189264,7 +190326,7 @@ var init_template = __esm({
|
|
|
189264
190326
|
conditionMemo = /* @__PURE__ */ new Map();
|
|
189265
190327
|
/** The value of a node as far as the template's defaults give it. */
|
|
189266
190328
|
evaluate(node3, depth = 0) {
|
|
189267
|
-
if (node3 === void 0 || depth >
|
|
190329
|
+
if (node3 === void 0 || depth > MAX_DEPTH14) return new Unknown("value");
|
|
189268
190330
|
const intrinsic = intrinsicOf(node3);
|
|
189269
190331
|
if (intrinsic !== null) return this.call(intrinsic, depth);
|
|
189270
190332
|
if (node3.kind === "scalar") return node3.isNull ? null : node3.value;
|
|
@@ -189372,7 +190434,7 @@ var init_template = __esm({
|
|
|
189372
190434
|
}
|
|
189373
190435
|
/** The resources a node names: `Ref`, `GetAtt`, and `${ }` of `Sub`, and only the branch an `If` takes when its condition is known. */
|
|
189374
190436
|
refs(node3, depth = 0) {
|
|
189375
|
-
if (node3 === void 0 || depth >
|
|
190437
|
+
if (node3 === void 0 || depth > MAX_DEPTH14) return [];
|
|
189376
190438
|
const intrinsic = intrinsicOf(node3);
|
|
189377
190439
|
if (intrinsic !== null) {
|
|
189378
190440
|
const argument = intrinsic.argument;
|
|
@@ -189409,7 +190471,7 @@ var init_template = __esm({
|
|
|
189409
190471
|
}
|
|
189410
190472
|
/** Every reference a node holds, by the keys that lead to it. */
|
|
189411
190473
|
refsByPath(node3, path, out, depth = 0) {
|
|
189412
|
-
if (node3 === void 0 || depth >
|
|
190474
|
+
if (node3 === void 0 || depth > MAX_DEPTH14) return;
|
|
189413
190475
|
if (intrinsicOf(node3) === null && node3.kind === "map") {
|
|
189414
190476
|
for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
|
|
189415
190477
|
return;
|
|
@@ -189426,17 +190488,17 @@ var init_template = __esm({
|
|
|
189426
190488
|
});
|
|
189427
190489
|
|
|
189428
190490
|
// ../../packages/diagrams/src/importers/cloudformation/index.ts
|
|
189429
|
-
function
|
|
190491
|
+
function nodeOf3(value, depth = 0) {
|
|
189430
190492
|
const at3 = { line: 1, column: 1 };
|
|
189431
190493
|
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:
|
|
190494
|
+
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) => nodeOf3(item, depth + 1)), ...at3 };
|
|
190495
|
+
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value: nodeOf3(entry2, depth + 1), ...at3 })), ...at3 };
|
|
189434
190496
|
return { kind: "scalar", value: String(value), quoted: typeof value === "string", isNull: false, ...at3 };
|
|
189435
190497
|
}
|
|
189436
190498
|
function readFile(text3) {
|
|
189437
190499
|
if (/^\s*\{/.test(text3)) {
|
|
189438
190500
|
try {
|
|
189439
|
-
return { root:
|
|
190501
|
+
return { root: nodeOf3(JSON.parse(text3)), problem: null };
|
|
189440
190502
|
} catch (error62) {
|
|
189441
190503
|
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
190504
|
}
|
|
@@ -189669,7 +190731,7 @@ function readable(segment, stack) {
|
|
|
189669
190731
|
const at3 = stack.length >= 3 ? own2.indexOf(stack) : -1;
|
|
189670
190732
|
return (at3 > 0 ? own2.slice(0, at3) : own2) || segment;
|
|
189671
190733
|
}
|
|
189672
|
-
function frameModules2(tree, classes,
|
|
190734
|
+
function frameModules2(tree, classes, startOf4) {
|
|
189673
190735
|
const scopes = /* @__PURE__ */ new Map();
|
|
189674
190736
|
const used = /* @__PURE__ */ new Set();
|
|
189675
190737
|
const modules = [];
|
|
@@ -189684,7 +190746,7 @@ function frameModules2(tree, classes, startOf3) {
|
|
|
189684
190746
|
const kind = tree.frames.get(path) ?? "Construct";
|
|
189685
190747
|
const fqn = classes.get(path) ?? "";
|
|
189686
190748
|
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:
|
|
190749
|
+
modules.push({ scope, name: path, label: id, instance: null, source: own2, start: startOf4(path), noun: kind });
|
|
189688
190750
|
}
|
|
189689
190751
|
return { modules, scopes };
|
|
189690
190752
|
}
|
|
@@ -189849,7 +190911,7 @@ function readCdk(joined2, context) {
|
|
|
189849
190911
|
}
|
|
189850
190912
|
let hops = 0;
|
|
189851
190913
|
const refsOf = (read, node3) => {
|
|
189852
|
-
if (node3 === void 0 || hops >=
|
|
190914
|
+
if (node3 === void 0 || hops >= MAX_HOPS2) return [];
|
|
189853
190915
|
hops += 1;
|
|
189854
190916
|
try {
|
|
189855
190917
|
return read.model.refs(node3).map((ref) => read.names.get(ref) ?? ref);
|
|
@@ -189915,12 +190977,12 @@ function readCdk(joined2, context) {
|
|
|
189915
190977
|
const maker = makers.get(item.name) ?? null;
|
|
189916
190978
|
if ((labelCount.get(item.label) ?? 0) > 1 && maker !== null && !item.label.startsWith(`${maker}_`)) items2[position] = { ...item, label: `${maker}_${item.label}` };
|
|
189917
190979
|
}
|
|
189918
|
-
const
|
|
190980
|
+
const startOf4 = (path) => {
|
|
189919
190981
|
const owner = reads.find((read) => read.template.stackPath === path) ?? reads.find((read) => read.template.topPath === path.split("/")[0]);
|
|
189920
190982
|
const at3 = owner === void 0 ? -1 : owner.template.file.text.indexOf(`"${path}/`);
|
|
189921
190983
|
return owner === void 0 ? 0 : owner.template.file.start + Math.max(0, at3);
|
|
189922
190984
|
};
|
|
189923
|
-
const { modules, scopes } = frameModules2(tree, assembly.classes,
|
|
190985
|
+
const { modules, scopes } = frameModules2(tree, assembly.classes, startOf4);
|
|
189924
190986
|
const scoped = items2.map((item) => {
|
|
189925
190987
|
const frames = placements.get(item.name) ?? [];
|
|
189926
190988
|
const innermost = frames[frames.length - 1];
|
|
@@ -189950,7 +191012,7 @@ function readCdk(joined2, context) {
|
|
|
189950
191012
|
framing: "construct"
|
|
189951
191013
|
});
|
|
189952
191014
|
}
|
|
189953
|
-
var LISTED9,
|
|
191015
|
+
var LISTED9, MAX_HOPS2, METADATA_TYPE, withoutHash, cdkImporter;
|
|
189954
191016
|
var init_cdk = __esm({
|
|
189955
191017
|
"../../packages/diagrams/src/importers/cdk/index.ts"() {
|
|
189956
191018
|
"use strict";
|
|
@@ -189964,7 +191026,7 @@ var init_cdk = __esm({
|
|
|
189964
191026
|
init_assembly();
|
|
189965
191027
|
init_constructs();
|
|
189966
191028
|
LISTED9 = 3;
|
|
189967
|
-
|
|
191029
|
+
MAX_HOPS2 = 8;
|
|
189968
191030
|
METADATA_TYPE = "AWS::CDK::Metadata";
|
|
189969
191031
|
withoutHash = (logical) => logical.replace(/[0-9A-F]{8}$/, "") || logical;
|
|
189970
191032
|
cdkImporter = { format: "cdk", kinds: ["flow"], joins: "\n", extensions: [".json", ".yaml", ".yml", ".out"], read: readCdk };
|
|
@@ -190119,17 +191181,17 @@ var init_services2 = __esm({
|
|
|
190119
191181
|
});
|
|
190120
191182
|
|
|
190121
191183
|
// ../../packages/diagrams/src/importers/compose/index.ts
|
|
190122
|
-
function
|
|
191184
|
+
function subOf2(service) {
|
|
190123
191185
|
const runs = service.image ?? (service.build === null ? null : `build ${service.build}`);
|
|
190124
191186
|
const ports = service.ports.length === 0 ? null : `${service.ports.length === 1 ? "port" : "ports"} ${service.ports.join(", ")}`;
|
|
190125
191187
|
const replicas = service.replicas === null || service.replicas === "1" ? null : `${service.replicas} replicas`;
|
|
190126
191188
|
const parts = [runs, ports, replicas].filter((part) => part !== null);
|
|
190127
191189
|
return parts.length === 0 ? null : parts.join(", ");
|
|
190128
191190
|
}
|
|
190129
|
-
function
|
|
191191
|
+
function nodeOf4(service, group2) {
|
|
190130
191192
|
const look = (service.image === null ? null : imageLook(service.image)) ?? imageLook(service.name);
|
|
190131
191193
|
const type = look?.type ?? "service";
|
|
190132
|
-
return { key: `service:${service.name}`, type, label: service.name, sub:
|
|
191194
|
+
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
191195
|
}
|
|
190134
191196
|
function groupsOf(services, networks) {
|
|
190135
191197
|
const home = /* @__PURE__ */ new Map();
|
|
@@ -190160,7 +191222,7 @@ function edgesOf2(services, volumes) {
|
|
|
190160
191222
|
for (const other of services) {
|
|
190161
191223
|
if (other.name !== service.name && service.environment.some((value) => namesHost2(value, other.name))) edges.push({ from: `service:${service.name}`, to: `service:${other.name}` });
|
|
190162
191224
|
}
|
|
190163
|
-
for (const volume of service.volumes) if (volumes.has(volume)) edges.push({ from: `service:${service.name}`, to: `volume:${volume}`, label: "mounts" });
|
|
191225
|
+
for (const volume of service.volumes) if (volumes.has(volume)) edges.push({ from: `service:${service.name}`, to: `volume:${volume}`, label: "mounts", verb: "mounts" });
|
|
190164
191226
|
}
|
|
190165
191227
|
return edges;
|
|
190166
191228
|
}
|
|
@@ -190187,7 +191249,7 @@ function readCompose(source, context) {
|
|
|
190187
191249
|
const mounted = new Set(services.flatMap((service) => service.volumes));
|
|
190188
191250
|
const volumes = declared(root, "volumes").filter((volume) => mounted.has(volume));
|
|
190189
191251
|
const nodes = [
|
|
190190
|
-
...services.map((service) =>
|
|
191252
|
+
...services.map((service) => nodeOf4(service, home.get(service.name) ?? null)),
|
|
190191
191253
|
...volumes.map((volume) => ({ key: `volume:${volume}`, type: "storage", label: volume, sub: "Named volume", idHint: `${volume}_volume` }))
|
|
190192
191254
|
];
|
|
190193
191255
|
const name2 = text(get(root, "name"));
|
|
@@ -191876,12 +192938,12 @@ function helmFrames(manifests) {
|
|
|
191876
192938
|
const release = releaseOf(manifest);
|
|
191877
192939
|
const chart = chartLabel(manifest);
|
|
191878
192940
|
const partOf2 = manifest.meta.get("app.kubernetes.io/part-of");
|
|
191879
|
-
if (partOf2 !== void 0 && partOf2 !== "" && partOf2 !== release) frames.push({ key: `part-of:${partOf2}`, label: partOf2, sub: "Application", icon: "lucide:boxes", idHint: partOf2 });
|
|
192941
|
+
if (partOf2 !== void 0 && partOf2 !== "" && partOf2 !== release) frames.push({ key: `part-of:${partOf2}`, label: partOf2, sub: "Application", icon: "lucide:boxes", type: "app-tier", idHint: partOf2 });
|
|
191880
192942
|
if (release === null) return frames;
|
|
191881
192943
|
const several = (charts.get(release)?.size ?? 0) > 1;
|
|
191882
192944
|
const only = several || chart === null ? null : chart;
|
|
191883
|
-
frames.push({ key: `release:${release}`, label: release, sub: cleanText(only === null ? "Release" : `Release of ${only.name}${only.version === null ? "" : ` ${only.version}`}`), icon: "simple:helm", idHint: release });
|
|
191884
|
-
if (several && chart !== null) frames.push({ key: `chart:${release}/${chart.name}`, label: chart.name, sub: cleanText(`Chart${chart.version === null ? "" : ` ${chart.version}`}`), icon: "lucide:package", idHint: chart.name });
|
|
192945
|
+
frames.push({ key: `release:${release}`, label: release, sub: cleanText(only === null ? "Release" : `Release of ${only.name}${only.version === null ? "" : ` ${only.version}`}`), icon: "simple:helm", type: "resource-group", tone: "blue", idHint: release });
|
|
192946
|
+
if (several && chart !== null) frames.push({ key: `chart:${release}/${chart.name}`, label: chart.name, sub: cleanText(`Chart${chart.version === null ? "" : ` ${chart.version}`}`), icon: "lucide:package", type: "resource-group", idHint: chart.name });
|
|
191885
192947
|
return frames;
|
|
191886
192948
|
};
|
|
191887
192949
|
}
|
|
@@ -191942,8 +193004,8 @@ function actionLabel(uses) {
|
|
|
191942
193004
|
}
|
|
191943
193005
|
function commandLabel(run3) {
|
|
191944
193006
|
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,
|
|
193007
|
+
if (first.length <= MAX_STEP_LABEL2) return first;
|
|
193008
|
+
const cut = first.slice(0, MAX_STEP_LABEL2);
|
|
191947
193009
|
const space = cut.lastIndexOf(" ");
|
|
191948
193010
|
return space > 12 ? cut.slice(0, space) : cut;
|
|
191949
193011
|
}
|
|
@@ -192015,13 +193077,13 @@ function triggerOf(root) {
|
|
|
192015
193077
|
const short3 = `${words2.map((word2) => word2.short).join(" or ")}${more}`;
|
|
192016
193078
|
return { label: cleanText(`${short3.charAt(0).toUpperCase()}${short3.slice(1)}`), sentence: cleanText(`${words2.map((word2) => word2.long).join(" or ")}${more}`) };
|
|
192017
193079
|
}
|
|
192018
|
-
var
|
|
193080
|
+
var MAX_STEP_LABEL2, ACTION_ICONS, COMMAND_ICONS;
|
|
192019
193081
|
var init_workflow = __esm({
|
|
192020
193082
|
"../../packages/diagrams/src/importers/github-actions/workflow.ts"() {
|
|
192021
193083
|
"use strict";
|
|
192022
193084
|
init_shared2();
|
|
192023
193085
|
init_yaml();
|
|
192024
|
-
|
|
193086
|
+
MAX_STEP_LABEL2 = 48;
|
|
192025
193087
|
ACTION_ICONS = {
|
|
192026
193088
|
"actions/checkout": "lucide:git-branch",
|
|
192027
193089
|
"actions/setup-node": "simple:nodedotjs",
|
|
@@ -192095,7 +193157,7 @@ function stepBoxes(jobs) {
|
|
|
192095
193157
|
last.set(job.id, keys[keys.length - 1]);
|
|
192096
193158
|
}
|
|
192097
193159
|
for (const job of jobs) for (const need of job.needs) edges.push({ from: last.get(need) ?? "", to: first.get(job.id) ?? "" });
|
|
192098
|
-
const groups = jobs.map((job) => ({ key: `job:${job.id}`, label: job.label, sub: job.detail, idHint: `job_${job.id}` }));
|
|
193160
|
+
const groups = jobs.map((job) => ({ key: `job:${job.id}`, label: job.label, sub: job.detail, otherwise: "ci-cd", idHint: `job_${job.id}` }));
|
|
192099
193161
|
return { nodes, edges, groups };
|
|
192100
193162
|
}
|
|
192101
193163
|
function readWorkflow(source, context) {
|
|
@@ -192111,31 +193173,31 @@ function readWorkflow(source, context) {
|
|
|
192111
193173
|
return null;
|
|
192112
193174
|
}
|
|
192113
193175
|
const ids = new Set(jobs.map((job) => job.id));
|
|
192114
|
-
const
|
|
193176
|
+
const resolved2 = jobs.map((job) => {
|
|
192115
193177
|
const missing = job.needs.filter((need) => !ids.has(need));
|
|
192116
193178
|
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
193179
|
return missing.length === 0 ? job : { ...job, needs: job.needs.filter((need) => ids.has(need)) };
|
|
192118
193180
|
});
|
|
192119
|
-
const expanded = fitsSteps(
|
|
192120
|
-
const drawn = expanded ? stepBoxes(
|
|
193181
|
+
const expanded = fitsSteps(resolved2);
|
|
193182
|
+
const drawn = expanded ? stepBoxes(resolved2) : { ...jobBoxes(resolved2), groups: [] };
|
|
192121
193183
|
const trigger = triggerOf(root);
|
|
192122
193184
|
const firstOf = (job) => expanded ? job.steps.length === 0 ? `job:${job.id}` : `step:${job.id}:0` : `job:${job.id}`;
|
|
192123
|
-
const starts =
|
|
193185
|
+
const starts = resolved2.filter((job) => job.needs.length === 0).map((job) => ({ from: TRIGGER, to: firstOf(job) }));
|
|
192124
193186
|
const name2 = text(get(root, "name"));
|
|
192125
|
-
const depth = depthOf5(
|
|
192126
|
-
const steps =
|
|
193187
|
+
const depth = depthOf5(resolved2);
|
|
193188
|
+
const steps = resolved2.reduce((sum, job) => sum + job.steps.length, 0);
|
|
192127
193189
|
const coverage = expanded ? { noun: "steps", total: drawn.nodes.length, drawn: drawn.nodes.length, summarised: 0 } : { noun: "steps", total: steps, drawn: 0, summarised: steps };
|
|
192128
193190
|
return writeFlow(
|
|
192129
193191
|
{
|
|
192130
193192
|
title: context.title ?? name2 ?? "GitHub Actions workflow",
|
|
192131
|
-
desc: `${countOf2(
|
|
193193
|
+
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
193194
|
direction: expanded || depth > 4 ? "down" : "right",
|
|
192133
193195
|
nodes: [{ key: TRIGGER, type: "terminal", label: trigger?.label ?? "Workflow starts" }, ...drawn.nodes],
|
|
192134
193196
|
groups: drawn.groups,
|
|
192135
193197
|
edges: [...starts, ...drawn.edges],
|
|
192136
193198
|
noun: expanded ? "steps" : "jobs",
|
|
192137
193199
|
capSpan: (key) => {
|
|
192138
|
-
const job =
|
|
193200
|
+
const job = resolved2.find((candidate2) => key === `job:${candidate2.id}`);
|
|
192139
193201
|
return spanAt3(job?.line ?? 1, job?.column ?? 1);
|
|
192140
193202
|
},
|
|
192141
193203
|
coverage,
|
|
@@ -192159,6 +193221,213 @@ var init_github_actions = __esm({
|
|
|
192159
193221
|
}
|
|
192160
193222
|
});
|
|
192161
193223
|
|
|
193224
|
+
// ../../packages/diagrams/src/importers/gitlab-ci/pipeline.ts
|
|
193225
|
+
function resolved(name2, byName, missing, depth = 0) {
|
|
193226
|
+
const own2 = byName.get(name2);
|
|
193227
|
+
const out = /* @__PURE__ */ new Map();
|
|
193228
|
+
if (own2 === void 0 || depth > MAX_EXTENDS) return out;
|
|
193229
|
+
for (const parent of names5(get(own2, "extends"))) {
|
|
193230
|
+
if (!byName.has(parent)) {
|
|
193231
|
+
if (!missing.includes(parent)) missing.push(parent);
|
|
193232
|
+
continue;
|
|
193233
|
+
}
|
|
193234
|
+
for (const [key, value] of resolved(parent, byName, missing, depth + 1)) out.set(key, value);
|
|
193235
|
+
}
|
|
193236
|
+
for (const entry2 of entries(own2)) if (entry2.key !== "extends") out.set(entry2.key, entry2.value);
|
|
193237
|
+
return out;
|
|
193238
|
+
}
|
|
193239
|
+
function runsOf5(parallel) {
|
|
193240
|
+
const count3 = Number(text(parallel));
|
|
193241
|
+
if (Number.isInteger(count3) && count3 > 1) return { runs: count3, matrix: false };
|
|
193242
|
+
const matrix = items(get(parallel, "matrix"));
|
|
193243
|
+
if (matrix.length === 0) return { runs: 1, matrix: false };
|
|
193244
|
+
const runs = matrix.reduce((sum, entry2) => sum + entries(entry2).reduce((product, variable) => product * Math.max(1, items(variable.value).length), 1), 0);
|
|
193245
|
+
return { runs, matrix: true };
|
|
193246
|
+
}
|
|
193247
|
+
function startOf3(keys) {
|
|
193248
|
+
const when = text(keys.get("when"));
|
|
193249
|
+
if (when === "manual") return "manual";
|
|
193250
|
+
if (when === "delayed") return "delayed";
|
|
193251
|
+
if (when === "on_failure") return "on_failure";
|
|
193252
|
+
const rules = items(keys.get("rules"));
|
|
193253
|
+
if (rules.some((rule) => text(get(rule, "when")) === "manual")) return "manual";
|
|
193254
|
+
if (rules.length > 0) return "rules";
|
|
193255
|
+
if (keys.has("only") || keys.has("except")) return "only";
|
|
193256
|
+
return "always";
|
|
193257
|
+
}
|
|
193258
|
+
function triggerOf2(node3) {
|
|
193259
|
+
if (node3 === void 0) return null;
|
|
193260
|
+
const project2 = text(node3) ?? text(get(node3, "project"));
|
|
193261
|
+
if (project2 !== null) return { label: project2, child: false };
|
|
193262
|
+
const include = get(node3, "include");
|
|
193263
|
+
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;
|
|
193264
|
+
return { label: file2 ?? "Child pipeline", child: true };
|
|
193265
|
+
}
|
|
193266
|
+
function includesOf(root) {
|
|
193267
|
+
const include = get(root, "include");
|
|
193268
|
+
return items(include).map((entry2) => {
|
|
193269
|
+
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";
|
|
193270
|
+
return { said: cleanText(said), line: entry2.line, column: entry2.column };
|
|
193271
|
+
});
|
|
193272
|
+
}
|
|
193273
|
+
function readPipeline2(root) {
|
|
193274
|
+
const byName = /* @__PURE__ */ new Map();
|
|
193275
|
+
for (const entry2 of entries(root)) if (entry2.value.kind === "map") byName.set(entry2.key, entry2.value);
|
|
193276
|
+
const written3 = names5(get(root, "stages"));
|
|
193277
|
+
const defaults = get(root, "default");
|
|
193278
|
+
const fallbackImage = text(get(defaults, "image")) ?? text(get(get(defaults, "image"), "name")) ?? text(get(root, "image")) ?? text(get(get(root, "image"), "name"));
|
|
193279
|
+
const jobs = [];
|
|
193280
|
+
for (const entry2 of entries(root)) {
|
|
193281
|
+
if (entry2.key.startsWith(".") || GLOBAL_KEYS.has(entry2.key) || entry2.value.kind !== "map") continue;
|
|
193282
|
+
const missing = [];
|
|
193283
|
+
const keys = resolved(entry2.key, byName, missing);
|
|
193284
|
+
const needsNode = keys.get("needs");
|
|
193285
|
+
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);
|
|
193286
|
+
const image = text(keys.get("image")) ?? text(get(keys.get("image"), "name")) ?? fallbackImage;
|
|
193287
|
+
const environment = text(keys.get("environment")) ?? text(get(keys.get("environment"), "name"));
|
|
193288
|
+
const allow = keys.get("allow_failure");
|
|
193289
|
+
jobs.push({
|
|
193290
|
+
name: entry2.key,
|
|
193291
|
+
stage: text(keys.get("stage")) ?? "test",
|
|
193292
|
+
needs: needs2,
|
|
193293
|
+
start: startOf3(keys),
|
|
193294
|
+
image: image === null ? null : image.split("/").pop() ?? image,
|
|
193295
|
+
...runsOf5(keys.get("parallel")),
|
|
193296
|
+
environment,
|
|
193297
|
+
trigger: triggerOf2(keys.get("trigger")),
|
|
193298
|
+
allowFailure: text(allow) === "true" || allow?.kind === "map",
|
|
193299
|
+
missingExtends: missing,
|
|
193300
|
+
line: entry2.line,
|
|
193301
|
+
column: entry2.column
|
|
193302
|
+
});
|
|
193303
|
+
}
|
|
193304
|
+
return { stages: written3.length > 0 ? written3 : [...DEFAULT_STAGES], stagesWritten: written3.length > 0, jobs, includes: includesOf(root) };
|
|
193305
|
+
}
|
|
193306
|
+
var DEFAULT_STAGES, GLOBAL_KEYS, MAX_EXTENDS;
|
|
193307
|
+
var init_pipeline2 = __esm({
|
|
193308
|
+
"../../packages/diagrams/src/importers/gitlab-ci/pipeline.ts"() {
|
|
193309
|
+
"use strict";
|
|
193310
|
+
init_shared2();
|
|
193311
|
+
init_yaml();
|
|
193312
|
+
DEFAULT_STAGES = [".pre", "build", "test", "deploy", ".post"];
|
|
193313
|
+
GLOBAL_KEYS = /* @__PURE__ */ new Set(["default", "include", "stages", "variables", "workflow", "image", "services", "cache", "before_script", "after_script", "types", "spec"]);
|
|
193314
|
+
MAX_EXTENDS = 11;
|
|
193315
|
+
}
|
|
193316
|
+
});
|
|
193317
|
+
|
|
193318
|
+
// ../../packages/diagrams/src/importers/gitlab-ci/index.ts
|
|
193319
|
+
function subOf3(job) {
|
|
193320
|
+
const parts = [
|
|
193321
|
+
START_WORDS[job.start],
|
|
193322
|
+
job.runs > 1 ? `${job.runs} ${job.matrix ? "matrix" : "parallel"} runs` : null,
|
|
193323
|
+
job.environment === null ? null : `deploys to ${job.environment}`,
|
|
193324
|
+
job.image,
|
|
193325
|
+
job.allowFailure ? "may fail" : null
|
|
193326
|
+
].filter((part) => part !== null);
|
|
193327
|
+
return parts.length === 0 ? null : cleanText(parts.join(", "));
|
|
193328
|
+
}
|
|
193329
|
+
function readGitlabCi(source, context) {
|
|
193330
|
+
const read = parseYaml(source);
|
|
193331
|
+
if (read.error !== null) {
|
|
193332
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
193333
|
+
return null;
|
|
193334
|
+
}
|
|
193335
|
+
const root = [...read.documents].reverse().find((document2) => document2.root?.kind === "map")?.root ?? null;
|
|
193336
|
+
const pipeline = root === null ? null : readPipeline2(root);
|
|
193337
|
+
if (pipeline === null || pipeline.jobs.length === 0) {
|
|
193338
|
+
const includes = pipeline?.includes.length ?? 0;
|
|
193339
|
+
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.");
|
|
193340
|
+
return null;
|
|
193341
|
+
}
|
|
193342
|
+
const firstInclude = pipeline.includes[0];
|
|
193343
|
+
if (firstInclude !== void 0) {
|
|
193344
|
+
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.");
|
|
193345
|
+
}
|
|
193346
|
+
const names8 = new Set(pipeline.jobs.map((job) => job.name));
|
|
193347
|
+
const missingExtends = pipeline.jobs.filter((job) => job.missingExtends.length > 0);
|
|
193348
|
+
const firstMissing = missingExtends[0];
|
|
193349
|
+
if (firstMissing !== void 0) {
|
|
193350
|
+
const parents = [...new Set(missingExtends.flatMap((job) => job.missingExtends))];
|
|
193351
|
+
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.");
|
|
193352
|
+
}
|
|
193353
|
+
const stages = pipeline.stages.filter((stage) => pipeline.jobs.some((job) => job.stage === stage));
|
|
193354
|
+
const unknown2 = [...new Set(pipeline.jobs.map((job) => job.stage).filter((stage) => !pipeline.stages.includes(stage)))];
|
|
193355
|
+
const firstUnknown = pipeline.jobs.find((job) => unknown2.includes(job.stage));
|
|
193356
|
+
if (firstUnknown !== void 0) {
|
|
193357
|
+
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.");
|
|
193358
|
+
}
|
|
193359
|
+
const ordered = [...stages, ...unknown2];
|
|
193360
|
+
const jobsOf2 = (stage) => pipeline.jobs.filter((job) => job.stage === stage);
|
|
193361
|
+
const nodes = [{ key: START_KEY2, type: "terminal", label: "Pipeline starts" }];
|
|
193362
|
+
const groups = [];
|
|
193363
|
+
const edges = [];
|
|
193364
|
+
const unresolvedNeeds = [];
|
|
193365
|
+
for (const stage of ordered) {
|
|
193366
|
+
groups.push({ key: `stage:${stage}`, label: cleanText(stage), type: "ci-cd", idHint: `stage_${stage.replace(/^\./, "")}` });
|
|
193367
|
+
for (const job of jobsOf2(stage)) {
|
|
193368
|
+
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 });
|
|
193369
|
+
if (job.trigger !== null) {
|
|
193370
|
+
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` });
|
|
193371
|
+
edges.push({ from: `job:${job.name}`, to: `trigger:${job.name}`, label: "triggers", verb: "triggers" });
|
|
193372
|
+
}
|
|
193373
|
+
}
|
|
193374
|
+
}
|
|
193375
|
+
for (const job of pipeline.jobs) {
|
|
193376
|
+
const arrow = job.start === "always" ? void 0 : "-->";
|
|
193377
|
+
const into = (from) => {
|
|
193378
|
+
edges.push({ from, to: `job:${job.name}`, ...arrow === void 0 ? {} : { arrow } });
|
|
193379
|
+
};
|
|
193380
|
+
if (job.needs !== null) {
|
|
193381
|
+
for (const need of job.needs) {
|
|
193382
|
+
if (names8.has(need)) into(`job:${need}`);
|
|
193383
|
+
else unresolvedNeeds.push({ job, need });
|
|
193384
|
+
}
|
|
193385
|
+
if (job.needs.filter((need) => names8.has(need)).length === 0) into(START_KEY2);
|
|
193386
|
+
continue;
|
|
193387
|
+
}
|
|
193388
|
+
const before = ordered.slice(0, ordered.indexOf(job.stage)).reverse().find((stage) => jobsOf2(stage).length > 0);
|
|
193389
|
+
if (before === void 0) into(START_KEY2);
|
|
193390
|
+
else for (const previous of jobsOf2(before)) into(`job:${previous.name}`);
|
|
193391
|
+
}
|
|
193392
|
+
const firstNeed = unresolvedNeeds[0];
|
|
193393
|
+
if (firstNeed !== void 0) {
|
|
193394
|
+
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.");
|
|
193395
|
+
}
|
|
193396
|
+
const triggers = pipeline.jobs.filter((job) => job.trigger !== null).length;
|
|
193397
|
+
return writeFlow(
|
|
193398
|
+
{
|
|
193399
|
+
title: context.title ?? "GitLab CI/CD pipeline",
|
|
193400
|
+
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.`,
|
|
193401
|
+
// Stages run down the page: across, even three stages of a few jobs are wider than a column.
|
|
193402
|
+
direction: "down",
|
|
193403
|
+
nodes,
|
|
193404
|
+
groups,
|
|
193405
|
+
edges,
|
|
193406
|
+
noun: "jobs",
|
|
193407
|
+
capSpan: (key) => {
|
|
193408
|
+
const job = pipeline.jobs.find((candidate2) => key === `job:${candidate2.name}`);
|
|
193409
|
+
return spanAt3(job?.line ?? 1, job?.column ?? 1);
|
|
193410
|
+
},
|
|
193411
|
+
coverage: { noun: "jobs", total: pipeline.jobs.length, drawn: pipeline.jobs.length, summarised: 0 },
|
|
193412
|
+
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."
|
|
193413
|
+
},
|
|
193414
|
+
context.report
|
|
193415
|
+
);
|
|
193416
|
+
}
|
|
193417
|
+
var START_KEY2, START_WORDS, gitlabCiImporter;
|
|
193418
|
+
var init_gitlab_ci = __esm({
|
|
193419
|
+
"../../packages/diagrams/src/importers/gitlab-ci/index.ts"() {
|
|
193420
|
+
"use strict";
|
|
193421
|
+
init_core();
|
|
193422
|
+
init_shared2();
|
|
193423
|
+
init_yaml();
|
|
193424
|
+
init_pipeline2();
|
|
193425
|
+
START_KEY2 = "pipeline";
|
|
193426
|
+
START_WORDS = { always: null, manual: "manual", rules: "when its rules match", only: "only on some refs", delayed: "delayed", on_failure: "on failure" };
|
|
193427
|
+
gitlabCiImporter = { format: "gitlab-ci", kinds: ["flow"], joins: null, extensions: [], read: readGitlabCi };
|
|
193428
|
+
}
|
|
193429
|
+
});
|
|
193430
|
+
|
|
192162
193431
|
// ../../packages/diagrams/src/importers/json/locate.ts
|
|
192163
193432
|
function stringEnd3(text3, start2) {
|
|
192164
193433
|
for (let index2 = start2 + 1; index2 < text3.length; index2 += 1) {
|
|
@@ -192483,7 +193752,7 @@ function withoutSchemaBodies(text3) {
|
|
|
192483
193752
|
}
|
|
192484
193753
|
return lines.join("\n");
|
|
192485
193754
|
}
|
|
192486
|
-
function
|
|
193755
|
+
function readDocument2(text3, report3) {
|
|
192487
193756
|
const index2 = new LineIndex(text3);
|
|
192488
193757
|
if (text3.trimStart().startsWith("{")) {
|
|
192489
193758
|
try {
|
|
@@ -192503,7 +193772,7 @@ function readDocument(text3, report3) {
|
|
|
192503
193772
|
return root === void 0 || root === null ? null : plain2(root);
|
|
192504
193773
|
}
|
|
192505
193774
|
var UNREAD_SECTIONS;
|
|
192506
|
-
var
|
|
193775
|
+
var init_document3 = __esm({
|
|
192507
193776
|
"../../packages/diagrams/src/importers/openapi/document.ts"() {
|
|
192508
193777
|
"use strict";
|
|
192509
193778
|
init_core();
|
|
@@ -192860,7 +194129,7 @@ var METHODS;
|
|
|
192860
194129
|
var init_operations = __esm({
|
|
192861
194130
|
"../../packages/diagrams/src/importers/openapi/operations.ts"() {
|
|
192862
194131
|
"use strict";
|
|
192863
|
-
|
|
194132
|
+
init_document3();
|
|
192864
194133
|
METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
|
|
192865
194134
|
}
|
|
192866
194135
|
});
|
|
@@ -192964,7 +194233,7 @@ function readOpenApi(text3, context) {
|
|
|
192964
194233
|
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
194234
|
return null;
|
|
192966
194235
|
}
|
|
192967
|
-
const document2 =
|
|
194236
|
+
const document2 = readDocument2(text3, report3);
|
|
192968
194237
|
if (document2 === null) return null;
|
|
192969
194238
|
if (!isOpenApi3(document2)) {
|
|
192970
194239
|
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 +194280,7 @@ var init_openapi = __esm({
|
|
|
193011
194280
|
"use strict";
|
|
193012
194281
|
init_core();
|
|
193013
194282
|
init_shared2();
|
|
193014
|
-
|
|
194283
|
+
init_document3();
|
|
193015
194284
|
init_endpoints();
|
|
193016
194285
|
init_map();
|
|
193017
194286
|
init_operations();
|
|
@@ -193303,19 +194572,19 @@ function piecesOf4(value) {
|
|
|
193303
194572
|
}
|
|
193304
194573
|
return out;
|
|
193305
194574
|
}
|
|
193306
|
-
var
|
|
194575
|
+
var MAX_DEPTH15, Program;
|
|
193307
194576
|
var init_program = __esm({
|
|
193308
194577
|
"../../packages/diagrams/src/importers/pulumi/program.ts"() {
|
|
193309
194578
|
"use strict";
|
|
193310
194579
|
init_value();
|
|
193311
194580
|
init_yaml();
|
|
193312
194581
|
init_item();
|
|
193313
|
-
|
|
194582
|
+
MAX_DEPTH15 = 16;
|
|
193314
194583
|
Program = class {
|
|
193315
|
-
constructor(root, config2, stack,
|
|
194584
|
+
constructor(root, config2, stack, project2) {
|
|
193316
194585
|
this.config = config2;
|
|
193317
194586
|
this.stack = stack;
|
|
193318
|
-
this.project =
|
|
194587
|
+
this.project = project2;
|
|
193319
194588
|
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
194589
|
this.variables = new Map(entries(get(root, "variables")).map((entry2) => [entry2.key, entry2.value]));
|
|
193321
194590
|
const defaults = /* @__PURE__ */ new Map();
|
|
@@ -193338,7 +194607,7 @@ var init_program = __esm({
|
|
|
193338
194607
|
}
|
|
193339
194608
|
/** The value of a node as far as the program and the stack give it. */
|
|
193340
194609
|
evaluate(node3, depth = 0) {
|
|
193341
|
-
if (node3 === void 0 || depth >
|
|
194610
|
+
if (node3 === void 0 || depth > MAX_DEPTH15) return new Unknown("value");
|
|
193342
194611
|
if (node3.kind === "scalar") {
|
|
193343
194612
|
if (node3.isNull) return null;
|
|
193344
194613
|
if (!node3.value.includes("${")) return node3.value;
|
|
@@ -193423,7 +194692,7 @@ var init_program = __esm({
|
|
|
193423
194692
|
}
|
|
193424
194693
|
/** The resources a node names, through the variables it uses. */
|
|
193425
194694
|
refs(node3, depth = 0) {
|
|
193426
|
-
if (node3 === void 0 || depth >
|
|
194695
|
+
if (node3 === void 0 || depth > MAX_DEPTH15) return [];
|
|
193427
194696
|
if (node3.kind === "scalar") {
|
|
193428
194697
|
if (!node3.value.includes("${")) return [];
|
|
193429
194698
|
return piecesOf4(node3.value).flatMap((piece) => {
|
|
@@ -193446,7 +194715,7 @@ var init_program = __esm({
|
|
|
193446
194715
|
}
|
|
193447
194716
|
/** Every reference a node holds, by the keys that lead to it. */
|
|
193448
194717
|
refsByPath(node3, path, out, depth) {
|
|
193449
|
-
if (node3 === void 0 || depth >
|
|
194718
|
+
if (node3 === void 0 || depth > MAX_DEPTH15) return;
|
|
193450
194719
|
if (node3.kind === "map" && !(node3.entries.length === 1 && node3.entries[0]?.key.startsWith("fn::"))) {
|
|
193451
194720
|
for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
|
|
193452
194721
|
return;
|
|
@@ -193561,7 +194830,7 @@ function stateResources(state, offsetOf) {
|
|
|
193561
194830
|
const byUrn = new Map(all.map((resource) => [resource.urn, resource]));
|
|
193562
194831
|
const counts = /* @__PURE__ */ new Map();
|
|
193563
194832
|
for (const resource of all) counts.set(logicalName(resource.urn), (counts.get(logicalName(resource.urn)) ?? 0) + 1);
|
|
193564
|
-
const
|
|
194833
|
+
const nameOf11 = (urn) => (counts.get(logicalName(urn)) ?? 0) > 1 ? urn : logicalName(urn);
|
|
193565
194834
|
const safe3 = (name2) => name2.replace(/[^A-Za-z0-9_-]+/g, "_");
|
|
193566
194835
|
const scopeOf2 = (resource) => {
|
|
193567
194836
|
const chain2 = [];
|
|
@@ -193586,21 +194855,21 @@ function stateResources(state, offsetOf) {
|
|
|
193586
194855
|
const outputs = target?.outputs;
|
|
193587
194856
|
const name2 = typeof outputs === "object" && outputs !== null && !Array.isArray(outputs) ? outputs["name"] : null;
|
|
193588
194857
|
const path = pathTo(inputs[property] ?? null, [target?.id ?? "", typeof name2 === "string" && property.endsWith("Name") ? name2 : ""], [property]);
|
|
193589
|
-
return { path: path ?? [property], refs: [
|
|
194858
|
+
return { path: path ?? [property], refs: [nameOf11(urn)] };
|
|
193590
194859
|
})
|
|
193591
194860
|
);
|
|
193592
194861
|
const parent = resource.parent === null ? void 0 : byUrn.get(resource.parent);
|
|
193593
194862
|
for (const urns of Object.values(resource.propertyDependencies)) for (const urn of urns) named.add(urn);
|
|
193594
|
-
const dependsOn = resource.dependencies.filter((urn) => !named.has(urn) && byUrn.get(urn)?.custom === true && urn !== resource.urn && urn !== resource.parent).map(
|
|
194863
|
+
const dependsOn = resource.dependencies.filter((urn) => !named.has(urn) && byUrn.get(urn)?.custom === true && urn !== resource.urn && urn !== resource.parent).map(nameOf11);
|
|
193595
194864
|
const properties = mergeValues2(resource.outputs, resource.inputs);
|
|
193596
194865
|
return {
|
|
193597
|
-
name:
|
|
194866
|
+
name: nameOf11(resource.urn),
|
|
193598
194867
|
logical: logicalName(resource.urn),
|
|
193599
194868
|
token: resource.type,
|
|
193600
194869
|
properties,
|
|
193601
194870
|
refs: refs.filter((entry2) => entry2.refs.length > 0),
|
|
193602
194871
|
dependsOn,
|
|
193603
|
-
parent: parent?.custom === true ?
|
|
194872
|
+
parent: parent?.custom === true ? nameOf11(parent.urn) : null,
|
|
193604
194873
|
existing: false,
|
|
193605
194874
|
start: offsetOf(resource.urn),
|
|
193606
194875
|
scope: scopeOf2(resource)
|
|
@@ -194244,6 +195513,724 @@ var init_sql = __esm({
|
|
|
194244
195513
|
}
|
|
194245
195514
|
});
|
|
194246
195515
|
|
|
195516
|
+
// ../../packages/diagrams/src/importers/structurizr/tokens.ts
|
|
195517
|
+
function tokensOf(line3) {
|
|
195518
|
+
const tokens = [];
|
|
195519
|
+
let index2 = 0;
|
|
195520
|
+
while (index2 < line3.length) {
|
|
195521
|
+
const char = line3.charAt(index2);
|
|
195522
|
+
if (char === " " || char === " ") {
|
|
195523
|
+
index2 += 1;
|
|
195524
|
+
continue;
|
|
195525
|
+
}
|
|
195526
|
+
if (char === '"') {
|
|
195527
|
+
let value = "";
|
|
195528
|
+
let at3 = index2 + 1;
|
|
195529
|
+
for (; at3 < line3.length && line3.charAt(at3) !== '"'; at3 += 1) {
|
|
195530
|
+
if (line3.charAt(at3) === "\\" && at3 + 1 < line3.length) at3 += 1;
|
|
195531
|
+
value += line3.charAt(at3);
|
|
195532
|
+
}
|
|
195533
|
+
tokens.push({ text: value, quoted: true, column: index2 + 1 });
|
|
195534
|
+
index2 = at3 + 1;
|
|
195535
|
+
continue;
|
|
195536
|
+
}
|
|
195537
|
+
if (char === "#" || line3.startsWith("//", index2)) break;
|
|
195538
|
+
let end = index2;
|
|
195539
|
+
while (end < line3.length && !' "'.includes(line3.charAt(end))) end += 1;
|
|
195540
|
+
const word2 = line3.slice(index2, end);
|
|
195541
|
+
let start2 = 0;
|
|
195542
|
+
for (let at3 = 0; at3 < word2.length; at3 += 1) {
|
|
195543
|
+
const single = word2.charAt(at3) === "{" || word2.charAt(at3) === "}" || word2.charAt(at3) === "=";
|
|
195544
|
+
const arrow = word2.startsWith("->", at3);
|
|
195545
|
+
if (!single && !arrow) continue;
|
|
195546
|
+
if (at3 > start2) tokens.push({ text: word2.slice(start2, at3), quoted: false, column: index2 + start2 + 1 });
|
|
195547
|
+
const size = arrow ? 2 : 1;
|
|
195548
|
+
tokens.push({ text: word2.slice(at3, at3 + size), quoted: false, column: index2 + at3 + 1 });
|
|
195549
|
+
start2 = at3 + size;
|
|
195550
|
+
at3 += size - 1;
|
|
195551
|
+
}
|
|
195552
|
+
if (start2 < word2.length) tokens.push({ text: word2.slice(start2), quoted: false, column: index2 + start2 + 1 });
|
|
195553
|
+
index2 = end;
|
|
195554
|
+
}
|
|
195555
|
+
return tokens;
|
|
195556
|
+
}
|
|
195557
|
+
function statementsOf2(text3) {
|
|
195558
|
+
const lines = text3.split("\n");
|
|
195559
|
+
const out = [];
|
|
195560
|
+
let inComment = false;
|
|
195561
|
+
let pending = null;
|
|
195562
|
+
for (let index2 = 0; index2 < lines.length && out.length < MAX_STATEMENTS; index2 += 1) {
|
|
195563
|
+
let line3 = lines[index2] ?? "";
|
|
195564
|
+
if (inComment) {
|
|
195565
|
+
const close2 = line3.indexOf("*/");
|
|
195566
|
+
if (close2 === -1) continue;
|
|
195567
|
+
line3 = " ".repeat(close2 + 2) + line3.slice(close2 + 2);
|
|
195568
|
+
inComment = false;
|
|
195569
|
+
}
|
|
195570
|
+
const trimmed4 = line3.trim();
|
|
195571
|
+
if (trimmed4.startsWith("/*")) {
|
|
195572
|
+
const close2 = line3.indexOf("*/", line3.indexOf("/*") + 2);
|
|
195573
|
+
if (close2 === -1) {
|
|
195574
|
+
inComment = true;
|
|
195575
|
+
continue;
|
|
195576
|
+
}
|
|
195577
|
+
line3 = " ".repeat(close2 + 2) + line3.slice(close2 + 2);
|
|
195578
|
+
}
|
|
195579
|
+
if (line3.trimEnd().endsWith("\\")) {
|
|
195580
|
+
const head = line3.trimEnd().slice(0, -1);
|
|
195581
|
+
pending = pending === null ? { text: head, line: index2 + 1 } : { text: `${pending.text} ${head.trim()}`, line: pending.line };
|
|
195582
|
+
continue;
|
|
195583
|
+
}
|
|
195584
|
+
const whole2 = pending === null ? { text: line3, line: index2 + 1 } : { text: `${pending.text} ${line3.trim()}`, line: pending.line };
|
|
195585
|
+
pending = null;
|
|
195586
|
+
const tokens = tokensOf(whole2.text);
|
|
195587
|
+
if (tokens.length === 0) continue;
|
|
195588
|
+
const open2 = tokens.findIndex((token) => !token.quoted && token.text === "{");
|
|
195589
|
+
const last = tokens[tokens.length - 1];
|
|
195590
|
+
if (open2 !== -1 && open2 < tokens.length - 1 && last !== void 0 && !last.quoted && last.text === "}") {
|
|
195591
|
+
out.push({ tokens: tokens.slice(0, open2 + 1), line: whole2.line });
|
|
195592
|
+
if (open2 + 1 < tokens.length - 1) out.push({ tokens: tokens.slice(open2 + 1, -1), line: whole2.line });
|
|
195593
|
+
out.push({ tokens: [last], line: whole2.line });
|
|
195594
|
+
continue;
|
|
195595
|
+
}
|
|
195596
|
+
out.push({ tokens, line: whole2.line });
|
|
195597
|
+
}
|
|
195598
|
+
return out;
|
|
195599
|
+
}
|
|
195600
|
+
var MAX_STATEMENTS;
|
|
195601
|
+
var init_tokens4 = __esm({
|
|
195602
|
+
"../../packages/diagrams/src/importers/structurizr/tokens.ts"() {
|
|
195603
|
+
"use strict";
|
|
195604
|
+
MAX_STATEMENTS = 5e4;
|
|
195605
|
+
}
|
|
195606
|
+
});
|
|
195607
|
+
|
|
195608
|
+
// ../../packages/diagrams/src/importers/structurizr/dsl.ts
|
|
195609
|
+
function readDsl(text3) {
|
|
195610
|
+
const statements = statementsOf2(text3);
|
|
195611
|
+
const elements = [];
|
|
195612
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
195613
|
+
const groups = [];
|
|
195614
|
+
const relationships = [];
|
|
195615
|
+
const views = [];
|
|
195616
|
+
const cylinderTags = [];
|
|
195617
|
+
const skipped = [];
|
|
195618
|
+
const constants = /* @__PURE__ */ new Map();
|
|
195619
|
+
const stack = [];
|
|
195620
|
+
let hierarchical = false;
|
|
195621
|
+
let name2 = null;
|
|
195622
|
+
let description = null;
|
|
195623
|
+
const skip = (what, at3, hint2) => {
|
|
195624
|
+
if (!skipped.some((entry2) => entry2.what === what)) skipped.push({ what, line: at3.line, column: at3.column, hint: hint2 });
|
|
195625
|
+
};
|
|
195626
|
+
const expand2 = (value) => value.includes("${") ? value.replace(/\$\{([A-Za-z0-9_-]{1,64})\}/g, (whole2, key) => constants.get(key) ?? whole2) : value;
|
|
195627
|
+
const currentElement = () => {
|
|
195628
|
+
for (let index2 = stack.length - 1; index2 >= 0; index2 -= 1) {
|
|
195629
|
+
const frame = stack[index2];
|
|
195630
|
+
if (frame?.type === "element") return frame.key;
|
|
195631
|
+
}
|
|
195632
|
+
return null;
|
|
195633
|
+
};
|
|
195634
|
+
const currentGroup = () => {
|
|
195635
|
+
for (let index2 = stack.length - 1; index2 >= 0; index2 -= 1) {
|
|
195636
|
+
const frame = stack[index2];
|
|
195637
|
+
if (frame?.type === "group") return frame.key;
|
|
195638
|
+
if (frame?.type === "element") return null;
|
|
195639
|
+
}
|
|
195640
|
+
return null;
|
|
195641
|
+
};
|
|
195642
|
+
const resolve5 = (reference, scope) => {
|
|
195643
|
+
if (reference === "this") return scope;
|
|
195644
|
+
const lower = reference.toLowerCase();
|
|
195645
|
+
if (hierarchical) {
|
|
195646
|
+
for (let at3 = scope; at3 !== null; at3 = byKey.get(at3.toLowerCase())?.parent ?? null) {
|
|
195647
|
+
const found = byKey.get(`${at3.toLowerCase()}.${lower}`);
|
|
195648
|
+
if (found !== void 0) return found.key;
|
|
195649
|
+
}
|
|
195650
|
+
}
|
|
195651
|
+
return byKey.get(lower)?.key ?? null;
|
|
195652
|
+
};
|
|
195653
|
+
const addElement = (statement, identifier, kind, args) => {
|
|
195654
|
+
const parent = currentElement();
|
|
195655
|
+
const parentDraft = parent === null ? void 0 : byKey.get(parent.toLowerCase());
|
|
195656
|
+
const label = args[0]?.text ?? kind;
|
|
195657
|
+
const named = parentDraft === void 0 ? label : `${parentDraft.key}/${label}`;
|
|
195658
|
+
const key = identifier === null ? named : hierarchical && parentDraft !== void 0 ? `${parentDraft.key}.${identifier}` : identifier;
|
|
195659
|
+
const hasTech = kind === "container" || kind === "component";
|
|
195660
|
+
const tags = tagsOf2(args.slice(hasTech ? 3 : 2));
|
|
195661
|
+
const draft = {
|
|
195662
|
+
key,
|
|
195663
|
+
kind,
|
|
195664
|
+
name: label,
|
|
195665
|
+
description: args[1]?.text === "" ? null : args[1]?.text ?? null,
|
|
195666
|
+
technology: hasTech && args[2] !== void 0 && args[2].text !== "" ? args[2].text : null,
|
|
195667
|
+
tags,
|
|
195668
|
+
parent: parentDraft?.key ?? null,
|
|
195669
|
+
group: currentGroup(),
|
|
195670
|
+
external: tags.some((tag) => tag.toLowerCase() === "external"),
|
|
195671
|
+
line: statement.line,
|
|
195672
|
+
column: statement.tokens[0]?.column ?? 1
|
|
195673
|
+
};
|
|
195674
|
+
if (!byKey.has(key.toLowerCase())) {
|
|
195675
|
+
elements.push(draft);
|
|
195676
|
+
byKey.set(key.toLowerCase(), draft);
|
|
195677
|
+
}
|
|
195678
|
+
return { type: "element", key: byKey.get(key.toLowerCase())?.key ?? key };
|
|
195679
|
+
};
|
|
195680
|
+
const readModelStatement = (statement, words2) => {
|
|
195681
|
+
const first = words2[0];
|
|
195682
|
+
if (first === void 0) return { type: "skip" };
|
|
195683
|
+
const keyword = first.text.toLowerCase();
|
|
195684
|
+
const scope = currentElement();
|
|
195685
|
+
if (!first.quoted && keyword === "!identifiers") {
|
|
195686
|
+
hierarchical = words2[1]?.text.toLowerCase() === "hierarchical";
|
|
195687
|
+
return { type: "skip" };
|
|
195688
|
+
}
|
|
195689
|
+
if (!first.quoted && (keyword === "!element" || keyword === "!ref")) {
|
|
195690
|
+
const key = resolve5(words2[1]?.text ?? "", scope);
|
|
195691
|
+
if (key === null) {
|
|
195692
|
+
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.");
|
|
195693
|
+
return { type: "skip" };
|
|
195694
|
+
}
|
|
195695
|
+
return { type: "element", key };
|
|
195696
|
+
}
|
|
195697
|
+
const assigned = words2[1]?.text === "=" && !words2[1].quoted;
|
|
195698
|
+
const rest = assigned ? words2.slice(2) : words2;
|
|
195699
|
+
const arrow = rest.findIndex((token) => !token.quoted && token.text === "->");
|
|
195700
|
+
if (arrow === 0 || arrow === 1) {
|
|
195701
|
+
const from = arrow === 0 ? "this" : rest[0]?.text ?? "";
|
|
195702
|
+
const to = rest[arrow + 1];
|
|
195703
|
+
if (to === void 0 || arrow === 0 && scope === null) {
|
|
195704
|
+
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.");
|
|
195705
|
+
return { type: "skip" };
|
|
195706
|
+
}
|
|
195707
|
+
const args = rest.slice(arrow + 2);
|
|
195708
|
+
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 });
|
|
195709
|
+
return { type: "relationship", index: relationships.length - 1 };
|
|
195710
|
+
}
|
|
195711
|
+
const word2 = (rest[0]?.text ?? "").toLowerCase();
|
|
195712
|
+
const kind = rest[0]?.quoted === true ? void 0 : ELEMENT_WORDS[word2];
|
|
195713
|
+
if (kind !== void 0) return addElement(statement, assigned ? first.text : null, kind, rest.slice(1));
|
|
195714
|
+
if (word2 === "group" || word2 === "enterprise") {
|
|
195715
|
+
const label = rest[1]?.text ?? (word2 === "enterprise" ? "Enterprise" : "Group");
|
|
195716
|
+
const parent = currentGroup();
|
|
195717
|
+
const key = parent !== null ? `${parent}/${label}` : scope !== null ? `${scope}/${label}` : label;
|
|
195718
|
+
if (!groups.some((group2) => group2.key === key)) groups.push({ key, name: label, parent, enterprise: word2 === "enterprise", line: statement.line });
|
|
195719
|
+
return { type: "group", key };
|
|
195720
|
+
}
|
|
195721
|
+
if (DEPLOYMENT_WORDS.has(word2)) {
|
|
195722
|
+
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.");
|
|
195723
|
+
return { type: "skip" };
|
|
195724
|
+
}
|
|
195725
|
+
if (word2 === "element") {
|
|
195726
|
+
skip("Custom elements", { line: statement.line, column: first.column }, "Only people, software systems, containers, and components are drawn.");
|
|
195727
|
+
return { type: "skip" };
|
|
195728
|
+
}
|
|
195729
|
+
if (scope !== null && (word2 === "description" || word2 === "technology" || word2 === "tags" || word2 === "tag")) {
|
|
195730
|
+
const draft = byKey.get(scope.toLowerCase());
|
|
195731
|
+
const value = rest[1]?.text ?? "";
|
|
195732
|
+
if (draft !== void 0 && word2 === "description") draft.description = value === "" ? null : value;
|
|
195733
|
+
if (draft !== void 0 && word2 === "technology") draft.technology = value === "" ? null : value;
|
|
195734
|
+
if (draft !== void 0 && (word2 === "tags" || word2 === "tag")) {
|
|
195735
|
+
draft.tags = [...draft.tags, ...tagsOf2(rest.slice(1))];
|
|
195736
|
+
draft.external ||= draft.tags.some((tag) => tag.toLowerCase() === "external");
|
|
195737
|
+
}
|
|
195738
|
+
return { type: "skip" };
|
|
195739
|
+
}
|
|
195740
|
+
if (scope !== null && word2 === "location") {
|
|
195741
|
+
const draft = byKey.get(scope.toLowerCase());
|
|
195742
|
+
if (draft !== void 0 && rest[1]?.text.toLowerCase() === "external") draft.external = true;
|
|
195743
|
+
return { type: "skip" };
|
|
195744
|
+
}
|
|
195745
|
+
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.");
|
|
195746
|
+
return { type: "skip" };
|
|
195747
|
+
};
|
|
195748
|
+
for (const statement of statements) {
|
|
195749
|
+
const tokens = statement.tokens.map((token) => ({ ...token, text: expand2(token.text) }));
|
|
195750
|
+
const first = tokens[0];
|
|
195751
|
+
if (first === void 0) continue;
|
|
195752
|
+
if (!first.quoted && first.text === "}") {
|
|
195753
|
+
stack.pop();
|
|
195754
|
+
continue;
|
|
195755
|
+
}
|
|
195756
|
+
const last = tokens[tokens.length - 1];
|
|
195757
|
+
const opens = last !== void 0 && !last.quoted && last.text === "{";
|
|
195758
|
+
const words2 = opens ? tokens.slice(0, -1) : tokens;
|
|
195759
|
+
const keyword = first.quoted ? "" : first.text.toLowerCase();
|
|
195760
|
+
const frame = stack[stack.length - 1];
|
|
195761
|
+
let next = { type: "skip" };
|
|
195762
|
+
if (keyword === "!const" || keyword === "!constant" || keyword === "!var") {
|
|
195763
|
+
const key = words2[1]?.text;
|
|
195764
|
+
if (key !== void 0) constants.set(key, words2[2]?.text ?? "");
|
|
195765
|
+
} else if (frame === void 0) {
|
|
195766
|
+
if (keyword === "workspace") {
|
|
195767
|
+
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.");
|
|
195768
|
+
else {
|
|
195769
|
+
name2 = words2[1]?.text ?? null;
|
|
195770
|
+
description = words2[2]?.text ?? null;
|
|
195771
|
+
}
|
|
195772
|
+
next = { type: "workspace" };
|
|
195773
|
+
}
|
|
195774
|
+
} else if (frame.type === "workspace") {
|
|
195775
|
+
if (keyword === "model") next = { type: "model" };
|
|
195776
|
+
else if (keyword === "views") next = { type: "views" };
|
|
195777
|
+
else if (keyword === "name") name2 = words2[1]?.text ?? name2;
|
|
195778
|
+
else if (keyword === "description") description = words2[1]?.text ?? description;
|
|
195779
|
+
else if (keyword === "!identifiers") hierarchical = words2[1]?.text.toLowerCase() === "hierarchical";
|
|
195780
|
+
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.");
|
|
195781
|
+
} else if (frame.type === "model" || frame.type === "element" || frame.type === "group") {
|
|
195782
|
+
next = readModelStatement(statement, words2);
|
|
195783
|
+
} else if (frame.type === "relationship") {
|
|
195784
|
+
const relationship = relationships[frame.index];
|
|
195785
|
+
if (relationship !== void 0 && (keyword === "tags" || keyword === "tag")) relationship.tags.push(...tagsOf2(words2.slice(1)));
|
|
195786
|
+
if (relationship !== void 0 && keyword === "description") relationship.description = words2[1]?.text ?? relationship.description;
|
|
195787
|
+
if (relationship !== void 0 && keyword === "technology") relationship.technology = words2[1]?.text ?? relationship.technology;
|
|
195788
|
+
} else if (frame.type === "views") {
|
|
195789
|
+
const level2 = VIEW_WORDS2[keyword];
|
|
195790
|
+
if (level2 !== void 0 && words2[1] !== void 0) {
|
|
195791
|
+
views.push({ level: level2, scope: words2[1].text, title: null, direction: null, line: statement.line, column: words2[1].column });
|
|
195792
|
+
next = { type: "view", index: views.length - 1 };
|
|
195793
|
+
} else if (keyword === "styles") next = { type: "styles" };
|
|
195794
|
+
} else if (frame.type === "view") {
|
|
195795
|
+
const view = views[frame.index];
|
|
195796
|
+
if (view !== void 0 && keyword === "title") view.title = words2[1]?.text ?? null;
|
|
195797
|
+
if (view !== void 0 && keyword === "autolayout") view.direction = /^(?:lr|rl)$/i.test(words2[1]?.text ?? "") ? "right" : "down";
|
|
195798
|
+
} else if (frame.type === "styles") {
|
|
195799
|
+
if (keyword === "element" && words2[1] !== void 0) next = { type: "style", tag: words2[1].text };
|
|
195800
|
+
} else if (frame.type === "style") {
|
|
195801
|
+
if (keyword === "shape" && words2[1]?.text.toLowerCase() === "cylinder") cylinderTags.push(frame.tag);
|
|
195802
|
+
}
|
|
195803
|
+
if (opens) stack.push(next);
|
|
195804
|
+
}
|
|
195805
|
+
const unresolved = [];
|
|
195806
|
+
const resolved2 = [];
|
|
195807
|
+
for (const relationship of relationships) {
|
|
195808
|
+
const from = resolve5(relationship.from, relationship.scope);
|
|
195809
|
+
const to = resolve5(relationship.to, relationship.scope);
|
|
195810
|
+
for (const [written3, key] of [[relationship.from, from], [relationship.to, to]]) if (key === null) unresolved.push({ name: written3, line: relationship.line, column: relationship.column });
|
|
195811
|
+
if (from !== null && to !== null) resolved2.push({ from, to, description: relationship.description, technology: relationship.technology, tags: relationship.tags, line: relationship.line, column: relationship.column });
|
|
195812
|
+
}
|
|
195813
|
+
const modelViews = [];
|
|
195814
|
+
for (const view of views) {
|
|
195815
|
+
const scope = resolve5(view.scope, null);
|
|
195816
|
+
if (scope === null) unresolved.push({ name: view.scope, line: view.line, column: view.column });
|
|
195817
|
+
else modelViews.push({ level: view.level, scope, title: view.title, direction: view.direction, line: view.line });
|
|
195818
|
+
}
|
|
195819
|
+
return { workspace: { name: name2, description, elements, relationships: resolved2, groups, views: modelViews, cylinderTags, skipped }, unresolved };
|
|
195820
|
+
}
|
|
195821
|
+
var ELEMENT_WORDS, VIEW_WORDS2, DEPLOYMENT_WORDS, tagsOf2;
|
|
195822
|
+
var init_dsl = __esm({
|
|
195823
|
+
"../../packages/diagrams/src/importers/structurizr/dsl.ts"() {
|
|
195824
|
+
"use strict";
|
|
195825
|
+
init_tokens4();
|
|
195826
|
+
ELEMENT_WORDS = { person: "person", softwaresystem: "system", container: "container", component: "component" };
|
|
195827
|
+
VIEW_WORDS2 = { systemcontext: "context", container: "container", component: "component" };
|
|
195828
|
+
DEPLOYMENT_WORDS = /* @__PURE__ */ new Set(["deploymentenvironment", "deploymentnode", "infrastructurenode", "softwaresysteminstance", "containerinstance", "deploymentgroup"]);
|
|
195829
|
+
tagsOf2 = (tokens) => tokens.flatMap((token) => token.text.split(",")).map((tag) => tag.trim()).filter((tag) => tag !== "");
|
|
195830
|
+
}
|
|
195831
|
+
});
|
|
195832
|
+
|
|
195833
|
+
// ../../packages/diagrams/src/importers/structurizr/json.ts
|
|
195834
|
+
function isWorkspaceJson(value) {
|
|
195835
|
+
return isObject4(value) && isObject4(value["model"]) && (Array.isArray(value["model"]["softwareSystems"]) || Array.isArray(value["model"]["people"]));
|
|
195836
|
+
}
|
|
195837
|
+
function readWorkspaceJson(json2) {
|
|
195838
|
+
const model = isObject4(json2["model"]) ? json2["model"] : {};
|
|
195839
|
+
const elements = [];
|
|
195840
|
+
const keyOfId = /* @__PURE__ */ new Map();
|
|
195841
|
+
const groups = [];
|
|
195842
|
+
const rawRelationships = [];
|
|
195843
|
+
const add2 = (entry2, kind, parent) => {
|
|
195844
|
+
const name2 = textOf7(entry2["name"]) ?? kind;
|
|
195845
|
+
const properties = isObject4(entry2["properties"]) ? entry2["properties"] : {};
|
|
195846
|
+
const identifier = textOf7(properties["structurizr.dsl.identifier"]);
|
|
195847
|
+
const tags = tagsOf3(entry2["tags"]);
|
|
195848
|
+
const group2 = textOf7(entry2["group"]);
|
|
195849
|
+
if (group2 !== null && !groups.some((existing) => existing.key === group2)) groups.push({ key: group2, name: group2, parent: null, enterprise: false, line: 1 });
|
|
195850
|
+
const element = {
|
|
195851
|
+
key: identifier ?? (parent === null ? name2 : `${parent.key}/${name2}`),
|
|
195852
|
+
kind,
|
|
195853
|
+
name: name2,
|
|
195854
|
+
description: textOf7(entry2["description"]),
|
|
195855
|
+
technology: kind === "container" || kind === "component" ? textOf7(entry2["technology"]) : null,
|
|
195856
|
+
tags,
|
|
195857
|
+
parent: parent?.key ?? null,
|
|
195858
|
+
group: group2,
|
|
195859
|
+
external: textOf7(entry2["location"])?.toLowerCase() === "external" || tags.some((tag) => tag.toLowerCase() === "external"),
|
|
195860
|
+
line: 1,
|
|
195861
|
+
column: 1
|
|
195862
|
+
};
|
|
195863
|
+
elements.push(element);
|
|
195864
|
+
const id = textOf7(entry2["id"]);
|
|
195865
|
+
if (id !== null) keyOfId.set(id, element.key);
|
|
195866
|
+
rawRelationships.push(...listOf4(entry2["relationships"]));
|
|
195867
|
+
return element;
|
|
195868
|
+
};
|
|
195869
|
+
for (const person of listOf4(model["people"])) add2(person, "person", null);
|
|
195870
|
+
for (const system of listOf4(model["softwareSystems"])) {
|
|
195871
|
+
const parent = add2(system, "system", null);
|
|
195872
|
+
for (const container of listOf4(system["containers"])) {
|
|
195873
|
+
const holder = add2(container, "container", parent);
|
|
195874
|
+
for (const component of listOf4(container["components"])) add2(component, "component", holder);
|
|
195875
|
+
}
|
|
195876
|
+
}
|
|
195877
|
+
const relationships = [];
|
|
195878
|
+
for (const relationship of rawRelationships) {
|
|
195879
|
+
if (relationship["linkedRelationshipId"] !== void 0) continue;
|
|
195880
|
+
const from = keyOfId.get(textOf7(relationship["sourceId"]) ?? "");
|
|
195881
|
+
const to = keyOfId.get(textOf7(relationship["destinationId"]) ?? "");
|
|
195882
|
+
if (from === void 0 || to === void 0) continue;
|
|
195883
|
+
relationships.push({ from, to, description: textOf7(relationship["description"]), technology: textOf7(relationship["technology"]), tags: tagsOf3(relationship["tags"]), line: 1, column: 1 });
|
|
195884
|
+
}
|
|
195885
|
+
const viewsJson = isObject4(json2["views"]) ? json2["views"] : {};
|
|
195886
|
+
const views = [];
|
|
195887
|
+
const lists = [
|
|
195888
|
+
["systemContextViews", "context", "softwareSystemId"],
|
|
195889
|
+
["containerViews", "container", "softwareSystemId"],
|
|
195890
|
+
["componentViews", "component", "containerId"]
|
|
195891
|
+
];
|
|
195892
|
+
for (const [list, level2, field] of lists) {
|
|
195893
|
+
for (const view of listOf4(viewsJson[list])) {
|
|
195894
|
+
const scope = keyOfId.get(textOf7(view[field]) ?? "");
|
|
195895
|
+
const rank = isObject4(view["automaticLayout"]) ? textOf7(view["automaticLayout"]["rankDirection"]) : null;
|
|
195896
|
+
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 });
|
|
195897
|
+
}
|
|
195898
|
+
}
|
|
195899
|
+
const configuration = isObject4(viewsJson["configuration"]) ? viewsJson["configuration"] : {};
|
|
195900
|
+
const styles = isObject4(configuration["styles"]) ? configuration["styles"] : {};
|
|
195901
|
+
const cylinderTags = listOf4(styles["elements"]).filter((style) => textOf7(style["shape"])?.toLowerCase() === "cylinder").map((style) => textOf7(style["tag"]) ?? "").filter((tag) => tag !== "");
|
|
195902
|
+
return { name: textOf7(json2["name"]), description: textOf7(json2["description"]), elements, relationships, groups, views, cylinderTags, skipped: [] };
|
|
195903
|
+
}
|
|
195904
|
+
var isObject4, listOf4, textOf7, DEFAULT_TAGS, tagsOf3;
|
|
195905
|
+
var init_json2 = __esm({
|
|
195906
|
+
"../../packages/diagrams/src/importers/structurizr/json.ts"() {
|
|
195907
|
+
"use strict";
|
|
195908
|
+
isObject4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
195909
|
+
listOf4 = (value) => Array.isArray(value) ? value.filter(isObject4) : [];
|
|
195910
|
+
textOf7 = (value) => typeof value === "string" && value.trim() !== "" ? value : typeof value === "number" ? String(value) : null;
|
|
195911
|
+
DEFAULT_TAGS = /* @__PURE__ */ new Set(["element", "person", "software system", "container", "component", "relationship"]);
|
|
195912
|
+
tagsOf3 = (value) => (textOf7(value) ?? "").split(",").map((tag) => tag.trim()).filter((tag) => tag !== "" && !DEFAULT_TAGS.has(tag.toLowerCase()));
|
|
195913
|
+
}
|
|
195914
|
+
});
|
|
195915
|
+
|
|
195916
|
+
// ../../packages/diagrams/src/importers/structurizr/view.ts
|
|
195917
|
+
function find(workspace, name2) {
|
|
195918
|
+
const lower = name2.toLowerCase();
|
|
195919
|
+
return workspace.elements.find((element) => element.key.toLowerCase() === lower) ?? workspace.elements.find((element) => element.name.toLowerCase() === lower);
|
|
195920
|
+
}
|
|
195921
|
+
function chooseView(workspace, level2, root) {
|
|
195922
|
+
const named = root === null ? null : find(workspace, root) ?? null;
|
|
195923
|
+
if (root !== null && named === null) return { view: null, missing: root };
|
|
195924
|
+
const systems = workspace.elements.filter((element) => element.kind === "system");
|
|
195925
|
+
const withChildren = (kind) => workspace.elements.find((element) => element.kind === kind && childrenOf(workspace, element.key).length > 0);
|
|
195926
|
+
const systemOf = (element) => {
|
|
195927
|
+
let at3 = element;
|
|
195928
|
+
for (let depth = 0; at3.parent !== null && depth < 3; depth += 1) at3 = workspace.elements.find((candidate2) => candidate2.key === at3.parent) ?? at3;
|
|
195929
|
+
return at3;
|
|
195930
|
+
};
|
|
195931
|
+
if (level2 === null && named === null) {
|
|
195932
|
+
const defined2 = workspace.views[0];
|
|
195933
|
+
const scope = defined2 === void 0 ? void 0 : workspace.elements.find((element) => element.key === defined2.scope);
|
|
195934
|
+
if (defined2 !== void 0 && scope !== void 0) return { view: { level: defined2.level, scope, title: defined2.title, direction: defined2.direction }, missing: null };
|
|
195935
|
+
const system2 = withChildren("system");
|
|
195936
|
+
if (system2 !== void 0) return { view: { level: "container", scope: system2, title: null, direction: null }, missing: null };
|
|
195937
|
+
const first = systems[0];
|
|
195938
|
+
return { view: first === void 0 ? null : { level: "context", scope: first, title: null, direction: null }, missing: null };
|
|
195939
|
+
}
|
|
195940
|
+
const wanted2 = level2 ?? (named?.kind === "container" || named?.kind === "component" ? "component" : named !== null && childrenOf(workspace, named.key).length > 0 ? "container" : "context");
|
|
195941
|
+
const defined = (scope) => workspace.views.find((view) => view.level === wanted2 && view.scope === scope.key);
|
|
195942
|
+
if (wanted2 === "component") {
|
|
195943
|
+
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];
|
|
195944
|
+
return { view: container === void 0 ? null : { level: "component", scope: container, title: defined(container)?.title ?? null, direction: defined(container)?.direction ?? null }, missing: null };
|
|
195945
|
+
}
|
|
195946
|
+
const system = named === null ? wanted2 === "container" ? withChildren("system") ?? systems[0] : withChildren("system") ?? systems[0] : named.kind === "person" ? void 0 : systemOf(named);
|
|
195947
|
+
return { view: system === void 0 ? null : { level: wanted2, scope: system, title: defined(system)?.title ?? null, direction: defined(system)?.direction ?? null }, missing: null };
|
|
195948
|
+
}
|
|
195949
|
+
function hiddenWords(workspace, element) {
|
|
195950
|
+
const containers = childrenOf(workspace, element.key);
|
|
195951
|
+
const components = containers.flatMap((child) => childrenOf(workspace, child.key));
|
|
195952
|
+
const parts = [
|
|
195953
|
+
containers.length === 0 ? null : `${containers.length} ${element.kind === "container" ? containers.length === 1 ? "component" : "components" : containers.length === 1 ? "container" : "containers"}`,
|
|
195954
|
+
components.length === 0 ? null : `${components.length} ${components.length === 1 ? "component" : "components"}`
|
|
195955
|
+
].filter((part) => part !== null);
|
|
195956
|
+
return { count: containers.length + components.length, words: parts.join(" and ") };
|
|
195957
|
+
}
|
|
195958
|
+
function project(workspace, view) {
|
|
195959
|
+
const byKey = new Map(workspace.elements.map((element) => [element.key, element]));
|
|
195960
|
+
const ancestors = (element) => {
|
|
195961
|
+
const out = [];
|
|
195962
|
+
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);
|
|
195963
|
+
return out;
|
|
195964
|
+
};
|
|
195965
|
+
const within = (element, holder) => element.key === holder.key || ancestors(element).some((ancestor) => ancestor.key === holder.key);
|
|
195966
|
+
const top = (element) => ancestors(element).pop() ?? element;
|
|
195967
|
+
const scope = view.scope;
|
|
195968
|
+
const system = top(scope);
|
|
195969
|
+
const inner = view.level === "context" ? [scope] : childrenOf(workspace, scope.key);
|
|
195970
|
+
const innerKeys = new Set(inner.map((element) => element.key));
|
|
195971
|
+
const innerOf2 = (element) => [element, ...ancestors(element)].find((candidate2) => innerKeys.has(candidate2.key)) ?? null;
|
|
195972
|
+
const outerOf = (element) => {
|
|
195973
|
+
if (view.level === "component" && within(element, system) && !within(element, scope)) return [element, ...ancestors(element)].find((candidate2) => candidate2.kind === "container") ?? null;
|
|
195974
|
+
if (within(element, system)) return null;
|
|
195975
|
+
return top(element);
|
|
195976
|
+
};
|
|
195977
|
+
const shown = new Map(inner.map((element) => [element.key, element]));
|
|
195978
|
+
const lines = [];
|
|
195979
|
+
const seen = /* @__PURE__ */ new Set();
|
|
195980
|
+
for (const relationship of workspace.relationships) {
|
|
195981
|
+
const fromElement = byKey.get(relationship.from);
|
|
195982
|
+
const toElement = byKey.get(relationship.to);
|
|
195983
|
+
if (fromElement === void 0 || toElement === void 0) continue;
|
|
195984
|
+
const fromInner = innerOf2(fromElement);
|
|
195985
|
+
const toInner = innerOf2(toElement);
|
|
195986
|
+
if (fromInner === null && toInner === null) continue;
|
|
195987
|
+
const from = fromInner ?? outerOf(fromElement);
|
|
195988
|
+
const to = toInner ?? outerOf(toElement);
|
|
195989
|
+
if (from === null || to === null || from.key === to.key) continue;
|
|
195990
|
+
shown.set(from.key, from);
|
|
195991
|
+
shown.set(to.key, to);
|
|
195992
|
+
const pair2 = `${from.key}\0${to.key}`;
|
|
195993
|
+
if (seen.has(pair2)) continue;
|
|
195994
|
+
seen.add(pair2);
|
|
195995
|
+
lines.push({ from: from.key, to: to.key, relationship });
|
|
195996
|
+
}
|
|
195997
|
+
for (const relationship of workspace.relationships) {
|
|
195998
|
+
const fromElement = byKey.get(relationship.from);
|
|
195999
|
+
const toElement = byKey.get(relationship.to);
|
|
196000
|
+
if (fromElement === void 0 || toElement === void 0 || innerOf2(fromElement) !== null || innerOf2(toElement) !== null) continue;
|
|
196001
|
+
const from = outerOf(fromElement);
|
|
196002
|
+
const to = outerOf(toElement);
|
|
196003
|
+
if (from === null || to === null || from.key === to.key || !shown.has(from.key) || !shown.has(to.key)) continue;
|
|
196004
|
+
const pair2 = `${from.key}\0${to.key}`;
|
|
196005
|
+
if (seen.has(pair2)) continue;
|
|
196006
|
+
seen.add(pair2);
|
|
196007
|
+
lines.push({ from: from.key, to: to.key, relationship });
|
|
196008
|
+
}
|
|
196009
|
+
const boundaries = [];
|
|
196010
|
+
const groupBoundary = (groupKey, holder) => {
|
|
196011
|
+
const group2 = groupKey === null ? void 0 : workspace.groups.find((entry2) => entry2.key === groupKey);
|
|
196012
|
+
if (group2 === void 0) return holder;
|
|
196013
|
+
const parent = groupBoundary(group2.parent, holder);
|
|
196014
|
+
const key = `group:${group2.key}`;
|
|
196015
|
+
if (!boundaries.some((boundary) => boundary.key === key)) boundaries.push({ key, name: group2.name, kind: group2.enterprise ? "enterprise" : "group", parent, tech: null, element: null });
|
|
196016
|
+
return key;
|
|
196017
|
+
};
|
|
196018
|
+
let scopeBoundary = null;
|
|
196019
|
+
if (view.level === "component") {
|
|
196020
|
+
boundaries.push({ key: system.key, name: system.name, kind: "system", parent: groupBoundary(system.group, null), tech: null, element: system });
|
|
196021
|
+
boundaries.push({ key: scope.key, name: scope.name, kind: "container", parent: system.key, tech: scope.technology, element: scope });
|
|
196022
|
+
scopeBoundary = scope.key;
|
|
196023
|
+
} else if (view.level === "container") {
|
|
196024
|
+
boundaries.push({ key: scope.key, name: scope.name, kind: "system", parent: groupBoundary(scope.group, null), tech: null, element: scope });
|
|
196025
|
+
scopeBoundary = scope.key;
|
|
196026
|
+
}
|
|
196027
|
+
const enterprise = workspace.groups.some((group2) => group2.enterprise);
|
|
196028
|
+
const inEnterprise = (element) => {
|
|
196029
|
+
let group2 = workspace.groups.find((entry2) => entry2.key === top(element).group);
|
|
196030
|
+
for (let depth = 0; group2 !== void 0 && depth < workspace.groups.length; depth += 1) {
|
|
196031
|
+
if (group2.enterprise) return true;
|
|
196032
|
+
group2 = workspace.groups.find((entry2) => entry2.key === group2?.parent);
|
|
196033
|
+
}
|
|
196034
|
+
return false;
|
|
196035
|
+
};
|
|
196036
|
+
const order = (element) => innerKeys.has(element.key) ? 1 : element.kind === "person" ? 0 : 2;
|
|
196037
|
+
const placed = [...shown.values()].sort((a, b) => order(a) - order(b) || workspace.elements.indexOf(a) - workspace.elements.indexOf(b)).map((element) => {
|
|
196038
|
+
const holder = innerKeys.has(element.key) && view.level !== "context" ? scopeBoundary : view.level === "component" && within(element, system) ? system.key : null;
|
|
196039
|
+
const hidden = hiddenWords(workspace, element);
|
|
196040
|
+
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 };
|
|
196041
|
+
});
|
|
196042
|
+
const depthOf7 = (key) => {
|
|
196043
|
+
let depth = 0;
|
|
196044
|
+
for (let at3 = key; at3 !== null && depth <= boundaries.length; depth += 1) at3 = boundaries.find((boundary) => boundary.key === at3)?.parent ?? null;
|
|
196045
|
+
return depth;
|
|
196046
|
+
};
|
|
196047
|
+
const kept2 = (key) => {
|
|
196048
|
+
let at3 = key;
|
|
196049
|
+
while (at3 !== null && depthOf7(at3) > MAX_DEPTH16) at3 = boundaries.find((boundary) => boundary.key === at3)?.parent ?? null;
|
|
196050
|
+
return at3;
|
|
196051
|
+
};
|
|
196052
|
+
const elements = placed.map((entry2) => ({ ...entry2, boundary: kept2(entry2.boundary) }));
|
|
196053
|
+
const used = new Set(elements.map((entry2) => entry2.boundary));
|
|
196054
|
+
for (let changed = true, round2 = 0; changed && round2 <= boundaries.length; round2 += 1) {
|
|
196055
|
+
changed = false;
|
|
196056
|
+
for (const boundary of boundaries) if (used.has(boundary.key) && boundary.parent !== null && !used.has(boundary.parent)) {
|
|
196057
|
+
used.add(boundary.parent);
|
|
196058
|
+
changed = true;
|
|
196059
|
+
}
|
|
196060
|
+
}
|
|
196061
|
+
const shownBoundaries = boundaries.filter((boundary) => depthOf7(boundary.key) <= MAX_DEPTH16 && (boundary.element !== null || used.has(boundary.key)));
|
|
196062
|
+
const drawn = /* @__PURE__ */ new Set([...elements.map((entry2) => entry2.element.key), ...shownBoundaries.flatMap((boundary) => boundary.element === null ? [] : [boundary.element.key])]);
|
|
196063
|
+
const summarisedBy = (element) => ancestors(element).some((ancestor) => shown.has(ancestor.key));
|
|
196064
|
+
const summarised = workspace.elements.filter((element) => !drawn.has(element.key) && summarisedBy(element)).length;
|
|
196065
|
+
const omitted = workspace.elements.filter((element) => !drawn.has(element.key) && !summarisedBy(element));
|
|
196066
|
+
return { elements, boundaries: shownBoundaries, relationships: lines, summarised, omitted };
|
|
196067
|
+
}
|
|
196068
|
+
var MAX_DEPTH16, childrenOf;
|
|
196069
|
+
var init_view = __esm({
|
|
196070
|
+
"../../packages/diagrams/src/importers/structurizr/view.ts"() {
|
|
196071
|
+
"use strict";
|
|
196072
|
+
MAX_DEPTH16 = 4;
|
|
196073
|
+
childrenOf = (workspace, key) => workspace.elements.filter((element) => element.parent === key);
|
|
196074
|
+
}
|
|
196075
|
+
});
|
|
196076
|
+
|
|
196077
|
+
// ../../packages/diagrams/src/importers/structurizr/index.ts
|
|
196078
|
+
function isDatabase(element, workspace) {
|
|
196079
|
+
if (element.kind !== "container" && element.kind !== "component") return false;
|
|
196080
|
+
const tags = element.tags.map((tag) => tag.toLowerCase());
|
|
196081
|
+
return tags.includes("database") || workspace.cylinderTags.some((tag) => tags.includes(tag.toLowerCase())) || element.technology !== null && DATABASE_WORDS.test(element.technology);
|
|
196082
|
+
}
|
|
196083
|
+
function readWorkspace(text3, context) {
|
|
196084
|
+
if (/^\s*\{/.test(text3)) {
|
|
196085
|
+
let json2;
|
|
196086
|
+
try {
|
|
196087
|
+
json2 = JSON.parse(text3);
|
|
196088
|
+
} catch (error62) {
|
|
196089
|
+
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).");
|
|
196090
|
+
return null;
|
|
196091
|
+
}
|
|
196092
|
+
if (!isWorkspaceJson(json2)) {
|
|
196093
|
+
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.");
|
|
196094
|
+
return null;
|
|
196095
|
+
}
|
|
196096
|
+
return { workspace: readWorkspaceJson(json2), unresolved: [] };
|
|
196097
|
+
}
|
|
196098
|
+
return readDsl(text3);
|
|
196099
|
+
}
|
|
196100
|
+
function writeC4(workspace, view, shown, title, desc) {
|
|
196101
|
+
const ids = new IdAllocator();
|
|
196102
|
+
const hint2 = (element) => element.key.includes("/") ? element.name : element.key.split(".").pop() ?? element.name;
|
|
196103
|
+
for (const boundary of shown.boundaries) if (boundary.element !== null) ids.idFor(`b:${boundary.key}`, hint2(boundary.element));
|
|
196104
|
+
for (const entry2 of shown.elements) ids.idFor(`e:${entry2.element.key}`, hint2(entry2.element));
|
|
196105
|
+
for (const boundary of shown.boundaries) if (boundary.element === null) ids.idFor(`b:${boundary.key}`, boundary.name.toLowerCase());
|
|
196106
|
+
const lines = new SourceLines();
|
|
196107
|
+
lines.add(`c4 ${quote(title)}${options2({ view: view.level, direction: view.direction, desc })}`);
|
|
196108
|
+
const elementLine2 = (entry2, depth) => {
|
|
196109
|
+
const { element } = entry2;
|
|
196110
|
+
const type = isDatabase(element, workspace) ? "db" : element.kind;
|
|
196111
|
+
const text3 = [element.description === null ? null : cleanText(element.description), entry2.hidden === 0 ? null : `Holds ${entry2.hiddenWords}.`].filter((part) => part !== null).join(" ");
|
|
196112
|
+
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);
|
|
196113
|
+
};
|
|
196114
|
+
const writeBoundary = (boundary, depth) => {
|
|
196115
|
+
lines.gap();
|
|
196116
|
+
lines.add(`boundary ${ids.idFor(`b:${boundary.key}`)} ${quote(cleanText(boundary.name))}${options2({ kind: boundary.kind, tech: boundary.tech === null ? null : cleanText(boundary.tech), icon: BOUNDARY_LOOKS2[boundary.kind].icon, tone: BOUNDARY_LOOKS2[boundary.kind].tone }, ["tech"])} {`, depth);
|
|
196117
|
+
for (const entry2 of shown.elements) if (entry2.boundary === boundary.key) elementLine2(entry2, depth + 1);
|
|
196118
|
+
for (const child of shown.boundaries) if (child.parent === boundary.key) writeBoundary(child, depth + 1);
|
|
196119
|
+
lines.add("}", depth);
|
|
196120
|
+
};
|
|
196121
|
+
lines.gap();
|
|
196122
|
+
const people = shown.elements.filter((entry2) => entry2.boundary === null && entry2.element.kind === "person");
|
|
196123
|
+
for (const entry2 of people) elementLine2(entry2, 0);
|
|
196124
|
+
for (const boundary of shown.boundaries) if (boundary.parent === null) writeBoundary(boundary, 0);
|
|
196125
|
+
lines.gap();
|
|
196126
|
+
for (const entry2 of shown.elements) if (entry2.boundary === null && entry2.element.kind !== "person") elementLine2(entry2, 0);
|
|
196127
|
+
lines.gap();
|
|
196128
|
+
const kindOf3 = new Map(shown.elements.map((entry2) => [entry2.element.key, entry2.element.kind]));
|
|
196129
|
+
const ordered = [...shown.relationships].sort((a, b) => Number(kindOf3.get(a.from) !== "person") - Number(kindOf3.get(b.from) !== "person"));
|
|
196130
|
+
for (const line3 of ordered) {
|
|
196131
|
+
const { relationship } = line3;
|
|
196132
|
+
const async = relationship.tags.some((tag) => /^async(?:hronous)?$/i.test(tag));
|
|
196133
|
+
const label = relationship.description === null ? "" : ` : ${quote(cleanText(relationship.description))}${options2({ tech: relationship.technology === null ? null : cleanText(relationship.technology) }, ["tech"])}`;
|
|
196134
|
+
lines.add(`${ids.idFor(`e:${line3.from}`)} ${async ? "-->" : "->"} ${ids.idFor(`e:${line3.to}`)}${label}`);
|
|
196135
|
+
}
|
|
196136
|
+
return { source: lines.toString(), ids: { ...ids.mapped("b:"), ...ids.mapped("e:") }, links: shown.relationships.length };
|
|
196137
|
+
}
|
|
196138
|
+
function capped(shown, context) {
|
|
196139
|
+
const elements = shown.elements.slice(0, C4_BUDGET.maxElements);
|
|
196140
|
+
const keys = new Set(elements.map((entry2) => entry2.element.key));
|
|
196141
|
+
const relationships = shown.relationships.filter((line3) => keys.has(line3.from) && keys.has(line3.to)).slice(0, C4_BUDGET.maxRelationships);
|
|
196142
|
+
const leftElements = shown.elements.length - elements.length;
|
|
196143
|
+
const leftLines = shown.relationships.length - relationships.length;
|
|
196144
|
+
if (leftElements + leftLines > 0) {
|
|
196145
|
+
const first = shown.elements[C4_BUDGET.maxElements]?.element;
|
|
196146
|
+
context.report.add(
|
|
196147
|
+
DIAGNOSTIC_CODES.importDropped,
|
|
196148
|
+
first === void 0 ? START : spanAt3(first.line, first.column),
|
|
196149
|
+
`${[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.`,
|
|
196150
|
+
"Draw a smaller view: one container with options.view component, or one system with options.root."
|
|
196151
|
+
);
|
|
196152
|
+
}
|
|
196153
|
+
return { ...shown, elements, relationships, omitted: [...shown.omitted, ...shown.elements.slice(C4_BUDGET.maxElements).map((entry2) => entry2.element)] };
|
|
196154
|
+
}
|
|
196155
|
+
function readStructurizr(text3, context) {
|
|
196156
|
+
const read = readWorkspace(text3, context);
|
|
196157
|
+
if (read === null) return null;
|
|
196158
|
+
const { workspace, unresolved } = read;
|
|
196159
|
+
if (workspace.elements.length === 0) {
|
|
196160
|
+
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" } }.');
|
|
196161
|
+
return null;
|
|
196162
|
+
}
|
|
196163
|
+
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);
|
|
196164
|
+
const firstUnresolved = unresolved[0];
|
|
196165
|
+
if (firstUnresolved !== void 0) {
|
|
196166
|
+
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.");
|
|
196167
|
+
}
|
|
196168
|
+
const requested = context.options.view;
|
|
196169
|
+
const level2 = requested !== void 0 && LEVELS.includes(requested) ? requested : null;
|
|
196170
|
+
const chosen = chooseView(workspace, level2, context.options.root ?? null);
|
|
196171
|
+
if (chosen.missing !== null) {
|
|
196172
|
+
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"}.`);
|
|
196173
|
+
return null;
|
|
196174
|
+
}
|
|
196175
|
+
if (chosen.view === null) {
|
|
196176
|
+
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.");
|
|
196177
|
+
return null;
|
|
196178
|
+
}
|
|
196179
|
+
const view = chosen.view;
|
|
196180
|
+
const shown = capped(project(workspace, view), context);
|
|
196181
|
+
const omitted = shown.omitted;
|
|
196182
|
+
const firstOmitted = omitted[0];
|
|
196183
|
+
if (firstOmitted !== void 0) {
|
|
196184
|
+
context.report.add(
|
|
196185
|
+
DIAGNOSTIC_CODES.importSkipped,
|
|
196186
|
+
spanAt3(firstOmitted.line, firstOmitted.column),
|
|
196187
|
+
`${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(", ")}.`,
|
|
196188
|
+
"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."
|
|
196189
|
+
);
|
|
196190
|
+
}
|
|
196191
|
+
const scopeName = cleanText(view.scope.name);
|
|
196192
|
+
const title = context.title ?? (view.title === null ? `${scopeName}: ${LEVEL_WORDS[view.level].title}` : cleanText(view.title));
|
|
196193
|
+
const what = view.level === "context" ? `${scopeName} ${LEVEL_WORDS.context.sentence}` : `${LEVEL_WORDS[view.level].sentence} ${scopeName} and what they talk to`;
|
|
196194
|
+
const desc = `${what.charAt(0).toUpperCase()}${what.slice(1)}, imported from the Structurizr workspace${workspace.name === null ? "" : ` ${cleanText(workspace.name)}`}.`;
|
|
196195
|
+
const written3 = writeC4(workspace, view, shown, title, desc);
|
|
196196
|
+
const drawn = shown.elements.length + shown.boundaries.filter((boundary) => boundary.element !== null).length;
|
|
196197
|
+
const others = workspace.views.length > 1 ? ` The workspace defines ${countOf2(workspace.views.length, "view")}; draw another with options.view and options.root.` : "";
|
|
196198
|
+
return {
|
|
196199
|
+
kind: "c4",
|
|
196200
|
+
source: written3.source,
|
|
196201
|
+
stats: { items: shown.elements.length, links: written3.links, groups: shown.boundaries.length, dropped: omitted.length },
|
|
196202
|
+
advice: `Check that each element has a description and each relationship a technology, so the cards and lines say what they do.${others}`,
|
|
196203
|
+
coverage: { noun: "elements", total: workspace.elements.length, drawn, summarised: shown.summarised },
|
|
196204
|
+
ids: written3.ids
|
|
196205
|
+
};
|
|
196206
|
+
}
|
|
196207
|
+
var BOUNDARY_LOOKS2, DATABASE_WORDS, LEVELS, LEVEL_WORDS, structurizrImporter;
|
|
196208
|
+
var init_structurizr = __esm({
|
|
196209
|
+
"../../packages/diagrams/src/importers/structurizr/index.ts"() {
|
|
196210
|
+
"use strict";
|
|
196211
|
+
init_core();
|
|
196212
|
+
init_limits();
|
|
196213
|
+
init_shared2();
|
|
196214
|
+
init_dsl();
|
|
196215
|
+
init_json2();
|
|
196216
|
+
init_view();
|
|
196217
|
+
BOUNDARY_LOOKS2 = {
|
|
196218
|
+
system: { icon: "lucide:blocks", tone: "blue" },
|
|
196219
|
+
container: { icon: "lucide:box", tone: "blue" },
|
|
196220
|
+
group: { icon: "lucide:boxes", tone: "violet" },
|
|
196221
|
+
enterprise: { icon: "lucide:building", tone: "neutral" }
|
|
196222
|
+
};
|
|
196223
|
+
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;
|
|
196224
|
+
LEVELS = ["context", "container", "component"];
|
|
196225
|
+
LEVEL_WORDS = {
|
|
196226
|
+
context: { title: "system context", sentence: "and the people and systems around it" },
|
|
196227
|
+
container: { title: "containers", sentence: "the containers of" },
|
|
196228
|
+
component: { title: "components", sentence: "the components of" }
|
|
196229
|
+
};
|
|
196230
|
+
structurizrImporter = { format: "structurizr", kinds: ["c4"], joins: null, extensions: [".dsl", ".json"], read: readStructurizr };
|
|
196231
|
+
}
|
|
196232
|
+
});
|
|
196233
|
+
|
|
194247
196234
|
// ../../packages/diagrams/src/importers/terraform-plan/document.ts
|
|
194248
196235
|
function moduleOfAddress(address, type, mode) {
|
|
194249
196236
|
const own2 = `${mode === "data" ? "data." : ""}${type}.`;
|
|
@@ -194251,7 +196238,7 @@ function moduleOfAddress(address, type, mode) {
|
|
|
194251
196238
|
return at3 <= 0 ? "" : address.slice(0, at3 - 1);
|
|
194252
196239
|
}
|
|
194253
196240
|
function resourceOf3(raw, module) {
|
|
194254
|
-
if (!
|
|
196241
|
+
if (!isObject5(raw) || typeof raw["address"] !== "string" || typeof raw["type"] !== "string" || typeof raw["name"] !== "string") return null;
|
|
194255
196242
|
const mode = raw["mode"] === "data" ? "data" : "managed";
|
|
194256
196243
|
const index2 = typeof raw["index"] === "string" || typeof raw["index"] === "number" ? raw["index"] : null;
|
|
194257
196244
|
return {
|
|
@@ -194261,13 +196248,13 @@ function resourceOf3(raw, module) {
|
|
|
194261
196248
|
name: raw["name"],
|
|
194262
196249
|
index: index2,
|
|
194263
196250
|
module: module === "" ? moduleOfAddress(raw["address"], raw["type"], mode) : module,
|
|
194264
|
-
values:
|
|
194265
|
-
sensitive:
|
|
196251
|
+
values: isObject5(raw["values"]) ? raw["values"] : {},
|
|
196252
|
+
sensitive: isObject5(raw["sensitive_values"]) ? raw["sensitive_values"] : {},
|
|
194266
196253
|
dependsOn: strings2(raw["depends_on"])
|
|
194267
196254
|
};
|
|
194268
196255
|
}
|
|
194269
196256
|
function moduleResources(raw, depth = 0) {
|
|
194270
|
-
if (!
|
|
196257
|
+
if (!isObject5(raw) || depth > MAX_MODULE_DEPTH2) return [];
|
|
194271
196258
|
const address = typeof raw["address"] === "string" ? raw["address"] : "";
|
|
194272
196259
|
const own2 = (Array.isArray(raw["resources"]) ? raw["resources"] : []).map((entry2) => resourceOf3(entry2, address)).filter((entry2) => entry2 !== null);
|
|
194273
196260
|
const children = Array.isArray(raw["child_modules"]) ? raw["child_modules"].flatMap((child) => moduleResources(child, depth + 1)) : [];
|
|
@@ -194275,9 +196262,9 @@ function moduleResources(raw, depth = 0) {
|
|
|
194275
196262
|
}
|
|
194276
196263
|
function variablesOf(raw, sensitive) {
|
|
194277
196264
|
const out = /* @__PURE__ */ new Map();
|
|
194278
|
-
if (!
|
|
196265
|
+
if (!isObject5(raw)) return out;
|
|
194279
196266
|
for (const [name2, entry2] of Object.entries(raw)) {
|
|
194280
|
-
if (sensitive.has(name2) || !
|
|
196267
|
+
if (sensitive.has(name2) || !isObject5(entry2)) continue;
|
|
194281
196268
|
const value = entry2["value"];
|
|
194282
196269
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out.set(name2, String(value));
|
|
194283
196270
|
}
|
|
@@ -194286,28 +196273,28 @@ function variablesOf(raw, sensitive) {
|
|
|
194286
196273
|
function sensitiveVariables(configuration) {
|
|
194287
196274
|
const out = /* @__PURE__ */ new Set();
|
|
194288
196275
|
const root = configuration === null ? null : configuration["root_module"];
|
|
194289
|
-
const variables =
|
|
194290
|
-
for (const [name2, entry2] of Object.entries(variables)) if (
|
|
196276
|
+
const variables = isObject5(root) && isObject5(root["variables"]) ? root["variables"] : {};
|
|
196277
|
+
for (const [name2, entry2] of Object.entries(variables)) if (isObject5(entry2) && entry2["sensitive"] === true) out.add(name2);
|
|
194291
196278
|
return out;
|
|
194292
196279
|
}
|
|
194293
196280
|
function changesOf(raw) {
|
|
194294
196281
|
const out = /* @__PURE__ */ new Map();
|
|
194295
196282
|
if (!Array.isArray(raw)) return out;
|
|
194296
196283
|
for (const entry2 of raw) {
|
|
194297
|
-
if (!
|
|
196284
|
+
if (!isObject5(entry2) || typeof entry2["address"] !== "string" || !isObject5(entry2["change"])) continue;
|
|
194298
196285
|
const change = entry2["change"];
|
|
194299
|
-
out.set(entry2["address"], { actions: strings2(change["actions"]), previous: typeof entry2["previous_address"] === "string" ? entry2["previous_address"] : null, before:
|
|
196286
|
+
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
196287
|
}
|
|
194301
196288
|
return out;
|
|
194302
196289
|
}
|
|
194303
196290
|
function readPlanDocument(json2) {
|
|
194304
|
-
if (!
|
|
194305
|
-
const configuration =
|
|
194306
|
-
const providers = configuration !== null &&
|
|
196291
|
+
if (!isObject5(json2)) return null;
|
|
196292
|
+
const configuration = isObject5(json2["configuration"]) ? json2["configuration"] : null;
|
|
196293
|
+
const providers = configuration !== null && isObject5(configuration["provider_config"]) ? configuration["provider_config"] : {};
|
|
194307
196294
|
const variables = variablesOf(json2["variables"], sensitiveVariables(configuration));
|
|
194308
|
-
if (
|
|
194309
|
-
const planned =
|
|
194310
|
-
const prior =
|
|
196295
|
+
if (isObject5(json2["planned_values"]) || Array.isArray(json2["resource_changes"])) {
|
|
196296
|
+
const planned = isObject5(json2["planned_values"]) ? moduleResources(json2["planned_values"]["root_module"]) : [];
|
|
196297
|
+
const prior = isObject5(json2["prior_state"]) && isObject5(json2["prior_state"]["values"]) ? moduleResources(json2["prior_state"]["values"]["root_module"]) : [];
|
|
194311
196298
|
const changes = changesOf(json2["resource_changes"]);
|
|
194312
196299
|
const kept2 = new Set(planned.map((resource) => resource.address));
|
|
194313
196300
|
const data = prior.filter((resource) => resource.mode === "data" && !kept2.has(resource.address));
|
|
@@ -194320,11 +196307,11 @@ function readPlanDocument(json2) {
|
|
|
194320
196307
|
}
|
|
194321
196308
|
const drift = /* @__PURE__ */ new Set();
|
|
194322
196309
|
if (Array.isArray(json2["resource_drift"])) {
|
|
194323
|
-
for (const entry2 of json2["resource_drift"]) if (
|
|
196310
|
+
for (const entry2 of json2["resource_drift"]) if (isObject5(entry2) && typeof entry2["address"] === "string") drift.add(entry2["address"]);
|
|
194324
196311
|
}
|
|
194325
196312
|
return { kind: "plan", resources: [...planned, ...data], destroyed, changes, drift, configuration, providers, variables };
|
|
194326
196313
|
}
|
|
194327
|
-
if (
|
|
196314
|
+
if (isObject5(json2["values"]) && isObject5(json2["values"]["root_module"])) {
|
|
194328
196315
|
return { kind: "state", resources: moduleResources(json2["values"]["root_module"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration, providers, variables };
|
|
194329
196316
|
}
|
|
194330
196317
|
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 +196320,12 @@ function readPlanDocument(json2) {
|
|
|
194333
196320
|
function rawStateResources(raw) {
|
|
194334
196321
|
const out = [];
|
|
194335
196322
|
for (const block of raw) {
|
|
194336
|
-
if (!
|
|
196323
|
+
if (!isObject5(block) || typeof block["type"] !== "string" || typeof block["name"] !== "string" || !Array.isArray(block["instances"])) continue;
|
|
194337
196324
|
const module = typeof block["module"] === "string" ? block["module"] : "";
|
|
194338
196325
|
const mode = block["mode"] === "data" ? "data" : "managed";
|
|
194339
196326
|
const base = `${module === "" ? "" : `${module}.`}${mode === "data" ? "data." : ""}${block["type"]}.${block["name"]}`;
|
|
194340
196327
|
for (const instance of block["instances"]) {
|
|
194341
|
-
if (!
|
|
196328
|
+
if (!isObject5(instance)) continue;
|
|
194342
196329
|
const key = instance["index_key"];
|
|
194343
196330
|
const index2 = typeof key === "string" || typeof key === "number" ? key : null;
|
|
194344
196331
|
const address = `${base}${index2 === null ? "" : typeof index2 === "number" ? `[${index2}]` : `[${JSON.stringify(index2)}]`}`;
|
|
@@ -194346,20 +196333,20 @@ function rawStateResources(raw) {
|
|
|
194346
196333
|
if (Array.isArray(instance["sensitive_attributes"])) {
|
|
194347
196334
|
for (const path of instance["sensitive_attributes"]) {
|
|
194348
196335
|
const first = Array.isArray(path) ? path[0] : null;
|
|
194349
|
-
if (
|
|
196336
|
+
if (isObject5(first) && typeof first["value"] === "string") sensitive[first["value"]] = true;
|
|
194350
196337
|
}
|
|
194351
196338
|
}
|
|
194352
|
-
out.push({ address, mode, type: block["type"], name: block["name"], index: index2, module, values:
|
|
196339
|
+
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
196340
|
}
|
|
194354
196341
|
}
|
|
194355
196342
|
return out;
|
|
194356
196343
|
}
|
|
194357
|
-
var MAX_MODULE_DEPTH2,
|
|
194358
|
-
var
|
|
196344
|
+
var MAX_MODULE_DEPTH2, isObject5, strings2, destroys;
|
|
196345
|
+
var init_document4 = __esm({
|
|
194359
196346
|
"../../packages/diagrams/src/importers/terraform-plan/document.ts"() {
|
|
194360
196347
|
"use strict";
|
|
194361
196348
|
MAX_MODULE_DEPTH2 = 16;
|
|
194362
|
-
|
|
196349
|
+
isObject5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
194363
196350
|
strings2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
194364
196351
|
destroys = (change) => change !== void 0 && change.actions.length === 1 && change.actions[0] === "delete";
|
|
194365
196352
|
}
|
|
@@ -194367,14 +196354,14 @@ var init_document3 = __esm({
|
|
|
194367
196354
|
|
|
194368
196355
|
// ../../packages/diagrams/src/importers/terraform-plan/references.ts
|
|
194369
196356
|
function attributesOf3(expressions, depth = 0) {
|
|
194370
|
-
if (!
|
|
196357
|
+
if (!isObject5(expressions) || depth > MAX_NESTING) return [];
|
|
194371
196358
|
const out = [];
|
|
194372
196359
|
for (const [name2, value] of Object.entries(expressions)) {
|
|
194373
|
-
if (
|
|
196360
|
+
if (isObject5(value) && ("references" in value || "constant_value" in value)) {
|
|
194374
196361
|
const refs = strings3(value["references"]);
|
|
194375
196362
|
out.push({ name: name2, refs: refs.filter((ref) => !SAME_INSTANCE.has(ref)), paired: refs.some((ref) => SAME_INSTANCE.has(ref)) });
|
|
194376
196363
|
} else if (Array.isArray(value)) for (const block of value) out.push(...attributesOf3(block, depth + 1));
|
|
194377
|
-
else if (
|
|
196364
|
+
else if (isObject5(value)) out.push(...attributesOf3(value, depth + 1));
|
|
194378
196365
|
}
|
|
194379
196366
|
return out;
|
|
194380
196367
|
}
|
|
@@ -194399,13 +196386,13 @@ function parentOf3(module) {
|
|
|
194399
196386
|
const at3 = module.lastIndexOf(".module.");
|
|
194400
196387
|
return at3 === -1 ? "" : module.slice(0, at3);
|
|
194401
196388
|
}
|
|
194402
|
-
var
|
|
196389
|
+
var MAX_DEPTH17, MAX_NESTING, TYPE2, SAME_INSTANCE, strings3, Configuration;
|
|
194403
196390
|
var init_references2 = __esm({
|
|
194404
196391
|
"../../packages/diagrams/src/importers/terraform-plan/references.ts"() {
|
|
194405
196392
|
"use strict";
|
|
194406
196393
|
init_address();
|
|
194407
|
-
|
|
194408
|
-
|
|
196394
|
+
init_document4();
|
|
196395
|
+
MAX_DEPTH17 = 8;
|
|
194409
196396
|
MAX_NESTING = 8;
|
|
194410
196397
|
TYPE2 = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
|
|
194411
196398
|
SAME_INSTANCE = /* @__PURE__ */ new Set(["each.key", "each.value", "count.index"]);
|
|
@@ -194421,11 +196408,11 @@ var init_references2 = __esm({
|
|
|
194421
196408
|
moduleAt(address) {
|
|
194422
196409
|
let module = this.root;
|
|
194423
196410
|
for (const call of callsOf2(address)) {
|
|
194424
|
-
const calls =
|
|
196411
|
+
const calls = isObject5(module) && isObject5(module["module_calls"]) ? module["module_calls"] : null;
|
|
194425
196412
|
const entry2 = calls === null ? null : calls[call.name];
|
|
194426
|
-
module =
|
|
196413
|
+
module = isObject5(entry2) ? entry2["module"] : null;
|
|
194427
196414
|
}
|
|
194428
|
-
return
|
|
196415
|
+
return isObject5(module) ? module : null;
|
|
194429
196416
|
}
|
|
194430
196417
|
/** The call of a module instance, as its parent's configuration writes it: its source, version, and the values it passes. */
|
|
194431
196418
|
callAt(address) {
|
|
@@ -194433,20 +196420,20 @@ var init_references2 = __esm({
|
|
|
194433
196420
|
const last = calls[calls.length - 1];
|
|
194434
196421
|
if (last === void 0) return null;
|
|
194435
196422
|
const parent = this.moduleAt(parentOf3(address));
|
|
194436
|
-
const entry2 = parent !== null &&
|
|
194437
|
-
return
|
|
196423
|
+
const entry2 = parent !== null && isObject5(parent["module_calls"]) ? parent["module_calls"][last.name] : null;
|
|
196424
|
+
return isObject5(entry2) ? entry2 : null;
|
|
194438
196425
|
}
|
|
194439
196426
|
/** The configured block of a resource, by the module instance it is in and its address inside the module. */
|
|
194440
196427
|
resourceAt(module, local2) {
|
|
194441
196428
|
const config2 = this.moduleAt(module);
|
|
194442
196429
|
const list = config2 !== null && Array.isArray(config2["resources"]) ? config2["resources"] : [];
|
|
194443
|
-
const found = list.find((entry2) =>
|
|
196430
|
+
const found = list.find((entry2) => isObject5(entry2) && entry2["address"] === local2);
|
|
194444
196431
|
if (found === void 0) return null;
|
|
194445
196432
|
return { attributes: attributesOf3(found["expressions"]), dependsOn: strings3(found["depends_on"]), providerKey: typeof found["provider_config_key"] === "string" ? found["provider_config_key"] : null };
|
|
194446
196433
|
}
|
|
194447
196434
|
/** What a reference written in a module instance names, followed through module outputs and the variables its call passes. */
|
|
194448
196435
|
resolve(ref, module, depth = 0) {
|
|
194449
|
-
if (depth >
|
|
196436
|
+
if (depth > MAX_DEPTH17) return [];
|
|
194450
196437
|
const steps = references(ref)[0] ?? [];
|
|
194451
196438
|
const [first, second, third, fourth] = steps;
|
|
194452
196439
|
const name2 = (step) => step?.kind === "name" ? step.text : null;
|
|
@@ -194471,9 +196458,9 @@ var init_references2 = __esm({
|
|
|
194471
196458
|
const out = [];
|
|
194472
196459
|
for (const instance of chosen) {
|
|
194473
196460
|
const config2 = this.moduleAt(instance);
|
|
194474
|
-
const outputs = config2 !== null &&
|
|
196461
|
+
const outputs = config2 !== null && isObject5(config2["outputs"]) ? config2["outputs"] : {};
|
|
194475
196462
|
const entry2 = outputs[output2];
|
|
194476
|
-
const expression2 =
|
|
196463
|
+
const expression2 = isObject5(entry2) && isObject5(entry2["expression"]) ? entry2["expression"] : null;
|
|
194477
196464
|
for (const inner of strings3(expression2?.["references"])) out.push(...this.resolve(inner, instance, depth + 1));
|
|
194478
196465
|
}
|
|
194479
196466
|
return out;
|
|
@@ -194482,9 +196469,9 @@ var init_references2 = __esm({
|
|
|
194482
196469
|
variable(module, variable, depth) {
|
|
194483
196470
|
if (module === "") return [{ kind: "var", name: variable }];
|
|
194484
196471
|
const call = this.callAt(module);
|
|
194485
|
-
const expressions = call !== null &&
|
|
196472
|
+
const expressions = call !== null && isObject5(call["expressions"]) ? call["expressions"] : {};
|
|
194486
196473
|
const passed = expressions[variable];
|
|
194487
|
-
const refs =
|
|
196474
|
+
const refs = isObject5(passed) ? strings3(passed["references"]).filter((ref) => !SAME_INSTANCE.has(ref)) : [];
|
|
194488
196475
|
return refs.flatMap((ref) => this.resolve(ref, parentOf3(module), depth + 1));
|
|
194489
196476
|
}
|
|
194490
196477
|
};
|
|
@@ -194493,7 +196480,7 @@ var init_references2 = __esm({
|
|
|
194493
196480
|
|
|
194494
196481
|
// ../../packages/diagrams/src/importers/terraform-plan/resources.ts
|
|
194495
196482
|
function rawOf(value) {
|
|
194496
|
-
if (
|
|
196483
|
+
if (isObject5(value)) {
|
|
194497
196484
|
const entries2 = Object.entries(value).filter((entry2) => typeof entry2[1] === "string");
|
|
194498
196485
|
return `{ ${entries2.map(([key, entry2]) => `${key} = ${JSON.stringify(entry2)}`).join(", ")} }`;
|
|
194499
196486
|
}
|
|
@@ -194507,7 +196494,7 @@ function valuesOf2(resource) {
|
|
|
194507
196494
|
}
|
|
194508
196495
|
const tags = resource.values["tags"];
|
|
194509
196496
|
const hidden = resource.sensitive["tags"];
|
|
194510
|
-
if (
|
|
196497
|
+
if (isObject5(tags) && typeof tags["Name"] === "string" && !(isObject5(hidden) && hidden["Name"] === true) && hidden !== true) out.set("tags.Name", tags["Name"]);
|
|
194511
196498
|
return out;
|
|
194512
196499
|
}
|
|
194513
196500
|
function blockOf2(resource, values, start2) {
|
|
@@ -194525,7 +196512,7 @@ function stringsOf(values, sensitive) {
|
|
|
194525
196512
|
if (out.length >= MAX_VALUES || depth > MAX_VALUE_DEPTH || hidden === true) return;
|
|
194526
196513
|
if (typeof value === "string") out.push({ name: name2, value });
|
|
194527
196514
|
else if (Array.isArray(value)) value.forEach((item, index2) => walk(item, name2, Array.isArray(hidden) ? hidden[index2] : void 0, depth + 1));
|
|
194528
|
-
else if (
|
|
196515
|
+
else if (isObject5(value)) for (const [key, entry2] of Object.entries(value)) walk(entry2, key, isObject5(hidden) ? hidden[key] : void 0, depth + 1);
|
|
194529
196516
|
};
|
|
194530
196517
|
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
196518
|
return out;
|
|
@@ -194546,7 +196533,7 @@ function planResources(document2, text3) {
|
|
|
194546
196533
|
if (byBase.has(same)) alias.set(baseOf(resource), same);
|
|
194547
196534
|
}
|
|
194548
196535
|
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 :
|
|
196536
|
+
const configuration = new Configuration(document2.configuration === null ? null : isObject5(document2.configuration["root_module"]) ? document2.configuration["root_module"] : null, instances);
|
|
194550
196537
|
const expand2 = (target, own2, paired) => {
|
|
194551
196538
|
if (target.kind !== "item") return [];
|
|
194552
196539
|
const base = alias.get(target.address) ?? target.address;
|
|
@@ -194688,7 +196675,7 @@ var init_resources2 = __esm({
|
|
|
194688
196675
|
init_generic();
|
|
194689
196676
|
init_graph4();
|
|
194690
196677
|
init_resources();
|
|
194691
|
-
|
|
196678
|
+
init_document4();
|
|
194692
196679
|
init_references2();
|
|
194693
196680
|
MAX_VALUE_DEPTH = 6;
|
|
194694
196681
|
MAX_VALUES = 400;
|
|
@@ -194719,19 +196706,19 @@ function importedOf(json2) {
|
|
|
194719
196706
|
const out = /* @__PURE__ */ new Set();
|
|
194720
196707
|
const changes = json2["resource_changes"];
|
|
194721
196708
|
if (Array.isArray(changes)) {
|
|
194722
|
-
for (const entry2 of changes) if (
|
|
196709
|
+
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
196710
|
}
|
|
194724
196711
|
return out;
|
|
194725
196712
|
}
|
|
194726
196713
|
function accountsOf(document2, types) {
|
|
194727
196714
|
const out = /* @__PURE__ */ new Map();
|
|
194728
196715
|
for (const entry2 of Object.values(document2.providers)) {
|
|
194729
|
-
if (!
|
|
196716
|
+
if (!isObject5(entry2) || typeof entry2["name"] !== "string") continue;
|
|
194730
196717
|
const cloud = providerOf2(`${entry2["name"]}_x`);
|
|
194731
196718
|
if (cloud === null || out.get(cloud) !== void 0) continue;
|
|
194732
|
-
const expressions =
|
|
194733
|
-
const
|
|
194734
|
-
out.set(cloud, cloud === "gcp" && typeof
|
|
196719
|
+
const expressions = isObject5(entry2["expressions"]) ? entry2["expressions"] : {};
|
|
196720
|
+
const project2 = isObject5(expressions["project"]) ? expressions["project"]["constant_value"] : void 0;
|
|
196721
|
+
out.set(cloud, cloud === "gcp" && typeof project2 === "string" ? project2 : null);
|
|
194735
196722
|
}
|
|
194736
196723
|
for (const type of types) {
|
|
194737
196724
|
const cloud = providerOf2(type);
|
|
@@ -194743,9 +196730,9 @@ function regionsOf2(document2) {
|
|
|
194743
196730
|
const out = /* @__PURE__ */ new Map();
|
|
194744
196731
|
const byProvider = /* @__PURE__ */ new Map();
|
|
194745
196732
|
for (const [key, entry2] of Object.entries(document2.providers)) {
|
|
194746
|
-
if (!
|
|
194747
|
-
const expressions =
|
|
194748
|
-
const region =
|
|
196733
|
+
if (!isObject5(entry2) || typeof entry2["name"] !== "string" || key.includes(":")) continue;
|
|
196734
|
+
const expressions = isObject5(entry2["expressions"]) ? entry2["expressions"] : {};
|
|
196735
|
+
const region = isObject5(expressions["region"]) ? expressions["region"]["constant_value"] : void 0;
|
|
194749
196736
|
if (typeof region !== "string" || region === "") continue;
|
|
194750
196737
|
out.set(key, region);
|
|
194751
196738
|
byProvider.set(entry2["name"], /* @__PURE__ */ new Set([...byProvider.get(entry2["name"]) ?? [], region]));
|
|
@@ -194778,7 +196765,7 @@ function readTerraformPlan(text3, context) {
|
|
|
194778
196765
|
return null;
|
|
194779
196766
|
}
|
|
194780
196767
|
const document2 = readPlanDocument(json2);
|
|
194781
|
-
if (document2 === null || !
|
|
196768
|
+
if (document2 === null || !isObject5(json2)) {
|
|
194782
196769
|
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
196770
|
return null;
|
|
194784
196771
|
}
|
|
@@ -194846,7 +196833,7 @@ var init_terraform_plan = __esm({
|
|
|
194846
196833
|
init_labels();
|
|
194847
196834
|
init_resources();
|
|
194848
196835
|
init_values2();
|
|
194849
|
-
|
|
196836
|
+
init_document4();
|
|
194850
196837
|
init_resources2();
|
|
194851
196838
|
CHANGES = {
|
|
194852
196839
|
create: { tone: "green", word: "create", said: "one marked + is created", mark: "create" },
|
|
@@ -194869,7 +196856,7 @@ function childOf(parent, name2, line3) {
|
|
|
194869
196856
|
parent.push(entry2);
|
|
194870
196857
|
return entry2;
|
|
194871
196858
|
}
|
|
194872
|
-
function
|
|
196859
|
+
function nameOf9(raw) {
|
|
194873
196860
|
const text3 = cleanText(raw, "");
|
|
194874
196861
|
const isDir = text3.endsWith("/") && text3.length > 1;
|
|
194875
196862
|
return { name: isDir ? text3.slice(0, -1) : text3, isDir };
|
|
@@ -194896,7 +196883,7 @@ function readCommand(lines) {
|
|
|
194896
196883
|
depth += 1;
|
|
194897
196884
|
at3 += 4;
|
|
194898
196885
|
}
|
|
194899
|
-
const { name: name2, isDir } =
|
|
196886
|
+
const { name: name2, isDir } = nameOf9(line3.slice(at3));
|
|
194900
196887
|
if (name2 === "") continue;
|
|
194901
196888
|
if (!branched && root === null && top.length === 0) {
|
|
194902
196889
|
root = name2;
|
|
@@ -194946,7 +196933,7 @@ function readOutline(lines) {
|
|
|
194946
196933
|
for (const [index2, raw] of lines.entries()) {
|
|
194947
196934
|
if (raw.trim() === "") continue;
|
|
194948
196935
|
const { width, text: text3 } = indentOf6(raw);
|
|
194949
|
-
const { name: name2, isDir } =
|
|
196936
|
+
const { name: name2, isDir } = nameOf9(text3);
|
|
194950
196937
|
if (name2 === "") continue;
|
|
194951
196938
|
while (stack.length > 0 && (stack[stack.length - 1]?.width ?? 0) >= width) stack.pop();
|
|
194952
196939
|
const parent = stack[stack.length - 1]?.entry;
|
|
@@ -195162,6 +197149,8 @@ var init_registry4 = __esm({
|
|
|
195162
197149
|
"../../packages/diagrams/src/importers/registry.ts"() {
|
|
195163
197150
|
"use strict";
|
|
195164
197151
|
init_arm();
|
|
197152
|
+
init_asyncapi();
|
|
197153
|
+
init_azure_pipelines();
|
|
195165
197154
|
init_backstage();
|
|
195166
197155
|
init_bicep();
|
|
195167
197156
|
init_cdk();
|
|
@@ -195172,6 +197161,7 @@ var init_registry4 = __esm({
|
|
|
195172
197161
|
init_git_log();
|
|
195173
197162
|
init_helm();
|
|
195174
197163
|
init_github_actions();
|
|
197164
|
+
init_gitlab_ci();
|
|
195175
197165
|
init_json();
|
|
195176
197166
|
init_kubernetes();
|
|
195177
197167
|
init_kustomize();
|
|
@@ -195179,6 +197169,7 @@ var init_registry4 = __esm({
|
|
|
195179
197169
|
init_prisma();
|
|
195180
197170
|
init_pulumi();
|
|
195181
197171
|
init_sql();
|
|
197172
|
+
init_structurizr();
|
|
195182
197173
|
init_terraform();
|
|
195183
197174
|
init_terraform_plan();
|
|
195184
197175
|
init_tree5();
|
|
@@ -195199,7 +197190,11 @@ var init_registry4 = __esm({
|
|
|
195199
197190
|
helm: helmImporter,
|
|
195200
197191
|
kustomize: kustomizeImporter,
|
|
195201
197192
|
backstage: backstageImporter,
|
|
197193
|
+
structurizr: structurizrImporter,
|
|
197194
|
+
asyncapi: asyncapiImporter,
|
|
195202
197195
|
"github-actions": githubActionsImporter,
|
|
197196
|
+
"gitlab-ci": gitlabCiImporter,
|
|
197197
|
+
"azure-pipelines": azurePipelinesImporter,
|
|
195203
197198
|
csv: csvImporter,
|
|
195204
197199
|
json: jsonImporter,
|
|
195205
197200
|
tree: treeImporter,
|
|
@@ -196698,14 +198693,14 @@ function isProduct(ref) {
|
|
|
196698
198693
|
return cloudSetOf2(ref) !== void 0 || setOf(ref) === "simple";
|
|
196699
198694
|
}
|
|
196700
198695
|
function isTheIcon(query, ref) {
|
|
196701
|
-
if (normalizePhrase(
|
|
198696
|
+
if (normalizePhrase(nameOf10(ref)) === query) return true;
|
|
196702
198697
|
if (customIconPhrases(ref)?.has(query) === true) return true;
|
|
196703
198698
|
const set2 = cloudSetOf2(ref);
|
|
196704
|
-
if (set2 !== void 0 &&
|
|
198699
|
+
if (set2 !== void 0 && nameOf10(ref) === "cloud" && CLOUD_PROVIDER_SPECS[set2].names.includes(query)) return true;
|
|
196705
198700
|
return (phrasesByText().get(query) ?? []).some((phrase2) => phrase2.ref === ref && !phrase2.isGeneric);
|
|
196706
198701
|
}
|
|
196707
198702
|
function nameHasWords(query, ref) {
|
|
196708
|
-
const words2 =
|
|
198703
|
+
const words2 = nameOf10(ref).split("-");
|
|
196709
198704
|
return query.split(" ").every((word2) => words2.includes(word2));
|
|
196710
198705
|
}
|
|
196711
198706
|
function isContested(query, top, others, needsSameMatch) {
|
|
@@ -196721,7 +198716,7 @@ function classifyIcon(name2, results) {
|
|
|
196721
198716
|
if (nameHasWords(query, top) && !isContested(query, top, others, false)) return "strong";
|
|
196722
198717
|
return "ambiguous";
|
|
196723
198718
|
}
|
|
196724
|
-
var phraseIndex, setOf,
|
|
198719
|
+
var phraseIndex, setOf, nameOf10, cloudSetOf2;
|
|
196725
198720
|
var init_icon_confidence = __esm({
|
|
196726
198721
|
"../../packages/diagrams/src/tools/workflows/icon-confidence.ts"() {
|
|
196727
198722
|
"use strict";
|
|
@@ -196729,7 +198724,7 @@ var init_icon_confidence = __esm({
|
|
|
196729
198724
|
init_icons();
|
|
196730
198725
|
phraseIndex = null;
|
|
196731
198726
|
setOf = (ref) => ref.slice(0, ref.indexOf(":"));
|
|
196732
|
-
|
|
198727
|
+
nameOf10 = (ref) => ref.slice(ref.indexOf(":") + 1);
|
|
196733
198728
|
cloudSetOf2 = (ref) => CLOUD_SETS.find((set2) => set2 === setOf(ref));
|
|
196734
198729
|
}
|
|
196735
198730
|
});
|
|
@@ -197080,13 +199075,13 @@ function isMarkCell(cell2) {
|
|
|
197080
199075
|
const word2 = cell2.trim().toLowerCase();
|
|
197081
199076
|
return YES_WORDS.includes(word2) || NO_WORDS.includes(word2) || TICKS.includes(word2) || CROSSES2.includes(word2) || word2 === "partial";
|
|
197082
199077
|
}
|
|
197083
|
-
function
|
|
199078
|
+
function wordsOf6(text3) {
|
|
197084
199079
|
return text3.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim().split(" ").filter((word2) => word2 !== "");
|
|
197085
199080
|
}
|
|
197086
199081
|
function cleanLabel2(text3) {
|
|
197087
199082
|
return text3.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[`*_~"\\]/g, "").replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
|
|
197088
199083
|
}
|
|
197089
|
-
function
|
|
199084
|
+
function stepLabel2(text3) {
|
|
197090
199085
|
const clean = cleanLabel2(text3).replace(/[.;]$/, "");
|
|
197091
199086
|
const capital2 = `${clean.charAt(0).toUpperCase()}${clean.slice(1)}`;
|
|
197092
199087
|
if (capital2.length <= ONE_LINE) return { label: capital2, sub: null };
|
|
@@ -197097,7 +199092,7 @@ function stepLabel(text3) {
|
|
|
197097
199092
|
return { label: capital2, sub: null };
|
|
197098
199093
|
}
|
|
197099
199094
|
function stepText2(text3) {
|
|
197100
|
-
const { label, sub } =
|
|
199095
|
+
const { label, sub } = stepLabel2(text3);
|
|
197101
199096
|
return sub === null ? `"${label}"` : `"${label}" sub="${sub}"`;
|
|
197102
199097
|
}
|
|
197103
199098
|
function withDescription(source, description) {
|
|
@@ -197114,7 +199109,7 @@ function idMaker(fallback) {
|
|
|
197114
199109
|
let count3 = 0;
|
|
197115
199110
|
return (label) => {
|
|
197116
199111
|
count3 += 1;
|
|
197117
|
-
const words2 =
|
|
199112
|
+
const words2 = wordsOf6(label).slice(0, 3);
|
|
197118
199113
|
let id = words2.join("_");
|
|
197119
199114
|
if (!/^[a-z]/.test(id) || RESERVED_IDS.has(id)) id = `${fallback}${count3}`;
|
|
197120
199115
|
id = id.slice(0, 24);
|
|
@@ -197852,7 +199847,7 @@ function singular2(word2) {
|
|
|
197852
199847
|
function iconFor(name2) {
|
|
197853
199848
|
const product = iconNamedBy(name2, null);
|
|
197854
199849
|
if (product !== null) return product;
|
|
197855
|
-
for (const word2 of
|
|
199850
|
+
for (const word2 of wordsOf6(name2)) {
|
|
197856
199851
|
const ref = ROLE_ICONS2[word2] ?? ROLE_ICONS2[singular2(word2)];
|
|
197857
199852
|
if (ref !== void 0 && isKnownIcon(ref)) return ref;
|
|
197858
199853
|
}
|
|
@@ -197944,7 +199939,7 @@ var init_icons4 = __esm({
|
|
|
197944
199939
|
function chain(ids, arrow = "->", label = "") {
|
|
197945
199940
|
return ids.slice(1).map((id, index2) => `${ids[index2] ?? id} ${arrow} ${id}${label}`);
|
|
197946
199941
|
}
|
|
197947
|
-
function
|
|
199942
|
+
function layersOf2(material) {
|
|
197948
199943
|
const lists = listsOf(material);
|
|
197949
199944
|
if (lists.length >= 2) return lists.slice(0, 6).map((list) => ({ name: list.label, blocks: list.values.slice(0, 6) }));
|
|
197950
199945
|
if (material.items.some((item) => item.depth > 0)) {
|
|
@@ -197966,10 +199961,15 @@ function partType(name2) {
|
|
|
197966
199961
|
if (/\b(web app|browser|mobile|app|client|frontend)\b/i.test(name2)) return "client";
|
|
197967
199962
|
return "service";
|
|
197968
199963
|
}
|
|
199964
|
+
function roleOption(verb) {
|
|
199965
|
+
const named = verbNamedBy(verb);
|
|
199966
|
+
const role = named === null ? null : EDGE_STYLES[named].role;
|
|
199967
|
+
return role === null ? "" : ` role=${role}`;
|
|
199968
|
+
}
|
|
197969
199969
|
function linkedFlow(material, title) {
|
|
197970
199970
|
const ids = idMaker("part");
|
|
197971
199971
|
const nodes = /* @__PURE__ */ new Map();
|
|
197972
|
-
const
|
|
199972
|
+
const nodeOf5 = (label) => {
|
|
197973
199973
|
const key = label.toLowerCase();
|
|
197974
199974
|
const known3 = nodes.get(key);
|
|
197975
199975
|
if (known3 !== void 0 && /^[a-z]/.test(known3.label) && /^[A-Z]/.test(label)) known3.label = label;
|
|
@@ -197978,8 +199978,8 @@ function linkedFlow(material, title) {
|
|
|
197978
199978
|
nodes.set(key, node3);
|
|
197979
199979
|
return node3.id;
|
|
197980
199980
|
};
|
|
197981
|
-
const links = material.relations.slice(0, MOST * 2).map((relation2) => ({ from:
|
|
197982
|
-
const edges = links.map((link2) => `${link2.from} -> ${link2.to} : ${quoted4(link2.verb)}`);
|
|
199981
|
+
const links = material.relations.slice(0, MOST * 2).map((relation2) => ({ from: nodeOf5(relation2.from), to: nodeOf5(relation2.to), verb: relation2.verb }));
|
|
199982
|
+
const edges = links.map((link2) => `${link2.from} -> ${link2.to} : ${quoted4(link2.verb)}${roleOption(link2.verb)}`);
|
|
197983
199983
|
return sourceOf(`flow ${quoted4(title)} direction=${directionFor(longestChain2(links))}`, [
|
|
197984
199984
|
...[...nodes.values()].map((node3) => `node ${node3.id} ${partType(node3.label)} ${quoted4(node3.label)}${iconOption(node3.label)}`),
|
|
197985
199985
|
"",
|
|
@@ -197998,7 +199998,7 @@ function longestChain2(links) {
|
|
|
197998
199998
|
};
|
|
197999
199999
|
return Math.max(0, ...links.map((link2) => walk(link2.from, /* @__PURE__ */ new Set([link2.from]))));
|
|
198000
200000
|
}
|
|
198001
|
-
function
|
|
200001
|
+
function stepsOf2(material) {
|
|
198002
200002
|
const pairs = material.labelled.filter((line3) => cleanLabel2(line3.text) !== "");
|
|
198003
200003
|
const repeated = new Set(pairs.map((line3) => line3.label.toLowerCase())).size < pairs.length;
|
|
198004
200004
|
if (pairs.length >= 2 && repeated || pairs.length >= 3) return pairs.slice(0, MOST).map((pair2) => ({ label: pair2.label, text: pair2.text }));
|
|
@@ -198015,6 +200015,8 @@ var WIDEST_CHAIN, SYSTEM_BUILDERS;
|
|
|
198015
200015
|
var init_systems = __esm({
|
|
198016
200016
|
"../../packages/diagrams/src/guidance/starters/systems.ts"() {
|
|
198017
200017
|
"use strict";
|
|
200018
|
+
init_constants();
|
|
200019
|
+
init_label_icon();
|
|
198018
200020
|
init_icons4();
|
|
198019
200021
|
init_text6();
|
|
198020
200022
|
init_shared4();
|
|
@@ -198101,7 +200103,7 @@ var init_systems = __esm({
|
|
|
198101
200103
|
},
|
|
198102
200104
|
layers: (material, title) => {
|
|
198103
200105
|
const ids = idMaker("block");
|
|
198104
|
-
const body6 =
|
|
200106
|
+
const body6 = layersOf2(material).flatMap((layer2) => {
|
|
198105
200107
|
const blocks2 = distinctLabels(layer2.blocks);
|
|
198106
200108
|
return [`layer ${quoted4(layer2.name)} {`, ...(blocks2.length > 0 ? blocks2 : [layer2.name]).map((block) => ` block ${ids(block)} ${quoted4(block)}`), "}", ""];
|
|
198107
200109
|
});
|
|
@@ -198109,7 +200111,7 @@ var init_systems = __esm({
|
|
|
198109
200111
|
},
|
|
198110
200112
|
swimlane: (material, title) => {
|
|
198111
200113
|
const ids = idMaker("step");
|
|
198112
|
-
const steps =
|
|
200114
|
+
const steps = stepsOf2(material);
|
|
198113
200115
|
const laneNames = distinctLabels(steps.map((step) => step.label)).slice(0, 6);
|
|
198114
200116
|
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
200117
|
const begin = ids("Start");
|
|
@@ -198155,13 +200157,13 @@ function stem(word2) {
|
|
|
198155
200157
|
return word2;
|
|
198156
200158
|
}
|
|
198157
200159
|
function keyOf4(text3) {
|
|
198158
|
-
return
|
|
200160
|
+
return wordsOf6(text3).map(stem).join(" ");
|
|
198159
200161
|
}
|
|
198160
200162
|
function wordPoints(texts) {
|
|
198161
200163
|
const strong = /* @__PURE__ */ new Map();
|
|
198162
200164
|
const weak = /* @__PURE__ */ new Map();
|
|
198163
200165
|
for (const { text: text3, weight } of texts) {
|
|
198164
|
-
const words2 =
|
|
200166
|
+
const words2 = wordsOf6(text3).map(stem);
|
|
198165
200167
|
const seen = /* @__PURE__ */ new Set();
|
|
198166
200168
|
for (let start2 = 0; start2 < words2.length; start2 += 1) {
|
|
198167
200169
|
let key = "";
|
|
@@ -198284,8 +200286,8 @@ var init_rank = __esm({
|
|
|
198284
200286
|
MEDIUM = 4;
|
|
198285
200287
|
INDEX = /* @__PURE__ */ new Map();
|
|
198286
200288
|
for (const intent of INTENTS) {
|
|
198287
|
-
for (const [
|
|
198288
|
-
for (const phrase2 of
|
|
200289
|
+
for (const [phrases2, isStrong] of [[intent.strong, true], [intent.weak, false]]) {
|
|
200290
|
+
for (const phrase2 of phrases2) INDEX.set(keyOf4(phrase2), [...INDEX.get(keyOf4(phrase2)) ?? [], { id: intent.id, isStrong }]);
|
|
198289
200291
|
}
|
|
198290
200292
|
}
|
|
198291
200293
|
LONGEST_PHRASE = Math.max(...[...INDEX.keys()].map((key) => key.split(" ").length));
|
|
@@ -198889,7 +200891,7 @@ var init_draw_for_view = __esm({
|
|
|
198889
200891
|
});
|
|
198890
200892
|
|
|
198891
200893
|
// ../../packages/diagrams/src/view/index.ts
|
|
198892
|
-
var
|
|
200894
|
+
var init_view2 = __esm({
|
|
198893
200895
|
"../../packages/diagrams/src/view/index.ts"() {
|
|
198894
200896
|
"use strict";
|
|
198895
200897
|
init_fragment();
|
|
@@ -198974,7 +200976,7 @@ var init_view_link = __esm({
|
|
|
198974
200976
|
init_constants();
|
|
198975
200977
|
init_apply_defaults();
|
|
198976
200978
|
init_schema4();
|
|
198977
|
-
|
|
200979
|
+
init_view2();
|
|
198978
200980
|
SOURCE_OF = {
|
|
198979
200981
|
draw_diagram: (args, answer) => answer["valid"] === true ? args["source"] : null,
|
|
198980
200982
|
draw_from_pattern: (_args, answer) => answer["valid"] === true ? answer["source"] : null,
|
|
@@ -199379,7 +201381,7 @@ var init_server_info = __esm({
|
|
|
199379
201381
|
`Draws ${joinWords(kindNouns(), "and")} diagrams from a small line-oriented text language.`,
|
|
199380
201382
|
"Prefer the workflow tools: each does the work of several single tools in one call.",
|
|
199381
201383
|
"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.",
|
|
201384
|
+
"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
201385
|
"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
201386
|
"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
201387
|
'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.',
|
|
@@ -199387,6 +201389,7 @@ var init_server_info = __esm({
|
|
|
199387
201389
|
"Set embedSource true on draw_diagram whenever you save an SVG into a repository, so the file carries its source and read_diagram can give it back next time; the source is then readable by anyone who has the file.",
|
|
199388
201390
|
...SAVING_INSTRUCTIONS,
|
|
199389
201391
|
'An item with no icon= gets the icon its label names when the match is certain, such as the Postgres mark on a node labelled "Postgres", so label items with the product they are; icon=none keeps one item plain and icons=off on the header keeps them all plain.',
|
|
201392
|
+
'For a finished look, label flow arrows with verbs ("reads", "publishes", "deploys to") so they draw icons, add role= (data, async, identity, private) to the lines that carry those, and give groups a type=; style in get_diagram_syntax says more.',
|
|
199390
201393
|
"Use map_icons to choose icons for many names at once; it never guesses, so choose from the candidates for an ambiguous name, and never invent an icon.",
|
|
199391
201394
|
"To move Mermaid to Plotwork, call convert_mermaid with one diagram, read every diagnostic and its hint, then choose node types and icons; for a whole Markdown file call sync_markdown with the document, its path, and convertMermaid true, write the returned markdown and files, then review the diff.",
|
|
199392
201395
|
"When the repository has a plotwork.config.json (or .plotwork/config.json) at its root, read it and pass it as settings to every tool that takes settings: its defaults fill the header options the source leaves out, and broken style rules come back as warnings to fix.",
|
|
@@ -199763,7 +201766,7 @@ var init_create_server = __esm({
|
|
|
199763
201766
|
"use strict";
|
|
199764
201767
|
init_dist();
|
|
199765
201768
|
init_tools();
|
|
199766
|
-
|
|
201769
|
+
init_view2();
|
|
199767
201770
|
init_activity();
|
|
199768
201771
|
init_audit();
|
|
199769
201772
|
init_engine_runner();
|
|
@@ -200227,7 +202230,7 @@ var VIEWER_URL_VARIABLE;
|
|
|
200227
202230
|
var init_viewer_address = __esm({
|
|
200228
202231
|
"src/viewer-address.ts"() {
|
|
200229
202232
|
"use strict";
|
|
200230
|
-
|
|
202233
|
+
init_view2();
|
|
200231
202234
|
VIEWER_URL_VARIABLE = "PLOTWORK_VIEWER_URL";
|
|
200232
202235
|
}
|
|
200233
202236
|
});
|