@r0kshan/cairn 1.0.0-RC13 → 1.0.0-RC14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -21
- package/THIRD-PARTY-NOTICES.md +311 -7
- package/bin/cairn.mjs +1468 -563
- package/dist/cairn.mjs +1159 -501
- package/licenses/Apache-2.0.txt +73 -0
- package/licenses/BSD-3-Clause.txt +11 -0
- package/licenses/CC-BY-4.0.txt +396 -0
- package/licenses/LGPL-2.1.txt +501 -0
- package/licenses/MIT-javascript-logo.js.txt +21 -0
- package/licenses/README.md +50 -0
- package/licenses/bun-LICENSE.md +84 -0
- package/licenses/simple-icons-CC0-1.0.md +30 -0
- package/package.json +3 -3
package/bin/cairn.mjs
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/*!
|
|
3
|
+
* cairn — Apache-2.0 — https://github.com/R0kshan/cairn
|
|
4
|
+
* Copyright 2026 Røkshan.
|
|
5
|
+
*
|
|
6
|
+
* This artifact contains third-party code and artwork:
|
|
7
|
+
*
|
|
8
|
+
* elkjs 0.12.0 — (c) 2017 Kiel University and others.
|
|
9
|
+
* Dual-licensed EPL-2.0 OR GPL-3.0-or-later; cairn elects EPL-2.0.
|
|
10
|
+
* Full text: licenses/elkjs-EPL-2.0.md — https://www.eclipse.org/legal/epl-2.0
|
|
11
|
+
*
|
|
12
|
+
* Simple Icons 16.29.0 artwork — CC0-1.0 project-wide.
|
|
13
|
+
* Six of the vendored icons carry their own terms instead — MIT,
|
|
14
|
+
* BSD-3-Clause, CC-BY-4.0 or Apache-2.0 — and are attributed individually.
|
|
15
|
+
* Full texts: licenses/
|
|
16
|
+
*
|
|
17
|
+
* Per-icon attribution and the full licence texts ship with this artifact:
|
|
18
|
+
* the package root (npm), the app directory (Scoop), or
|
|
19
|
+
* share/doc/cairn (Homebrew, install.sh). Also at
|
|
20
|
+
* https://github.com/R0kshan/cairn/blob/main/THIRD-PARTY-NOTICES.md
|
|
21
|
+
*/
|
|
2
22
|
var __create = Object.create;
|
|
3
23
|
var __defProp = Object.defineProperty;
|
|
4
24
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -251,13 +271,13 @@ var require_elk_bundled = __commonJS({
|
|
|
251
271
|
this.id = id + 1;
|
|
252
272
|
msg.id = id;
|
|
253
273
|
var self2 = this;
|
|
254
|
-
return new Promise(function(
|
|
274
|
+
return new Promise(function(resolve2, reject) {
|
|
255
275
|
self2.resolvers[id] = function(err, res) {
|
|
256
276
|
if (err) {
|
|
257
277
|
self2.convertGwtStyleError(err);
|
|
258
278
|
reject(err);
|
|
259
279
|
} else {
|
|
260
|
-
|
|
280
|
+
resolve2(res);
|
|
261
281
|
}
|
|
262
282
|
};
|
|
263
283
|
self2.worker.postMessage(msg);
|
|
@@ -92343,7 +92363,11 @@ var init_ast = __esm({
|
|
|
92343
92363
|
});
|
|
92344
92364
|
explanations = {
|
|
92345
92365
|
E0101: "Syntax error: the file does not follow the DSL grammar.",
|
|
92366
|
+
E0105: '`logo:` takes either a built-in name (`logo: react`) or a quoted path to a file in the workspace (`logo: "./logos/acme.svg"`). A URL is refused on purpose: a diagram that fetches its logos stops being self-contained, leaks the reader\'s IP to whoever hosts them, and rots silently when the address dies \u2014 so cairn inlines a file instead of linking one.',
|
|
92346
92367
|
E0106: "`order:` takes a whole number \u2265 0. On a top-level element it sets the reading order the disposition defines \u2014 left to right for `wide`/`slide`, top to bottom for `tall`/`page` \u2014 by banding the element inside its own layout partition, so it never crosses into another partition. Inside a container the axis flips: a child's layer belongs to the flows and elk honors no constraint that would change it, so there `order:` sorts the siblings that share a layer. Values need not be contiguous.",
|
|
92368
|
+
E0107: 'Unknown built-in logo. The built-in set is deliberately small \u2014 it covers common stack technologies, not every brand. Anything outside it is still reachable as a workspace file: `logo: "./logos/name.svg"`.',
|
|
92369
|
+
E0108: "This element kind does not carry a logo. A logo marks what a piece of software is built with, so the kinds that accept one are the kinds that run code; actors are people and containers are groupings, so neither takes one.",
|
|
92370
|
+
W0580: "A `logo:` file could not be inlined \u2014 it is missing, too large, or not one of the supported types. Only a warning: the diagram is still valid and renders without the mark, because a decoration that failed to load is no reason to fail a build.",
|
|
92347
92371
|
E0201: "Unknown element kind for the active view. Each view defines its own kinds (e.g. logical: actor-group, actor, system, layer, block, external).",
|
|
92348
92372
|
E0202: "Duplicate identifier. IDs are flat and unique per file (decision D1): every element needs a distinct ID so flows can reference it unambiguously.",
|
|
92349
92373
|
E0203: "The logical view forbids unlabelled arrows: every flow must name the data, command or event it carries. A logical diagram tells what circulates, not just who talks to whom.",
|
|
@@ -92363,39 +92387,48 @@ var init_ast = __esm({
|
|
|
92363
92387
|
E0223: "Unknown attachment side. A flow endpoint may name the side it attaches to \u2014 `APP.right -> DB.left` \u2014 using the diagram as it is read: `left`, `right`, `top`, `bottom`. The side is a hint, not a guarantee: a side the layout cannot reach is dropped with a W0570 warning rather than forced.",
|
|
92364
92388
|
E0240: "The infrastructure view requires every flow to carry its protocol (and port if relevant): the flow matrix is the primary output of this view. Add `(HTTPS/443)` after the label.",
|
|
92365
92389
|
E0221: 'Unknown business-object reference: a flow carries `[AN_ID]` that no `business-object` declaration defines. Declare it once (`business-object ID "Name" "description"`) so the registry and the chips stay consistent.',
|
|
92366
|
-
E0222: "Business objects are a logical-view concept (what data circulates between functional blocks). They are not part of the application
|
|
92390
|
+
E0222: "Business objects are a logical-view concept (what data circulates between functional blocks). They are not part of the application or infrastructure views \u2014 model the exchange with the flow label and technical tail instead. Remove the `business-object` declaration and its `[refs]`, or switch the diagram to `logical`.",
|
|
92367
92391
|
W0530: "Completeness check: a declared business object is never carried by any flow \u2014 either connect it to the flows that transport it, or remove it from this view.",
|
|
92368
|
-
E0217: "A sensitive asset must sit inside a trust zone: its protection level is defined by the zone that contains it.",
|
|
92369
|
-
E0218: "A security node (firewall, WAF, bastion, reverse proxy) lives inside a trust zone \u2014 typically the exposed zone whose traffic it filters.",
|
|
92370
|
-
E0250: 'The security view requires each trust zone to declare a sensitivity level in parentheses after the label: `trust-zone DMZ "DMZ" (public)`. Levels, least \u2192 most trusted: public, internal, restricted, secret. The level drives the zone color and the trust-boundary crossing checks.',
|
|
92371
92392
|
W0570: "A declared attachment side (`APP.right -> DB.left`) did not survive layout: the flow ended up on another side of the element. Pins are honored where the layout can reach them and dropped where it cannot, rather than forced into an unreadable route. Move the element instead (`order:`), pin the other endpoint, or drop the pin.",
|
|
92372
|
-
W0571: "An endpoint reads `ID.side`, but `ID.side` is itself a declared element, and a declared id always wins \u2014 so the flow attaches to that element and no side is pinned. Rename the element if you meant the side."
|
|
92373
|
-
W0560: "Security check: this flow enters a more-trusted zone from a less-trusted one without passing through a security-node (firewall/WAF/bastion). Route it through a filtering point, or confirm the direct path is deliberate. This is the diagram equivalent of a missing firewall rule review.",
|
|
92374
|
-
W0561: "Security check: an inter-zone flow does not state its encryption/protocol. Cross-zone traffic should declare how it is protected: add `(TLS1.3)` or the relevant protocol after the label."
|
|
92393
|
+
W0571: "An endpoint reads `ID.side`, but `ID.side` is itself a declared element, and a declared id always wins \u2014 so the flow attaches to that element and no side is pinned. Rename the element if you meant the side."
|
|
92375
92394
|
};
|
|
92376
92395
|
}
|
|
92377
92396
|
});
|
|
92378
92397
|
|
|
92379
92398
|
// src/themes.ts
|
|
92399
|
+
function isDarkTheme(name) {
|
|
92400
|
+
return name === "classic-dark" || THEME_SPECS[name]?.dark === true;
|
|
92401
|
+
}
|
|
92402
|
+
function registerTheme(name, spec) {
|
|
92403
|
+
if (RESERVED_THEME_NAMES.includes(name)) {
|
|
92404
|
+
throw new Error(`\`${name}\` is a reserved theme name \u2014 rename the theme file`);
|
|
92405
|
+
}
|
|
92406
|
+
THEME_SPECS[name] = spec;
|
|
92407
|
+
themes[name] = buildTheme(spec);
|
|
92408
|
+
if (!themeNames.includes(name)) themeNames.push(name);
|
|
92409
|
+
}
|
|
92380
92410
|
function themeFor(name, view) {
|
|
92381
|
-
if (name === "classic")
|
|
92382
|
-
|
|
92383
|
-
|
|
92384
|
-
|
|
92385
|
-
|
|
92386
|
-
|
|
92387
|
-
|
|
92388
|
-
|
|
92389
|
-
|
|
92390
|
-
|
|
92391
|
-
|
|
92392
|
-
|
|
92393
|
-
|
|
92411
|
+
if (name === "classic") return { palette: lightPalette, kinds: view.defaults };
|
|
92412
|
+
if (name === "classic-dark") return { palette: darkPalette, kinds: view.defaultsDark };
|
|
92413
|
+
return applyTheme(themes[name] ?? themes.light, view);
|
|
92414
|
+
}
|
|
92415
|
+
function themeFromSpec(spec, view) {
|
|
92416
|
+
return applyTheme(buildTheme(spec), view);
|
|
92417
|
+
}
|
|
92418
|
+
function paletteFor(name) {
|
|
92419
|
+
if (name === "classic") return lightPalette;
|
|
92420
|
+
if (name === "classic-dark") return darkPalette;
|
|
92421
|
+
return themes[name]?.palette ?? lightPalette;
|
|
92422
|
+
}
|
|
92423
|
+
function paletteFromSpec(spec) {
|
|
92424
|
+
return buildTheme(spec).palette;
|
|
92425
|
+
}
|
|
92426
|
+
function applyTheme(theme, view) {
|
|
92394
92427
|
const kinds = {};
|
|
92395
|
-
for (const kind of view.kinds) kinds[kind] = theme.roles[roleForKind(kind
|
|
92396
|
-
return { palette: theme.palette, kinds
|
|
92428
|
+
for (const kind of view.kinds) kinds[kind] = theme.roles[roleForKind(kind)] ?? {};
|
|
92429
|
+
return { palette: theme.palette, kinds };
|
|
92397
92430
|
}
|
|
92398
|
-
var lightPalette, darkPalette,
|
|
92431
|
+
var lightPalette, darkPalette, flowPalette, containerStyle, leafStyle, KIND_ROLE_MAP, roleForKind, buildTheme, THEME_SPECS, themes, themeNames, RESERVED_THEME_NAMES;
|
|
92399
92432
|
var init_themes = __esm({
|
|
92400
92433
|
"src/themes.ts"() {
|
|
92401
92434
|
"use strict";
|
|
@@ -92447,10 +92480,6 @@ var init_themes = __esm({
|
|
|
92447
92480
|
chipStroke: "#b08d2a",
|
|
92448
92481
|
chipText: "#e0c068"
|
|
92449
92482
|
};
|
|
92450
|
-
palettes = {
|
|
92451
|
-
light: lightPalette,
|
|
92452
|
-
dark: darkPalette
|
|
92453
|
-
};
|
|
92454
92483
|
flowPalette = {
|
|
92455
92484
|
light: [
|
|
92456
92485
|
"#1f77b4",
|
|
@@ -92497,16 +92526,15 @@ var init_themes = __esm({
|
|
|
92497
92526
|
datastore: "datastore",
|
|
92498
92527
|
queue: "datastore",
|
|
92499
92528
|
gateway: "authGateway",
|
|
92529
|
+
firewall: "firewall",
|
|
92500
92530
|
auth: "auth",
|
|
92501
92531
|
idp: "identityProvider",
|
|
92502
92532
|
site: "site",
|
|
92503
92533
|
"network-zone": "networkZone",
|
|
92504
92534
|
server: "server",
|
|
92505
|
-
"app-instance": "appInstance"
|
|
92506
|
-
"security-node": "securityNode",
|
|
92507
|
-
asset: "leaf"
|
|
92535
|
+
"app-instance": "appInstance"
|
|
92508
92536
|
};
|
|
92509
|
-
roleForKind = (kind
|
|
92537
|
+
roleForKind = (kind) => KIND_ROLE_MAP[kind] ?? "leaf";
|
|
92510
92538
|
buildTheme = (spec) => {
|
|
92511
92539
|
const paletteSpec = spec.pal, accentColors = spec.accentColors;
|
|
92512
92540
|
const palette = {
|
|
@@ -92542,28 +92570,25 @@ var init_themes = __esm({
|
|
|
92542
92570
|
application: containerStyle(accentColors.appF, accentColors.app),
|
|
92543
92571
|
layer: containerStyle(accentColors.goldF, accentColors.gold, false, 1),
|
|
92544
92572
|
external: containerStyle(accentColors.violetF, accentColors.violet, true),
|
|
92545
|
-
untrusted: containerStyle(accentColors.redF, accentColors.red, true, 1.3),
|
|
92546
92573
|
leaf: leafStyle(accentColors.leafF, accentColors.leafS),
|
|
92547
92574
|
datastore: leafStyle(accentColors.purpleF, accentColors.purple),
|
|
92548
92575
|
site: containerStyle(accentColors.siteF, accentColors.siteS, false, 1.4),
|
|
92549
92576
|
networkZone: containerStyle(accentColors.greenF, accentColors.green, true),
|
|
92550
92577
|
server: containerStyle(accentColors.serverF, accentColors.serverS, false, 1.5),
|
|
92551
92578
|
appInstance: leafStyle(accentColors.aiF, accentColors.aiS, 1.2),
|
|
92552
|
-
|
|
92579
|
+
// Accent keys predate the roles that read them: `auth`/`authF` is the
|
|
92580
|
+
// gateway's orange, `authn`/`authnF` the auth middleware's blue. The two
|
|
92581
|
+
// used to share the `node` orange, which is what made a gateway and an
|
|
92582
|
+
// auth middleware indistinguishable in a dense infrastructure view.
|
|
92553
92583
|
authGateway: leafStyle(accentColors.authF, accentColors.auth, 1.4),
|
|
92554
|
-
|
|
92584
|
+
firewall: leafStyle(accentColors.fwF, accentColors.fw, 1.6),
|
|
92585
|
+
auth: leafStyle(accentColors.authnF, accentColors.authn, 1.5),
|
|
92555
92586
|
identityProvider: leafStyle(accentColors.idpF, accentColors.idp)
|
|
92556
|
-
},
|
|
92557
|
-
levels: {
|
|
92558
|
-
public: containerStyle(spec.lv.public[0], spec.lv.public[1], false, 1.4),
|
|
92559
|
-
internal: containerStyle(spec.lv.internal[0], spec.lv.internal[1], false, 1.4),
|
|
92560
|
-
restricted: containerStyle(spec.lv.restricted[0], spec.lv.restricted[1], false, 1.4),
|
|
92561
|
-
secret: containerStyle(spec.lv.secret[0], spec.lv.secret[1], false, 1.4)
|
|
92562
92587
|
}
|
|
92563
92588
|
};
|
|
92564
92589
|
};
|
|
92565
|
-
|
|
92566
|
-
light:
|
|
92590
|
+
THEME_SPECS = {
|
|
92591
|
+
light: {
|
|
92567
92592
|
pal: {
|
|
92568
92593
|
bg: "#ffffff",
|
|
92569
92594
|
text: "#17202c",
|
|
@@ -92611,16 +92636,15 @@ var init_themes = __esm({
|
|
|
92611
92636
|
auth: "#b85a30",
|
|
92612
92637
|
authF: "#f5e6dd",
|
|
92613
92638
|
idp: "#3a8f8f",
|
|
92614
|
-
idpF: "#e0f0f0"
|
|
92615
|
-
|
|
92616
|
-
|
|
92617
|
-
|
|
92618
|
-
|
|
92619
|
-
restricted: ["#e9f2fb", "#2f7cc4"],
|
|
92620
|
-
secret: ["#efe9f7", "#7a55a8"]
|
|
92639
|
+
idpF: "#e0f0f0",
|
|
92640
|
+
fw: "#c0392b",
|
|
92641
|
+
fwF: "#fdecea",
|
|
92642
|
+
authn: "#2f6fb5",
|
|
92643
|
+
authnF: "#e8f1fb"
|
|
92621
92644
|
}
|
|
92622
|
-
}
|
|
92623
|
-
dark:
|
|
92645
|
+
},
|
|
92646
|
+
dark: {
|
|
92647
|
+
dark: true,
|
|
92624
92648
|
pal: {
|
|
92625
92649
|
bg: "#1e2530",
|
|
92626
92650
|
text: "#e6edf3",
|
|
@@ -92668,16 +92692,14 @@ var init_themes = __esm({
|
|
|
92668
92692
|
auth: "#c96a4a",
|
|
92669
92693
|
authF: "#332218",
|
|
92670
92694
|
idp: "#4fafaf",
|
|
92671
|
-
idpF: "#1a2e2e"
|
|
92672
|
-
|
|
92673
|
-
|
|
92674
|
-
|
|
92675
|
-
|
|
92676
|
-
restricted: ["#1f2a37", "#4a86b8"],
|
|
92677
|
-
secret: ["#291f33", "#8a6cb0"]
|
|
92695
|
+
idpF: "#1a2e2e",
|
|
92696
|
+
fw: "#e5675a",
|
|
92697
|
+
fwF: "#33211f",
|
|
92698
|
+
authn: "#6fa8e0",
|
|
92699
|
+
authnF: "#1d2735"
|
|
92678
92700
|
}
|
|
92679
|
-
}
|
|
92680
|
-
slate:
|
|
92701
|
+
},
|
|
92702
|
+
slate: {
|
|
92681
92703
|
pal: {
|
|
92682
92704
|
bg: "#f7f9fb",
|
|
92683
92705
|
text: "#26303c",
|
|
@@ -92725,16 +92747,14 @@ var init_themes = __esm({
|
|
|
92725
92747
|
auth: "#a85a30",
|
|
92726
92748
|
authF: "#f0e4dd",
|
|
92727
92749
|
idp: "#3a8f8f",
|
|
92728
|
-
idpF: "#e4f0f0"
|
|
92729
|
-
|
|
92730
|
-
|
|
92731
|
-
|
|
92732
|
-
|
|
92733
|
-
restricted: ["#e8eff6", "#3b6ea5"],
|
|
92734
|
-
secret: ["#efecf5", "#7d6ba8"]
|
|
92750
|
+
idpF: "#e4f0f0",
|
|
92751
|
+
fw: "#bd4b3c",
|
|
92752
|
+
fwF: "#f9e9e6",
|
|
92753
|
+
authn: "#3a6ea5",
|
|
92754
|
+
authnF: "#e9f0f8"
|
|
92735
92755
|
}
|
|
92736
|
-
}
|
|
92737
|
-
sand:
|
|
92756
|
+
},
|
|
92757
|
+
sand: {
|
|
92738
92758
|
pal: {
|
|
92739
92759
|
bg: "#faf6ee",
|
|
92740
92760
|
text: "#3a2f22",
|
|
@@ -92782,16 +92802,14 @@ var init_themes = __esm({
|
|
|
92782
92802
|
auth: "#a85a30",
|
|
92783
92803
|
authF: "#f0e5dd",
|
|
92784
92804
|
idp: "#3a7a6f",
|
|
92785
|
-
idpF: "#e5f0ed"
|
|
92786
|
-
|
|
92787
|
-
|
|
92788
|
-
|
|
92789
|
-
|
|
92790
|
-
restricted: ["#e6f0f1", "#3f7a8c"],
|
|
92791
|
-
secret: ["#f0e8ef", "#8a5f7a"]
|
|
92805
|
+
idpF: "#e5f0ed",
|
|
92806
|
+
fw: "#b8492f",
|
|
92807
|
+
fwF: "#f8e8e0",
|
|
92808
|
+
authn: "#3a6b9a",
|
|
92809
|
+
authnF: "#e9eff7"
|
|
92792
92810
|
}
|
|
92793
|
-
}
|
|
92794
|
-
contrast:
|
|
92811
|
+
},
|
|
92812
|
+
contrast: {
|
|
92795
92813
|
pal: {
|
|
92796
92814
|
bg: "#ffffff",
|
|
92797
92815
|
text: "#000000",
|
|
@@ -92839,16 +92857,15 @@ var init_themes = __esm({
|
|
|
92839
92857
|
auth: "#993a1a",
|
|
92840
92858
|
authF: "#f6e3dd",
|
|
92841
92859
|
idp: "#005a5a",
|
|
92842
|
-
idpF: "#daf0f0"
|
|
92843
|
-
|
|
92844
|
-
|
|
92845
|
-
|
|
92846
|
-
|
|
92847
|
-
restricted: ["#e0edf7", "#005a9c"],
|
|
92848
|
-
secret: ["#eee0f7", "#6a2fa0"]
|
|
92860
|
+
idpF: "#daf0f0",
|
|
92861
|
+
fw: "#a3140a",
|
|
92862
|
+
fwF: "#fbe3df",
|
|
92863
|
+
authn: "#00408f",
|
|
92864
|
+
authnF: "#dfe8fb"
|
|
92849
92865
|
}
|
|
92850
|
-
}
|
|
92851
|
-
nord:
|
|
92866
|
+
},
|
|
92867
|
+
nord: {
|
|
92868
|
+
dark: true,
|
|
92852
92869
|
pal: {
|
|
92853
92870
|
bg: "#2e3440",
|
|
92854
92871
|
text: "#eceff4",
|
|
@@ -92896,16 +92913,14 @@ var init_themes = __esm({
|
|
|
92896
92913
|
auth: "#c96a4a",
|
|
92897
92914
|
authF: "#332218",
|
|
92898
92915
|
idp: "#6fafaf",
|
|
92899
|
-
idpF: "#203432"
|
|
92900
|
-
|
|
92901
|
-
|
|
92902
|
-
|
|
92903
|
-
|
|
92904
|
-
restricted: ["#2f3a44", "#81a1c1"],
|
|
92905
|
-
secret: ["#312a3a", "#a38bbd"]
|
|
92916
|
+
idpF: "#203432",
|
|
92917
|
+
fw: "#bf616a",
|
|
92918
|
+
fwF: "#3b2f34",
|
|
92919
|
+
authn: "#81a1c1",
|
|
92920
|
+
authnF: "#333c4a"
|
|
92906
92921
|
}
|
|
92907
|
-
}
|
|
92908
|
-
solarized:
|
|
92922
|
+
},
|
|
92923
|
+
solarized: {
|
|
92909
92924
|
pal: {
|
|
92910
92925
|
bg: "#fdf6e3",
|
|
92911
92926
|
text: "#586e75",
|
|
@@ -92953,17 +92968,25 @@ var init_themes = __esm({
|
|
|
92953
92968
|
auth: "#b85a30",
|
|
92954
92969
|
authF: "#f5e6dd",
|
|
92955
92970
|
idp: "#2aa198",
|
|
92956
|
-
idpF: "#dff0ec"
|
|
92957
|
-
|
|
92958
|
-
|
|
92959
|
-
|
|
92960
|
-
|
|
92961
|
-
restricted: ["#e3edf3", "#268bd2"],
|
|
92962
|
-
secret: ["#e8e6f2", "#6c71c4"]
|
|
92971
|
+
idpF: "#dff0ec",
|
|
92972
|
+
fw: "#dc322f",
|
|
92973
|
+
fwF: "#f7e3dd",
|
|
92974
|
+
authn: "#268bd2",
|
|
92975
|
+
authnF: "#e3edf5"
|
|
92963
92976
|
}
|
|
92964
|
-
}
|
|
92977
|
+
}
|
|
92965
92978
|
};
|
|
92979
|
+
themes = Object.fromEntries(
|
|
92980
|
+
Object.entries(THEME_SPECS).map(([name, spec]) => [name, buildTheme(spec)])
|
|
92981
|
+
);
|
|
92966
92982
|
themeNames = [...Object.keys(themes), "classic", "classic-dark"];
|
|
92983
|
+
RESERVED_THEME_NAMES = [
|
|
92984
|
+
"classic",
|
|
92985
|
+
"classic-dark",
|
|
92986
|
+
"__proto__",
|
|
92987
|
+
"constructor",
|
|
92988
|
+
"prototype"
|
|
92989
|
+
];
|
|
92967
92990
|
}
|
|
92968
92991
|
});
|
|
92969
92992
|
|
|
@@ -93087,7 +93110,7 @@ function parseFlow(p, sourceToken) {
|
|
|
93087
93110
|
model.flows.push(flow);
|
|
93088
93111
|
}
|
|
93089
93112
|
function parseElement(p, sourceToken, parent) {
|
|
93090
|
-
const { matchToken, advance, reportError,
|
|
93113
|
+
const { matchToken, advance, reportError, syncToNextLine, model } = p;
|
|
93091
93114
|
if (!matchToken("id")) {
|
|
93092
93115
|
reportError(
|
|
93093
93116
|
`invalid declaration: \`${sourceToken.text}\` alone on this line`,
|
|
@@ -93107,28 +93130,6 @@ function parseElement(p, sourceToken, parent) {
|
|
|
93107
93130
|
parent: parent ?? void 0
|
|
93108
93131
|
};
|
|
93109
93132
|
if (matchToken("str")) element.label = advance().text;
|
|
93110
|
-
if (matchToken("lparen")) {
|
|
93111
|
-
advance();
|
|
93112
|
-
if (matchToken("id")) {
|
|
93113
|
-
const token = advance();
|
|
93114
|
-
element.attr = {
|
|
93115
|
-
value: token.text,
|
|
93116
|
-
span: token.span
|
|
93117
|
-
};
|
|
93118
|
-
} else
|
|
93119
|
-
reportError(
|
|
93120
|
-
"attribute value expected after `(`",
|
|
93121
|
-
lookAhead().span,
|
|
93122
|
-
'e.g. `trust-zone DMZ "DMZ" (public)`'
|
|
93123
|
-
);
|
|
93124
|
-
if (matchToken("rparen")) advance();
|
|
93125
|
-
else
|
|
93126
|
-
reportError(
|
|
93127
|
-
"`)` expected to close the attribute",
|
|
93128
|
-
lookAhead().span,
|
|
93129
|
-
'e.g. `trust-zone DMZ "DMZ" (public)`'
|
|
93130
|
-
);
|
|
93131
|
-
}
|
|
93132
93133
|
if (matchToken("lbrace")) {
|
|
93133
93134
|
advance();
|
|
93134
93135
|
p.parseElementBody(element);
|
|
@@ -93213,6 +93214,34 @@ function tryOrderEntry(p, parent) {
|
|
|
93213
93214
|
parent.order = { value, span: valueToken.span };
|
|
93214
93215
|
return true;
|
|
93215
93216
|
}
|
|
93217
|
+
function tryLogoEntry(p, parent) {
|
|
93218
|
+
const { matchToken, advance, reportCoded, save, restore, syncToNextLine } = p;
|
|
93219
|
+
if (!parent || !matchToken("id", "logo")) return false;
|
|
93220
|
+
const mark = save();
|
|
93221
|
+
const keyToken = advance();
|
|
93222
|
+
if (!matchToken("colon")) {
|
|
93223
|
+
restore(mark);
|
|
93224
|
+
return false;
|
|
93225
|
+
}
|
|
93226
|
+
advance();
|
|
93227
|
+
const valueToken = matchToken("id") || matchToken("str") ? advance() : null;
|
|
93228
|
+
if (!valueToken || valueToken.text.length === 0) {
|
|
93229
|
+
reportCoded(
|
|
93230
|
+
"E0105",
|
|
93231
|
+
"`logo` expects a built-in name or a quoted file path",
|
|
93232
|
+
(valueToken ?? keyToken).span,
|
|
93233
|
+
'e.g. `logo: react`, or `logo: "./logos/acme.svg"` for your own'
|
|
93234
|
+
);
|
|
93235
|
+
syncToNextLine();
|
|
93236
|
+
return true;
|
|
93237
|
+
}
|
|
93238
|
+
parent.logo = {
|
|
93239
|
+
value: valueToken.text,
|
|
93240
|
+
source: valueToken.kind === "str" ? "file" : "builtin",
|
|
93241
|
+
span: valueToken.span
|
|
93242
|
+
};
|
|
93243
|
+
return true;
|
|
93244
|
+
}
|
|
93216
93245
|
function tryLegendBlock(p) {
|
|
93217
93246
|
const { matchToken, advance, reportError, lookAhead, skipNewlines, syncToNextLine, model } = p;
|
|
93218
93247
|
if (!matchToken("id", "legend")) return false;
|
|
@@ -93420,6 +93449,7 @@ function parse(src) {
|
|
|
93420
93449
|
}
|
|
93421
93450
|
if (tryStyleBlock(parent)) return;
|
|
93422
93451
|
if (tryOrderEntry(parser, parent)) return;
|
|
93452
|
+
if (tryLogoEntry(parser, parent)) return;
|
|
93423
93453
|
if (!parent && tryLegendBlock(parser)) return;
|
|
93424
93454
|
if (!parent && tryBusinessObject(parser)) return;
|
|
93425
93455
|
parseFlowOrElement(parser, parent);
|
|
@@ -93664,12 +93694,13 @@ var init_parser = __esm({
|
|
|
93664
93694
|
});
|
|
93665
93695
|
|
|
93666
93696
|
// src/views.ts
|
|
93667
|
-
var logicalView, applicationView, infrastructureView,
|
|
93697
|
+
var logicalView, applicationView, infrastructureView, views;
|
|
93668
93698
|
var init_views = __esm({
|
|
93669
93699
|
"src/views.ts"() {
|
|
93670
93700
|
"use strict";
|
|
93671
93701
|
logicalView = {
|
|
93672
93702
|
name: "logical",
|
|
93703
|
+
laneKinds: ["external"],
|
|
93673
93704
|
kinds: ["actor-group", "actor", "system", "layer", "block", "external"],
|
|
93674
93705
|
containerKinds: ["actor-group", "system", "layer", "external"],
|
|
93675
93706
|
// Logical flows carry no technical detail (flowTech* are null below), so the
|
|
@@ -93792,17 +93823,32 @@ var init_views = __esm({
|
|
|
93792
93823
|
};
|
|
93793
93824
|
applicationView = {
|
|
93794
93825
|
name: "application",
|
|
93826
|
+
laneKinds: ["external"],
|
|
93795
93827
|
kinds: [
|
|
93796
93828
|
"actor-group",
|
|
93797
93829
|
"actor",
|
|
93798
93830
|
"system",
|
|
93799
93831
|
"application",
|
|
93800
93832
|
"module",
|
|
93833
|
+
"gateway",
|
|
93834
|
+
"auth",
|
|
93835
|
+
"idp",
|
|
93801
93836
|
"queue",
|
|
93802
93837
|
"datastore",
|
|
93803
93838
|
"external"
|
|
93804
93839
|
],
|
|
93805
93840
|
containerKinds: ["actor-group", "system", "application", "external"],
|
|
93841
|
+
// A logo says what a thing is built with, so it belongs to the kinds that run
|
|
93842
|
+
// code. `actor` and `actor-group` are people; `system` is a grouping whose
|
|
93843
|
+
// children carry their own stacks. `gateway`, `auth` and `idp` are left out
|
|
93844
|
+
// on purpose: they are drawn with a corner glyph, and the glyph renderer has
|
|
93845
|
+
// no logo slot — a logo on them would reserve width and draw nothing.
|
|
93846
|
+
logoKinds: ["application", "module", "queue", "datastore", "external"],
|
|
93847
|
+
// The same three kinds as the infrastructure view, drawn the same way: an API
|
|
93848
|
+
// gateway, an auth middleware and an identity provider are containers in
|
|
93849
|
+
// their own right at the application level, and the glyph is what tells them
|
|
93850
|
+
// apart from a plain `application` at a glance.
|
|
93851
|
+
glyphKinds: ["gateway", "auth", "idp"],
|
|
93806
93852
|
// C4-style `(API_REST, JSON)`: the protocol half is worth tabulating, the port is not.
|
|
93807
93853
|
// `zoneOf` walks ancestors nearest-first, so an endpoint inside an application
|
|
93808
93854
|
// still reads `Name (App)`; the system only annotates what sits directly in it.
|
|
@@ -93814,6 +93860,9 @@ var init_views = __esm({
|
|
|
93814
93860
|
"actor-group": 0,
|
|
93815
93861
|
system: 1,
|
|
93816
93862
|
application: 1,
|
|
93863
|
+
gateway: 1,
|
|
93864
|
+
auth: 1,
|
|
93865
|
+
idp: 1,
|
|
93817
93866
|
queue: 1,
|
|
93818
93867
|
datastore: 1,
|
|
93819
93868
|
external: 2
|
|
@@ -93824,6 +93873,9 @@ var init_views = __esm({
|
|
|
93824
93873
|
system: "System",
|
|
93825
93874
|
application: "Application",
|
|
93826
93875
|
module: "Application module",
|
|
93876
|
+
gateway: "Gateway / reverse proxy",
|
|
93877
|
+
auth: "Auth middleware",
|
|
93878
|
+
idp: "Identity provider (IdP)",
|
|
93827
93879
|
queue: "Message queue / broker",
|
|
93828
93880
|
datastore: "Datastore / registry",
|
|
93829
93881
|
external: "External system"
|
|
@@ -93834,6 +93886,9 @@ var init_views = __esm({
|
|
|
93834
93886
|
system: "Syst\xE8me",
|
|
93835
93887
|
application: "Application",
|
|
93836
93888
|
module: "Module applicatif",
|
|
93889
|
+
gateway: "Passerelle / proxy",
|
|
93890
|
+
auth: "Middleware d'authentification",
|
|
93891
|
+
idp: "Fournisseur d'identit\xE9 (IdP)",
|
|
93837
93892
|
queue: "File de messages / broker",
|
|
93838
93893
|
datastore: "Entrep\xF4t / r\xE9f\xE9rentiel",
|
|
93839
93894
|
external: "Syst\xE8me externe"
|
|
@@ -93871,7 +93926,7 @@ var init_views = __esm({
|
|
|
93871
93926
|
minCounts: [],
|
|
93872
93927
|
isolatedWarn: {
|
|
93873
93928
|
code: "W0510",
|
|
93874
|
-
kinds: ["module", "queue", "datastore"],
|
|
93929
|
+
kinds: ["module", "gateway", "auth", "idp", "queue", "datastore"],
|
|
93875
93930
|
message: "isolated element: no incoming or outgoing flow"
|
|
93876
93931
|
},
|
|
93877
93932
|
defaults: {
|
|
@@ -93893,6 +93948,20 @@ var init_views = __esm({
|
|
|
93893
93948
|
fill: "#ffffff",
|
|
93894
93949
|
stroke: { color: "#5b7a99", style: "solid", width: 1.3 }
|
|
93895
93950
|
},
|
|
93951
|
+
// Same colours as the infrastructure view's `gateway`, `auth` and `idp`: one
|
|
93952
|
+
// thing drawn one way, whichever view it appears in.
|
|
93953
|
+
gateway: {
|
|
93954
|
+
fill: "#f5e6dd",
|
|
93955
|
+
stroke: { color: "#bf5530", style: "solid", width: 1.6 }
|
|
93956
|
+
},
|
|
93957
|
+
auth: {
|
|
93958
|
+
fill: "#e8f1fb",
|
|
93959
|
+
stroke: { color: "#2f6fb5", style: "solid", width: 1.5 }
|
|
93960
|
+
},
|
|
93961
|
+
idp: {
|
|
93962
|
+
fill: "#e0f0f0",
|
|
93963
|
+
stroke: { color: "#3a8f8f", style: "solid", width: 1.3 }
|
|
93964
|
+
},
|
|
93896
93965
|
queue: {
|
|
93897
93966
|
fill: "#f3eef8",
|
|
93898
93967
|
stroke: { color: "#8a6fae", style: "solid", width: 1.3 }
|
|
@@ -93924,6 +93993,18 @@ var init_views = __esm({
|
|
|
93924
93993
|
fill: "#252a31",
|
|
93925
93994
|
stroke: { color: "#5f7f9e", style: "solid", width: 1.3 }
|
|
93926
93995
|
},
|
|
93996
|
+
gateway: {
|
|
93997
|
+
fill: "#332218",
|
|
93998
|
+
stroke: { color: "#c96a4a", style: "solid", width: 1.6 }
|
|
93999
|
+
},
|
|
94000
|
+
auth: {
|
|
94001
|
+
fill: "#1d2735",
|
|
94002
|
+
stroke: { color: "#6fa8e0", style: "solid", width: 1.5 }
|
|
94003
|
+
},
|
|
94004
|
+
idp: {
|
|
94005
|
+
fill: "#1a2e2e",
|
|
94006
|
+
stroke: { color: "#4fafaf", style: "solid", width: 1.3 }
|
|
94007
|
+
},
|
|
93927
94008
|
queue: {
|
|
93928
94009
|
fill: "#2a2433",
|
|
93929
94010
|
stroke: { color: "#7a5f9e", style: "solid", width: 1.3 }
|
|
@@ -93941,19 +94022,26 @@ var init_views = __esm({
|
|
|
93941
94022
|
};
|
|
93942
94023
|
infrastructureView = {
|
|
93943
94024
|
name: "infrastructure",
|
|
94025
|
+
laneKinds: ["external"],
|
|
93944
94026
|
kinds: [
|
|
93945
94027
|
"actor",
|
|
94028
|
+
"device",
|
|
93946
94029
|
"site",
|
|
93947
94030
|
"network-zone",
|
|
93948
94031
|
"server",
|
|
93949
94032
|
"app-instance",
|
|
93950
94033
|
"queue",
|
|
93951
94034
|
"gateway",
|
|
94035
|
+
"firewall",
|
|
93952
94036
|
"auth",
|
|
93953
94037
|
"idp",
|
|
93954
94038
|
"external"
|
|
93955
94039
|
],
|
|
93956
94040
|
containerKinds: ["site", "network-zone", "server"],
|
|
94041
|
+
glyphKinds: ["gateway", "firewall", "auth", "idp", "device"],
|
|
94042
|
+
// A `device` is a flow origin, so it belongs on the entry side with the
|
|
94043
|
+
// actors rather than in a declaration-order band with the zones.
|
|
94044
|
+
ingressKinds: ["actor", "actor-group", "device"],
|
|
93957
94045
|
// The reference shape: the matrice des flux techniques as an EA dossier expects it.
|
|
93958
94046
|
matrix: {
|
|
93959
94047
|
zoneKinds: ["network-zone", "site"],
|
|
@@ -93964,24 +94052,28 @@ var init_views = __esm({
|
|
|
93964
94052
|
actorLegend: true,
|
|
93965
94053
|
legendNames: {
|
|
93966
94054
|
actor: "User / consumer",
|
|
94055
|
+
device: "Device / workstation",
|
|
93967
94056
|
site: "Site / data center",
|
|
93968
94057
|
"network-zone": "Network zone",
|
|
93969
94058
|
server: "Server / VM",
|
|
93970
94059
|
"app-instance": "Deployed application",
|
|
93971
94060
|
queue: "Message queue / broker",
|
|
93972
94061
|
gateway: "Gateway / reverse proxy",
|
|
94062
|
+
firewall: "Firewall",
|
|
93973
94063
|
auth: "Auth middleware",
|
|
93974
94064
|
idp: "Identity provider (IdP)",
|
|
93975
94065
|
external: "External system"
|
|
93976
94066
|
},
|
|
93977
94067
|
legendNamesFr: {
|
|
93978
94068
|
actor: "Utilisateur / consommateur",
|
|
94069
|
+
device: "Poste de travail",
|
|
93979
94070
|
site: "Site / centre de donn\xE9es",
|
|
93980
94071
|
"network-zone": "Zone r\xE9seau",
|
|
93981
94072
|
server: "Serveur / VM",
|
|
93982
94073
|
"app-instance": "Application d\xE9ploy\xE9e",
|
|
93983
94074
|
queue: "File de messages / broker",
|
|
93984
94075
|
gateway: "Passerelle / proxy",
|
|
94076
|
+
firewall: "Pare-feu",
|
|
93985
94077
|
auth: "Middleware d'authentification",
|
|
93986
94078
|
idp: "Fournisseur d'identit\xE9 (IdP)",
|
|
93987
94079
|
external: "Syst\xE8me externe"
|
|
@@ -94026,7 +94118,7 @@ var init_views = __esm({
|
|
|
94026
94118
|
minCounts: [],
|
|
94027
94119
|
isolatedWarn: {
|
|
94028
94120
|
code: "W0510",
|
|
94029
|
-
kinds: ["app-instance", "queue", "gateway", "auth", "idp"],
|
|
94121
|
+
kinds: ["app-instance", "queue", "gateway", "firewall", "auth", "idp", "device"],
|
|
94030
94122
|
message: "isolated element: no incoming or outgoing flow"
|
|
94031
94123
|
},
|
|
94032
94124
|
defaults: {
|
|
@@ -94043,6 +94135,12 @@ var init_views = __esm({
|
|
|
94043
94135
|
fill: "#ffffff",
|
|
94044
94136
|
stroke: { color: "#55606b", style: "solid", width: 1.5 }
|
|
94045
94137
|
},
|
|
94138
|
+
// The server's grey: a workstation is hardware like a server is, and the
|
|
94139
|
+
// monitor glyph is what tells the two apart.
|
|
94140
|
+
device: {
|
|
94141
|
+
fill: "#eef0f2",
|
|
94142
|
+
stroke: { color: "#55606b", style: "solid", width: 1.3 }
|
|
94143
|
+
},
|
|
94046
94144
|
"app-instance": {
|
|
94047
94145
|
fill: "#fff7e6",
|
|
94048
94146
|
stroke: { color: "#b08d2a", style: "solid", width: 1.2 }
|
|
@@ -94055,9 +94153,13 @@ var init_views = __esm({
|
|
|
94055
94153
|
fill: "#f5e6dd",
|
|
94056
94154
|
stroke: { color: "#bf5530", style: "solid", width: 1.6 }
|
|
94057
94155
|
},
|
|
94156
|
+
firewall: {
|
|
94157
|
+
fill: "#fdecea",
|
|
94158
|
+
stroke: { color: "#c0392b", style: "solid", width: 1.6 }
|
|
94159
|
+
},
|
|
94058
94160
|
auth: {
|
|
94059
|
-
fill: "#
|
|
94060
|
-
stroke: { color: "#
|
|
94161
|
+
fill: "#e8f1fb",
|
|
94162
|
+
stroke: { color: "#2f6fb5", style: "solid", width: 1.5 }
|
|
94061
94163
|
},
|
|
94062
94164
|
idp: {
|
|
94063
94165
|
fill: "#e0f0f0",
|
|
@@ -94082,6 +94184,10 @@ var init_views = __esm({
|
|
|
94082
94184
|
fill: "#252a31",
|
|
94083
94185
|
stroke: { color: "#6b7885", style: "solid", width: 1.5 }
|
|
94084
94186
|
},
|
|
94187
|
+
device: {
|
|
94188
|
+
fill: "#242a30",
|
|
94189
|
+
stroke: { color: "#6b7885", style: "solid", width: 1.3 }
|
|
94190
|
+
},
|
|
94085
94191
|
"app-instance": {
|
|
94086
94192
|
fill: "#2e2717",
|
|
94087
94193
|
stroke: { color: "#b08d2a", style: "solid", width: 1.2 }
|
|
@@ -94094,9 +94200,13 @@ var init_views = __esm({
|
|
|
94094
94200
|
fill: "#332218",
|
|
94095
94201
|
stroke: { color: "#c96a4a", style: "solid", width: 1.6 }
|
|
94096
94202
|
},
|
|
94203
|
+
firewall: {
|
|
94204
|
+
fill: "#33211f",
|
|
94205
|
+
stroke: { color: "#e5675a", style: "solid", width: 1.6 }
|
|
94206
|
+
},
|
|
94097
94207
|
auth: {
|
|
94098
|
-
fill: "#
|
|
94099
|
-
stroke: { color: "#
|
|
94208
|
+
fill: "#1d2735",
|
|
94209
|
+
stroke: { color: "#6fa8e0", style: "solid", width: 1.5 }
|
|
94100
94210
|
},
|
|
94101
94211
|
idp: {
|
|
94102
94212
|
fill: "#1a2e2e",
|
|
@@ -94108,186 +94218,186 @@ var init_views = __esm({
|
|
|
94108
94218
|
}
|
|
94109
94219
|
}
|
|
94110
94220
|
};
|
|
94111
|
-
|
|
94112
|
-
|
|
94113
|
-
|
|
94114
|
-
|
|
94115
|
-
|
|
94116
|
-
|
|
94117
|
-
|
|
94118
|
-
|
|
94119
|
-
|
|
94120
|
-
|
|
94221
|
+
views = {
|
|
94222
|
+
logical: logicalView,
|
|
94223
|
+
application: applicationView,
|
|
94224
|
+
infrastructure: infrastructureView
|
|
94225
|
+
};
|
|
94226
|
+
}
|
|
94227
|
+
});
|
|
94228
|
+
|
|
94229
|
+
// src/logos.ts
|
|
94230
|
+
var LOGOS, LOGO_NAMES;
|
|
94231
|
+
var init_logos = __esm({
|
|
94232
|
+
"src/logos.ts"() {
|
|
94233
|
+
"use strict";
|
|
94234
|
+
LOGOS = {
|
|
94235
|
+
angular: {
|
|
94236
|
+
title: "Angular",
|
|
94237
|
+
d: "M16.712 17.711H7.288l-1.204 2.916L12 24l5.916-3.373-1.204-2.916ZM14.692 0l7.832 16.855.814-12.856L14.692 0ZM9.308 0 .662 3.999l.814 12.856L9.308 0Zm-.405 13.93h6.198L12 6.396 8.903 13.93Z",
|
|
94238
|
+
license: "CC-BY-4.0",
|
|
94239
|
+
licenseUrl: "https://creativecommons.org/licenses/by/4.0/legalcode",
|
|
94240
|
+
source: "https://angular.dev/press-kit"
|
|
94121
94241
|
},
|
|
94122
|
-
|
|
94123
|
-
|
|
94124
|
-
|
|
94125
|
-
|
|
94126
|
-
|
|
94127
|
-
|
|
94128
|
-
external: "Untrusted external"
|
|
94242
|
+
apache: {
|
|
94243
|
+
title: "Apache",
|
|
94244
|
+
d: "M17.805 2.197v.066h.156v.44h.072v-.44h.156v-.066zm.9 0l-.175.353-.172-.353h-.087v.506h.067V2.3l.172.35h.045l.172-.35v.404h.066v-.506zm-4.257 1c-.204.31-.424.66-.66 1.06l-.04.062a44.457 44.457 0 00-1.265 2.29c-.187.36-.38.742-.577 1.146l2.267-.25c.66-.302.955-.578 1.242-.976a15.5 15.5 0 00.23-.342c.23-.363.46-.763.663-1.16.197-.386.37-.767.505-1.11.083-.22.15-.422.198-.6.042-.158.074-.307.1-.45-.884.15-1.965.295-2.668.33zM11.894 7.78l-.077.16c-.078.16-.157.32-.236.488-.086.18-.172.364-.26.552l-.132.287a75.265 75.265 0 00-1.427 3.3c-.163.397-.327.807-.493 1.23-.15.38-.297.765-.45 1.164l-.02.06c-.15.396-.3.802-.453 1.22l-.01.027.72-.08a.213.213 0 01-.042-.006c.863-.106 2.01-.75 2.75-1.547.342-.367.652-.8.94-1.306.213-.377.413-.795.604-1.258.168-.405.328-.843.48-1.318-.196.105-.423.18-.673.235a2.184 2.184 0 01-.273.046c.806-.31 1.314-.905 1.683-1.64a2.816 2.816 0 01-.968.428c-.06.012-.116.022-.174.03l-.043.006h.002c.278-.118.514-.248.718-.403a2.571 2.571 0 00.637-.698l.063-.104.077-.154a8.107 8.107 0 00.367-.85l.03-.088a3.04 3.04 0 00.123-.463.733.733 0 01-.094.065c-.243.145-.66.277-.996.34l.663-.074-.664.073h-.017l-.1.017c.006-.003.01-.006.017-.008l-2.265.25-.013.022zM8.27 16.45c-.117.323-.236.654-.355.992l-.005.015c-.016.046-.032.094-.05.142-.08.227-.15.432-.31.9.264.12.475.435.675.793a1.44 1.44 0 00-.466-.99c1.293.06 2.41-.27 2.99-1.217.05-.084.096-.173.14-.268-.26.333-.59.474-1.2.44 0 0-.004 0-.005.002l.004-.002c.9-.404 1.354-.79 1.754-1.433.094-.153.186-.32.28-.503-.788.81-1.702 1.04-2.664.865l-.72.078a6.43 6.43 0 00-.067.183zM15.42.112c-.376.222-1 .85-1.748 1.763l.686 1.294c.48-.687.97-1.307 1.462-1.836l.058-.062c-.02.02-.04.04-.057.062-.16.176-.644.74-1.375 1.863.703-.035 1.784-.18 2.666-.33.262-1.47-.258-2.142-.258-2.142s-.66-1.07-1.436-.61zm-3.084 6.402a40.253 40.253 0 011.306-2.26l.04-.064c.224-.352.45-.693.677-1.02l-.685-1.293-.157.192c-.197.245-.403.51-.613.79a39.853 39.853 0 00-2.016 2.97l-.022.038.893 1.763c.19-.378.38-.752.575-1.118zm-3.73 8.32c.158-.406.319-.81.483-1.225.156-.394.32-.79.484-1.19a91.133 91.133 0 011.6-3.604l.205-.424c.12-.243.237-.485.36-.724a.125.125 0 01.02-.04l-.895-1.763-.044.07c-.207.34-.414.687-.617 1.042a38.056 38.056 0 00-1.092 2.04l-.094.193a24.573 24.573 0 00-1.258 3.087 18.492 18.492 0 00-.52 1.997l.896 1.77c.117-.317.24-.638.364-.963zm-1.376-.476a13.38 13.38 0 00-.234 1.692c0 .02-.004.04-.005.06-.28-.45-1.03-.888-1.026-.884.537.778.944 1.55 1.005 2.31-.29.058-.684-.027-1.14-.195.475.436.83.556.97.588-.434.03-.89.328-1.346.67.668-.27 1.21-.38 1.596-.29-.61 1.74-1.23 3.655-1.843 5.69a.538.538 0 00.364-.354c.11-.368.84-2.786 1.978-5.965l.097-.27.028-.078c.12-.332.246-.672.374-1.02l.09-.237v-.004L7.24 14.3c-.003.02-.01.04-.012.06z",
|
|
94245
|
+
license: "Apache-2.0",
|
|
94246
|
+
licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
|
|
94247
|
+
source: "https://www.apache.org/foundation/press/kit"
|
|
94129
94248
|
},
|
|
94130
|
-
|
|
94131
|
-
|
|
94132
|
-
|
|
94133
|
-
|
|
94134
|
-
|
|
94135
|
-
|
|
94136
|
-
external: "Externe non ma\xEEtris\xE9"
|
|
94249
|
+
apachekafka: {
|
|
94250
|
+
title: "Apache Kafka",
|
|
94251
|
+
d: "M9.71 2.136a1.43 1.43 0 0 0-2.047 0h-.007a1.48 1.48 0 0 0-.421 1.042c0 .41.161.777.422 1.039l.007.007c.257.264.616.426 1.019.426.404 0 .766-.162 1.027-.426l.003-.007c.261-.262.421-.629.421-1.039 0-.408-.159-.777-.421-1.042H9.71zM8.683 22.295c.404 0 .766-.167 1.027-.429l.003-.008c.261-.261.421-.631.421-1.036 0-.41-.159-.778-.421-1.044H9.71a1.42 1.42 0 0 0-1.027-.432 1.4 1.4 0 0 0-1.02.432h-.007c-.26.266-.422.634-.422 1.044 0 .406.161.775.422 1.036l.007.008c.258.262.617.429 1.02.429zm7.89-4.462c.359-.096.683-.33.882-.684l.027-.052a1.47 1.47 0 0 0 .114-1.067 1.454 1.454 0 0 0-.675-.896l-.021-.014a1.425 1.425 0 0 0-1.078-.132c-.36.091-.684.335-.881.686-.2.349-.241.75-.146 1.119.099.363.33.691.675.896h.002c.346.203.737.239 1.101.144zm-6.405-7.342a2.083 2.083 0 0 0-1.485-.627c-.58 0-1.103.242-1.482.627-.378.385-.612.916-.612 1.507s.233 1.124.612 1.514a2.08 2.08 0 0 0 2.967 0c.379-.39.612-.923.612-1.514s-.233-1.122-.612-1.507zm-.835-2.51c.843.141 1.6.552 2.178 1.144h.004c.092.093.182.196.265.299l1.446-.851a3.176 3.176 0 0 1-.047-1.808 3.149 3.149 0 0 1 1.456-1.926l.025-.016a3.062 3.062 0 0 1 2.345-.306c.77.21 1.465.721 1.898 1.482v.002c.431.757.518 1.626.313 2.408a3.145 3.145 0 0 1-1.456 1.928l-.198.118h-.02a3.095 3.095 0 0 1-2.154.201 3.127 3.127 0 0 1-1.514-.944l-1.444.848a4.162 4.162 0 0 1 0 2.879l1.444.846c.413-.47.939-.789 1.514-.944a3.041 3.041 0 0 1 2.371.319l.048.023v.002a3.17 3.17 0 0 1 1.408 1.906 3.215 3.215 0 0 1-.313 2.405l-.026.053-.003-.005a3.147 3.147 0 0 1-1.867 1.436 3.096 3.096 0 0 1-2.371-.318v-.006a3.156 3.156 0 0 1-1.456-1.927 3.175 3.175 0 0 1 .047-1.805l-1.446-.848a3.905 3.905 0 0 1-.265.294l-.004.005a3.938 3.938 0 0 1-2.178 1.138v1.699a3.09 3.09 0 0 1 1.56.862l.002.004c.565.572.914 1.368.914 2.243 0 .873-.35 1.664-.914 2.239l-.002.009a3.1 3.1 0 0 1-2.21.931 3.1 3.1 0 0 1-2.206-.93h-.002v-.009a3.186 3.186 0 0 1-.916-2.239c0-.875.35-1.672.916-2.243v-.004h.002a3.1 3.1 0 0 1 1.558-.862v-1.699a3.926 3.926 0 0 1-2.176-1.138l-.006-.005a4.098 4.098 0 0 1-1.173-2.874c0-1.122.452-2.136 1.173-2.872h.006a3.947 3.947 0 0 1 2.176-1.144V6.289a3.137 3.137 0 0 1-1.558-.864h-.002v-.004a3.192 3.192 0 0 1-.916-2.243c0-.871.35-1.669.916-2.243l.002-.002A3.084 3.084 0 0 1 8.683 0c.861 0 1.641.355 2.21.932v.002h.002c.565.574.914 1.372.914 2.243 0 .876-.35 1.667-.914 2.243l-.002.005a3.142 3.142 0 0 1-1.56.864v1.692zm8.121-1.129l-.012-.019a1.452 1.452 0 0 0-.87-.668 1.43 1.43 0 0 0-1.103.146h.002c-.347.2-.58.529-.677.896-.095.365-.054.768.146 1.119l.007.009c.2.347.519.579.874.673.357.103.755.059 1.098-.144l.019-.009a1.47 1.47 0 0 0 .657-.885 1.493 1.493 0 0 0-.141-1.118",
|
|
94252
|
+
license: "Apache-2.0",
|
|
94253
|
+
licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
|
|
94254
|
+
source: "https://apache.org/logos"
|
|
94137
94255
|
},
|
|
94138
|
-
|
|
94139
|
-
|
|
94140
|
-
|
|
94141
|
-
|
|
94256
|
+
apachespark: {
|
|
94257
|
+
title: "Apache Spark",
|
|
94258
|
+
d: "M10.812 0c-.425.013-.845.215-1.196.605a3.593 3.593 0 00-.493.722c-.355.667-.425 1.415-.556 2.143a551.9 551.9 0 00-.726 4.087c-.027.16-.096.227-.244.273C5.83 8.386 4.06 8.94 2.3 9.514c-.387.125-.773.289-1.114.506-1.042.665-1.196 1.753-.415 2.71.346.422.79.715 1.284.936 1.1.49 2.202.976 3.3 1.47.019.01.036.013.053.019h-.004l1.306.535c0 .023.002.045 0 .073-.2 2.03-.39 4.063-.58 6.095-.04.419-.012.831.134 1.23.317.87 1.065 1.148 1.881.701.372-.204.666-.497.937-.818 1.372-1.623 2.746-3.244 4.113-4.872.111-.133.205-.15.363-.098.349.117.697.231 1.045.347h.001c.02.012.045.02.073.03l.142.042c1.248.416 2.68.775 3.929 1.19.4.132.622.164 1.045.098.311-.048.592-.062.828-.236.602-.33.995-.957.988-1.682-.005-.427-.154-.813-.35-1.186-.82-1.556-1.637-3.113-2.461-4.666-.078-.148-.076-.243.037-.375 1.381-1.615 2.756-3.236 4.133-4.855.272-.32.513-.658.653-1.058.308-.878-.09-1.57-1-1.741a2.783 2.783 0 00-1.235.069c-1.974.521-3.947 1.041-5.918 1.57-.175.047-.26.015-.355-.144a353.08 353.08 0 00-2.421-4.018 4.61 4.61 0 00-.652-.849c-.371-.37-.802-.549-1.227-.536zm.172 3.703a.592.592 0 01.189.211c.87 1.446 1.742 2.89 2.609 4.338.07.118.135.16.277.121 1.525-.41 3.052-.813 4.579-1.217.367-.098.735-.193 1.103-.289a.399.399 0 01-.1.2c-1.259 1.48-2.516 2.962-3.779 4.438-.11.13-.12.22-.04.37.937 1.803 1.768 3.309 2.498 4.76l-3.696-1.019c-.538-.18-1.077-.358-1.615-.539-.163-.055-.25-.03-.36.1-1.248 1.488-2.504 2.97-3.759 4.454a.398.398 0 01-.18.132c.035-.378.068-.757.104-1.136.149-1.572.297-3.144.451-4.716-.03-.318.117-.405-.322-.545-1.493-.593-3.346-1.321-4.816-1.905a.595.595 0 01.24-.134c1.797-.57 3.595-1.14 5.394-1.705.127-.04.199-.092.211-.233.013-.148.05-.294.076-.441.241-1.363.483-2.726.726-4.088.068-.386.14-.771.21-1.157z",
|
|
94259
|
+
license: "Apache-2.0",
|
|
94260
|
+
licenseUrl: "https://www.apache.org/licenses/LICENSE-2.0.txt",
|
|
94261
|
+
source: "https://apache.org/logos"
|
|
94142
94262
|
},
|
|
94143
|
-
|
|
94144
|
-
|
|
94145
|
-
|
|
94146
|
-
partitionByOrder: true,
|
|
94147
|
-
flowLabelRequired: {
|
|
94148
|
-
code: "E0203",
|
|
94149
|
-
message: "flow without a label",
|
|
94150
|
-
help: 'add a label describing the exchange: `A -> B : "\u2026" (TLS1.3)`'
|
|
94263
|
+
django: {
|
|
94264
|
+
title: "Django",
|
|
94265
|
+
d: "M11.146 0h3.924v18.166c-2.013.382-3.491.535-5.096.535-4.791 0-7.288-2.166-7.288-6.32 0-4.002 2.65-6.6 6.753-6.6.637 0 1.121.05 1.707.203zm0 9.143a3.894 3.894 0 00-1.325-.204c-1.988 0-3.134 1.223-3.134 3.365 0 2.09 1.096 3.236 3.109 3.236.433 0 .79-.025 1.35-.102V9.142zM21.314 6.06v9.098c0 3.134-.229 4.638-.917 5.937-.637 1.249-1.478 2.039-3.211 2.905l-3.644-1.733c1.733-.815 2.574-1.53 3.109-2.625.561-1.121.739-2.421.739-5.835V6.059h3.924zM17.39.021h3.924v4.026H17.39z"
|
|
94151
94266
|
},
|
|
94152
|
-
|
|
94153
|
-
|
|
94154
|
-
|
|
94155
|
-
kind: "trust-zone",
|
|
94156
|
-
values: SEC_LEVELS,
|
|
94157
|
-
code: "E0250",
|
|
94158
|
-
message: "trust zone without a valid sensitivity level",
|
|
94159
|
-
help: 'set a level in parentheses: `trust-zone DMZ "DMZ" (public)` \u2014 one of public, internal, restricted, secret'
|
|
94267
|
+
docker: {
|
|
94268
|
+
title: "Docker",
|
|
94269
|
+
d: "M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.185.185 0 00-.185.185v1.888c0 .102.083.185.185.185m-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.887c0 .102.082.185.185.186m-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.185.185 0 00-.185.185v1.887c0 .102.083.185.185.186m-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.185.185 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.185.186.186m5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.083.185.185.185m-2.964 0h2.119a.185.185 0 00.185-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185m-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.082.185.185.185M23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.376 11.376 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.248 12.248 0 003.823-1.389c.98-.567 1.86-1.288 2.61-2.136 1.252-1.418 1.998-2.997 2.553-4.4h.221c1.372 0 2.215-.549 2.68-1.009.309-.293.55-.65.707-1.046l.098-.288Z"
|
|
94160
94270
|
},
|
|
94161
|
-
|
|
94162
|
-
|
|
94163
|
-
|
|
94164
|
-
nodeKind: "security-node",
|
|
94165
|
-
message: "unfiltered trust-boundary crossing",
|
|
94166
|
-
help: "route this flow through a `security-node` (firewall/WAF/bastion), or confirm the direct path is intended"
|
|
94271
|
+
dotnet: {
|
|
94272
|
+
title: ".NET",
|
|
94273
|
+
d: "M24 8.77h-2.468v7.565h-1.425V8.77h-2.462V7.53H24zm-6.852 7.565h-4.821V7.53h4.63v1.24h-3.205v2.494h2.953v1.234h-2.953v2.604h3.396zm-6.708 0H8.882L4.78 9.863a2.896 2.896 0 0 1-.258-.51h-.036c.032.189.048.592.048 1.21v5.772H3.157V7.53h1.659l3.965 6.32c.167.261.275.442.323.54h.024c-.04-.233-.06-.629-.06-1.185V7.529h1.372zm-8.703-.693a.868.829 0 0 1-.869.829.868.829 0 0 1-.868-.83.868.829 0 0 1 .868-.828.868.829 0 0 1 .869.829Z"
|
|
94167
94274
|
},
|
|
94168
|
-
|
|
94169
|
-
|
|
94170
|
-
|
|
94171
|
-
help: 'add the protocol/encryption on inter-zone flows: `A -> B : "\u2026" (TLS1.3)`'
|
|
94275
|
+
elasticsearch: {
|
|
94276
|
+
title: "Elasticsearch",
|
|
94277
|
+
d: "M13.394 0C8.683 0 4.609 2.716 2.644 6.667h15.641a4.77 4.77 0 0 0 3.073-1.11c.446-.375.864-.785 1.247-1.243l.001-.002A11.974 11.974 0 0 0 13.394 0zM1.804 8.889a12.009 12.009 0 0 0 0 6.222h14.7a3.111 3.111 0 1 0 0-6.222zm.84 8.444C4.61 21.283 8.684 24 13.395 24c3.701 0 7.011-1.677 9.212-4.312l-.001-.002a9.958 9.958 0 0 0-1.247-1.243 4.77 4.77 0 0 0-3.073-1.11z"
|
|
94172
94278
|
},
|
|
94173
|
-
|
|
94174
|
-
|
|
94175
|
-
|
|
94176
|
-
child: "asset",
|
|
94177
|
-
parents: ["trust-zone"],
|
|
94178
|
-
message: "sensitive asset outside any trust zone",
|
|
94179
|
-
help: "move this `asset` inside a `trust-zone`"
|
|
94180
|
-
},
|
|
94181
|
-
{
|
|
94182
|
-
code: "E0218",
|
|
94183
|
-
child: "security-node",
|
|
94184
|
-
parents: ["trust-zone"],
|
|
94185
|
-
message: "security node outside any trust zone",
|
|
94186
|
-
help: "place this `security-node` inside a `trust-zone` (typically the exposed one it protects)"
|
|
94187
|
-
},
|
|
94188
|
-
{
|
|
94189
|
-
code: "E0211",
|
|
94190
|
-
child: "actor",
|
|
94191
|
-
parents: ["actor-group"],
|
|
94192
|
-
message: "actor outside any group",
|
|
94193
|
-
help: "move this `actor` inside an `actor-group`"
|
|
94194
|
-
}
|
|
94195
|
-
],
|
|
94196
|
-
minCounts: [],
|
|
94197
|
-
isolatedWarn: {
|
|
94198
|
-
code: "W0510",
|
|
94199
|
-
kinds: ["asset"],
|
|
94200
|
-
message: "isolated element: no incoming or outgoing flow"
|
|
94279
|
+
express: {
|
|
94280
|
+
title: "Express",
|
|
94281
|
+
d: "M12.262 16.666h1.146l6.975-9.325H19.22zm9.778 1.441v.004l-4.334-5.706-.557.74 4.873 6.682H.945V4.173h9.505l5.026 6.7.574-.772-4.374-5.928h.003l-.719-.945H0v17.544h24zM10.917 8.705a3.8 3.8 0 0 0-1.292-1.183q-.796-.45-1.916-.45c-.746 0-1.37.14-1.906.424a3.76 3.76 0 0 0-1.31 1.12 4.9 4.9 0 0 0-.75 1.581 7.17 7.17 0 0 0 0 3.696c.148.567.402 1.101.75 1.573a3.5 3.5 0 0 0 1.31 1.066q.803.39 1.906.389 1.77 0 2.739-.868.966-.867 1.328-2.457h-1.139q-.271 1.084-.977 1.734-.704.651-1.952.65-.812 0-1.392-.342a3.1 3.1 0 0 1-.957-.869 3.5 3.5 0 0 1-.551-1.182 5 5 0 0 1-.17-1.133 9 9 0 0 0-.015-.286 4.5 4.5 0 0 1 .015-.829c.047-.418.147-.83.296-1.223A3.7 3.7 0 0 1 5.54 9.05a2.9 2.9 0 0 1 .922-.742q.541-.28 1.246-.28c.47 0 .869.093 1.23.28q.541.281.922.742.379.461.587 1.057t.225 1.246H5.625l.004.957h6.182a7.3 7.3 0 0 0-.18-1.924 4.9 4.9 0 0 0-.715-1.68z"
|
|
94201
94282
|
},
|
|
94202
|
-
|
|
94203
|
-
"
|
|
94204
|
-
|
|
94205
|
-
stroke: { color: "#8a8a85", style: "solid", width: 1.3 }
|
|
94206
|
-
},
|
|
94207
|
-
"security-node": {
|
|
94208
|
-
fill: "#fff7e6",
|
|
94209
|
-
stroke: { color: "#c46b2a", style: "solid", width: 1.6 }
|
|
94210
|
-
},
|
|
94211
|
-
asset: {
|
|
94212
|
-
fill: "#ffffff",
|
|
94213
|
-
stroke: { color: "#55606b", style: "solid", width: 1.3 }
|
|
94214
|
-
},
|
|
94215
|
-
"actor-group": {
|
|
94216
|
-
fill: "#eef4fb",
|
|
94217
|
-
stroke: { color: "#7a9cc4", style: "dashed", width: 1.2 }
|
|
94218
|
-
},
|
|
94219
|
-
external: {
|
|
94220
|
-
fill: "#fdecea",
|
|
94221
|
-
stroke: { color: "#d9534f", style: "dashed", width: 1.3 }
|
|
94222
|
-
},
|
|
94223
|
-
actor: {}
|
|
94283
|
+
fastapi: {
|
|
94284
|
+
title: "FastAPI",
|
|
94285
|
+
d: "M12 .0387C5.3729.0384.0003 5.3931 0 11.9988c-.001 6.6066 5.372 11.9628 12 11.9625 6.628.0003 12.001-5.3559 12-11.9625-.0003-6.6057-5.3729-11.9604-12-11.96m-.829 5.4153h7.55l-7.5805 5.3284h5.1828L5.279 18.5436q2.9466-6.5444 5.892-13.0896"
|
|
94224
94286
|
},
|
|
94225
|
-
|
|
94226
|
-
"
|
|
94227
|
-
|
|
94228
|
-
stroke: { color: "#8a8a72", style: "solid", width: 1.3 }
|
|
94229
|
-
},
|
|
94230
|
-
"security-node": {
|
|
94231
|
-
fill: "#2e2717",
|
|
94232
|
-
stroke: { color: "#c46b2a", style: "solid", width: 1.6 }
|
|
94233
|
-
},
|
|
94234
|
-
asset: {
|
|
94235
|
-
fill: "#252a31",
|
|
94236
|
-
stroke: { color: "#6b7885", style: "solid", width: 1.3 }
|
|
94237
|
-
},
|
|
94238
|
-
"actor-group": {
|
|
94239
|
-
fill: "#232a33",
|
|
94240
|
-
stroke: { color: "#5c7fa8", style: "dashed", width: 1.2 }
|
|
94241
|
-
},
|
|
94242
|
-
external: {
|
|
94243
|
-
fill: "#3a2422",
|
|
94244
|
-
stroke: { color: "#c25a54", style: "dashed", width: 1.3 }
|
|
94245
|
-
},
|
|
94246
|
-
actor: {}
|
|
94287
|
+
github: {
|
|
94288
|
+
title: "GitHub",
|
|
94289
|
+
d: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
|
|
94247
94290
|
},
|
|
94248
|
-
|
|
94249
|
-
|
|
94250
|
-
|
|
94251
|
-
stroke: { color: "#d9534f", style: "solid", width: 1.4 }
|
|
94252
|
-
},
|
|
94253
|
-
internal: {
|
|
94254
|
-
fill: "#fff4e5",
|
|
94255
|
-
stroke: { color: "#e0a458", style: "solid", width: 1.4 }
|
|
94256
|
-
},
|
|
94257
|
-
restricted: {
|
|
94258
|
-
fill: "#e8f1f8",
|
|
94259
|
-
stroke: { color: "#5b8db8", style: "solid", width: 1.4 }
|
|
94260
|
-
},
|
|
94261
|
-
secret: {
|
|
94262
|
-
fill: "#ece8f5",
|
|
94263
|
-
stroke: { color: "#7a5fae", style: "solid", width: 1.4 }
|
|
94264
|
-
}
|
|
94291
|
+
gitlab: {
|
|
94292
|
+
title: "GitLab",
|
|
94293
|
+
d: "m23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z"
|
|
94265
94294
|
},
|
|
94266
|
-
|
|
94267
|
-
|
|
94268
|
-
|
|
94269
|
-
|
|
94270
|
-
|
|
94271
|
-
|
|
94272
|
-
|
|
94273
|
-
|
|
94274
|
-
|
|
94275
|
-
|
|
94276
|
-
|
|
94277
|
-
|
|
94278
|
-
|
|
94279
|
-
|
|
94280
|
-
|
|
94281
|
-
|
|
94282
|
-
|
|
94295
|
+
go: {
|
|
94296
|
+
title: "Go",
|
|
94297
|
+
d: "M1.811 10.231c-.047 0-.058-.023-.035-.059l.246-.315c.023-.035.081-.058.128-.058h4.172c.046 0 .058.035.035.07l-.199.303c-.023.036-.082.07-.117.07zM.047 11.306c-.047 0-.059-.023-.035-.058l.245-.316c.023-.035.082-.058.129-.058h5.328c.047 0 .07.035.058.07l-.093.28c-.012.047-.058.07-.105.07zm2.828 1.075c-.047 0-.059-.035-.035-.07l.163-.292c.023-.035.07-.07.117-.07h2.337c.047 0 .07.035.07.082l-.023.28c0 .047-.047.082-.082.082zm12.129-2.36c-.736.187-1.239.327-1.963.514-.176.046-.187.058-.34-.117-.174-.199-.303-.327-.548-.444-.737-.362-1.45-.257-2.115.175-.795.514-1.204 1.274-1.192 2.22.011.935.654 1.706 1.577 1.835.795.105 1.46-.175 1.987-.77.105-.13.198-.27.315-.434H10.47c-.245 0-.304-.152-.222-.35.152-.362.432-.97.596-1.274a.315.315 0 01.292-.187h4.253c-.023.316-.023.631-.07.947a4.983 4.983 0 01-.958 2.29c-.841 1.11-1.94 1.8-3.33 1.986-1.145.152-2.209-.07-3.143-.77-.865-.655-1.356-1.52-1.484-2.595-.152-1.274.222-2.419.993-3.424.83-1.086 1.928-1.776 3.272-2.02 1.098-.2 2.15-.07 3.096.571.62.41 1.063.97 1.356 1.648.07.105.023.164-.117.2m3.868 6.461c-1.064-.024-2.034-.328-2.852-1.029a3.665 3.665 0 01-1.262-2.255c-.21-1.32.152-2.489.947-3.529.853-1.122 1.881-1.706 3.272-1.95 1.192-.21 2.314-.095 3.33.595.923.63 1.496 1.484 1.648 2.605.198 1.578-.257 2.863-1.344 3.962-.771.783-1.718 1.273-2.805 1.495-.315.06-.63.07-.934.106zm2.78-4.72c-.011-.153-.011-.27-.034-.387-.21-1.157-1.274-1.81-2.384-1.554-1.087.245-1.788.935-2.045 2.033-.21.912.234 1.835 1.075 2.21.643.28 1.285.244 1.905-.07.923-.48 1.425-1.228 1.484-2.233z"
|
|
94298
|
+
},
|
|
94299
|
+
googlecloud: {
|
|
94300
|
+
title: "Google Cloud",
|
|
94301
|
+
d: "M12.19 2.38a9.344 9.344 0 0 0-9.234 6.893c.053-.02-.055.013 0 0-3.875 2.551-3.922 8.11-.247 10.941l.006-.007-.007.03a6.717 6.717 0 0 0 4.077 1.356h5.173l.03.03h5.192c6.687.053 9.376-8.605 3.835-12.35a9.365 9.365 0 0 0-2.821-4.552l-.043.043.006-.05A9.344 9.344 0 0 0 12.19 2.38zm-.358 4.146c1.244-.04 2.518.368 3.486 1.15a5.186 5.186 0 0 1 1.862 4.078v.518c3.53-.07 3.53 5.262 0 5.193h-5.193l-.008.009v-.04H6.785a2.59 2.59 0 0 1-1.067-.23h.001a2.597 2.597 0 1 1 3.437-3.437l3.013-3.012A6.747 6.747 0 0 0 8.11 8.24c.018-.01.04-.026.054-.023a5.186 5.186 0 0 1 3.67-1.69z"
|
|
94302
|
+
},
|
|
94303
|
+
grafana: {
|
|
94304
|
+
title: "Grafana",
|
|
94305
|
+
d: "M23.02 10.59a8.578 8.578 0 0 0-.862-3.034 8.911 8.911 0 0 0-1.789-2.445c.337-1.342-.413-2.505-.413-2.505-1.292-.08-2.113.4-2.416.62-.052-.02-.102-.044-.154-.064-.22-.089-.446-.172-.677-.247-.231-.073-.47-.14-.711-.197a9.867 9.867 0 0 0-.875-.161C14.557.753 12.94 0 12.94 0c-1.804 1.145-2.147 2.744-2.147 2.744l-.018.093c-.098.029-.2.057-.298.088-.138.042-.275.094-.413.143-.138.055-.275.107-.41.166a8.869 8.869 0 0 0-1.557.87l-.063-.029c-2.497-.955-4.716.195-4.716.195-.203 2.658.996 4.33 1.235 4.636a11.608 11.608 0 0 0-.607 2.635C1.636 12.677.953 15.014.953 15.014c1.926 2.214 4.171 2.351 4.171 2.351.003-.002.006-.002.006-.005.285.509.615.994.986 1.446.156.19.32.371.488.548-.704 2.009.099 3.68.099 3.68 2.144.08 3.553-.937 3.849-1.173a9.784 9.784 0 0 0 3.164.501h.08l.055-.003.107-.002.103-.005.003.002c1.01 1.44 2.788 1.646 2.788 1.646 1.264-1.332 1.337-2.653 1.337-2.94v-.058c0-.02-.003-.039-.003-.06.265-.187.52-.387.758-.6a7.875 7.875 0 0 0 1.415-1.7c1.43.083 2.437-.885 2.437-.885-.236-1.49-1.085-2.216-1.264-2.354l-.018-.013-.016-.013a.217.217 0 0 1-.031-.02c.008-.092.016-.18.02-.27.011-.162.016-.323.016-.48v-.253l-.005-.098-.008-.135a1.891 1.891 0 0 0-.01-.13c-.003-.042-.008-.083-.013-.125l-.016-.124-.018-.122a6.215 6.215 0 0 0-2.032-3.73 6.015 6.015 0 0 0-3.222-1.46 6.292 6.292 0 0 0-.85-.048l-.107.002h-.063l-.044.003-.104.008a4.777 4.777 0 0 0-3.335 1.695c-.332.4-.592.84-.768 1.297a4.594 4.594 0 0 0-.312 1.817l.003.091c.005.055.007.11.013.164a3.615 3.615 0 0 0 .698 1.82 3.53 3.53 0 0 0 1.827 1.282c.33.098.66.14.971.137.039 0 .078 0 .114-.002l.063-.003c.02 0 .041-.003.062-.003.034-.002.065-.007.099-.01.007 0 .018-.003.028-.003l.031-.005.06-.008a1.18 1.18 0 0 0 .112-.02c.036-.008.072-.013.109-.024a2.634 2.634 0 0 0 .914-.415c.028-.02.056-.041.085-.065a.248.248 0 0 0 .039-.35.244.244 0 0 0-.309-.06l-.078.042c-.09.044-.184.083-.283.116a2.476 2.476 0 0 1-.475.096c-.028.003-.054.006-.083.006l-.083.002c-.026 0-.054 0-.08-.002l-.102-.006h-.012l-.024.006c-.016-.003-.031-.003-.044-.006-.031-.002-.06-.007-.091-.01a2.59 2.59 0 0 1-.724-.213 2.557 2.557 0 0 1-.667-.438 2.52 2.52 0 0 1-.805-1.475 2.306 2.306 0 0 1-.029-.444l.006-.122v-.023l.002-.031c.003-.021.003-.04.005-.06a3.163 3.163 0 0 1 1.352-2.29 3.12 3.12 0 0 1 .937-.43 2.946 2.946 0 0 1 .776-.101h.06l.07.002.045.003h.026l.07.005a4.041 4.041 0 0 1 1.635.49 3.94 3.94 0 0 1 1.602 1.662 3.77 3.77 0 0 1 .397 1.414l.005.076.003.075c.002.026.002.05.002.075 0 .024.003.052 0 .07v.065l-.002.073-.008.174a6.195 6.195 0 0 1-.08.639 5.1 5.1 0 0 1-.267.927 5.31 5.31 0 0 1-.624 1.13 5.052 5.052 0 0 1-3.237 2.014 4.82 4.82 0 0 1-.649.066l-.039.003h-.287a6.607 6.607 0 0 1-1.716-.265 6.776 6.776 0 0 1-3.4-2.274 6.75 6.75 0 0 1-.746-1.15 6.616 6.616 0 0 1-.714-2.596l-.005-.083-.002-.02v-.056l-.003-.073v-.096l-.003-.104v-.07l.003-.163c.008-.22.026-.45.054-.678a8.707 8.707 0 0 1 .28-1.355c.128-.444.286-.872.473-1.277a7.04 7.04 0 0 1 1.456-2.1 5.925 5.925 0 0 1 .953-.763c.169-.111.343-.213.524-.306.089-.05.182-.091.273-.135.047-.02.093-.042.138-.062a7.177 7.177 0 0 1 .714-.267l.145-.045c.049-.015.098-.026.148-.041.098-.029.197-.052.296-.076.049-.013.1-.02.15-.033l.15-.032.151-.028.076-.013.075-.01.153-.024c.057-.01.114-.013.171-.023l.169-.021c.036-.003.073-.008.106-.01l.073-.008.036-.003.042-.002c.057-.003.114-.008.171-.01l.086-.006h.023l.037-.003.145-.007a7.999 7.999 0 0 1 1.708.125 7.917 7.917 0 0 1 2.048.68 8.253 8.253 0 0 1 1.672 1.09l.09.077.089.078c.06.052.114.107.171.159.057.052.112.106.166.16.052.055.107.107.159.164a8.671 8.671 0 0 1 1.41 1.978c.012.026.028.052.04.078l.04.078.075.156c.023.051.05.1.07.153l.065.15a8.848 8.848 0 0 1 .45 1.34.19.19 0 0 0 .201.142.186.186 0 0 0 .172-.184c.01-.246.002-.532-.024-.856z"
|
|
94306
|
+
},
|
|
94307
|
+
graphql: {
|
|
94308
|
+
title: "GraphQL",
|
|
94309
|
+
d: "M12.002 0a2.138 2.138 0 1 0 0 4.277 2.138 2.138 0 1 0 0-4.277zm8.54 4.931a2.138 2.138 0 1 0 0 4.277 2.138 2.138 0 1 0 0-4.277zm0 9.862a2.138 2.138 0 1 0 0 4.277 2.138 2.138 0 1 0 0-4.277zm-8.54 4.931a2.138 2.138 0 1 0 0 4.276 2.138 2.138 0 1 0 0-4.276zm-8.542-4.93a2.138 2.138 0 1 0 0 4.276 2.138 2.138 0 1 0 0-4.277zm0-9.863a2.138 2.138 0 1 0 0 4.277 2.138 2.138 0 1 0 0-4.277zm8.542-3.378L2.953 6.777v10.448l9.049 5.224 9.047-5.224V6.777zm0 1.601 7.66 13.27H4.34zm-1.387.371L3.97 15.037V7.363zm2.774 0 6.646 3.838v7.674zM5.355 17.44h13.293l-6.646 3.836z"
|
|
94310
|
+
},
|
|
94311
|
+
javascript: {
|
|
94312
|
+
title: "JavaScript",
|
|
94313
|
+
d: "M0 0h24v24H0V0zm22.034 18.276c-.175-1.095-.888-2.015-3.003-2.873-.736-.345-1.554-.585-1.797-1.14-.091-.33-.105-.51-.046-.705.15-.646.915-.84 1.515-.66.39.12.75.42.976.9 1.034-.676 1.034-.676 1.755-1.125-.27-.42-.404-.601-.586-.78-.63-.705-1.469-1.065-2.834-1.034l-.705.089c-.676.165-1.32.525-1.71 1.005-1.14 1.291-.811 3.541.569 4.471 1.365 1.02 3.361 1.244 3.616 2.205.24 1.17-.87 1.545-1.966 1.41-.811-.18-1.26-.586-1.755-1.336l-1.83 1.051c.21.48.45.689.81 1.109 1.74 1.756 6.09 1.666 6.871-1.004.029-.09.24-.705.074-1.65l.046.067zm-8.983-7.245h-2.248c0 1.938-.009 3.864-.009 5.805 0 1.232.063 2.363-.138 2.711-.33.689-1.18.601-1.566.48-.396-.196-.597-.466-.83-.855-.063-.105-.11-.196-.127-.196l-1.825 1.125c.305.63.75 1.172 1.324 1.517.855.51 2.004.675 3.207.405.783-.226 1.458-.691 1.811-1.411.51-.93.402-2.07.397-3.346.012-2.054 0-4.109 0-6.179l.004-.056z",
|
|
94314
|
+
license: "MIT",
|
|
94315
|
+
licenseUrl: "https://spdx.org/licenses/MIT.html",
|
|
94316
|
+
source: "https://github.com/voodootikigod/logo.js/blob/1544bdeed6d618a6cfe4f0650d04ab8d9cfa76d9/js.svg",
|
|
94317
|
+
copyright: "Copyright (c) 2011 Christopher Williams <chris@iterativedesigns.com>"
|
|
94318
|
+
},
|
|
94319
|
+
kotlin: { title: "Kotlin", d: "M24 24H0V0h24L12 12Z" },
|
|
94320
|
+
kubernetes: {
|
|
94321
|
+
title: "Kubernetes",
|
|
94322
|
+
d: "M10.204 14.35l.007.01-.999 2.413a5.171 5.171 0 0 1-2.075-2.597l2.578-.437.004.005a.44.44 0 0 1 .484.606zm-.833-2.129a.44.44 0 0 0 .173-.756l.002-.011L7.585 9.7a5.143 5.143 0 0 0-.73 3.255l2.514-.725.002-.009zm1.145-1.98a.44.44 0 0 0 .699-.337l.01-.005.15-2.62a5.144 5.144 0 0 0-3.01 1.442l2.147 1.523.004-.002zm.76 2.75l.723.349.722-.347.18-.78-.5-.623h-.804l-.5.623.179.779zm1.5-3.095a.44.44 0 0 0 .7.336l.008.003 2.134-1.513a5.188 5.188 0 0 0-2.992-1.442l.148 2.615.002.001zm10.876 5.97l-5.773 7.181a1.6 1.6 0 0 1-1.248.594l-9.261.003a1.6 1.6 0 0 1-1.247-.596l-5.776-7.18a1.583 1.583 0 0 1-.307-1.34L2.1 5.573c.108-.47.425-.864.863-1.073L11.305.513a1.606 1.606 0 0 1 1.385 0l8.345 3.985c.438.209.755.604.863 1.073l2.062 8.955c.108.47-.005.963-.308 1.34zm-3.289-2.057c-.042-.01-.103-.026-.145-.034-.174-.033-.315-.025-.479-.038-.35-.037-.638-.067-.895-.148-.105-.04-.18-.165-.216-.216l-.201-.059a6.45 6.45 0 0 0-.105-2.332 6.465 6.465 0 0 0-.936-2.163c.052-.047.15-.133.177-.159.008-.09.001-.183.094-.282.197-.185.444-.338.743-.522.142-.084.273-.137.415-.242.032-.024.076-.062.11-.089.24-.191.295-.52.123-.736-.172-.216-.506-.236-.745-.045-.034.027-.08.062-.111.088-.134.116-.217.23-.33.35-.246.25-.45.458-.673.609-.097.056-.239.037-.303.033l-.19.135a6.545 6.545 0 0 0-4.146-2.003l-.012-.223c-.065-.062-.143-.115-.163-.25-.022-.268.015-.557.057-.905.023-.163.061-.298.068-.475.001-.04-.001-.099-.001-.142 0-.306-.224-.555-.5-.555-.275 0-.499.249-.499.555l.001.014c0 .041-.002.092 0 .128.006.177.044.312.067.475.042.348.078.637.056.906a.545.545 0 0 1-.162.258l-.012.211a6.424 6.424 0 0 0-4.166 2.003 8.373 8.373 0 0 1-.18-.128c-.09.012-.18.04-.297-.029-.223-.15-.427-.358-.673-.608-.113-.12-.195-.234-.329-.349-.03-.026-.077-.062-.111-.088a.594.594 0 0 0-.348-.132.481.481 0 0 0-.398.176c-.172.216-.117.546.123.737l.007.005.104.083c.142.105.272.159.414.242.299.185.546.338.743.522.076.082.09.226.1.288l.16.143a6.462 6.462 0 0 0-1.02 4.506l-.208.06c-.055.072-.133.184-.215.217-.257.081-.546.11-.895.147-.164.014-.305.006-.48.039-.037.007-.09.02-.133.03l-.004.002-.007.002c-.295.071-.484.342-.423.608.061.267.349.429.645.365l.007-.001.01-.003.129-.029c.17-.046.294-.113.448-.172.33-.118.604-.217.87-.256.112-.009.23.069.288.101l.217-.037a6.5 6.5 0 0 0 2.88 3.596l-.09.218c.033.084.069.199.044.282-.097.252-.263.517-.452.813-.091.136-.185.242-.268.399-.02.037-.045.095-.064.134-.128.275-.034.591.213.71.248.12.556-.007.69-.282v-.002c.02-.039.046-.09.062-.127.07-.162.094-.301.144-.458.132-.332.205-.68.387-.897.05-.06.13-.082.215-.105l.113-.205a6.453 6.453 0 0 0 4.609.012l.106.192c.086.028.18.042.256.155.136.232.229.507.342.84.05.156.074.295.145.457.016.037.043.09.062.129.133.276.442.402.69.282.247-.118.341-.435.213-.71-.02-.039-.045-.096-.065-.134-.083-.156-.177-.261-.268-.398-.19-.296-.346-.541-.443-.793-.04-.13.007-.21.038-.294-.018-.022-.059-.144-.083-.202a6.499 6.499 0 0 0 2.88-3.622c.064.01.176.03.213.038.075-.05.144-.114.28-.104.266.039.54.138.87.256.154.06.277.128.448.173.036.01.088.019.13.028l.009.003.007.001c.297.064.584-.098.645-.365.06-.266-.128-.537-.423-.608zM16.4 9.701l-1.95 1.746v.005a.44.44 0 0 0 .173.757l.003.01 2.526.728a5.199 5.199 0 0 0-.108-1.674A5.208 5.208 0 0 0 16.4 9.7zm-4.013 5.325a.437.437 0 0 0-.404-.232.44.44 0 0 0-.372.233h-.002l-1.268 2.292a5.164 5.164 0 0 0 3.326.003l-1.27-2.296h-.01zm1.888-1.293a.44.44 0 0 0-.27.036.44.44 0 0 0-.214.572l-.003.004 1.01 2.438a5.15 5.15 0 0 0 2.081-2.615l-2.6-.44-.004.005z"
|
|
94323
|
+
},
|
|
94324
|
+
mongodb: {
|
|
94325
|
+
title: "MongoDB",
|
|
94326
|
+
d: "M17.193 9.555c-1.264-5.58-4.252-7.414-4.573-8.115-.28-.394-.53-.954-.735-1.44-.036.495-.055.685-.523 1.184-.723.566-4.438 3.682-4.74 10.02-.282 5.912 4.27 9.435 4.888 9.884l.07.05A73.49 73.49 0 0111.91 24h.481c.114-1.032.284-2.056.51-3.07.417-.296.604-.463.85-.693a11.342 11.342 0 003.639-8.464c.01-.814-.103-1.662-.197-2.218zm-5.336 8.195s0-8.291.275-8.29c.213 0 .49 10.695.49 10.695-.381-.045-.765-1.76-.765-2.405z"
|
|
94327
|
+
},
|
|
94328
|
+
mysql: {
|
|
94329
|
+
title: "MySQL",
|
|
94330
|
+
d: "M16.405 5.501c-.115 0-.193.014-.274.033v.013h.014c.054.104.146.18.214.273.054.107.1.214.154.32l.014-.015c.094-.066.14-.172.14-.333-.04-.047-.046-.094-.08-.14-.04-.067-.126-.1-.18-.153zM5.77 18.695h-.927a50.854 50.854 0 00-.27-4.41h-.008l-1.41 4.41H2.45l-1.4-4.41h-.01a72.892 72.892 0 00-.195 4.41H0c.055-1.966.192-3.81.41-5.53h1.15l1.335 4.064h.008l1.347-4.064h1.095c.242 2.015.384 3.86.428 5.53zm4.017-4.08c-.378 2.045-.876 3.533-1.492 4.46-.482.716-1.01 1.073-1.583 1.073-.153 0-.34-.046-.566-.138v-.494c.11.017.24.026.386.026.268 0 .483-.075.647-.222.197-.18.295-.382.295-.605 0-.155-.077-.47-.23-.944L6.23 14.615h.91l.727 2.36c.164.536.233.91.205 1.123.4-1.064.678-2.227.835-3.483zm12.325 4.08h-2.63v-5.53h.885v4.85h1.745zm-3.32.135l-1.016-.5c.09-.076.177-.158.255-.25.433-.506.648-1.258.648-2.253 0-1.83-.718-2.746-2.155-2.746-.704 0-1.254.232-1.65.697-.43.508-.646 1.256-.646 2.245 0 .972.19 1.686.574 2.14.35.41.877.615 1.583.615.264 0 .506-.033.725-.098l1.325.772.36-.622zM15.5 17.588c-.225-.36-.337-.94-.337-1.736 0-1.393.424-2.09 1.27-2.09.443 0 .77.167.977.5.224.362.336.936.336 1.723 0 1.404-.424 2.108-1.27 2.108-.445 0-.77-.167-.978-.5zm-1.658-.425c0 .47-.172.856-.516 1.156-.344.3-.803.45-1.384.45-.543 0-1.064-.172-1.573-.515l.237-.476c.438.22.833.328 1.19.328.332 0 .593-.073.783-.22a.754.754 0 00.3-.615c0-.33-.23-.61-.648-.845-.388-.213-1.163-.657-1.163-.657-.422-.307-.632-.636-.632-1.177 0-.45.157-.81.47-1.085.315-.278.72-.415 1.22-.415.512 0 .98.136 1.4.41l-.213.476a2.726 2.726 0 00-1.064-.23c-.283 0-.502.068-.654.206a.685.685 0 00-.248.524c0 .328.234.61.666.85.393.215 1.187.67 1.187.67.433.305.648.63.648 1.168zm9.382-5.852c-.535-.014-.95.04-1.297.188-.1.04-.26.04-.274.167.055.053.063.14.11.214.08.134.218.313.346.407.14.11.28.216.427.31.26.16.555.255.81.416.145.094.293.213.44.313.073.05.12.14.214.172v-.02c-.046-.06-.06-.147-.105-.214-.067-.067-.134-.127-.2-.193a3.223 3.223 0 00-.695-.675c-.214-.146-.682-.35-.77-.595l-.013-.014c.146-.013.32-.066.46-.106.227-.06.435-.047.67-.106.106-.027.213-.06.32-.094v-.06c-.12-.12-.21-.283-.334-.395a8.867 8.867 0 00-1.104-.823c-.21-.134-.476-.22-.697-.334-.08-.04-.214-.06-.26-.127-.12-.146-.19-.34-.275-.514a17.69 17.69 0 01-.547-1.163c-.12-.262-.193-.523-.34-.763-.69-1.137-1.437-1.826-2.586-2.5-.247-.14-.543-.2-.856-.274-.167-.008-.334-.02-.5-.027-.11-.047-.216-.174-.31-.235-.38-.24-1.364-.76-1.644-.072-.18.434.267.862.422 1.082.115.153.26.328.34.5.047.116.06.235.107.356.106.294.207.622.347.897.073.14.153.287.247.413.054.073.146.107.167.227-.094.136-.1.334-.154.5-.24.757-.146 1.693.194 2.25.107.166.362.534.703.393.3-.12.234-.5.32-.835.02-.08.007-.133.048-.187v.015c.094.188.188.367.274.555.206.328.566.668.867.895.16.12.287.328.487.402v-.02h-.015c-.043-.058-.1-.086-.154-.133a3.445 3.445 0 01-.35-.4 8.76 8.76 0 01-.747-1.218c-.11-.21-.202-.436-.29-.643-.04-.08-.04-.2-.107-.24-.1.146-.247.273-.32.453-.127.288-.14.642-.188 1.01-.027.007-.014 0-.027.014-.214-.052-.287-.274-.367-.46-.2-.475-.233-1.238-.06-1.785.047-.14.247-.582.167-.716-.042-.127-.174-.2-.247-.303a2.478 2.478 0 01-.24-.427c-.16-.374-.24-.788-.414-1.162-.08-.173-.22-.354-.334-.513-.127-.18-.267-.307-.368-.52-.033-.073-.08-.194-.027-.274.014-.054.042-.075.094-.09.088-.072.335.022.422.062.247.1.455.194.662.334.094.066.195.193.315.226h.14c.214.047.455.014.655.073.355.114.675.28.962.46a5.953 5.953 0 012.085 2.286c.08.154.115.295.188.455.14.33.313.663.455.982.14.315.275.636.476.897.1.14.502.213.682.286.133.06.34.115.46.188.23.14.454.3.67.454.11.076.443.243.463.378z"
|
|
94331
|
+
},
|
|
94332
|
+
natsdotio: {
|
|
94333
|
+
title: "NATS.io",
|
|
94334
|
+
d: "M12.004 0H.404v18.807h9.938l1.714 1.602v-.026L15.966 24v-5.193h7.63V0H12.003zm7.578 14.45H15.38L6.898 6.519v7.93H4.116V4.376h4.349l8.344 7.784V4.375h2.773V14.45z"
|
|
94335
|
+
},
|
|
94336
|
+
nextdotjs: {
|
|
94337
|
+
title: "Next.js",
|
|
94338
|
+
d: "M18.665 21.978C16.758 23.255 14.465 24 12 24 5.377 24 0 18.623 0 12S5.377 0 12 0s12 5.377 12 12c0 3.583-1.574 6.801-4.067 9.001L9.219 7.2H7.2v9.596h1.615V9.251l9.85 12.727Zm-3.332-8.533 1.6 2.061V7.2h-1.6v6.245Z"
|
|
94339
|
+
},
|
|
94340
|
+
nginx: {
|
|
94341
|
+
title: "NGINX",
|
|
94342
|
+
d: "M12 0L1.605 6v12L12 24l10.395-6V6L12 0zm6 16.59c0 .705-.646 1.29-1.529 1.29-.631 0-1.351-.255-1.801-.81l-6-7.141v6.66c0 .721-.57 1.29-1.274 1.29H7.32c-.721 0-1.29-.6-1.29-1.29V7.41c0-.705.63-1.29 1.5-1.29.646 0 1.38.255 1.83.81l5.97 7.141V7.41c0-.721.6-1.29 1.29-1.29h.075c.72 0 1.29.6 1.29 1.29v9.18H18z"
|
|
94343
|
+
},
|
|
94344
|
+
nodedotjs: {
|
|
94345
|
+
title: "Node.js",
|
|
94346
|
+
d: "M11.998,24c-0.321,0-0.641-0.084-0.922-0.247l-2.936-1.737c-0.438-0.245-0.224-0.332-0.08-0.383 c0.585-0.203,0.703-0.25,1.328-0.604c0.065-0.037,0.151-0.023,0.218,0.017l2.256,1.339c0.082,0.045,0.197,0.045,0.272,0l8.795-5.076 c0.082-0.047,0.134-0.141,0.134-0.238V6.921c0-0.099-0.053-0.192-0.137-0.242l-8.791-5.072c-0.081-0.047-0.189-0.047-0.271,0 L3.075,6.68C2.99,6.729,2.936,6.825,2.936,6.921v10.15c0,0.097,0.054,0.189,0.139,0.235l2.409,1.392 c1.307,0.654,2.108-0.116,2.108-0.89V7.787c0-0.142,0.114-0.253,0.256-0.253h1.115c0.139,0,0.255,0.112,0.255,0.253v10.021 c0,1.745-0.95,2.745-2.604,2.745c-0.508,0-0.909,0-2.026-0.551L2.28,18.675c-0.57-0.329-0.922-0.945-0.922-1.604V6.921 c0-0.659,0.353-1.275,0.922-1.603l8.795-5.082c0.557-0.315,1.296-0.315,1.848,0l8.794,5.082c0.57,0.329,0.924,0.944,0.924,1.603 v10.15c0,0.659-0.354,1.273-0.924,1.604l-8.794,5.078C12.643,23.916,12.324,24,11.998,24z M19.099,13.993 c0-1.9-1.284-2.406-3.987-2.763c-2.731-0.361-3.009-0.548-3.009-1.187c0-0.528,0.235-1.233,2.258-1.233 c1.807,0,2.473,0.389,2.747,1.607c0.024,0.115,0.129,0.199,0.247,0.199h1.141c0.071,0,0.138-0.031,0.186-0.081 c0.048-0.054,0.074-0.123,0.067-0.196c-0.177-2.098-1.571-3.076-4.388-3.076c-2.508,0-4.004,1.058-4.004,2.833 c0,1.925,1.488,2.457,3.895,2.695c2.88,0.282,3.103,0.703,3.103,1.269c0,0.983-0.789,1.402-2.642,1.402 c-2.327,0-2.839-0.584-3.011-1.742c-0.02-0.124-0.126-0.215-0.253-0.215h-1.137c-0.141,0-0.254,0.112-0.254,0.253 c0,1.482,0.806,3.248,4.655,3.248C17.501,17.007,19.099,15.91,19.099,13.993z"
|
|
94347
|
+
},
|
|
94348
|
+
openjdk: {
|
|
94349
|
+
title: "OpenJDK",
|
|
94350
|
+
d: "M11.915 0 11.7.215C9.515 2.4 7.47 6.39 6.046 10.483c-1.064 1.024-3.633 2.81-3.711 3.551-.093.87 1.746 2.611 1.55 3.235-.198.625-1.304 1.408-1.014 1.939.1.188.823.011 1.277-.491a13.389 13.389 0 0 0-.017 2.14c.076.906.27 1.668.643 2.232.372.563.956.911 1.667.911.397 0 .727-.114 1.024-.264.298-.149.571-.33.91-.5.68-.34 1.634-.666 3.53-.604 1.903.062 2.872.39 3.559.704.687.314 1.15.664 1.925.664.767 0 1.395-.336 1.807-.9.412-.563.631-1.33.72-2.24.06-.623.055-1.32 0-2.066.454.45 1.117.604 1.213.424.29-.53-.816-1.314-1.013-1.937-.198-.624 1.642-2.366 1.549-3.236-.08-.748-2.707-2.568-3.748-3.586C16.428 6.374 14.308 2.394 12.13.215zm.175 6.038a2.95 2.95 0 0 1 2.943 2.942 2.95 2.95 0 0 1-2.943 2.943A2.95 2.95 0 0 1 9.148 8.98a2.95 2.95 0 0 1 2.942-2.942zM8.685 7.983a3.515 3.515 0 0 0-.145.997c0 1.951 1.6 3.55 3.55 3.55 1.95 0 3.55-1.598 3.55-3.55 0-.329-.046-.648-.132-.951.334.095.64.208.915.336a42.699 42.699 0 0 1 2.042 5.829c.678 2.545 1.01 4.92.846 6.607-.082.844-.29 1.51-.606 1.94-.315.431-.713.651-1.315.651-.593 0-.932-.27-1.673-.61-.741-.338-1.825-.694-3.792-.758-1.974-.064-3.073.293-3.821.669-.375.188-.659.373-.911.5s-.466.2-.752.2c-.53 0-.876-.209-1.16-.64-.285-.43-.474-1.101-.545-1.948-.141-1.693.176-4.069.823-6.614a43.155 43.155 0 0 1 1.934-5.783c.348-.167.749-.31 1.192-.425zm-3.382 4.362a.216.216 0 0 1 .13.031c-.166.56-.323 1.116-.463 1.665a33.849 33.849 0 0 0-.547 2.555 3.9 3.9 0 0 0-.2-.39c-.58-1.012-.914-1.642-1.16-2.08.315-.24 1.679-1.755 2.24-1.781zm13.394.01c.562.027 1.926 1.543 2.24 1.783-.246.438-.58 1.068-1.16 2.08a4.428 4.428 0 0 0-.163.309 32.354 32.354 0 0 0-.562-2.49 40.579 40.579 0 0 0-.482-1.652.216.216 0 0 1 .127-.03z",
|
|
94351
|
+
license: "BSD-3-Clause",
|
|
94352
|
+
licenseUrl: "https://spdx.org/licenses/BSD-3-Clause.html",
|
|
94353
|
+
source: "https://github.com/openjdk/duke/blob/master/vector/Agent.svg"
|
|
94354
|
+
},
|
|
94355
|
+
postgresql: {
|
|
94356
|
+
title: "PostgreSQL",
|
|
94357
|
+
d: "M23.5594 14.7228a.5269.5269 0 0 0-.0563-.1191c-.139-.2632-.4768-.3418-1.0074-.2321-1.6533.3411-2.2935.1312-2.5256-.0191 1.342-2.0482 2.445-4.522 3.0411-6.8297.2714-1.0507.7982-3.5237.1222-4.7316a1.5641 1.5641 0 0 0-.1509-.235C21.6931.9086 19.8007.0248 17.5099.0005c-1.4947-.0158-2.7705.3461-3.1161.4794a9.449 9.449 0 0 0-.5159-.0816 8.044 8.044 0 0 0-1.3114-.1278c-1.1822-.0184-2.2038.2642-3.0498.8406-.8573-.3211-4.7888-1.645-7.2219.0788C.9359 2.1526.3086 3.8733.4302 6.3043c.0409.818.5069 3.334 1.2423 5.7436.4598 1.5065.9387 2.7019 1.4334 3.582.553.9942 1.1259 1.5933 1.7143 1.7895.4474.1491 1.1327.1441 1.8581-.7279.8012-.9635 1.5903-1.8258 1.9446-2.2069.4351.2355.9064.3625 1.39.3772a.0569.0569 0 0 0 .0004.0041 11.0312 11.0312 0 0 0-.2472.3054c-.3389.4302-.4094.5197-1.5002.7443-.3102.064-1.1344.2339-1.1464.8115-.0025.1224.0329.2309.0919.3268.2269.4231.9216.6097 1.015.6331 1.3345.3335 2.5044.092 3.3714-.6787-.017 2.231.0775 4.4174.3454 5.0874.2212.5529.7618 1.9045 2.4692 1.9043.2505 0 .5263-.0291.8296-.0941 1.7819-.3821 2.5557-1.1696 2.855-2.9059.1503-.8707.4016-2.8753.5388-4.1012.0169-.0703.0357-.1207.057-.1362.0007-.0005.0697-.0471.4272.0307a.3673.3673 0 0 0 .0443.0068l.2539.0223.0149.001c.8468.0384 1.9114-.1426 2.5312-.4308.6438-.2988 1.8057-1.0323 1.5951-1.6698zM2.371 11.8765c-.7435-2.4358-1.1779-4.8851-1.2123-5.5719-.1086-2.1714.4171-3.6829 1.5623-4.4927 1.8367-1.2986 4.8398-.5408 6.108-.13-.0032.0032-.0066.0061-.0098.0094-2.0238 2.044-1.9758 5.536-1.9708 5.7495-.0002.0823.0066.1989.0162.3593.0348.5873.0996 1.6804-.0735 2.9184-.1609 1.1504.1937 2.2764.9728 3.0892.0806.0841.1648.1631.2518.2374-.3468.3714-1.1004 1.1926-1.9025 2.1576-.5677.6825-.9597.5517-1.0886.5087-.3919-.1307-.813-.5871-1.2381-1.3223-.4796-.839-.9635-2.0317-1.4155-3.5126zm6.0072 5.0871c-.1711-.0428-.3271-.1132-.4322-.1772.0889-.0394.2374-.0902.4833-.1409 1.2833-.2641 1.4815-.4506 1.9143-1.0002.0992-.126.2116-.2687.3673-.4426a.3549.3549 0 0 0 .0737-.1298c.1708-.1513.2724-.1099.4369-.0417.156.0646.3078.26.3695.4752.0291.1016.0619.2945-.0452.4444-.9043 1.2658-2.2216 1.2494-3.1676 1.0128zm2.094-3.988-.0525.141c-.133.3566-.2567.6881-.3334 1.003-.6674-.0021-1.3168-.2872-1.8105-.8024-.6279-.6551-.9131-1.5664-.7825-2.5004.1828-1.3079.1153-2.4468.079-3.0586-.005-.0857-.0095-.1607-.0122-.2199.2957-.2621 1.6659-.9962 2.6429-.7724.4459.1022.7176.4057.8305.928.5846 2.7038.0774 3.8307-.3302 4.7363-.084.1866-.1633.3629-.2311.5454zm7.3637 4.5725c-.0169.1768-.0358.376-.0618.5959l-.146.4383a.3547.3547 0 0 0-.0182.1077c-.0059.4747-.054.6489-.115.8693-.0634.2292-.1353.4891-.1794 1.0575-.11 1.4143-.8782 2.2267-2.4172 2.5565-1.5155.3251-1.7843-.4968-2.0212-1.2217a6.5824 6.5824 0 0 0-.0769-.2266c-.2154-.5858-.1911-1.4119-.1574-2.5551.0165-.5612-.0249-1.9013-.3302-2.6462.0044-.2932.0106-.5909.019-.8918a.3529.3529 0 0 0-.0153-.1126 1.4927 1.4927 0 0 0-.0439-.208c-.1226-.4283-.4213-.7866-.7797-.9351-.1424-.059-.4038-.1672-.7178-.0869.067-.276.1831-.5875.309-.9249l.0529-.142c.0595-.16.134-.3257.213-.5012.4265-.9476 1.0106-2.2453.3766-5.1772-.2374-1.0981-1.0304-1.6343-2.2324-1.5098-.7207.0746-1.3799.3654-1.7088.5321a5.6716 5.6716 0 0 0-.1958.1041c.0918-1.1064.4386-3.1741 1.7357-4.4823a4.0306 4.0306 0 0 1 .3033-.276.3532.3532 0 0 0 .1447-.0644c.7524-.5706 1.6945-.8506 2.802-.8325.4091.0067.8017.0339 1.1742.081 1.939.3544 3.2439 1.4468 4.0359 2.3827.8143.9623 1.2552 1.9315 1.4312 2.4543-1.3232-.1346-2.2234.1268-2.6797.779-.9926 1.4189.543 4.1729 1.2811 5.4964.1353.2426.2522.4522.2889.5413.2403.5825.5515.9713.7787 1.2552.0696.087.1372.1714.1885.245-.4008.1155-1.1208.3825-1.0552 1.717-.0123.1563-.0423.4469-.0834.8148-.0461.2077-.0702.4603-.0994.7662zm.8905-1.6211c-.0405-.8316.2691-.9185.5967-1.0105a2.8566 2.8566 0 0 0 .135-.0406 1.202 1.202 0 0 0 .1342.103c.5703.3765 1.5823.4213 3.0068.1344-.2016.1769-.5189.3994-.9533.6011-.4098.1903-1.0957.333-1.7473.3636-.7197.0336-1.0859-.0807-1.1721-.151zm.5695-9.2712c-.0059.3508-.0542.6692-.1054 1.0017-.055.3576-.112.7274-.1264 1.1762-.0142.4368.0404.8909.0932 1.3301.1066.887.216 1.8003-.2075 2.7014a3.5272 3.5272 0 0 1-.1876-.3856c-.0527-.1276-.1669-.3326-.3251-.6162-.6156-1.1041-2.0574-3.6896-1.3193-4.7446.3795-.5427 1.3408-.5661 2.1781-.463zm.2284 7.0137a12.3762 12.3762 0 0 0-.0853-.1074l-.0355-.0444c.7262-1.1995.5842-2.3862.4578-3.4385-.0519-.4318-.1009-.8396-.0885-1.2226.0129-.4061.0666-.7543.1185-1.0911.0639-.415.1288-.8443.1109-1.3505.0134-.0531.0188-.1158.0118-.1902-.0457-.4855-.5999-1.938-1.7294-3.253-.6076-.7073-1.4896-1.4972-2.6889-2.0395.5251-.1066 1.2328-.2035 2.0244-.1859 2.0515.0456 3.6746.8135 4.8242 2.2824a.908.908 0 0 1 .0667.1002c.7231 1.3556-.2762 6.2751-2.9867 10.5405zm-8.8166-6.1162c-.025.1794-.3089.4225-.6211.4225a.5821.5821 0 0 1-.0809-.0056c-.1873-.026-.3765-.144-.5059-.3156-.0458-.0605-.1203-.178-.1055-.2844.0055-.0401.0261-.0985.0925-.1488.1182-.0894.3518-.1226.6096-.0867.3163.0441.6426.1938.6113.4186zm7.9305-.4114c.0111.0792-.049.201-.1531.3102-.0683.0717-.212.1961-.4079.2232a.5456.5456 0 0 1-.075.0052c-.2935 0-.5414-.2344-.5607-.3717-.024-.1765.2641-.3106.5611-.352.297-.0414.6111.0088.6356.1851z"
|
|
94358
|
+
},
|
|
94359
|
+
prometheus: {
|
|
94360
|
+
title: "Prometheus",
|
|
94361
|
+
d: "M12 0C5.373 0 0 5.372 0 12c0 6.627 5.373 12 12 12s12-5.373 12-12c0-6.628-5.373-12-12-12zm0 22.46c-1.885 0-3.414-1.26-3.414-2.814h6.828c0 1.553-1.528 2.813-3.414 2.813zm5.64-3.745H6.36v-2.046h11.28v2.046zm-.04-3.098H6.391c-.037-.043-.075-.086-.111-.13-1.155-1.401-1.427-2.133-1.69-2.879-.005-.025 1.4.287 2.395.511 0 0 .513.119 1.262.255-.72-.843-1.147-1.915-1.147-3.01 0-2.406 1.845-4.508 1.18-6.207.648.053 1.34 1.367 1.387 3.422.689-.951.977-2.69.977-3.755 0-1.103.727-2.385 1.454-2.429-.648 1.069.168 1.984.894 4.256.272.854.237 2.29.447 3.201.07-1.892.395-4.652 1.595-5.605-.529 1.2.079 2.702.494 3.424.671 1.164 1.078 2.047 1.078 3.716a4.642 4.642 0 01-1.11 2.996c.792-.149 1.34-.283 1.34-.283l2.573-.502s-.374 1.538-1.81 3.019z"
|
|
94362
|
+
},
|
|
94363
|
+
python: {
|
|
94364
|
+
title: "Python",
|
|
94365
|
+
d: "M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01h8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01zm-6.47 14.25l-.23.33-.08.41.08.41.23.33.33.23.41.08.41-.08.33-.23.23-.33.08-.41-.08-.41-.23-.33-.33-.23-.41-.08-.41.08z"
|
|
94366
|
+
},
|
|
94367
|
+
rabbitmq: {
|
|
94368
|
+
title: "RabbitMQ",
|
|
94369
|
+
d: "M23.035 9.601h-7.677a.956.956 0 01-.962-.962V.962a.956.956 0 00-.962-.956H10.56a.956.956 0 00-.962.956V8.64a.956.956 0 01-.962.962H5.762a.956.956 0 01-.961-.962V.962A.956.956 0 003.839 0H.959a.956.956 0 00-.956.962v22.076A.956.956 0 00.965 24h22.07a.956.956 0 00.962-.962V10.58a.956.956 0 00-.962-.98zm-3.86 8.152a1.437 1.437 0 01-1.437 1.443h-1.924a1.437 1.437 0 01-1.436-1.443v-1.917a1.437 1.437 0 011.436-1.443h1.924a1.437 1.437 0 011.437 1.443z"
|
|
94370
|
+
},
|
|
94371
|
+
react: {
|
|
94372
|
+
title: "React",
|
|
94373
|
+
d: "M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"
|
|
94374
|
+
},
|
|
94375
|
+
redis: {
|
|
94376
|
+
title: "Redis",
|
|
94377
|
+
d: "M22.71 13.145c-1.66 2.092-3.452 4.483-7.038 4.483-3.203 0-4.397-2.825-4.48-5.12.701 1.484 2.073 2.685 4.214 2.63 4.117-.133 6.94-3.852 6.94-7.239 0-4.05-3.022-6.972-8.268-6.972-3.752 0-8.4 1.428-11.455 3.685C2.59 6.937 3.885 9.958 4.35 9.626c2.648-1.904 4.748-3.13 6.784-3.744C8.12 9.244.886 17.05 0 18.425c.1 1.261 1.66 4.648 2.424 4.648.232 0 .431-.133.664-.365a100.49 100.49 0 0 0 5.54-6.765c.222 3.104 1.748 6.898 6.014 6.898 3.819 0 7.604-2.756 9.33-8.965.2-.764-.73-1.361-1.261-.73zm-4.349-5.013c0 1.959-1.926 2.922-3.685 2.922-.941 0-1.664-.247-2.235-.568 1.051-1.592 2.092-3.225 3.21-4.973 1.972.334 2.71 1.43 2.71 2.619z"
|
|
94378
|
+
},
|
|
94379
|
+
spring: {
|
|
94380
|
+
title: "Spring",
|
|
94381
|
+
d: "M21.8537 1.4158a10.4504 10.4504 0 0 1-1.284 2.2471A11.9666 11.9666 0 1 0 3.8518 20.7757l.4445.3951a11.9543 11.9543 0 0 0 19.6316-8.2971c.3457-3.0126-.568-6.8649-2.0743-11.458zM5.5805 20.8745a1.0174 1.0174 0 1 1-.1482-1.4323 1.0396 1.0396 0 0 1 .1482 1.4323zm16.1991-3.5806c-2.9385 3.9263-9.2601 2.5928-13.2852 2.7904 0 0-.7161.0494-1.4323.1481 0 0 .2717-.1234.6174-.2469 2.8398-.9877 4.1732-1.1853 5.9018-2.0743 3.2349-1.6545 6.4698-5.2844 7.1118-9.0379-1.2347 3.6053-4.9881 6.7167-8.3959 7.9761-2.3459.8643-6.5685 1.7039-6.5685 1.7039l-.1729-.0988c-2.8645-1.4076-2.9632-7.6304 2.2718-9.6306 2.2966-.889 4.4696-.395 6.9637-.9877 2.6422-.6174 5.7043-2.5929 6.939-5.1857 1.3828 4.1732 3.062 10.643.0493 14.6434z"
|
|
94382
|
+
},
|
|
94383
|
+
sqlite: {
|
|
94384
|
+
title: "SQLite",
|
|
94385
|
+
d: "M21.678.521c-1.032-.92-2.28-.55-3.513.544a8.71 8.71 0 0 0-.547.535c-2.109 2.237-4.066 6.38-4.674 9.544.237.48.422 1.093.544 1.561a13.044 13.044 0 0 1 .164.703s-.019-.071-.096-.296l-.05-.146a1.689 1.689 0 0 0-.033-.08c-.138-.32-.518-.995-.686-1.289-.143.423-.27.818-.376 1.176.484.884.778 2.4.778 2.4s-.025-.099-.147-.442c-.107-.303-.644-1.244-.772-1.464-.217.804-.304 1.346-.226 1.478.152.256.296.698.422 1.186.286 1.1.485 2.44.485 2.44l.017.224a22.41 22.41 0 0 0 .056 2.748c.095 1.146.273 2.13.5 2.657l.155-.084c-.334-1.038-.47-2.399-.41-3.967.09-2.398.642-5.29 1.661-8.304 1.723-4.55 4.113-8.201 6.3-9.945-1.993 1.8-4.692 7.63-5.5 9.788-.904 2.416-1.545 4.684-1.931 6.857.666-2.037 2.821-2.912 2.821-2.912s1.057-1.304 2.292-3.166c-.74.169-1.955.458-2.362.629-.6.251-.762.337-.762.337s1.945-1.184 3.613-1.72C21.695 7.9 24.195 2.767 21.678.521m-18.573.543A1.842 1.842 0 0 0 1.27 2.9v16.608a1.84 1.84 0 0 0 1.835 1.834h9.418a22.953 22.953 0 0 1-.052-2.707c-.006-.062-.011-.141-.016-.2a27.01 27.01 0 0 0-.473-2.378c-.121-.47-.275-.898-.369-1.057-.116-.197-.098-.31-.097-.432 0-.12.015-.245.037-.386a9.98 9.98 0 0 1 .234-1.045l.217-.028c-.017-.035-.014-.065-.031-.097l-.041-.381a32.8 32.8 0 0 1 .382-1.194l.2-.019c-.008-.016-.01-.038-.018-.053l-.043-.316c.63-3.28 2.587-7.443 4.8-9.791.066-.069.133-.128.198-.194Z"
|
|
94386
|
+
},
|
|
94387
|
+
terraform: {
|
|
94388
|
+
title: "Terraform",
|
|
94389
|
+
d: "M1.44 0v7.575l6.561 3.79V3.787zm21.12 4.227l-6.561 3.791v7.574l6.56-3.787zM8.72 4.23v7.575l6.561 3.787V8.018zm0 8.405v7.575L15.28 24v-7.578z"
|
|
94390
|
+
},
|
|
94391
|
+
typescript: {
|
|
94392
|
+
title: "TypeScript",
|
|
94393
|
+
d: "M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"
|
|
94394
|
+
},
|
|
94395
|
+
vault: {
|
|
94396
|
+
title: "Vault",
|
|
94397
|
+
d: "M0 0l11.955 24L24 0zm13.366 4.827h1.393v1.38h-1.393zm-2.77 5.569H9.22V8.993h1.389zm0-2.087H9.22V6.906h1.389zm0-2.086H9.22V4.819h1.389zm2.087 6.263h-1.377V11.08h1.388zm0-2.09h-1.377V8.993h1.388zm0-2.087h-1.377V6.906h1.388zm0-2.086h-1.377V4.819h1.388zm.683.683h1.393v1.389h-1.393zm0 3.475V8.993h1.389v1.388Z"
|
|
94283
94398
|
}
|
|
94284
94399
|
};
|
|
94285
|
-
|
|
94286
|
-
logical: logicalView,
|
|
94287
|
-
application: applicationView,
|
|
94288
|
-
infrastructure: infrastructureView,
|
|
94289
|
-
security: securityView
|
|
94290
|
-
};
|
|
94400
|
+
LOGO_NAMES = Object.keys(LOGOS);
|
|
94291
94401
|
}
|
|
94292
94402
|
});
|
|
94293
94403
|
|
|
@@ -94313,8 +94423,7 @@ function validate(model) {
|
|
|
94313
94423
|
...checkMissingLabels(elements),
|
|
94314
94424
|
...checkNesting(elements, view),
|
|
94315
94425
|
...checkFlows(model, view),
|
|
94316
|
-
...
|
|
94317
|
-
...checkTrustBoundaries(model, view),
|
|
94426
|
+
...checkLogos(elements, view),
|
|
94318
94427
|
...checkBusinessObjects(model, view),
|
|
94319
94428
|
...checkMinimumCounts(elements, model, view),
|
|
94320
94429
|
...checkIsolatedElements(model, view, elements)
|
|
@@ -94356,6 +94465,48 @@ function checkUnknownKinds(elements, view) {
|
|
|
94356
94465
|
}
|
|
94357
94466
|
return diagnostics;
|
|
94358
94467
|
}
|
|
94468
|
+
function checkLogos(elements, view) {
|
|
94469
|
+
const diagnostics = [];
|
|
94470
|
+
const logoKinds = view.logoKinds ?? [];
|
|
94471
|
+
for (const element of elements) {
|
|
94472
|
+
const logo = element.logo;
|
|
94473
|
+
if (!logo) continue;
|
|
94474
|
+
if (!logoKinds.includes(element.kind)) {
|
|
94475
|
+
diagnostics.push({
|
|
94476
|
+
code: "E0108",
|
|
94477
|
+
severity: "error",
|
|
94478
|
+
message: `\`${element.kind}\` does not carry a logo`,
|
|
94479
|
+
span: logo.span,
|
|
94480
|
+
note: logoKinds.length ? `the \`${view.name}\` view accepts \`logo\` on: ${logoKinds.join(", ")}` : `the \`${view.name}\` view has no kinds that carry a logo`
|
|
94481
|
+
});
|
|
94482
|
+
continue;
|
|
94483
|
+
}
|
|
94484
|
+
if (logo.source === "builtin") {
|
|
94485
|
+
if (Object.hasOwn(LOGOS, logo.value)) continue;
|
|
94486
|
+
const suggestion = nearest(logo.value, LOGO_NAMES);
|
|
94487
|
+
diagnostics.push({
|
|
94488
|
+
code: "E0107",
|
|
94489
|
+
severity: "error",
|
|
94490
|
+
message: `unknown built-in logo \`${logo.value}\``,
|
|
94491
|
+
span: logo.span,
|
|
94492
|
+
note: `${LOGO_NAMES.length} built-ins available \u2014 run \`cairn logos\` to list them`,
|
|
94493
|
+
help: suggestion !== void 0 ? `did you mean \`${suggestion}\`?` : `use a file instead: \`logo: "./logos/${logo.value}.svg"\``
|
|
94494
|
+
});
|
|
94495
|
+
continue;
|
|
94496
|
+
}
|
|
94497
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(logo.value) || logo.value.startsWith("//")) {
|
|
94498
|
+
diagnostics.push({
|
|
94499
|
+
code: "E0105",
|
|
94500
|
+
severity: "error",
|
|
94501
|
+
message: `\`logo\` will not fetch \`${logo.value}\``,
|
|
94502
|
+
span: logo.span,
|
|
94503
|
+
note: "a linked logo leaves the diagram depending on a server that can change or vanish",
|
|
94504
|
+
help: 'download it next to the diagram and point at the file: `logo: "./logos/name.svg"`'
|
|
94505
|
+
});
|
|
94506
|
+
}
|
|
94507
|
+
}
|
|
94508
|
+
return diagnostics;
|
|
94509
|
+
}
|
|
94359
94510
|
function checkMissingLabels(elements) {
|
|
94360
94511
|
const diagnostics = [];
|
|
94361
94512
|
for (const element of elements) {
|
|
@@ -94447,75 +94598,6 @@ function checkFlows(model, view) {
|
|
|
94447
94598
|
}
|
|
94448
94599
|
return diagnostics;
|
|
94449
94600
|
}
|
|
94450
|
-
function checkElementAttributes(elements, view) {
|
|
94451
|
-
const spec = view.attrSpec;
|
|
94452
|
-
if (!spec) return [];
|
|
94453
|
-
const diagnostics = [];
|
|
94454
|
-
for (const element of elements) {
|
|
94455
|
-
if (element.kind !== spec.kind) continue;
|
|
94456
|
-
if (!element.attr) {
|
|
94457
|
-
diagnostics.push({
|
|
94458
|
-
code: spec.code,
|
|
94459
|
-
severity: "error",
|
|
94460
|
-
message: spec.message + ` (\`${element.id}\`)`,
|
|
94461
|
-
span: element.idSpan,
|
|
94462
|
-
help: spec.help
|
|
94463
|
-
});
|
|
94464
|
-
} else if (!spec.values.includes(element.attr.value)) {
|
|
94465
|
-
const suggestion = nearest(element.attr.value, spec.values);
|
|
94466
|
-
diagnostics.push({
|
|
94467
|
-
code: spec.code,
|
|
94468
|
-
severity: "error",
|
|
94469
|
-
message: `invalid ${spec.kind} value \`${element.attr.value}\` (\`${element.id}\`)`,
|
|
94470
|
-
span: element.attr.span,
|
|
94471
|
-
note: `allowed: ${spec.values.join(", ")}`,
|
|
94472
|
-
help: suggestion ? `did you mean \`${suggestion}\`?` : spec.help
|
|
94473
|
-
});
|
|
94474
|
-
}
|
|
94475
|
-
}
|
|
94476
|
-
return diagnostics;
|
|
94477
|
-
}
|
|
94478
|
-
function checkTrustBoundaries(model, view) {
|
|
94479
|
-
if (!view.boundaryLint && !view.crossZoneTechRecommended) return [];
|
|
94480
|
-
const diagnostics = [];
|
|
94481
|
-
const zoneOf2 = (id) => {
|
|
94482
|
-
for (let ancestor = model.index.get(id)?.parent; ancestor; ancestor = ancestor.parent)
|
|
94483
|
-
if (ancestor.kind === "trust-zone") return ancestor;
|
|
94484
|
-
return void 0;
|
|
94485
|
-
};
|
|
94486
|
-
const trustLevelOf = (id) => {
|
|
94487
|
-
const level = zoneOf2(id)?.attr?.value;
|
|
94488
|
-
return level && view.trustOrder?.[level] !== void 0 ? view.trustOrder[level] : -1;
|
|
94489
|
-
};
|
|
94490
|
-
const lint = view.boundaryLint;
|
|
94491
|
-
const isSecurityNode = (id) => lint !== void 0 && model.index.get(id)?.kind === lint.nodeKind;
|
|
94492
|
-
for (const flow of model.flows) {
|
|
94493
|
-
if (!model.index.has(flow.from) || !model.index.has(flow.to)) continue;
|
|
94494
|
-
const crossesZone = zoneOf2(flow.from) !== zoneOf2(flow.to);
|
|
94495
|
-
const boundaryViolation = lint !== void 0 && trustLevelOf(flow.to) > trustLevelOf(flow.from) && !isSecurityNode(flow.from) && !isSecurityNode(flow.to);
|
|
94496
|
-
if (boundaryViolation) {
|
|
94497
|
-
diagnostics.push({
|
|
94498
|
-
code: lint.code,
|
|
94499
|
-
severity: "warning",
|
|
94500
|
-
message: lint.message,
|
|
94501
|
-
span: flow.span,
|
|
94502
|
-
note: `flow enters a more-trusted zone without passing a \`${lint.nodeKind}\``,
|
|
94503
|
-
help: lint.help
|
|
94504
|
-
});
|
|
94505
|
-
}
|
|
94506
|
-
if (view.crossZoneTechRecommended && crossesZone && !flow.tech?.protocol) {
|
|
94507
|
-
diagnostics.push({
|
|
94508
|
-
code: view.crossZoneTechRecommended.code,
|
|
94509
|
-
severity: "warning",
|
|
94510
|
-
message: view.crossZoneTechRecommended.message,
|
|
94511
|
-
span: flow.span,
|
|
94512
|
-
note: "inter-zone flow \u2014 state how the traffic is protected",
|
|
94513
|
-
help: view.crossZoneTechRecommended.help
|
|
94514
|
-
});
|
|
94515
|
-
}
|
|
94516
|
-
}
|
|
94517
|
-
return diagnostics;
|
|
94518
|
-
}
|
|
94519
94601
|
function checkForbiddenBusinessObjects(model, view) {
|
|
94520
94602
|
const diagnostics = [];
|
|
94521
94603
|
for (const businessObject of model.businessObjects) {
|
|
@@ -94674,6 +94756,7 @@ var init_validator = __esm({
|
|
|
94674
94756
|
"use strict";
|
|
94675
94757
|
init_views();
|
|
94676
94758
|
init_element_tree();
|
|
94759
|
+
init_logos();
|
|
94677
94760
|
}
|
|
94678
94761
|
});
|
|
94679
94762
|
|
|
@@ -94780,13 +94863,15 @@ function wrapText(text, maxChars) {
|
|
|
94780
94863
|
if (currentLine) lines.push(currentLine);
|
|
94781
94864
|
return lines.join("\n");
|
|
94782
94865
|
}
|
|
94783
|
-
var DEFAULT_FONT_SIZE_NODE, FONT_SIZE_BASE, CHAR_WIDTH, fontSizes, measure, CHIP_HEIGHT, chipW, techText, flowLabelBox, nodeSize;
|
|
94866
|
+
var DEFAULT_FONT_SIZE_NODE, FONT_SIZE_BASE, CHAR_WIDTH, GLYPH_GUTTER, LOGO_GUTTER, fontSizes, measure, CHIP_HEIGHT, chipW, techText, flowLabelBox, nodeSize;
|
|
94784
94867
|
var init_text_metrics = __esm({
|
|
94785
94868
|
"src/text-metrics.ts"() {
|
|
94786
94869
|
"use strict";
|
|
94787
94870
|
DEFAULT_FONT_SIZE_NODE = 12.5;
|
|
94788
94871
|
FONT_SIZE_BASE = 12.5;
|
|
94789
94872
|
CHAR_WIDTH = 0.56;
|
|
94873
|
+
GLYPH_GUTTER = 26;
|
|
94874
|
+
LOGO_GUTTER = 30;
|
|
94790
94875
|
fontSizes = (base) => {
|
|
94791
94876
|
const scale = base / FONT_SIZE_BASE;
|
|
94792
94877
|
return {
|
|
@@ -94823,11 +94908,11 @@ var init_text_metrics = __esm({
|
|
|
94823
94908
|
height: measured.height + (tech ? 12 * scale : 0) + (chipNames.length ? CHIP_HEIGHT * scale : 0)
|
|
94824
94909
|
};
|
|
94825
94910
|
};
|
|
94826
|
-
nodeSize = (kind, label, fontSize = DEFAULT_FONT_SIZE_NODE) => {
|
|
94911
|
+
nodeSize = (kind, label, fontSize = DEFAULT_FONT_SIZE_NODE, gutter = 0) => {
|
|
94827
94912
|
const isActor = kind === "actor";
|
|
94828
94913
|
const measured = measure(label, isActor ? fontSize - 1.5 : fontSize);
|
|
94829
94914
|
return {
|
|
94830
|
-
width: isActor ? Math.max(64, measured.width + 8) : Math.max(140, measured.width + 16),
|
|
94915
|
+
width: isActor ? Math.max(64, measured.width + 8) : Math.max(140, measured.width + 16 + gutter),
|
|
94831
94916
|
height: isActor ? 56 + (label.split("\n").length - 1) * 11 : Math.max(46, measured.height + 18)
|
|
94832
94917
|
};
|
|
94833
94918
|
};
|
|
@@ -94835,12 +94920,13 @@ var init_text_metrics = __esm({
|
|
|
94835
94920
|
});
|
|
94836
94921
|
|
|
94837
94922
|
// src/slide-fold.ts
|
|
94838
|
-
function foldStyle(model) {
|
|
94923
|
+
function foldStyle(model, view) {
|
|
94839
94924
|
const businessObjectNames = new Map(model.businessObjects.map((bo) => [bo.id, bo.name]));
|
|
94840
94925
|
const numbered = model.style.flowText === "numbered";
|
|
94841
94926
|
const { edge, node, cont, scale } = fontSizes(model.style.font.size);
|
|
94842
94927
|
return {
|
|
94843
94928
|
numbered,
|
|
94929
|
+
glyphKinds: new Set(view.glyphKinds ?? []),
|
|
94844
94930
|
edge,
|
|
94845
94931
|
node,
|
|
94846
94932
|
cont,
|
|
@@ -94855,7 +94941,15 @@ function foldStyle(model) {
|
|
|
94855
94941
|
})
|
|
94856
94942
|
};
|
|
94857
94943
|
}
|
|
94858
|
-
function
|
|
94944
|
+
function leafSize(element, style) {
|
|
94945
|
+
return nodeSize(
|
|
94946
|
+
element.kind,
|
|
94947
|
+
element.label ?? element.id,
|
|
94948
|
+
style.node,
|
|
94949
|
+
style.glyphKinds.has(element.kind) ? GLYPH_GUTTER : 0
|
|
94950
|
+
);
|
|
94951
|
+
}
|
|
94952
|
+
function toElkNode(element, style) {
|
|
94859
94953
|
if (element.children.length) {
|
|
94860
94954
|
const lineCount = (element.label ?? element.id).split("\n").length;
|
|
94861
94955
|
return {
|
|
@@ -94866,13 +94960,13 @@ function toElkNode(element, containerFontSize, nodeFontSize) {
|
|
|
94866
94960
|
labels: [
|
|
94867
94961
|
{
|
|
94868
94962
|
text: element.label ?? element.id,
|
|
94869
|
-
...measure(element.label ?? element.id,
|
|
94963
|
+
...measure(element.label ?? element.id, style.cont)
|
|
94870
94964
|
}
|
|
94871
94965
|
],
|
|
94872
|
-
children: element.children.map((child) => toElkNode(child,
|
|
94966
|
+
children: element.children.map((child) => toElkNode(child, style))
|
|
94873
94967
|
};
|
|
94874
94968
|
}
|
|
94875
|
-
const size =
|
|
94969
|
+
const size = leafSize(element, style);
|
|
94876
94970
|
return { id: element.id, width: size.width, height: size.height };
|
|
94877
94971
|
}
|
|
94878
94972
|
function walkFoldedNodes(elkNode, offset, elementById, syntheticIds) {
|
|
@@ -94951,7 +95045,7 @@ function internalFlowLabels(flow, style) {
|
|
|
94951
95045
|
];
|
|
94952
95046
|
}
|
|
94953
95047
|
function buildGroupGraph(group, style, fg) {
|
|
94954
|
-
const node = toElkNode(group, style
|
|
95048
|
+
const node = toElkNode(group, style);
|
|
94955
95049
|
const nodeChildren = node.children ??= [];
|
|
94956
95050
|
for (const flow of fg.interFlows) {
|
|
94957
95051
|
if (fg.rootOf.get(flow.from) === group) {
|
|
@@ -95009,7 +95103,7 @@ function buildGroupGraph(group, style, fg) {
|
|
|
95009
95103
|
function layoutColumn(elements, style) {
|
|
95010
95104
|
return elements.map((group) => {
|
|
95011
95105
|
const blocks = group.children.map((child) => {
|
|
95012
|
-
const size =
|
|
95106
|
+
const size = leafSize(child, style);
|
|
95013
95107
|
return { element: child, width: size.width, height: size.height, x: 0, y: 0 };
|
|
95014
95108
|
});
|
|
95015
95109
|
const columnWidth = Math.max(
|
|
@@ -95047,7 +95141,7 @@ function layoutMiddleRows(middles, middleResults, geom, style) {
|
|
|
95047
95141
|
let yCursor = 16 + geom.gutterHeight(0);
|
|
95048
95142
|
middles.forEach((element, index) => {
|
|
95049
95143
|
const result = middleResults.get(element.id) ?? null;
|
|
95050
|
-
const size = result ? { width: result.children[0].width, height: result.children[0].height } :
|
|
95144
|
+
const size = result ? { width: result.children[0].width, height: result.children[0].height } : leafSize(element, style);
|
|
95051
95145
|
rows.push({
|
|
95052
95146
|
element,
|
|
95053
95147
|
box: { x: geom.xMiddle, y: yCursor, width: size.width, height: size.height },
|
|
@@ -95203,7 +95297,7 @@ function connectorLabel(flow, routed, style) {
|
|
|
95203
95297
|
}
|
|
95204
95298
|
async function foldedLayout(model, view, elk) {
|
|
95205
95299
|
const roots = model.elements;
|
|
95206
|
-
const style = foldStyle(model);
|
|
95300
|
+
const style = foldStyle(model, view);
|
|
95207
95301
|
const partitionOf = (element) => view.partitions[element.kind] ?? 1;
|
|
95208
95302
|
const sources = roots.filter((element) => partitionOf(element) === 0);
|
|
95209
95303
|
const middles = roots.filter((element) => partitionOf(element) === 1);
|
|
@@ -95250,7 +95344,7 @@ async function foldedLayout(model, view, elk) {
|
|
|
95250
95344
|
const widthSource = Math.max(0, ...sourceColumns.map((col) => col.width));
|
|
95251
95345
|
const widthMiddle = Math.max(
|
|
95252
95346
|
...middles.map(
|
|
95253
|
-
(element) => element.children.length ? middleResults.get(element.id).children[0].width :
|
|
95347
|
+
(element) => element.children.length ? middleResults.get(element.id).children[0].width : leafSize(element, style).width
|
|
95254
95348
|
)
|
|
95255
95349
|
);
|
|
95256
95350
|
const widthSink = Math.max(0, ...sinkColumns.map((col) => col.width));
|
|
@@ -96288,8 +96382,7 @@ function labelSeatable(blockers, pts, label) {
|
|
|
96288
96382
|
function scanLabelSeats(ctx, subj, profile) {
|
|
96289
96383
|
for (const label of subj.edge.labels) {
|
|
96290
96384
|
if (!label.width || !label.height) continue;
|
|
96291
|
-
if (!labelSeatable(ctx.blockers, subj.pts, label))
|
|
96292
|
-
profile.set(`unlabelled:${subj.edge.id}`, 1);
|
|
96385
|
+
if (!labelSeatable(ctx.blockers, subj.pts, label)) profile.set(`unlabelled:${subj.edge.id}`, 1);
|
|
96293
96386
|
}
|
|
96294
96387
|
}
|
|
96295
96388
|
function scanArrowRoom(subj, profile) {
|
|
@@ -96362,8 +96455,7 @@ function scanCrossings(a, b, key, profile) {
|
|
|
96362
96455
|
if (!end) continue;
|
|
96363
96456
|
const dx = Math.max(0, end.node.x - hit.x, hit.x - (end.node.x + end.node.width));
|
|
96364
96457
|
const dy = Math.max(0, end.node.y - hit.y, hit.y - (end.node.y + end.node.height));
|
|
96365
|
-
if (dx * dx + dy * dy <= FAN_REACH * FAN_REACH)
|
|
96366
|
-
profile.set(`fan:${key}@${end.node.id}`, 2);
|
|
96458
|
+
if (dx * dx + dy * dy <= FAN_REACH * FAN_REACH) profile.set(`fan:${key}@${end.node.id}`, 2);
|
|
96367
96459
|
}
|
|
96368
96460
|
}
|
|
96369
96461
|
}
|
|
@@ -96391,8 +96483,7 @@ function scanSharedSeats(a, b, key, profile) {
|
|
|
96391
96483
|
}
|
|
96392
96484
|
const side = vertical ? seatA.node.height : seatA.node.width;
|
|
96393
96485
|
const need = Math.min(12, (side - 6) / 2);
|
|
96394
|
-
if (apart < need * 0.8)
|
|
96395
|
-
profile.set(`tight:${key}@${seatA.node.id}|${seatA.side}`, 4);
|
|
96486
|
+
if (apart < need * 0.8) profile.set(`tight:${key}@${seatA.node.id}|${seatA.side}`, 4);
|
|
96396
96487
|
}
|
|
96397
96488
|
}
|
|
96398
96489
|
function scanPairs(ctx, subj, query) {
|
|
@@ -96407,7 +96498,11 @@ function scanPairs(ctx, subj, query) {
|
|
|
96407
96498
|
if (ids.has(other.id) && other.id < subj.edge.id) continue;
|
|
96408
96499
|
const overridden = overrides.has(other.id);
|
|
96409
96500
|
if (farApart(myBounds, ctx.boundsFor(other, theirs, overridden))) continue;
|
|
96410
|
-
const them = {
|
|
96501
|
+
const them = {
|
|
96502
|
+
edge: other,
|
|
96503
|
+
pts: theirs,
|
|
96504
|
+
ends: ctx.endsFor(other, theirs, overridden)
|
|
96505
|
+
};
|
|
96411
96506
|
const key = pair(subj.edge.id, other.id);
|
|
96412
96507
|
scanCrossings(subj, them, key, profile);
|
|
96413
96508
|
scanParallelRuns(mine, ctx.runsFor(other, theirs, overridden), key, profile);
|
|
@@ -99233,7 +99328,8 @@ function computeIngressExternalElements(model) {
|
|
|
99233
99328
|
}
|
|
99234
99329
|
return ingressExternalElements;
|
|
99235
99330
|
}
|
|
99236
|
-
function toElkNode2(element,
|
|
99331
|
+
function toElkNode2(element, sizing, root = false) {
|
|
99332
|
+
const { compact, fonts, glyphKinds } = sizing;
|
|
99237
99333
|
const { cont: containerFontSize, node: nodeFontSize } = fonts;
|
|
99238
99334
|
if (element.children.length) {
|
|
99239
99335
|
const lineCount = (element.label ?? element.id).split("\n").length;
|
|
@@ -99250,17 +99346,16 @@ function toElkNode2(element, compact, fonts, root = false) {
|
|
|
99250
99346
|
...measure(element.label ?? element.id, containerFontSize)
|
|
99251
99347
|
}
|
|
99252
99348
|
],
|
|
99253
|
-
children: element.children.map(
|
|
99254
|
-
(child) => toElkNode2(child, compact, fonts)
|
|
99255
|
-
)
|
|
99349
|
+
children: element.children.map((child) => toElkNode2(child, sizing))
|
|
99256
99350
|
};
|
|
99257
99351
|
}
|
|
99258
99352
|
const measured = measure(element.label ?? element.id, nodeFontSize);
|
|
99259
99353
|
const isActor = element.kind === "actor";
|
|
99354
|
+
const gutter = (glyphKinds.has(element.kind) ? GLYPH_GUTTER : 0) + (element.logo ? LOGO_GUTTER : 0);
|
|
99260
99355
|
return {
|
|
99261
99356
|
id: element.id,
|
|
99262
99357
|
...element.order && !root ? { layoutOptions: orderOption(element) } : {},
|
|
99263
|
-
width: isActor ? Math.max(64, measure(element.label ?? element.id, nodeFontSize - 1.5).width + 8) : Math.max(compact ? 98 : 108, measured.width + (compact ? 10 : 12)),
|
|
99358
|
+
width: isActor ? Math.max(64, measure(element.label ?? element.id, nodeFontSize - 1.5).width + 8) : Math.max(compact ? 98 : 108, measured.width + (compact ? 10 : 12) + gutter),
|
|
99264
99359
|
height: isActor ? 54 + ((element.label ?? element.id).split("\n").length - 1) * 11 : Math.max(compact ? 36 : 38, measured.height + (compact ? 10 : 12))
|
|
99265
99360
|
};
|
|
99266
99361
|
}
|
|
@@ -99418,20 +99513,20 @@ function selectionExtras(scene, model) {
|
|
|
99418
99513
|
}
|
|
99419
99514
|
return extra;
|
|
99420
99515
|
}
|
|
99421
|
-
function
|
|
99516
|
+
function tallyProfile(profile) {
|
|
99422
99517
|
const normalize = (key) => key.replace(/@[-\d.,]+$/, "").replace(/:\d+(?=@|$)/, "");
|
|
99423
|
-
const
|
|
99424
|
-
|
|
99425
|
-
|
|
99426
|
-
|
|
99427
|
-
|
|
99428
|
-
|
|
99429
|
-
|
|
99430
|
-
|
|
99431
|
-
|
|
99432
|
-
|
|
99433
|
-
const was =
|
|
99434
|
-
const now =
|
|
99518
|
+
const out = /* @__PURE__ */ new Map();
|
|
99519
|
+
for (const [key, tier] of profile) {
|
|
99520
|
+
const id = normalize(key);
|
|
99521
|
+
const entry = out.get(id) ?? { tier, count: 0 };
|
|
99522
|
+
entry.count++;
|
|
99523
|
+
out.set(id, entry);
|
|
99524
|
+
}
|
|
99525
|
+
return out;
|
|
99526
|
+
}
|
|
99527
|
+
function relayoutVerdict(before, after) {
|
|
99528
|
+
const was = tallyProfile(before);
|
|
99529
|
+
const now = tallyProfile(after);
|
|
99435
99530
|
for (let tier = 0; tier < 5; tier++) {
|
|
99436
99531
|
let gained = false;
|
|
99437
99532
|
let lost = false;
|
|
@@ -99447,6 +99542,62 @@ function relayoutVerdict(before, after) {
|
|
|
99447
99542
|
}
|
|
99448
99543
|
return -1;
|
|
99449
99544
|
}
|
|
99545
|
+
function noLadderRegression(before, after) {
|
|
99546
|
+
const perTier = (profile) => {
|
|
99547
|
+
const totals = [0, 0, 0, 0, 0];
|
|
99548
|
+
for (const { tier, count } of tallyProfile(profile).values()) totals[tier] += count;
|
|
99549
|
+
return totals;
|
|
99550
|
+
};
|
|
99551
|
+
const was = perTier(before);
|
|
99552
|
+
const now = perTier(after);
|
|
99553
|
+
return now.every((count, tier) => count <= was[tier]);
|
|
99554
|
+
}
|
|
99555
|
+
function nodeCoverage(scene) {
|
|
99556
|
+
if (!scene.nodes.length) return 1;
|
|
99557
|
+
const left = Math.min(...scene.nodes.map((n) => n.x));
|
|
99558
|
+
const top = Math.min(...scene.nodes.map((n) => n.y));
|
|
99559
|
+
const right = Math.max(...scene.nodes.map((n) => n.x + n.width));
|
|
99560
|
+
const bottom = Math.max(...scene.nodes.map((n) => n.y + n.height));
|
|
99561
|
+
const width = right - left;
|
|
99562
|
+
const height = bottom - top;
|
|
99563
|
+
if (width <= 0 || height <= 0) return 1;
|
|
99564
|
+
const COLUMNS = 32;
|
|
99565
|
+
const ROWS = 16;
|
|
99566
|
+
let covered = 0;
|
|
99567
|
+
for (let row = 0; row < ROWS; row++) {
|
|
99568
|
+
for (let column = 0; column < COLUMNS; column++) {
|
|
99569
|
+
const cellLeft = left + column * width / COLUMNS;
|
|
99570
|
+
const cellRight = left + (column + 1) * width / COLUMNS;
|
|
99571
|
+
const cellTop = top + row * height / ROWS;
|
|
99572
|
+
const cellBottom = top + (row + 1) * height / ROWS;
|
|
99573
|
+
if (scene.nodes.some(
|
|
99574
|
+
(n) => n.x < cellRight && n.x + n.width > cellLeft && n.y < cellBottom && n.y + n.height > cellTop
|
|
99575
|
+
))
|
|
99576
|
+
covered++;
|
|
99577
|
+
}
|
|
99578
|
+
}
|
|
99579
|
+
return covered / (COLUMNS * ROWS);
|
|
99580
|
+
}
|
|
99581
|
+
async function denserLayout(base, elkPass) {
|
|
99582
|
+
const densitySpecs = [
|
|
99583
|
+
{ minLayers: true, dense: true },
|
|
99584
|
+
{ placement: "LINEAR_SEGMENTS", dense: true }
|
|
99585
|
+
];
|
|
99586
|
+
const laidOut = await Promise.allSettled(densitySpecs.map((spec) => elkPass.layout(spec)));
|
|
99587
|
+
const areaOf = (scene) => scene.width * scene.height;
|
|
99588
|
+
const baseProfile = elkPass.profile(base);
|
|
99589
|
+
let bestArea = areaOf(base) * DENSITY_GAIN;
|
|
99590
|
+
let winner = null;
|
|
99591
|
+
for (const [index, settled] of laidOut.entries()) {
|
|
99592
|
+
if (settled.status !== "fulfilled") continue;
|
|
99593
|
+
const candidate = elkPass.toScene(settled.value);
|
|
99594
|
+
if (areaOf(candidate) > bestArea) continue;
|
|
99595
|
+
if (!noLadderRegression(baseProfile, elkPass.profile(candidate))) continue;
|
|
99596
|
+
bestArea = areaOf(candidate);
|
|
99597
|
+
winner = { scene: candidate, options: densitySpecs[index] };
|
|
99598
|
+
}
|
|
99599
|
+
return winner;
|
|
99600
|
+
}
|
|
99450
99601
|
function sideToward(from, to) {
|
|
99451
99602
|
const dx = centerOf(to).x - centerOf(from).x;
|
|
99452
99603
|
const dy = centerOf(to).y - centerOf(from).y;
|
|
@@ -99509,7 +99660,8 @@ function constrainPorts(graph, scene, flagged, model) {
|
|
|
99509
99660
|
}
|
|
99510
99661
|
function elkPartitionOf(element, index, view, ingressExternal) {
|
|
99511
99662
|
if (!view.partitionByOrder) return view.partitions[element.kind] ?? 1;
|
|
99512
|
-
if (
|
|
99663
|
+
if ((view.ingressKinds ?? DEFAULT_INGRESS_KINDS).includes(element.kind))
|
|
99664
|
+
return INGRESS_PARTITION;
|
|
99513
99665
|
if (element.kind === "external")
|
|
99514
99666
|
return ingressExternal.has(element.id) ? INGRESS_PARTITION : EGRESS_PARTITION;
|
|
99515
99667
|
if (view.partitions[element.kind] !== void 0) return 90 + view.partitions[element.kind];
|
|
@@ -99533,16 +99685,13 @@ function readingSlots(model, view, ingressExternal) {
|
|
|
99533
99685
|
const lowestOf = /* @__PURE__ */ new Map();
|
|
99534
99686
|
for (const band of new Set(bandOf.values())) {
|
|
99535
99687
|
const members = model.elements.filter((element) => bandOf.get(element.id) === band);
|
|
99536
|
-
const declared = [
|
|
99537
|
-
|
|
99538
|
-
|
|
99688
|
+
const declared = [...new Set(members.filter((m) => m.order).map((m) => m.order.value))].sort(
|
|
99689
|
+
(a, b) => a - b
|
|
99690
|
+
);
|
|
99539
99691
|
const lowest = declared.length ? 1 : 0;
|
|
99540
99692
|
lowestOf.set(band, lowest);
|
|
99541
99693
|
for (const member of members)
|
|
99542
|
-
slotOf.set(
|
|
99543
|
-
member.id,
|
|
99544
|
-
member.order ? declared.indexOf(member.order.value) + 1 : lowest
|
|
99545
|
-
);
|
|
99694
|
+
slotOf.set(member.id, member.order ? declared.indexOf(member.order.value) + 1 : lowest);
|
|
99546
99695
|
}
|
|
99547
99696
|
const ordered = new Set(model.elements.filter((element) => element.order).map((e) => e.id));
|
|
99548
99697
|
for (let pass = 0; pass < model.elements.length; pass++) {
|
|
@@ -99672,6 +99821,7 @@ function attachSideDiagnostics(scene, model) {
|
|
|
99672
99821
|
}
|
|
99673
99822
|
function buildElkGraph(ctx, direction, options) {
|
|
99674
99823
|
const { model, view, ingressExternal, slotOf, compact, numbered, fonts } = ctx;
|
|
99824
|
+
const glyphKinds = new Set(view.glyphKinds ?? []);
|
|
99675
99825
|
const graph = {
|
|
99676
99826
|
id: "root",
|
|
99677
99827
|
layoutOptions: {
|
|
@@ -99707,19 +99857,28 @@ function buildElkGraph(ctx, direction, options) {
|
|
|
99707
99857
|
"elk.spacing.edgeNode": "18",
|
|
99708
99858
|
"elk.layered.thoroughness": "80",
|
|
99709
99859
|
"elk.layered.nodePlacement.favorStraightEdges": "true"
|
|
99710
|
-
} : {}
|
|
99860
|
+
} : {},
|
|
99861
|
+
// Spread last, after every spacing default above, because overriding them
|
|
99862
|
+
// is the whole point — a density candidate that lands before them is
|
|
99863
|
+
// silently shadowed and lays out exactly like the layout it was meant to
|
|
99864
|
+
// beat.
|
|
99865
|
+
...options?.dense ? {
|
|
99866
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": "14",
|
|
99867
|
+
"elk.spacing.nodeNode": "10",
|
|
99868
|
+
"elk.spacing.edgeEdge": "8",
|
|
99869
|
+
"elk.spacing.edgeNode": "9"
|
|
99870
|
+
} : {},
|
|
99871
|
+
...options?.placement ? { "elk.layered.nodePlacement.strategy": options.placement } : {}
|
|
99711
99872
|
},
|
|
99712
99873
|
children: model.elements.map((element, index) => {
|
|
99713
|
-
const elkNode = toElkNode2(element, compact, fonts, true);
|
|
99874
|
+
const elkNode = toElkNode2(element, { compact, fonts, glyphKinds }, true);
|
|
99714
99875
|
const band = elkPartitionOf(element, index, view, ingressExternal);
|
|
99715
99876
|
const slot = slotOf.get(element.id);
|
|
99716
99877
|
elkNode.layoutOptions = {
|
|
99717
99878
|
...elkNode.layoutOptions,
|
|
99718
99879
|
// Without an `order:` anywhere the band is emitted as it always was, so
|
|
99719
99880
|
// the drawing is byte-identical to one from before the hint existed.
|
|
99720
|
-
"elk.partitioning.partition": String(
|
|
99721
|
-
slot === void 0 ? band : band * SLOT_SCALE + slot
|
|
99722
|
-
)
|
|
99881
|
+
"elk.partitioning.partition": String(slot === void 0 ? band : band * SLOT_SCALE + slot)
|
|
99723
99882
|
};
|
|
99724
99883
|
return elkNode;
|
|
99725
99884
|
}),
|
|
@@ -99738,8 +99897,123 @@ function recordRepairs(scene, routesBefore) {
|
|
|
99738
99897
|
if (moved) edge.repairedFrom = original;
|
|
99739
99898
|
}
|
|
99740
99899
|
}
|
|
99900
|
+
function segmentsCross2(a1, a2, b1, b2) {
|
|
99901
|
+
const aH = Math.abs(a1.y - a2.y) < 0.5;
|
|
99902
|
+
const bH = Math.abs(b1.y - b2.y) < 0.5;
|
|
99903
|
+
if (aH === bH) return false;
|
|
99904
|
+
const [h1, h2, v1, v2] = aH ? [a1, a2, b1, b2] : [b1, b2, a1, a2];
|
|
99905
|
+
const hy = h1.y;
|
|
99906
|
+
const vx = v1.x;
|
|
99907
|
+
return vx > Math.min(h1.x, h2.x) + 0.5 && vx < Math.max(h1.x, h2.x) - 0.5 && hy > Math.min(v1.y, v2.y) + 0.5 && hy < Math.max(v1.y, v2.y) - 0.5;
|
|
99908
|
+
}
|
|
99909
|
+
function shortJogs(edges) {
|
|
99910
|
+
let total = 0;
|
|
99911
|
+
for (const edge of edges)
|
|
99912
|
+
for (let i = 1; i + 2 < edge.pts.length; i++) {
|
|
99913
|
+
const run = Math.abs(edge.pts[i + 1].x - edge.pts[i].x) + Math.abs(edge.pts[i + 1].y - edge.pts[i].y);
|
|
99914
|
+
if (run > 0 && run <= 20) total++;
|
|
99915
|
+
}
|
|
99916
|
+
return total;
|
|
99917
|
+
}
|
|
99918
|
+
function crossingsAround(scene, subject) {
|
|
99919
|
+
let total = 0;
|
|
99920
|
+
const subjectIds = new Set(subject.map((edge) => edge.id));
|
|
99921
|
+
for (const edge of subject)
|
|
99922
|
+
for (const other of scene.edges) {
|
|
99923
|
+
if (other.id === edge.id) continue;
|
|
99924
|
+
if (subjectIds.has(other.id) && other.id < edge.id) continue;
|
|
99925
|
+
for (let i = 1; i < edge.pts.length; i++)
|
|
99926
|
+
for (let j = 1; j < other.pts.length; j++)
|
|
99927
|
+
if (segmentsCross2(edge.pts[i - 1], edge.pts[i], other.pts[j - 1], other.pts[j])) total++;
|
|
99928
|
+
}
|
|
99929
|
+
return total;
|
|
99930
|
+
}
|
|
99931
|
+
function leafBoxesOf(scene) {
|
|
99932
|
+
return scene.nodes.filter((node) => !node.container);
|
|
99933
|
+
}
|
|
99934
|
+
function crossesLeaf(edge, leaves, attached) {
|
|
99935
|
+
for (let i = 1; i < edge.pts.length; i++) {
|
|
99936
|
+
const a = edge.pts[i - 1];
|
|
99937
|
+
const b = edge.pts[i];
|
|
99938
|
+
const horizontal = Math.abs(a.y - b.y) < 0.5;
|
|
99939
|
+
const vertical = Math.abs(a.x - b.x) < 0.5;
|
|
99940
|
+
if (!horizontal && !vertical) continue;
|
|
99941
|
+
const at = horizontal ? a.y : a.x;
|
|
99942
|
+
const lo = horizontal ? Math.min(a.x, b.x) : Math.min(a.y, b.y);
|
|
99943
|
+
const hi = horizontal ? Math.max(a.x, b.x) : Math.max(a.y, b.y);
|
|
99944
|
+
for (const node of leaves) {
|
|
99945
|
+
if (attached.has(node.id)) continue;
|
|
99946
|
+
const struck = horizontal ? at > node.y + 1 && at < node.y + node.height - 1 && lo < node.x + node.width - 1 && hi > node.x + 1 : at > node.x + 1 && at < node.x + node.width - 1 && lo < node.y + node.height - 1 && hi > node.y + 1;
|
|
99947
|
+
if (struck) return true;
|
|
99948
|
+
}
|
|
99949
|
+
}
|
|
99950
|
+
return false;
|
|
99951
|
+
}
|
|
99952
|
+
function snapLanes(scene, laneOf, axis) {
|
|
99953
|
+
if (!laneOf.size) return;
|
|
99954
|
+
const leaves = leafBoxesOf(scene);
|
|
99955
|
+
const tilted = (edges) => edges.reduce(
|
|
99956
|
+
(total, edge) => total + edge.pts.filter((point, i) => i > 0 && Math.abs(point.x - edge.pts[i - 1].x) >= 0.5 && Math.abs(point.y - edge.pts[i - 1].y) >= 0.5).length,
|
|
99957
|
+
0
|
|
99958
|
+
);
|
|
99959
|
+
const touching = /* @__PURE__ */ new Map();
|
|
99960
|
+
const attachedTo = /* @__PURE__ */ new Map();
|
|
99961
|
+
for (const edge of scene.edges) {
|
|
99962
|
+
const ends = /* @__PURE__ */ new Set();
|
|
99963
|
+
for (const point of [edge.pts[0], edge.pts[edge.pts.length - 1]]) {
|
|
99964
|
+
if (!point) continue;
|
|
99965
|
+
for (const node of scene.nodes)
|
|
99966
|
+
if (point.x >= node.x - 1 && point.x <= node.x + node.width + 1 && point.y >= node.y - 1 && point.y <= node.y + node.height + 1) {
|
|
99967
|
+
ends.add(node.id);
|
|
99968
|
+
if (!touching.has(node.id)) touching.set(node.id, []);
|
|
99969
|
+
touching.get(node.id).push(edge);
|
|
99970
|
+
}
|
|
99971
|
+
}
|
|
99972
|
+
attachedTo.set(edge.id, ends);
|
|
99973
|
+
}
|
|
99974
|
+
const byLane = /* @__PURE__ */ new Map();
|
|
99975
|
+
for (const node of scene.nodes) {
|
|
99976
|
+
const lane = laneOf.get(node.id);
|
|
99977
|
+
if (lane === void 0) continue;
|
|
99978
|
+
if (!byLane.has(lane)) byLane.set(lane, []);
|
|
99979
|
+
byLane.get(lane).push(node);
|
|
99980
|
+
}
|
|
99981
|
+
for (const members of [...byLane.entries()].sort((a, b) => a[0] - b[0]).map((e) => e[1])) {
|
|
99982
|
+
if (members.length < 2) continue;
|
|
99983
|
+
const target = Math.max(...members.map((node) => node[axis]));
|
|
99984
|
+
for (const node of members) {
|
|
99985
|
+
const delta = target - node[axis];
|
|
99986
|
+
if (!delta) continue;
|
|
99987
|
+
const box = { x: node.x, y: node.y, w: node.width, h: node.height };
|
|
99988
|
+
const edges = touching.get(node.id) ?? [];
|
|
99989
|
+
const before = edges.map((edge) => edge.pts.map((point) => ({ ...point })));
|
|
99990
|
+
const crossingsBefore = crossingsAround(scene, edges);
|
|
99991
|
+
const jogsBefore = shortJogs(edges);
|
|
99992
|
+
const tiltsBefore = tilted(edges);
|
|
99993
|
+
node[axis] = target;
|
|
99994
|
+
for (const edge of edges)
|
|
99995
|
+
for (const point of edge.pts)
|
|
99996
|
+
if (point.x >= box.x - 1 && point.x <= box.x + box.w + 1 && point.y >= box.y - 1 && point.y <= box.y + box.h + 1)
|
|
99997
|
+
point[axis] += delta;
|
|
99998
|
+
const broke = crossingsAround(scene, edges) > crossingsBefore || shortJogs(edges) > jogsBefore || tilted(edges) > tiltsBefore || edges.some((edge) => crossesLeaf(edge, leaves, attachedTo.get(edge.id) ?? /* @__PURE__ */ new Set())) || // Containers included: a lane member is top-level, so it has no
|
|
99999
|
+
// legitimate container ancestor and may not land on one.
|
|
100000
|
+
scene.nodes.some((other) => other !== node && !node.container && other.x < node.x + node.width && node.x < other.x + other.width && other.y < node.y + node.height && node.y < other.y + other.height);
|
|
100001
|
+
if (broke) {
|
|
100002
|
+
node[axis] = target - delta;
|
|
100003
|
+
edges.forEach((edge, i) => {
|
|
100004
|
+
edge.pts = before[i];
|
|
100005
|
+
});
|
|
100006
|
+
}
|
|
100007
|
+
}
|
|
100008
|
+
}
|
|
100009
|
+
const maxX = Math.max(...scene.nodes.map((node) => node.x + node.width));
|
|
100010
|
+
const maxY = Math.max(...scene.nodes.map((node) => node.y + node.height));
|
|
100011
|
+
scene.width = Math.max(scene.width, Math.ceil(maxX) + 10);
|
|
100012
|
+
scene.height = Math.max(scene.height, Math.ceil(maxY) + 10);
|
|
100013
|
+
}
|
|
99741
100014
|
function runGeometryPasses(scene, model, options) {
|
|
99742
100015
|
const { numbered, sideways } = options;
|
|
100016
|
+
if (options.laneOf) snapLanes(scene, options.laneOf, sideways ? "y" : "x");
|
|
99743
100017
|
const titleBoxes = titleBoxesOf(scene, model);
|
|
99744
100018
|
if (sideways) transpose(scene, titleBoxes);
|
|
99745
100019
|
rerouteDetours(scene, model, numbered, titleBoxes);
|
|
@@ -99759,6 +100033,62 @@ function runGeometryPasses(scene, model, options) {
|
|
|
99759
100033
|
anchorFlowLabels(scene, settledTitles);
|
|
99760
100034
|
swapCrossingSiblingSeats(scene);
|
|
99761
100035
|
}
|
|
100036
|
+
function laneAssignment(model, view) {
|
|
100037
|
+
const laneOf = /* @__PURE__ */ new Map();
|
|
100038
|
+
const laneKinds = new Set(view.laneKinds ?? []);
|
|
100039
|
+
if (!laneKinds.size || model.style.compact) return laneOf;
|
|
100040
|
+
const rootOf = /* @__PURE__ */ new Map();
|
|
100041
|
+
const walk = (element, root) => {
|
|
100042
|
+
rootOf.set(element.id, root);
|
|
100043
|
+
for (const child of element.children ?? []) walk(child, root);
|
|
100044
|
+
};
|
|
100045
|
+
for (const element of model.elements) walk(element, element.id);
|
|
100046
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
100047
|
+
for (const flow of model.flows) {
|
|
100048
|
+
const from = rootOf.get(flow.from);
|
|
100049
|
+
const to = rootOf.get(flow.to);
|
|
100050
|
+
if (!from || !to || from === to) continue;
|
|
100051
|
+
if (!adjacency.has(from)) adjacency.set(from, /* @__PURE__ */ new Set());
|
|
100052
|
+
adjacency.get(from).add(to);
|
|
100053
|
+
}
|
|
100054
|
+
const reaches = (from, to) => {
|
|
100055
|
+
const seen = /* @__PURE__ */ new Set([from]);
|
|
100056
|
+
const queue = [from];
|
|
100057
|
+
while (queue.length) {
|
|
100058
|
+
for (const next of adjacency.get(queue.pop()) ?? []) {
|
|
100059
|
+
if (next === to) return true;
|
|
100060
|
+
if (!seen.has(next)) {
|
|
100061
|
+
seen.add(next);
|
|
100062
|
+
queue.push(next);
|
|
100063
|
+
}
|
|
100064
|
+
}
|
|
100065
|
+
}
|
|
100066
|
+
return false;
|
|
100067
|
+
};
|
|
100068
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
100069
|
+
for (const element of model.elements) {
|
|
100070
|
+
if (!laneKinds.has(element.kind)) continue;
|
|
100071
|
+
if ((element.children ?? []).length) continue;
|
|
100072
|
+
if (!byKind.has(element.kind)) byKind.set(element.kind, []);
|
|
100073
|
+
byKind.get(element.kind).push(element);
|
|
100074
|
+
}
|
|
100075
|
+
const pinned = /* @__PURE__ */ new Set();
|
|
100076
|
+
for (const flow of model.flows) {
|
|
100077
|
+
if (!flow.fromSide && !flow.toSide) continue;
|
|
100078
|
+
pinned.add(rootOf.get(flow.from) ?? flow.from);
|
|
100079
|
+
pinned.add(rootOf.get(flow.to) ?? flow.to);
|
|
100080
|
+
}
|
|
100081
|
+
let laneId = 0;
|
|
100082
|
+
for (const members of byKind.values()) {
|
|
100083
|
+
if (members.length < 2) continue;
|
|
100084
|
+
if (members.some((member) => pinned.has(member.id))) continue;
|
|
100085
|
+
if (members.some((member) => member.order)) continue;
|
|
100086
|
+
if (members.some((a) => members.some((b) => a !== b && reaches(a.id, b.id)))) continue;
|
|
100087
|
+
laneId++;
|
|
100088
|
+
for (const member of members) laneOf.set(member.id, laneId);
|
|
100089
|
+
}
|
|
100090
|
+
return laneOf;
|
|
100091
|
+
}
|
|
99762
100092
|
async function layout(model, view) {
|
|
99763
100093
|
const elk = await getElk();
|
|
99764
100094
|
const businessObjectName = new Map(model.businessObjects.map((bo) => [bo.id, bo.name]));
|
|
@@ -99771,10 +100101,6 @@ async function layout(model, view) {
|
|
|
99771
100101
|
scale: fontScale
|
|
99772
100102
|
} = fontSizes(model.style.font.size);
|
|
99773
100103
|
const disposition = model.style.disposition;
|
|
99774
|
-
const ASPECT_TARGETS = {
|
|
99775
|
-
slide: 16 / 9,
|
|
99776
|
-
page: 0.71
|
|
99777
|
-
};
|
|
99778
100104
|
const aspectTarget = ASPECT_TARGETS[disposition];
|
|
99779
100105
|
const ingressExternalElements = view.partitionByOrder ? computeIngressExternalElements(model) : /* @__PURE__ */ new Set();
|
|
99780
100106
|
const graphContext = {
|
|
@@ -99794,7 +100120,7 @@ async function layout(model, view) {
|
|
|
99794
100120
|
};
|
|
99795
100121
|
const makeGraph = (direction, options) => buildElkGraph(graphContext, direction, options);
|
|
99796
100122
|
const kindOf = new Map(indexElementsById(model.elements));
|
|
99797
|
-
const sceneFromResult = (result2, layoutMs2) => {
|
|
100123
|
+
const sceneFromResult = (result2, layoutMs2, lanes = true) => {
|
|
99798
100124
|
const origins = {
|
|
99799
100125
|
root: { x: 0, y: 0 }
|
|
99800
100126
|
};
|
|
@@ -99818,10 +100144,12 @@ async function layout(model, view) {
|
|
|
99818
100144
|
};
|
|
99819
100145
|
runGeometryPasses(scene, model, {
|
|
99820
100146
|
numbered,
|
|
99821
|
-
sideways: disposition === "page" || disposition === "tall"
|
|
100147
|
+
sideways: disposition === "page" || disposition === "tall",
|
|
100148
|
+
laneOf: lanes ? laneOf : void 0
|
|
99822
100149
|
});
|
|
99823
100150
|
return scene;
|
|
99824
100151
|
};
|
|
100152
|
+
const laneOf = laneAssignment(model, view);
|
|
99825
100153
|
const startTime = Date.now();
|
|
99826
100154
|
let result;
|
|
99827
100155
|
let winnerDirection;
|
|
@@ -99866,16 +100194,27 @@ async function layout(model, view) {
|
|
|
99866
100194
|
result = await elk.layout(makeGraph(winnerDirection));
|
|
99867
100195
|
}
|
|
99868
100196
|
const layoutMs = Date.now() - startTime;
|
|
99869
|
-
|
|
99870
|
-
const skipPortPass = !!globalThis.process?.env?.CAIRN_NO_PORT_PASS;
|
|
99871
|
-
if (skipPortPass) return base;
|
|
100197
|
+
let base = sceneFromResult(result, layoutMs);
|
|
99872
100198
|
const layoutProfile = (candidate) => {
|
|
99873
100199
|
const everyEdge = new Set(candidate.edges.map((edge) => edge.id));
|
|
99874
100200
|
const profile = inspect(candidate, titleBoxesOf(candidate, model)).local(everyEdge, /* @__PURE__ */ new Map());
|
|
99875
100201
|
for (const [key, tier] of selectionExtras(candidate, model)) profile.set(key, tier);
|
|
99876
100202
|
return profile;
|
|
99877
100203
|
};
|
|
100204
|
+
if (!aspectTarget && nodeCoverage(base) < DENSE_ENOUGH) {
|
|
100205
|
+
const denser = await denserLayout(base, {
|
|
100206
|
+
layout: (spec) => elk.layout(makeGraph(winnerDirection, spec)),
|
|
100207
|
+
toScene: (laidOut) => sceneFromResult(laidOut, Date.now() - startTime),
|
|
100208
|
+
profile: layoutProfile
|
|
100209
|
+
});
|
|
100210
|
+
if (denser) {
|
|
100211
|
+
base = denser.scene;
|
|
100212
|
+
winnerOptions = denser.options;
|
|
100213
|
+
}
|
|
100214
|
+
}
|
|
99878
100215
|
const baseProfile = layoutProfile(base);
|
|
100216
|
+
const skipPortPass = !!globalThis.process?.env?.CAIRN_NO_PORT_PASS;
|
|
100217
|
+
if (skipPortPass) return base;
|
|
99879
100218
|
let current = base;
|
|
99880
100219
|
let best = null;
|
|
99881
100220
|
for (let round = 0; round < PORT_PASS_ROUNDS; round++) {
|
|
@@ -99898,7 +100237,7 @@ async function layout(model, view) {
|
|
|
99898
100237
|
}
|
|
99899
100238
|
return best?.scene ?? base;
|
|
99900
100239
|
}
|
|
99901
|
-
var orderOption, semiInteractiveOption, PORT_PASS_ROUNDS, centerOf, INGRESS_PARTITION, EGRESS_PARTITION, COMPACT_WRAP, SLOT_SCALE, SIDE_TO_ELK;
|
|
100240
|
+
var orderOption, semiInteractiveOption, PORT_PASS_ROUNDS, centerOf, DENSE_ENOUGH, DENSITY_GAIN, INGRESS_PARTITION, DEFAULT_INGRESS_KINDS, EGRESS_PARTITION, COMPACT_WRAP, SLOT_SCALE, SIDE_TO_ELK, ASPECT_TARGETS;
|
|
99902
100241
|
var init_scene_layout = __esm({
|
|
99903
100242
|
"src/scene-layout.ts"() {
|
|
99904
100243
|
"use strict";
|
|
@@ -99916,7 +100255,10 @@ var init_scene_layout = __esm({
|
|
|
99916
100255
|
semiInteractiveOption = (children) => children.some((child) => child.order) ? { "elk.layered.crossingMinimization.semiInteractive": "true" } : {};
|
|
99917
100256
|
PORT_PASS_ROUNDS = 2;
|
|
99918
100257
|
centerOf = (n) => ({ x: n.x + n.width / 2, y: n.y + n.height / 2 });
|
|
100258
|
+
DENSE_ENOUGH = 0.6;
|
|
100259
|
+
DENSITY_GAIN = 0.95;
|
|
99919
100260
|
INGRESS_PARTITION = -1;
|
|
100261
|
+
DEFAULT_INGRESS_KINDS = ["actor", "actor-group"];
|
|
99920
100262
|
EGRESS_PARTITION = 900;
|
|
99921
100263
|
COMPACT_WRAP = 10;
|
|
99922
100264
|
SLOT_SCALE = 1e3;
|
|
@@ -99926,6 +100268,10 @@ var init_scene_layout = __esm({
|
|
|
99926
100268
|
top: "NORTH",
|
|
99927
100269
|
bottom: "SOUTH"
|
|
99928
100270
|
};
|
|
100271
|
+
ASPECT_TARGETS = {
|
|
100272
|
+
slide: 16 / 9,
|
|
100273
|
+
page: 0.71
|
|
100274
|
+
};
|
|
99929
100275
|
}
|
|
99930
100276
|
});
|
|
99931
100277
|
|
|
@@ -99976,12 +100322,45 @@ var init_localization = __esm({
|
|
|
99976
100322
|
});
|
|
99977
100323
|
|
|
99978
100324
|
// src/xml-escape.ts
|
|
99979
|
-
var esc, escAttr;
|
|
100325
|
+
var esc, escAttr, escComment;
|
|
99980
100326
|
var init_xml_escape = __esm({
|
|
99981
100327
|
"src/xml-escape.ts"() {
|
|
99982
100328
|
"use strict";
|
|
99983
100329
|
esc = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
99984
100330
|
escAttr = (text) => esc(text).replace(/"/g, """);
|
|
100331
|
+
escComment = (text) => text.replace(/-{2,}/g, (run) => [...run].join(" ")).replace(/-$/, "- ");
|
|
100332
|
+
}
|
|
100333
|
+
});
|
|
100334
|
+
|
|
100335
|
+
// src/logo-attribution.ts
|
|
100336
|
+
function logoAttributionComment(drawn) {
|
|
100337
|
+
const licensed = [...drawn].sort().map((slug) => ({ slug, logo: LOGOS[slug] })).filter((entry) => entry.logo?.license);
|
|
100338
|
+
if (licensed.length === 0) return "";
|
|
100339
|
+
const lines = [...PREAMBLE];
|
|
100340
|
+
for (const { slug, logo } of licensed) {
|
|
100341
|
+
lines.push("", `${logo.title} (${slug}) \u2014 ${logo.license}`);
|
|
100342
|
+
if (logo.copyright) lines.push(` ${logo.copyright}`);
|
|
100343
|
+
if (logo.source) lines.push(` artwork: ${logo.source}`);
|
|
100344
|
+
if (logo.licenseUrl) lines.push(` licence: ${logo.licenseUrl}`);
|
|
100345
|
+
}
|
|
100346
|
+
return `<!--
|
|
100347
|
+
${lines.map((line) => escComment(` ${line}`).trimEnd()).join("\n")}
|
|
100348
|
+
-->
|
|
100349
|
+
`;
|
|
100350
|
+
}
|
|
100351
|
+
var PREAMBLE;
|
|
100352
|
+
var init_logo_attribution = __esm({
|
|
100353
|
+
"src/logo-attribution.ts"() {
|
|
100354
|
+
"use strict";
|
|
100355
|
+
init_logos();
|
|
100356
|
+
init_xml_escape();
|
|
100357
|
+
PREAMBLE = [
|
|
100358
|
+
"This diagram contains third-party artwork under its own licence.",
|
|
100359
|
+
"Keep this notice with the file \u2014 it is the attribution those licences ask for.",
|
|
100360
|
+
"",
|
|
100361
|
+
"Every mark below is modified from the original: simple-icons redrew it as a",
|
|
100362
|
+
"single monochrome path, and cairn paints that path in the diagram's colours."
|
|
100363
|
+
];
|
|
99985
100364
|
}
|
|
99986
100365
|
});
|
|
99987
100366
|
|
|
@@ -99996,7 +100375,7 @@ function assignSourceHues(model, hues) {
|
|
|
99996
100375
|
}
|
|
99997
100376
|
function collectElementStyles(elements) {
|
|
99998
100377
|
return elements.flatMap((element) => [
|
|
99999
|
-
{ id: element.id, style: element.style,
|
|
100378
|
+
{ id: element.id, style: element.style, logo: element.logo },
|
|
100000
100379
|
...collectElementStyles(element.children)
|
|
100001
100380
|
]);
|
|
100002
100381
|
}
|
|
@@ -100091,13 +100470,66 @@ function settleOneLabel(s, label) {
|
|
|
100091
100470
|
label.x = origin.x;
|
|
100092
100471
|
label.y = origin.y;
|
|
100093
100472
|
}
|
|
100094
|
-
function
|
|
100095
|
-
const
|
|
100473
|
+
function glyphSvg(kind, stroke, box) {
|
|
100474
|
+
const glyph = GLYPHS[kind];
|
|
100475
|
+
if (!glyph) return "";
|
|
100476
|
+
const { x, y, scale = 1 } = box;
|
|
100477
|
+
const width = round1(1.3 * scale);
|
|
100478
|
+
return glyph({
|
|
100479
|
+
x: (v) => round1(x + v * scale),
|
|
100480
|
+
y: (v) => round1(y + v * scale),
|
|
100481
|
+
r: (v) => round1(v * scale),
|
|
100482
|
+
line: `fill="none" stroke="${stroke}" stroke-width="${width}"`,
|
|
100483
|
+
stroke
|
|
100484
|
+
});
|
|
100485
|
+
}
|
|
100486
|
+
function logoSvg(mark) {
|
|
100487
|
+
const { logo, resolved, node, stroke, drawn, inset = {} } = mark;
|
|
100488
|
+
if (!logo) return "";
|
|
100489
|
+
const x = round1(node.x + node.width - (inset.right ?? LOGO_BOX.right) - LOGO_BOX.size);
|
|
100490
|
+
const y = round1(node.y + (inset.top ?? LOGO_BOX.top));
|
|
100491
|
+
if (logo.source === "file") {
|
|
100492
|
+
const href = resolved?.get(node.id);
|
|
100493
|
+
if (!href) return "";
|
|
100494
|
+
return `<image x="${x}" y="${y}" width="${LOGO_BOX.size}" height="${LOGO_BOX.size}" href="${escAttr(href)}" preserveAspectRatio="xMidYMid meet"/>
|
|
100495
|
+
`;
|
|
100496
|
+
}
|
|
100497
|
+
const builtin = Object.hasOwn(LOGOS, logo.value) ? LOGOS[logo.value] : void 0;
|
|
100498
|
+
if (!builtin) return "";
|
|
100499
|
+
drawn.add(logo.value);
|
|
100500
|
+
const scale = Math.round(LOGO_BOX.size / 24 * 1e4) / 1e4;
|
|
100501
|
+
return `<g transform="translate(${x} ${y}) scale(${scale})" fill="${stroke}"><title>${esc(builtin.title)}</title><path d="${builtin.d}"/></g>
|
|
100502
|
+
`;
|
|
100503
|
+
}
|
|
100504
|
+
function createNodeLabelHelpers(nodeFontSize) {
|
|
100096
100505
|
const centeredNodeLabel = (lines, centerX2, topBaseline, fill) => lines.map(
|
|
100097
100506
|
(line, index) => `<text x="${centerX2}" y="${topBaseline + index * (nodeFontSize + 2)}" font-size="${nodeFontSize}" text-anchor="middle" fill="${fill}">${esc(line)}</text>
|
|
100098
100507
|
`
|
|
100099
100508
|
).join("");
|
|
100100
100509
|
const centerLinesY = (top, height, lineCount) => top + height / 2 - (lineCount - 1) * (nodeFontSize + 2) / 2 + 4;
|
|
100510
|
+
const glyphLabelCenterX = (node) => node.x + GLYPH_GUTTER + (node.width - GLYPH_GUTTER) / 2;
|
|
100511
|
+
const logoLabelCenterX = (node, hasLogo) => node.x + (node.width - (hasLogo ? LOGO_GUTTER : 0)) / 2;
|
|
100512
|
+
return { centeredNodeLabel, centerLinesY, glyphLabelCenterX, logoLabelCenterX };
|
|
100513
|
+
}
|
|
100514
|
+
function createNodeRenderers(paint) {
|
|
100515
|
+
const {
|
|
100516
|
+
palette,
|
|
100517
|
+
nodeFontSize,
|
|
100518
|
+
containerFontSize,
|
|
100519
|
+
resolveStyle,
|
|
100520
|
+
elementLogo,
|
|
100521
|
+
resolvedLogos,
|
|
100522
|
+
drawnLogos
|
|
100523
|
+
} = paint;
|
|
100524
|
+
const logoFor = (node, stroke, inset) => logoSvg({
|
|
100525
|
+
logo: elementLogo.get(node.id),
|
|
100526
|
+
resolved: resolvedLogos,
|
|
100527
|
+
node,
|
|
100528
|
+
stroke,
|
|
100529
|
+
drawn: drawnLogos,
|
|
100530
|
+
inset
|
|
100531
|
+
});
|
|
100532
|
+
const { centeredNodeLabel, centerLinesY, glyphLabelCenterX, logoLabelCenterX } = createNodeLabelHelpers(nodeFontSize);
|
|
100101
100533
|
const renderContainerNode = (node) => {
|
|
100102
100534
|
const nodeStyle = resolveStyle(node.kind, node.id);
|
|
100103
100535
|
const fill = escAttr(nodeStyle.fill ?? palette.containerFill), stroke = escAttr(nodeStyle.stroke?.color ?? palette.containerStroke), text = escAttr(nodeStyle.text ?? palette.containerLabel);
|
|
@@ -100108,12 +100540,7 @@ function createNodeRenderers(paint) {
|
|
|
100108
100540
|
svg += `<text x="${node.x + 10}" y="${node.y + 18 + index * 14}" font-size="${containerFontSize}" font-weight="bold" fill="${text}">${esc(line)}</text>
|
|
100109
100541
|
`;
|
|
100110
100542
|
});
|
|
100111
|
-
|
|
100112
|
-
if (level) {
|
|
100113
|
-
const word = (style.lang === "fr" ? SEC_LEVEL_FR[level] : level) ?? level;
|
|
100114
|
-
svg += `<text x="${node.x + node.width - 9}" y="${node.y + node.height - 6}" font-size="${annot.tag}" text-anchor="end" font-weight="bold" fill="${stroke}" letter-spacing="0.5">${esc(word.toUpperCase())}</text>
|
|
100115
|
-
`;
|
|
100116
|
-
}
|
|
100543
|
+
svg += logoFor(node, stroke);
|
|
100117
100544
|
return svg;
|
|
100118
100545
|
};
|
|
100119
100546
|
const renderActor = (node, nodeStyle, lines) => {
|
|
@@ -100136,9 +100563,12 @@ function createNodeRenderers(paint) {
|
|
|
100136
100563
|
<ellipse cx="${node.x + node.width / 2}" cy="${node.y + ry}" rx="${node.width / 2}" ry="${ry}" fill="${fill}" stroke="${stroke}" stroke-width="1.3"/>
|
|
100137
100564
|
`;
|
|
100138
100565
|
const centerY2 = node.y + ry + (node.height - ry) / 2 - (lines.length - 1) * (nodeFontSize + 2) / 2 + 4;
|
|
100139
|
-
|
|
100566
|
+
const logo = logoFor(node, stroke, {
|
|
100567
|
+
top: ry + (node.height - 2 * ry - LOGO_BOX.size) / 2
|
|
100568
|
+
});
|
|
100569
|
+
return body + logo + centeredNodeLabel(
|
|
100140
100570
|
lines,
|
|
100141
|
-
node
|
|
100571
|
+
logoLabelCenterX(node, logo !== ""),
|
|
100142
100572
|
centerY2,
|
|
100143
100573
|
escAttr(nodeStyle.text ?? palette.nodeText)
|
|
100144
100574
|
);
|
|
@@ -100149,50 +100579,38 @@ function createNodeRenderers(paint) {
|
|
|
100149
100579
|
const body = `<path d="M ${node.x + rx} ${node.y} h ${node.width - 2 * rx} a ${rx} ${node.height / 2} 0 0 1 0 ${node.height} h ${-(node.width - 2 * rx)} a ${rx} ${node.height / 2} 0 0 1 0 ${-node.height}" fill="${fill}" stroke="${stroke}" stroke-width="1.3"/>
|
|
100150
100580
|
<ellipse cx="${node.x + rx}" cy="${node.y + node.height / 2}" rx="${rx}" ry="${node.height / 2}" fill="${fill}" stroke="${stroke}" stroke-width="1.3"/>
|
|
100151
100581
|
`;
|
|
100152
|
-
|
|
100582
|
+
const logo = logoFor(node, stroke, { right: LOGO_BOX.right + rx });
|
|
100583
|
+
return body + logo + centeredNodeLabel(
|
|
100153
100584
|
lines,
|
|
100154
|
-
node.x + rx + (node.width - rx) / 2,
|
|
100585
|
+
node.x + rx + (node.width - rx - (logo === "" ? 0 : LOGO_GUTTER)) / 2,
|
|
100155
100586
|
centerLinesY(node.y, node.height, lines.length),
|
|
100156
100587
|
text
|
|
100157
100588
|
);
|
|
100158
100589
|
};
|
|
100159
|
-
const
|
|
100160
|
-
const centerX2 = node.x + node.width / 2;
|
|
100161
|
-
const fill = escAttr(nodeStyle.fill ?? palette.nodeFill), stroke = escAttr(nodeStyle.stroke?.color ?? palette.nodeStroke), text = escAttr(nodeStyle.text ?? palette.nodeText);
|
|
100162
|
-
const body = `<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="4" fill="${fill}" stroke="${stroke}" stroke-width="1.3"/>
|
|
100163
|
-
<path d="M ${round1(node.x + 8)} ${round1(node.y + 8)} L ${round1(node.x + 22)} ${round1(node.y + 8)} Q ${round1(node.x + 24)} ${round1(node.y + 13)} ${round1(node.x + 15)} ${round1(node.y + 20)} Q ${round1(node.x + 6)} ${round1(node.y + 13)} ${round1(node.x + 8)} ${round1(node.y + 8)}" fill="none" stroke="${stroke}" stroke-width="1.3"/>
|
|
100164
|
-
`;
|
|
100165
|
-
return body + centeredNodeLabel(lines, centerX2 + 10, centerLinesY(node.y, node.height, lines.length), text);
|
|
100166
|
-
};
|
|
100167
|
-
const renderAuth = (node, nodeStyle, lines) => {
|
|
100168
|
-
const centerX2 = node.x + node.width / 2;
|
|
100169
|
-
const fill = escAttr(nodeStyle.fill ?? palette.nodeFill), stroke = escAttr(nodeStyle.stroke?.color ?? palette.nodeStroke), text = escAttr(nodeStyle.text ?? palette.nodeText);
|
|
100170
|
-
const body = `<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="4" fill="${fill}" stroke="${stroke}" stroke-width="1.3"/>
|
|
100171
|
-
<rect x="${node.x + 6}" y="${node.y + 6}" width="18" height="14" rx="3" fill="none" stroke="${stroke}" stroke-width="1.3"/>
|
|
100172
|
-
<path d="M ${node.x + 10} ${node.y + 9} v -4 a 5 5 0 0 1 10 0 v 4" fill="none" stroke="${stroke}" stroke-width="1.3"/>
|
|
100173
|
-
<circle cx="${node.x + 15}" cy="${node.y + 16}" r="2.5" fill="${stroke}"/>
|
|
100174
|
-
`;
|
|
100175
|
-
return body + centeredNodeLabel(lines, centerX2 + 10, centerLinesY(node.y, node.height, lines.length), text);
|
|
100176
|
-
};
|
|
100177
|
-
const renderPlainBox = (node, nodeStyle, lines) => {
|
|
100590
|
+
const renderGlyphBox = (node, nodeStyle, lines) => {
|
|
100178
100591
|
const fill = escAttr(nodeStyle.fill ?? palette.nodeFill), stroke = escAttr(nodeStyle.stroke?.color ?? palette.nodeStroke), text = escAttr(nodeStyle.text ?? palette.nodeText);
|
|
100179
100592
|
const dash = dashArray(nodeStyle.stroke?.style);
|
|
100180
100593
|
const body = `<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="4" fill="${fill}" stroke="${stroke}" stroke-width="${nodeStyle.stroke?.width ?? 1.3}"${dash ? ` stroke-dasharray="${dash}"` : ""}/>
|
|
100181
|
-
|
|
100594
|
+
` + glyphSvg(node.kind, stroke, {
|
|
100595
|
+
x: node.x + GLYPH_BOX.left,
|
|
100596
|
+
y: node.y + GLYPH_BOX.top
|
|
100597
|
+
}) + "\n";
|
|
100182
100598
|
return body + centeredNodeLabel(
|
|
100183
100599
|
lines,
|
|
100184
|
-
node
|
|
100600
|
+
glyphLabelCenterX(node),
|
|
100185
100601
|
centerLinesY(node.y, node.height, lines.length),
|
|
100186
100602
|
text
|
|
100187
100603
|
);
|
|
100188
100604
|
};
|
|
100189
|
-
const
|
|
100605
|
+
const renderPlainBox = (node, nodeStyle, lines) => {
|
|
100190
100606
|
const fill = escAttr(nodeStyle.fill ?? palette.nodeFill), stroke = escAttr(nodeStyle.stroke?.color ?? palette.nodeStroke), text = escAttr(nodeStyle.text ?? palette.nodeText);
|
|
100191
|
-
const
|
|
100607
|
+
const dash = dashArray(nodeStyle.stroke?.style);
|
|
100608
|
+
const logo = logoFor(node, stroke);
|
|
100609
|
+
const body = `<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="4" fill="${fill}" stroke="${stroke}" stroke-width="${nodeStyle.stroke?.width ?? 1.3}"${dash ? ` stroke-dasharray="${dash}"` : ""}/>
|
|
100192
100610
|
`;
|
|
100193
|
-
return body + centeredNodeLabel(
|
|
100611
|
+
return body + logo + centeredNodeLabel(
|
|
100194
100612
|
lines,
|
|
100195
|
-
node
|
|
100613
|
+
logoLabelCenterX(node, logo !== ""),
|
|
100196
100614
|
centerLinesY(node.y, node.height, lines.length),
|
|
100197
100615
|
text
|
|
100198
100616
|
);
|
|
@@ -100207,14 +100625,8 @@ function createNodeRenderers(paint) {
|
|
|
100207
100625
|
return renderDatastore(node, nodeStyle, lines);
|
|
100208
100626
|
case "queue":
|
|
100209
100627
|
return renderQueue(node, nodeStyle, lines);
|
|
100210
|
-
case "gateway":
|
|
100211
|
-
return renderGateway(node, nodeStyle, lines);
|
|
100212
|
-
case "auth":
|
|
100213
|
-
return renderAuth(node, nodeStyle, lines);
|
|
100214
|
-
case "idp":
|
|
100215
|
-
return renderIdp(node, nodeStyle, lines);
|
|
100216
100628
|
default:
|
|
100217
|
-
return renderPlainBox(node, nodeStyle, lines);
|
|
100629
|
+
return GLYPHS[node.kind] ? renderGlyphBox(node, nodeStyle, lines) : renderPlainBox(node, nodeStyle, lines);
|
|
100218
100630
|
}
|
|
100219
100631
|
};
|
|
100220
100632
|
return { renderContainerNode, renderLeafNode };
|
|
@@ -100460,8 +100872,15 @@ function createBandRenderers(paint) {
|
|
|
100460
100872
|
`;
|
|
100461
100873
|
} else {
|
|
100462
100874
|
const dash = dashArray(nodeStyle.stroke?.style);
|
|
100463
|
-
|
|
100875
|
+
const stroke = nodeStyle.stroke?.color ?? palette.nodeStroke;
|
|
100876
|
+
bandsSvg += `<rect x="${lx}" y="${bandY + 2}" width="${scaled(26)}" height="${scaled(14)}" rx="3" fill="${nodeStyle.fill ?? palette.nodeFill}" stroke="${escAttr(stroke)}"${dash ? ` stroke-dasharray="${dash}"` : ""}/>
|
|
100464
100877
|
`;
|
|
100878
|
+
const glyphScale = (scaled(14) - scaled(4)) / GLYPH_BOX.height;
|
|
100879
|
+
bandsSvg += glyphSvg(kind, escAttr(stroke), {
|
|
100880
|
+
x: lx + (scaled(26) - GLYPH_BOX.width * glyphScale) / 2,
|
|
100881
|
+
y: bandY + 2 + (scaled(14) - GLYPH_BOX.height * glyphScale) / 2,
|
|
100882
|
+
scale: glyphScale
|
|
100883
|
+
});
|
|
100465
100884
|
}
|
|
100466
100885
|
const name = legendNames[kind];
|
|
100467
100886
|
bandsSvg += `<text x="${lx + scaled(32)}" y="${bandY + scaled(13)}" font-size="${scaled(10)}" fill="${palette.bandText}">${esc(name)}</text>
|
|
@@ -100597,7 +101016,28 @@ function createEdgePainter(paint) {
|
|
|
100597
101016
|
};
|
|
100598
101017
|
return { renderEdgePath, renderEdgeLabels };
|
|
100599
101018
|
}
|
|
100600
|
-
function
|
|
101019
|
+
function svgDocument(args2) {
|
|
101020
|
+
const {
|
|
101021
|
+
width,
|
|
101022
|
+
height,
|
|
101023
|
+
fontFamily,
|
|
101024
|
+
background,
|
|
101025
|
+
arrowMarkers,
|
|
101026
|
+
markerSize,
|
|
101027
|
+
body,
|
|
101028
|
+
bandsSvg,
|
|
101029
|
+
attribution
|
|
101030
|
+
} = args2;
|
|
101031
|
+
const markers = [...arrowMarkers].map(
|
|
101032
|
+
([color, markerName]) => `<marker id="${markerName}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="${markerSize}" markerHeight="${markerSize}" orient="auto-start-reverse">
|
|
101033
|
+
<path d="M0,0 L10,5 L0,10 z" fill="${escAttr(color)}"/></marker>`
|
|
101034
|
+
).join("\n");
|
|
101035
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" font-family="${escAttr(fontFamily)},Arial,sans-serif">
|
|
101036
|
+
${attribution}<defs>${markers}</defs>
|
|
101037
|
+
<rect width="${width}" height="${height}" fill="${escAttr(background)}"/>
|
|
101038
|
+
` + body + bandsSvg + "</svg>\n";
|
|
101039
|
+
}
|
|
101040
|
+
function render(model, view, scene, options) {
|
|
100601
101041
|
const style = model.style;
|
|
100602
101042
|
const fonts = fontSizes(style.font.size);
|
|
100603
101043
|
const { edge: edgeFontSize, node: nodeFontSize, cont: containerFontSize } = fonts;
|
|
@@ -100613,10 +101053,10 @@ function render(model, view, scene) {
|
|
|
100613
101053
|
chipTextDy: round1(11 * fonts.scale)
|
|
100614
101054
|
};
|
|
100615
101055
|
const scaled = (n) => round1(n * fonts.scale);
|
|
100616
|
-
const { palette, kinds: kindDefaults
|
|
100617
|
-
const
|
|
101056
|
+
const { palette, kinds: kindDefaults } = options?.theme ? themeFromSpec(options.theme, view) : themeFor(style.theme, view);
|
|
101057
|
+
const onDarkGround = options?.theme ? options.theme.dark === true : isDarkTheme(style.theme);
|
|
100618
101058
|
const defaultEdgeColor = style.flowStrokeColorSet ? style.flowStroke.color : style.accent ?? palette.edge;
|
|
100619
|
-
const sourceHue = style.flowColor === "by-source" ? assignSourceHues(model, flowPalette[
|
|
101059
|
+
const sourceHue = style.flowColor === "by-source" ? assignSourceHues(model, flowPalette[onDarkGround ? "dark" : "light"]) : /* @__PURE__ */ new Map();
|
|
100620
101060
|
const flowColorOf = (flow) => flow?.style?.stroke?.color ?? (style.flowColor === "by-source" ? sourceHue.get(flow?.from ?? "") ?? defaultEdgeColor : defaultEdgeColor);
|
|
100621
101061
|
const arrowMarkers = /* @__PURE__ */ new Map();
|
|
100622
101062
|
const markerName = (color) => {
|
|
@@ -100634,15 +101074,13 @@ function render(model, view, scene) {
|
|
|
100634
101074
|
const legendNames = style.lang === "fr" ? view.legendNamesFr : view.legendNames;
|
|
100635
101075
|
const legendFlowLabel = style.lang === "fr" ? view.legendFlowLabelFr : view.legendFlowLabel;
|
|
100636
101076
|
const elementStyle = /* @__PURE__ */ new Map();
|
|
100637
|
-
const
|
|
101077
|
+
const elementLogo = /* @__PURE__ */ new Map();
|
|
100638
101078
|
for (const entry of collectElementStyles(model.elements)) {
|
|
100639
101079
|
elementStyle.set(entry.id, entry.style);
|
|
100640
|
-
|
|
101080
|
+
if (entry.logo) elementLogo.set(entry.id, entry.logo);
|
|
100641
101081
|
}
|
|
100642
101082
|
const resolveStyle = (kind, id) => {
|
|
100643
|
-
|
|
100644
|
-
const level = elementAttr.get(id);
|
|
100645
|
-
if (kind === "trust-zone" && level && levelDefaults?.[level]) base = levelDefaults[level];
|
|
101083
|
+
const base = kindDefaults[kind] ?? {};
|
|
100646
101084
|
const perKind = style.kind[kind] ?? {};
|
|
100647
101085
|
const inline = elementStyle.get(id) ?? {};
|
|
100648
101086
|
return {
|
|
@@ -100677,14 +101115,15 @@ function render(model, view, scene) {
|
|
|
100677
101115
|
});
|
|
100678
101116
|
const overlapsAfter = countLabelOverlaps();
|
|
100679
101117
|
compactVertical(scene);
|
|
101118
|
+
const drawnLogos = /* @__PURE__ */ new Set();
|
|
100680
101119
|
const { renderContainerNode, renderLeafNode } = createNodeRenderers({
|
|
100681
101120
|
palette,
|
|
100682
|
-
style,
|
|
100683
|
-
annot,
|
|
100684
101121
|
nodeFontSize,
|
|
100685
101122
|
containerFontSize,
|
|
100686
101123
|
resolveStyle,
|
|
100687
|
-
|
|
101124
|
+
elementLogo,
|
|
101125
|
+
resolvedLogos: options?.logos,
|
|
101126
|
+
drawnLogos
|
|
100688
101127
|
});
|
|
100689
101128
|
const { renderEdgePath, renderEdgeLabels } = createEdgePainter({
|
|
100690
101129
|
scene,
|
|
@@ -100727,21 +101166,24 @@ function render(model, view, scene) {
|
|
|
100727
101166
|
if (style.legend === "auto") bands.renderLegendBand();
|
|
100728
101167
|
const bandsSvg = bands.bandsSvg();
|
|
100729
101168
|
const bandY = bands.bandY();
|
|
100730
|
-
const
|
|
100731
|
-
const totalHeight = bandY > viewHeight ? bandY + 14 : viewHeight;
|
|
100732
|
-
const markerSize = style.arrows === "large" ? round1(11 * fonts.scale) : 7;
|
|
101169
|
+
const viewHeight = scene.height;
|
|
100733
101170
|
if (arrowMarkers.size === 0) markerName(defaultEdgeColor);
|
|
100734
|
-
const
|
|
100735
|
-
|
|
100736
|
-
|
|
100737
|
-
|
|
100738
|
-
|
|
100739
|
-
|
|
100740
|
-
|
|
100741
|
-
|
|
101171
|
+
const svg = svgDocument({
|
|
101172
|
+
width: scene.width,
|
|
101173
|
+
height: bandY > viewHeight ? bandY + 14 : viewHeight,
|
|
101174
|
+
fontFamily: style.font.family,
|
|
101175
|
+
background: style.background ?? palette.background,
|
|
101176
|
+
arrowMarkers,
|
|
101177
|
+
markerSize: style.arrows === "large" ? round1(11 * fonts.scale) : 7,
|
|
101178
|
+
body,
|
|
101179
|
+
bandsSvg,
|
|
101180
|
+
// Read after the body is built, so it names the marks that were painted
|
|
101181
|
+
// rather than the ones the model asked for.
|
|
101182
|
+
attribution: logoAttributionComment(drawnLogos)
|
|
101183
|
+
});
|
|
100742
101184
|
return { svg, overlapsBefore, overlapsAfter };
|
|
100743
101185
|
}
|
|
100744
|
-
var HOP_RADIUS, LABEL_HALO, RENDER_CHAR_WIDTH,
|
|
101186
|
+
var HOP_RADIUS, LABEL_HALO, RENDER_CHAR_WIDTH, dashArray, round1, ADRIFT_SQ, ATTACHED_SQ, GLYPH_BOX, GLYPHS, LOGO_BOX;
|
|
100745
101187
|
var init_svg_render = __esm({
|
|
100746
101188
|
"src/svg-render.ts"() {
|
|
100747
101189
|
"use strict";
|
|
@@ -100755,19 +101197,276 @@ var init_svg_render = __esm({
|
|
|
100755
101197
|
init_route_detour();
|
|
100756
101198
|
init_readability();
|
|
100757
101199
|
init_text_metrics();
|
|
101200
|
+
init_logo_attribution();
|
|
101201
|
+
init_logos();
|
|
100758
101202
|
HOP_RADIUS = 5;
|
|
100759
101203
|
LABEL_HALO = 4;
|
|
100760
101204
|
RENDER_CHAR_WIDTH = 0.52;
|
|
100761
|
-
SEC_LEVEL_FR = {
|
|
100762
|
-
public: "public",
|
|
100763
|
-
internal: "interne",
|
|
100764
|
-
restricted: "restreint",
|
|
100765
|
-
secret: "secret"
|
|
100766
|
-
};
|
|
100767
101205
|
dashArray = (lineStyle) => lineStyle === "dashed" ? "5 3" : lineStyle === "dotted" ? "2 2.5" : void 0;
|
|
100768
101206
|
round1 = (n) => Math.round(n * 10) / 10;
|
|
100769
101207
|
ADRIFT_SQ = 20 * 20;
|
|
100770
101208
|
ATTACHED_SQ = 6 * 6;
|
|
101209
|
+
GLYPH_BOX = { width: 18, height: 16, left: 6, top: 7 };
|
|
101210
|
+
GLYPHS = {
|
|
101211
|
+
// Padlock: authentication is a check something must pass.
|
|
101212
|
+
auth: ({ x, y, r, line, stroke }) => `<rect x="${x(3)}" y="${y(7)}" width="${r(12)}" height="${r(9)}" rx="${r(2)}" ${line}/><path d="M ${x(6)} ${y(7)} v ${-r(3)} a ${r(3)} ${r(3)} 0 0 1 ${r(6)} 0 v ${r(3)}" ${line}/><circle cx="${x(9)}" cy="${y(11)}" r="${r(1.5)}" fill="${stroke}"/>`,
|
|
101213
|
+
// Two posts with traffic passing between them: a gateway routes, it does not block.
|
|
101214
|
+
gateway: ({ x, y, r, line }) => `<path d="M ${x(2)} ${y(1)} V ${y(15)} M ${x(16)} ${y(1)} V ${y(15)}" ${line}/><path d="M ${x(4)} ${y(8)} H ${x(14)}" ${line}/><path d="M ${x(11)} ${y(5)} l ${r(3)} ${r(3)} l ${-r(3)} ${r(3)}" ${line}/>`,
|
|
101215
|
+
// ID badge: an identity provider issues who-you-are, it does not check it.
|
|
101216
|
+
idp: ({ x, y, r, line }) => `<rect x="${x(3)}" y="${y(2)}" width="${r(12)}" height="${r(13)}" rx="${r(2)}" ${line}/><path d="M ${x(7)} ${y(2)} H ${x(11)}" ${line}/><circle cx="${x(9)}" cy="${y(7)}" r="${r(2)}" ${line}/><path d="M ${x(5)} ${y(13)} q ${r(4)} ${-r(4)} ${r(8)} 0" ${line}/>`,
|
|
101217
|
+
// Brick wall: a firewall is a barrier, and no other kind reads as one.
|
|
101218
|
+
firewall: ({ x, y, r, line }) => `<rect x="${x(2)}" y="${y(2)}" width="${r(14)}" height="${r(12)}" rx="${r(1)}" ${line}/><path d="M ${x(2)} ${y(6)} H ${x(16)} M ${x(2)} ${y(10)} H ${x(16)}" ${line}/><path d="M ${x(9)} ${y(2)} V ${y(6)} M ${x(6)} ${y(6)} V ${y(10)} M ${x(12)} ${y(6)} V ${y(10)} M ${x(9)} ${y(10)} V ${y(14)}" ${line}/>`,
|
|
101219
|
+
// Monitor on a stand: a device is the machine a person works at. The screen is
|
|
101220
|
+
// left empty on purpose — that is what separates it from the firewall's wall
|
|
101221
|
+
// at legend size, where both are a rectangle and little else survives.
|
|
101222
|
+
device: ({ x, y, r, line }) => `<rect x="${x(2)}" y="${y(1)}" width="${r(14)}" height="${r(9)}" rx="${r(1)}" ${line}/><path d="M ${x(9)} ${y(10)} V ${y(13)}" ${line}/><path d="M ${x(4)} ${y(13)} H ${x(14)}" ${line}/>`
|
|
101223
|
+
};
|
|
101224
|
+
LOGO_BOX = { size: 18, right: 7, top: 6 };
|
|
101225
|
+
}
|
|
101226
|
+
});
|
|
101227
|
+
|
|
101228
|
+
// src/css-colours.ts
|
|
101229
|
+
var HEX, NUMBER, PERCENT, AMOUNT, ANGLE, commaForm, spaceForm, RGB, HSL, NUMERIC_COLOUR, COLOUR_KEYWORDS, isColour;
|
|
101230
|
+
var init_css_colours = __esm({
|
|
101231
|
+
"src/css-colours.ts"() {
|
|
101232
|
+
"use strict";
|
|
101233
|
+
HEX = "#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})";
|
|
101234
|
+
NUMBER = String.raw`[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?`;
|
|
101235
|
+
PERCENT = `${NUMBER}%`;
|
|
101236
|
+
AMOUNT = `${NUMBER}%?`;
|
|
101237
|
+
ANGLE = `${NUMBER}(?:deg|grad|rad|turn)?`;
|
|
101238
|
+
commaForm = (first, second, third) => `${first}\\s*,\\s*${second}\\s*,\\s*${third}(?:\\s*,\\s*${AMOUNT})?`;
|
|
101239
|
+
spaceForm = (first, second, third) => `${first}\\s+${second}\\s+${third}(?:\\s*/\\s*${AMOUNT})?`;
|
|
101240
|
+
RGB = `rgba?\\(\\s*(?:${commaForm(NUMBER, NUMBER, NUMBER)}|${commaForm(PERCENT, PERCENT, PERCENT)}|${spaceForm(AMOUNT, AMOUNT, AMOUNT)})\\s*\\)`;
|
|
101241
|
+
HSL = `hsla?\\(\\s*(?:${commaForm(ANGLE, PERCENT, PERCENT)}|${spaceForm(ANGLE, AMOUNT, AMOUNT)})\\s*\\)`;
|
|
101242
|
+
NUMERIC_COLOUR = new RegExp(`^(?:${HEX}|${RGB}|${HSL})$`, "i");
|
|
101243
|
+
COLOUR_KEYWORDS = /* @__PURE__ */ new Set([
|
|
101244
|
+
"currentcolor",
|
|
101245
|
+
"transparent",
|
|
101246
|
+
"aliceblue",
|
|
101247
|
+
"antiquewhite",
|
|
101248
|
+
"aqua",
|
|
101249
|
+
"aquamarine",
|
|
101250
|
+
"azure",
|
|
101251
|
+
"beige",
|
|
101252
|
+
"bisque",
|
|
101253
|
+
"black",
|
|
101254
|
+
"blanchedalmond",
|
|
101255
|
+
"blue",
|
|
101256
|
+
"blueviolet",
|
|
101257
|
+
"brown",
|
|
101258
|
+
"burlywood",
|
|
101259
|
+
"cadetblue",
|
|
101260
|
+
"chartreuse",
|
|
101261
|
+
"chocolate",
|
|
101262
|
+
"coral",
|
|
101263
|
+
"cornflowerblue",
|
|
101264
|
+
"cornsilk",
|
|
101265
|
+
"crimson",
|
|
101266
|
+
"cyan",
|
|
101267
|
+
"darkblue",
|
|
101268
|
+
"darkcyan",
|
|
101269
|
+
"darkgoldenrod",
|
|
101270
|
+
"darkgray",
|
|
101271
|
+
"darkgreen",
|
|
101272
|
+
"darkgrey",
|
|
101273
|
+
"darkkhaki",
|
|
101274
|
+
"darkmagenta",
|
|
101275
|
+
"darkolivegreen",
|
|
101276
|
+
"darkorange",
|
|
101277
|
+
"darkorchid",
|
|
101278
|
+
"darkred",
|
|
101279
|
+
"darksalmon",
|
|
101280
|
+
"darkseagreen",
|
|
101281
|
+
"darkslateblue",
|
|
101282
|
+
"darkslategray",
|
|
101283
|
+
"darkslategrey",
|
|
101284
|
+
"darkturquoise",
|
|
101285
|
+
"darkviolet",
|
|
101286
|
+
"deeppink",
|
|
101287
|
+
"deepskyblue",
|
|
101288
|
+
"dimgray",
|
|
101289
|
+
"dimgrey",
|
|
101290
|
+
"dodgerblue",
|
|
101291
|
+
"firebrick",
|
|
101292
|
+
"floralwhite",
|
|
101293
|
+
"forestgreen",
|
|
101294
|
+
"fuchsia",
|
|
101295
|
+
"gainsboro",
|
|
101296
|
+
"ghostwhite",
|
|
101297
|
+
"gold",
|
|
101298
|
+
"goldenrod",
|
|
101299
|
+
"gray",
|
|
101300
|
+
"green",
|
|
101301
|
+
"greenyellow",
|
|
101302
|
+
"grey",
|
|
101303
|
+
"honeydew",
|
|
101304
|
+
"hotpink",
|
|
101305
|
+
"indianred",
|
|
101306
|
+
"indigo",
|
|
101307
|
+
"ivory",
|
|
101308
|
+
"khaki",
|
|
101309
|
+
"lavender",
|
|
101310
|
+
"lavenderblush",
|
|
101311
|
+
"lawngreen",
|
|
101312
|
+
"lemonchiffon",
|
|
101313
|
+
"lightblue",
|
|
101314
|
+
"lightcoral",
|
|
101315
|
+
"lightcyan",
|
|
101316
|
+
"lightgoldenrodyellow",
|
|
101317
|
+
"lightgray",
|
|
101318
|
+
"lightgreen",
|
|
101319
|
+
"lightgrey",
|
|
101320
|
+
"lightpink",
|
|
101321
|
+
"lightsalmon",
|
|
101322
|
+
"lightseagreen",
|
|
101323
|
+
"lightskyblue",
|
|
101324
|
+
"lightslategray",
|
|
101325
|
+
"lightslategrey",
|
|
101326
|
+
"lightsteelblue",
|
|
101327
|
+
"lightyellow",
|
|
101328
|
+
"lime",
|
|
101329
|
+
"limegreen",
|
|
101330
|
+
"linen",
|
|
101331
|
+
"magenta",
|
|
101332
|
+
"maroon",
|
|
101333
|
+
"mediumaquamarine",
|
|
101334
|
+
"mediumblue",
|
|
101335
|
+
"mediumorchid",
|
|
101336
|
+
"mediumpurple",
|
|
101337
|
+
"mediumseagreen",
|
|
101338
|
+
"mediumslateblue",
|
|
101339
|
+
"mediumspringgreen",
|
|
101340
|
+
"mediumturquoise",
|
|
101341
|
+
"mediumvioletred",
|
|
101342
|
+
"midnightblue",
|
|
101343
|
+
"mintcream",
|
|
101344
|
+
"mistyrose",
|
|
101345
|
+
"moccasin",
|
|
101346
|
+
"navajowhite",
|
|
101347
|
+
"navy",
|
|
101348
|
+
"oldlace",
|
|
101349
|
+
"olive",
|
|
101350
|
+
"olivedrab",
|
|
101351
|
+
"orange",
|
|
101352
|
+
"orangered",
|
|
101353
|
+
"orchid",
|
|
101354
|
+
"palegoldenrod",
|
|
101355
|
+
"palegreen",
|
|
101356
|
+
"paleturquoise",
|
|
101357
|
+
"palevioletred",
|
|
101358
|
+
"papayawhip",
|
|
101359
|
+
"peachpuff",
|
|
101360
|
+
"peru",
|
|
101361
|
+
"pink",
|
|
101362
|
+
"plum",
|
|
101363
|
+
"powderblue",
|
|
101364
|
+
"purple",
|
|
101365
|
+
"rebeccapurple",
|
|
101366
|
+
"red",
|
|
101367
|
+
"rosybrown",
|
|
101368
|
+
"royalblue",
|
|
101369
|
+
"saddlebrown",
|
|
101370
|
+
"salmon",
|
|
101371
|
+
"sandybrown",
|
|
101372
|
+
"seagreen",
|
|
101373
|
+
"seashell",
|
|
101374
|
+
"sienna",
|
|
101375
|
+
"silver",
|
|
101376
|
+
"skyblue",
|
|
101377
|
+
"slateblue",
|
|
101378
|
+
"slategray",
|
|
101379
|
+
"slategrey",
|
|
101380
|
+
"snow",
|
|
101381
|
+
"springgreen",
|
|
101382
|
+
"steelblue",
|
|
101383
|
+
"tan",
|
|
101384
|
+
"teal",
|
|
101385
|
+
"thistle",
|
|
101386
|
+
"tomato",
|
|
101387
|
+
"turquoise",
|
|
101388
|
+
"violet",
|
|
101389
|
+
"wheat",
|
|
101390
|
+
"white",
|
|
101391
|
+
"whitesmoke",
|
|
101392
|
+
"yellow",
|
|
101393
|
+
"yellowgreen"
|
|
101394
|
+
]);
|
|
101395
|
+
isColour = (value) => NUMERIC_COLOUR.test(value) || COLOUR_KEYWORDS.has(value.toLowerCase());
|
|
101396
|
+
}
|
|
101397
|
+
});
|
|
101398
|
+
|
|
101399
|
+
// src/theme-spec.ts
|
|
101400
|
+
function checkEntry(path, value, arity) {
|
|
101401
|
+
if (arity === 1) {
|
|
101402
|
+
if (typeof value !== "string") {
|
|
101403
|
+
throw new ThemeSpecError(`\`${path}\` must be a colour, got ${describe(value)}`);
|
|
101404
|
+
}
|
|
101405
|
+
} else if (!Array.isArray(value) || value.length !== arity) {
|
|
101406
|
+
throw new ThemeSpecError(`\`${path}\` must be ${arity} colours, got ${describe(value)}`);
|
|
101407
|
+
}
|
|
101408
|
+
for (const colour of Array.isArray(value) ? value : [value]) {
|
|
101409
|
+
if (typeof colour !== "string" || !isColour(colour)) {
|
|
101410
|
+
throw new ThemeSpecError(`\`${path}\`: \`${String(colour)}\` is not a colour`);
|
|
101411
|
+
}
|
|
101412
|
+
}
|
|
101413
|
+
}
|
|
101414
|
+
function resolveThemeSpec(input) {
|
|
101415
|
+
if (!isObject(input)) throw new ThemeSpecError("a theme must be an object");
|
|
101416
|
+
const base = input.extends ?? DEFAULT_BASE;
|
|
101417
|
+
if (typeof base !== "string") throw new ThemeSpecError("`extends` must be a theme name");
|
|
101418
|
+
const baseSpec = Object.hasOwn(THEME_SPECS, base) ? THEME_SPECS[base] : void 0;
|
|
101419
|
+
if (!baseSpec) {
|
|
101420
|
+
throw new ThemeSpecError(
|
|
101421
|
+
`extends unknown theme \`${base}\` \u2014 pick one of: ${Object.keys(THEME_SPECS).join(", ")}`
|
|
101422
|
+
);
|
|
101423
|
+
}
|
|
101424
|
+
if ("dark" in input && typeof input.dark !== "boolean") {
|
|
101425
|
+
throw new ThemeSpecError("`dark` must be true or false");
|
|
101426
|
+
}
|
|
101427
|
+
for (const [section, value] of Object.entries(input)) {
|
|
101428
|
+
if (section === "extends" || section === "dark") continue;
|
|
101429
|
+
if (!SECTIONS.includes(section)) {
|
|
101430
|
+
throw new ThemeSpecError(
|
|
101431
|
+
`unknown section \`${section}\` \u2014 a theme overrides ${SECTIONS.join(", ")}`
|
|
101432
|
+
);
|
|
101433
|
+
}
|
|
101434
|
+
if (!isObject(value)) {
|
|
101435
|
+
throw new ThemeSpecError(
|
|
101436
|
+
`\`${section}\` must be an object of colours, got ${describe(value)}`
|
|
101437
|
+
);
|
|
101438
|
+
}
|
|
101439
|
+
for (const [key, colour] of Object.entries(value)) {
|
|
101440
|
+
checkEntry(`${section}.${key}`, colour, arityOf(section, key));
|
|
101441
|
+
}
|
|
101442
|
+
}
|
|
101443
|
+
return merge(baseSpec, input);
|
|
101444
|
+
}
|
|
101445
|
+
var DEFAULT_BASE, ThemeSpecError, isObject, merge, SECTIONS, arityOf, describe;
|
|
101446
|
+
var init_theme_spec = __esm({
|
|
101447
|
+
"src/theme-spec.ts"() {
|
|
101448
|
+
"use strict";
|
|
101449
|
+
init_css_colours();
|
|
101450
|
+
init_themes();
|
|
101451
|
+
DEFAULT_BASE = "light";
|
|
101452
|
+
ThemeSpecError = class extends Error {
|
|
101453
|
+
};
|
|
101454
|
+
isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
101455
|
+
merge = (base, patch) => {
|
|
101456
|
+
const merged = { ...base };
|
|
101457
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
101458
|
+
if (key === "extends") continue;
|
|
101459
|
+
const current = merged[key];
|
|
101460
|
+
merged[key] = isObject(value) && isObject(current) ? { ...current, ...value } : value;
|
|
101461
|
+
}
|
|
101462
|
+
return merged;
|
|
101463
|
+
};
|
|
101464
|
+
SECTIONS = ["pal", "accentColors"];
|
|
101465
|
+
arityOf = (section, key) => {
|
|
101466
|
+
if (section === "pal") return key === "chip" ? 3 : key === "badge" ? 2 : 1;
|
|
101467
|
+
return 1;
|
|
101468
|
+
};
|
|
101469
|
+
describe = (value) => Array.isArray(value) ? `an array of ${value.length}` : typeof value;
|
|
100771
101470
|
}
|
|
100772
101471
|
});
|
|
100773
101472
|
|
|
@@ -100834,8 +101533,9 @@ function matrixMd(matrix) {
|
|
|
100834
101533
|
for (const row of matrix.rows) outLines.push("| " + row.cells.map(mdCell).join(" | ") + " |");
|
|
100835
101534
|
return outLines.join("\n") + "\n";
|
|
100836
101535
|
}
|
|
100837
|
-
function matrixSvg(matrix) {
|
|
100838
|
-
const
|
|
101536
|
+
function matrixSvg(matrix, options) {
|
|
101537
|
+
const requested = options?.theme;
|
|
101538
|
+
const pal = typeof requested === "object" ? paletteFromSpec(resolveThemeSpec(requested)) : paletteFor(requested ?? matrix.style.theme);
|
|
100839
101539
|
const title = matrix.heading;
|
|
100840
101540
|
const headers = matrix.columns.map((column) => column.label);
|
|
100841
101541
|
const cells = matrix.rows.map((row) => row.cells);
|
|
@@ -100903,6 +101603,7 @@ var init_flow_matrix = __esm({
|
|
|
100903
101603
|
"use strict";
|
|
100904
101604
|
init_localization();
|
|
100905
101605
|
init_themes();
|
|
101606
|
+
init_theme_spec();
|
|
100906
101607
|
init_xml_escape();
|
|
100907
101608
|
init_text_metrics();
|
|
100908
101609
|
COLUMN_PRESENTATION = {
|
|
@@ -100939,9 +101640,81 @@ var init_flow_matrix = __esm({
|
|
|
100939
101640
|
}
|
|
100940
101641
|
});
|
|
100941
101642
|
|
|
101643
|
+
// src/logo-files.ts
|
|
101644
|
+
import { closeSync, constants, fstatSync, openSync, readSync } from "node:fs";
|
|
101645
|
+
import { dirname, resolve, extname } from "node:path";
|
|
101646
|
+
function resolveLogoFiles(model, sourceFile) {
|
|
101647
|
+
const logos = /* @__PURE__ */ new Map();
|
|
101648
|
+
const diagnostics = [];
|
|
101649
|
+
const base = dirname(resolve(sourceFile));
|
|
101650
|
+
for (const element of model.elements.flatMap((root) => subtreeElements(root))) {
|
|
101651
|
+
const logo = element.logo;
|
|
101652
|
+
if (logo?.source !== "file") continue;
|
|
101653
|
+
const warn = (message, help) => diagnostics.push({
|
|
101654
|
+
code: "W0580",
|
|
101655
|
+
severity: "warning",
|
|
101656
|
+
message,
|
|
101657
|
+
span: logo.span,
|
|
101658
|
+
help
|
|
101659
|
+
});
|
|
101660
|
+
const mime = MIME_BY_EXT[extname(logo.value).toLowerCase()];
|
|
101661
|
+
if (!mime) {
|
|
101662
|
+
warn(
|
|
101663
|
+
`unsupported logo file type \`${extname(logo.value) || logo.value}\``,
|
|
101664
|
+
`use one of: ${Object.keys(MIME_BY_EXT).join(", ")}`
|
|
101665
|
+
);
|
|
101666
|
+
continue;
|
|
101667
|
+
}
|
|
101668
|
+
const path = resolve(base, logo.value);
|
|
101669
|
+
let bytes;
|
|
101670
|
+
try {
|
|
101671
|
+
const fd = openSync(path, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
|
|
101672
|
+
try {
|
|
101673
|
+
const stat = fstatSync(fd);
|
|
101674
|
+
if (!stat.isFile()) {
|
|
101675
|
+
warn(`logo file \`${logo.value}\` is not a regular file`, "point at an image file");
|
|
101676
|
+
continue;
|
|
101677
|
+
}
|
|
101678
|
+
if (stat.size > MAX_BYTES) {
|
|
101679
|
+
warn(
|
|
101680
|
+
`logo file is ${Math.round(stat.size / 1024)} KB, over the ${MAX_BYTES / 1024} KB limit`,
|
|
101681
|
+
"a corner mark needs very little \u2014 export it smaller, or use a built-in"
|
|
101682
|
+
);
|
|
101683
|
+
continue;
|
|
101684
|
+
}
|
|
101685
|
+
bytes = Buffer.alloc(stat.size);
|
|
101686
|
+
const read = readSync(fd, bytes, 0, stat.size, 0);
|
|
101687
|
+
if (read < stat.size) bytes = bytes.subarray(0, read);
|
|
101688
|
+
} finally {
|
|
101689
|
+
closeSync(fd);
|
|
101690
|
+
}
|
|
101691
|
+
} catch {
|
|
101692
|
+
warn(`cannot read logo file \`${logo.value}\``, `looked in \`${base}\``);
|
|
101693
|
+
continue;
|
|
101694
|
+
}
|
|
101695
|
+
logos.set(element.id, `data:${mime};base64,${bytes.toString("base64")}`);
|
|
101696
|
+
}
|
|
101697
|
+
return { logos, diagnostics };
|
|
101698
|
+
}
|
|
101699
|
+
var MIME_BY_EXT, MAX_BYTES;
|
|
101700
|
+
var init_logo_files = __esm({
|
|
101701
|
+
"src/logo-files.ts"() {
|
|
101702
|
+
"use strict";
|
|
101703
|
+
init_element_tree();
|
|
101704
|
+
MIME_BY_EXT = {
|
|
101705
|
+
".svg": "image/svg+xml",
|
|
101706
|
+
".png": "image/png",
|
|
101707
|
+
".jpg": "image/jpeg",
|
|
101708
|
+
".jpeg": "image/jpeg",
|
|
101709
|
+
".webp": "image/webp"
|
|
101710
|
+
};
|
|
101711
|
+
MAX_BYTES = 256 * 1024;
|
|
101712
|
+
}
|
|
101713
|
+
});
|
|
101714
|
+
|
|
100942
101715
|
// src/watch.ts
|
|
100943
101716
|
import { watch as fsWatch, readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
100944
|
-
import { dirname, basename } from "node:path";
|
|
101717
|
+
import { dirname as dirname2, basename } from "node:path";
|
|
100945
101718
|
function errorPanelSvg(file, diagnostics) {
|
|
100946
101719
|
const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").slice(0, 10);
|
|
100947
101720
|
const more = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length - errors.length;
|
|
@@ -100966,7 +101739,7 @@ function errorPanelSvg(file, diagnostics) {
|
|
|
100966
101739
|
`;
|
|
100967
101740
|
return out + "</svg>\n";
|
|
100968
101741
|
}
|
|
100969
|
-
function watchCommand(file, outFile) {
|
|
101742
|
+
function watchCommand(file, outFile, theme) {
|
|
100970
101743
|
if (!existsSync(file)) {
|
|
100971
101744
|
console.error(`error: file not found \`${file}\``);
|
|
100972
101745
|
process.exit(2);
|
|
@@ -100982,6 +101755,7 @@ function watchCommand(file, outFile) {
|
|
|
100982
101755
|
const src = readFileSync(file, "utf8");
|
|
100983
101756
|
const { model, diags } = parse(src);
|
|
100984
101757
|
diags.push(...validate(model));
|
|
101758
|
+
if (theme) model.style.theme = theme;
|
|
100985
101759
|
const errors = diags.filter((diagnostic) => diagnostic.severity === "error");
|
|
100986
101760
|
const stamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
100987
101761
|
console.clear();
|
|
@@ -101000,7 +101774,9 @@ function watchCommand(file, outFile) {
|
|
|
101000
101774
|
const view = views[model.type];
|
|
101001
101775
|
const scene = await layout(model, view);
|
|
101002
101776
|
diags.push(...attachSideDiagnostics(scene, model));
|
|
101003
|
-
const {
|
|
101777
|
+
const { logos, diagnostics: logoDiagnostics } = resolveLogoFiles(model, file);
|
|
101778
|
+
diags.push(...logoDiagnostics);
|
|
101779
|
+
const { svg, overlapsAfter } = render(model, view, scene, { logos });
|
|
101004
101780
|
writeFileSync(outFile, svg);
|
|
101005
101781
|
if (diags.length)
|
|
101006
101782
|
console.log(renderHuman(file, src, diags, process.stdout.isTTY ?? false) + "\n");
|
|
@@ -101033,7 +101809,7 @@ function watchCommand(file, outFile) {
|
|
|
101033
101809
|
}
|
|
101034
101810
|
};
|
|
101035
101811
|
let timer = null;
|
|
101036
|
-
fsWatch(
|
|
101812
|
+
fsWatch(dirname2(file) || ".", (_event, fileName) => {
|
|
101037
101813
|
if (fileName && fileName !== basename(file)) return;
|
|
101038
101814
|
if (timer) clearTimeout(timer);
|
|
101039
101815
|
timer = setTimeout(rebuild, 120);
|
|
@@ -101050,28 +101826,113 @@ var init_watch = __esm({
|
|
|
101050
101826
|
init_svg_render();
|
|
101051
101827
|
init_views();
|
|
101052
101828
|
init_xml_escape();
|
|
101829
|
+
init_logo_files();
|
|
101830
|
+
}
|
|
101831
|
+
});
|
|
101832
|
+
|
|
101833
|
+
// src/theme-file.ts
|
|
101834
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
101835
|
+
function loadThemeFile(path) {
|
|
101836
|
+
let raw;
|
|
101837
|
+
try {
|
|
101838
|
+
raw = readFileSync2(path, "utf8");
|
|
101839
|
+
} catch {
|
|
101840
|
+
throw new ThemeFileError(`cannot read theme file \`${path}\``);
|
|
101841
|
+
}
|
|
101842
|
+
let parsed;
|
|
101843
|
+
try {
|
|
101844
|
+
parsed = JSON.parse(raw);
|
|
101845
|
+
} catch (error) {
|
|
101846
|
+
throw new ThemeFileError(
|
|
101847
|
+
`\`${path}\` is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
101848
|
+
);
|
|
101849
|
+
}
|
|
101850
|
+
let spec;
|
|
101851
|
+
try {
|
|
101852
|
+
spec = resolveThemeSpec(parsed);
|
|
101853
|
+
} catch (error) {
|
|
101854
|
+
if (error instanceof ThemeSpecError) throw new ThemeFileError(`\`${path}\`: ${error.message}`);
|
|
101855
|
+
throw error;
|
|
101856
|
+
}
|
|
101857
|
+
const name = (path.split(/[\\/]/).pop() ?? path).replace(/\.json$/i, "");
|
|
101858
|
+
if (!name) throw new ThemeFileError(`\`${path}\` has no usable theme name`);
|
|
101859
|
+
return { name, spec };
|
|
101860
|
+
}
|
|
101861
|
+
var ThemeFileError;
|
|
101862
|
+
var init_theme_file = __esm({
|
|
101863
|
+
"src/theme-file.ts"() {
|
|
101864
|
+
"use strict";
|
|
101865
|
+
init_theme_spec();
|
|
101866
|
+
ThemeFileError = class extends Error {
|
|
101867
|
+
};
|
|
101868
|
+
}
|
|
101869
|
+
});
|
|
101870
|
+
|
|
101871
|
+
// src/notice.ts
|
|
101872
|
+
function notice({ bun = embedsBun() } = {}) {
|
|
101873
|
+
return COMMON + (bun ? BUN_NOTICE : "") + "\n" + FOOTER;
|
|
101874
|
+
}
|
|
101875
|
+
var ELKJS_VERSION, SIMPLE_ICONS_VERSION, BUN_VERSION, NOTICES_URL, COMMON, BUN_NOTICE, FOOTER, embedsBun;
|
|
101876
|
+
var init_notice = __esm({
|
|
101877
|
+
"src/notice.ts"() {
|
|
101878
|
+
"use strict";
|
|
101879
|
+
ELKJS_VERSION = "0.12.0";
|
|
101880
|
+
SIMPLE_ICONS_VERSION = "16.29.0";
|
|
101881
|
+
BUN_VERSION = "1.4.0";
|
|
101882
|
+
NOTICES_URL = "https://github.com/R0kshan/cairn/blob/main/THIRD-PARTY-NOTICES.md";
|
|
101883
|
+
COMMON = `cairn \u2014 Apache-2.0 \u2014 https://github.com/R0kshan/cairn
|
|
101884
|
+
Copyright 2026 R\xF8kshan.
|
|
101885
|
+
|
|
101886
|
+
This artifact contains third-party code and artwork:
|
|
101887
|
+
|
|
101888
|
+
elkjs ${ELKJS_VERSION} \u2014 (c) 2017 Kiel University and others.
|
|
101889
|
+
Dual-licensed EPL-2.0 OR GPL-3.0-or-later; cairn elects EPL-2.0.
|
|
101890
|
+
Full text: licenses/elkjs-EPL-2.0.md \u2014 https://www.eclipse.org/legal/epl-2.0
|
|
101891
|
+
|
|
101892
|
+
Simple Icons ${SIMPLE_ICONS_VERSION} artwork \u2014 CC0-1.0 project-wide.
|
|
101893
|
+
Six of the vendored icons carry their own terms instead \u2014 MIT,
|
|
101894
|
+
BSD-3-Clause, CC-BY-4.0 or Apache-2.0 \u2014 and are attributed individually.
|
|
101895
|
+
Full texts: licenses/`;
|
|
101896
|
+
BUN_NOTICE = `
|
|
101897
|
+
|
|
101898
|
+
Bun ${BUN_VERSION} runtime \u2014 MIT \u2014 embedded by \`bun build --compile\`.
|
|
101899
|
+
It statically links JavaScriptCore/WebKit, which is LGPL-2.1 in part,
|
|
101900
|
+
alongside BSD- and Apache-licensed components. Bun's own LICENSE.md
|
|
101901
|
+
enumerates all of them verbatim: licenses/bun-LICENSE.md
|
|
101902
|
+
Relinking under LGPL-2.1 \xA76: see THIRD-PARTY-NOTICES.md.`;
|
|
101903
|
+
FOOTER = `
|
|
101904
|
+
Per-icon attribution and the full licence texts ship with this artifact:
|
|
101905
|
+
the package root (npm), the app directory (Scoop), or
|
|
101906
|
+
share/doc/cairn (Homebrew, install.sh). Also at
|
|
101907
|
+
${NOTICES_URL}`;
|
|
101908
|
+
embedsBun = () => typeof CAIRN_EMBEDS_BUN !== "undefined" && CAIRN_EMBEDS_BUN;
|
|
101053
101909
|
}
|
|
101054
101910
|
});
|
|
101055
101911
|
|
|
101056
101912
|
// src/cli.ts
|
|
101057
101913
|
var cli_exports = {};
|
|
101058
|
-
import { readFileSync as
|
|
101914
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "node:fs";
|
|
101059
101915
|
function usage() {
|
|
101060
101916
|
console.log(`cairn \u2014 architecture diagrams as code
|
|
101061
101917
|
|
|
101062
101918
|
Usage:
|
|
101063
|
-
cairn new (--logical-architecture|-L|-A|-I
|
|
101919
|
+
cairn new (--logical-architecture|-L|-A|-I) <file.cairn> scaffold a typed template
|
|
101064
101920
|
(-L logical, -A application,
|
|
101065
|
-
-I infrastructure
|
|
101921
|
+
-I infrastructure)
|
|
101066
101922
|
cairn validate <file.cairn> [--format json] [--strict]
|
|
101067
|
-
cairn build <file.cairn> [-o output.svg]
|
|
101068
|
-
cairn matrix <file.cairn> [--format csv|md|svg] [-o out]
|
|
101923
|
+
cairn build <file.cairn> [-o output.svg] [--theme <name|file.json>]
|
|
101924
|
+
cairn matrix <file.cairn> [--format csv|md|svg] [-o out] [--theme <name|file.json>]
|
|
101925
|
+
matrice des flux techniques
|
|
101069
101926
|
(default csv; honors style { lang })
|
|
101070
|
-
cairn watch <file.cairn> [-o output.svg]
|
|
101927
|
+
cairn watch <file.cairn> [-o output.svg] [--theme <name|file.json>]
|
|
101928
|
+
rebuild on save; SVG stays fresh
|
|
101071
101929
|
(error panel on failure) for an
|
|
101072
101930
|
editor auto-refresh preview
|
|
101073
101931
|
cairn explain <code> rule rationale (e.g. E0203)
|
|
101932
|
+
cairn logos list the built-in \`logo:\` names
|
|
101933
|
+
cairn themes list the built-in theme names
|
|
101074
101934
|
cairn version | --version | -v print the installed version
|
|
101935
|
+
cairn version --licenses third-party notices this build carries
|
|
101075
101936
|
`);
|
|
101076
101937
|
process.exit(2);
|
|
101077
101938
|
}
|
|
@@ -101080,7 +101941,7 @@ function loadAndCheck(file) {
|
|
|
101080
101941
|
console.error(`error: file not found \`${file}\``);
|
|
101081
101942
|
process.exit(2);
|
|
101082
101943
|
}
|
|
101083
|
-
const src =
|
|
101944
|
+
const src = readFileSync3(file, "utf8");
|
|
101084
101945
|
const { model, diags } = parse(src);
|
|
101085
101946
|
diags.push(...validate(model));
|
|
101086
101947
|
return { src, model, diagnostics: diags };
|
|
@@ -101111,13 +101972,41 @@ function densityReport(disposition, scene, typeSpan) {
|
|
|
101111
101972
|
}
|
|
101112
101973
|
};
|
|
101113
101974
|
}
|
|
101975
|
+
function themeFromArgs() {
|
|
101976
|
+
const index = args.indexOf("--theme");
|
|
101977
|
+
if (index === -1) return void 0;
|
|
101978
|
+
const value = args[index + 1];
|
|
101979
|
+
if (!value || value.startsWith("-")) {
|
|
101980
|
+
console.error("error: `--theme` needs a theme name or a path to a .json theme file");
|
|
101981
|
+
process.exit(2);
|
|
101982
|
+
}
|
|
101983
|
+
if (!value.toLowerCase().endsWith(".json")) {
|
|
101984
|
+
if (!themeNames.includes(value)) {
|
|
101985
|
+
console.error(
|
|
101986
|
+
`error: unknown theme \`${value}\`
|
|
101987
|
+
available: ${themeNames.join(", ")}
|
|
101988
|
+
or pass a path to a .json theme file`
|
|
101989
|
+
);
|
|
101990
|
+
process.exit(2);
|
|
101991
|
+
}
|
|
101992
|
+
return value;
|
|
101993
|
+
}
|
|
101994
|
+
try {
|
|
101995
|
+
const { name, spec } = loadThemeFile(value);
|
|
101996
|
+
registerTheme(name, spec);
|
|
101997
|
+
return name;
|
|
101998
|
+
} catch (error) {
|
|
101999
|
+
console.error(`error: ${error instanceof Error ? error.message : String(error)}`);
|
|
102000
|
+
process.exit(2);
|
|
102001
|
+
}
|
|
102002
|
+
}
|
|
101114
102003
|
function exitIfErrors(file, src, diagnostics) {
|
|
101115
102004
|
if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
101116
102005
|
console.error(renderHuman(file, src, diagnostics, process.stderr.isTTY ?? false));
|
|
101117
102006
|
process.exit(1);
|
|
101118
102007
|
}
|
|
101119
102008
|
}
|
|
101120
|
-
var TYPE_FLAGS, TEMPLATE_LOGICAL, TEMPLATE_APPLICATION, TEMPLATE_INFRASTRUCTURE,
|
|
102009
|
+
var TYPE_FLAGS, TEMPLATE_LOGICAL, TEMPLATE_APPLICATION, TEMPLATE_INFRASTRUCTURE, TEMPLATES, args, command, version, VALUE_FLAGS, positionalFile, PRINT_FRAMES;
|
|
101121
102010
|
var init_cli = __esm({
|
|
101122
102011
|
"src/cli.ts"() {
|
|
101123
102012
|
"use strict";
|
|
@@ -101130,15 +102019,18 @@ var init_cli = __esm({
|
|
|
101130
102019
|
init_views();
|
|
101131
102020
|
init_ast();
|
|
101132
102021
|
init_watch();
|
|
102022
|
+
init_logo_files();
|
|
102023
|
+
init_theme_file();
|
|
102024
|
+
init_themes();
|
|
102025
|
+
init_logos();
|
|
102026
|
+
init_notice();
|
|
101133
102027
|
TYPE_FLAGS = {
|
|
101134
102028
|
"--logical-architecture": "logical",
|
|
101135
102029
|
"-L": "logical",
|
|
101136
102030
|
"--application-architecture": "application",
|
|
101137
102031
|
"-A": "application",
|
|
101138
102032
|
"--infrastructure-architecture": "infrastructure",
|
|
101139
|
-
"-I": "infrastructure"
|
|
101140
|
-
"--security-architecture": "security",
|
|
101141
|
-
"-S": "security"
|
|
102033
|
+
"-I": "infrastructure"
|
|
101142
102034
|
};
|
|
101143
102035
|
TEMPLATE_LOGICAL = `diagram logical "Diagram title"
|
|
101144
102036
|
|
|
@@ -101259,45 +102151,16 @@ CORE_I -> PARTNER : "Nightly export" (SFTP/22)
|
|
|
101259
102151
|
# Export the flow matrix beside the physical diagram (French DA deliverable):
|
|
101260
102152
|
# cairn matrix this-file.cairn --format csv # or md | svg
|
|
101261
102153
|
# Add \`style { lang: fr }\` above to get French column headers (N\xB0, Protocole\u2026).
|
|
101262
|
-
`;
|
|
101263
|
-
TEMPLATE_SECURITY = `diagram security "Diagram title"
|
|
101264
|
-
|
|
101265
|
-
# A security diagram shows trust zones (each with a sensitivity level), the
|
|
101266
|
-
# filtering/security nodes between them, and the sensitive assets they protect.
|
|
101267
|
-
# Zones band left\u2192right in declaration order (most exposed \u2192 most protected).
|
|
101268
|
-
# Levels, least\u2192most trusted: public | internal | restricted | secret.
|
|
101269
|
-
|
|
101270
|
-
trust-zone INTERNET "Internet" (public) {
|
|
101271
|
-
security-node WAF "WAF / reverse proxy"
|
|
101272
|
-
}
|
|
101273
|
-
|
|
101274
|
-
trust-zone LAN "Internal zone" (internal) {
|
|
101275
|
-
asset APP "Business application"
|
|
101276
|
-
}
|
|
101277
|
-
|
|
101278
|
-
trust-zone DATA "Data zone" (restricted) {
|
|
101279
|
-
asset DB "Customer database"
|
|
101280
|
-
}
|
|
101281
|
-
|
|
101282
|
-
external USERS "End users"
|
|
101283
|
-
|
|
101284
|
-
# ---- security flows (cross-zone flows should be filtered + encrypted) ----
|
|
101285
|
-
USERS -> WAF : "HTTPS access" (TLS1.3)
|
|
101286
|
-
WAF -> APP : "Filtered traffic" (mTLS)
|
|
101287
|
-
APP -> DB : "Read/write" (TLS1.3)
|
|
101288
|
-
|
|
101289
|
-
# W0560 warns on any flow entering a more-trusted zone without a security-node.
|
|
101290
102154
|
`;
|
|
101291
102155
|
TEMPLATES = {
|
|
101292
102156
|
logical: TEMPLATE_LOGICAL,
|
|
101293
102157
|
application: TEMPLATE_APPLICATION,
|
|
101294
|
-
infrastructure: TEMPLATE_INFRASTRUCTURE
|
|
101295
|
-
security: TEMPLATE_SECURITY
|
|
102158
|
+
infrastructure: TEMPLATE_INFRASTRUCTURE
|
|
101296
102159
|
};
|
|
101297
102160
|
args = process.argv.slice(2);
|
|
101298
102161
|
command = args[0];
|
|
101299
|
-
version = true ? "1.0.0-
|
|
101300
|
-
VALUE_FLAGS = /* @__PURE__ */ new Set(["-o", "--format"]);
|
|
102162
|
+
version = true ? "1.0.0-RC14" : pkg.version;
|
|
102163
|
+
VALUE_FLAGS = /* @__PURE__ */ new Set(["-o", "--format", "--theme"]);
|
|
101301
102164
|
positionalFile = () => {
|
|
101302
102165
|
for (let index = 0; index < args.length; index++) {
|
|
101303
102166
|
const arg = args[index];
|
|
@@ -101315,7 +102178,24 @@ APP -> DB : "Read/write" (TLS1.3)
|
|
|
101315
102178
|
page: { width: 700, height: 1e3, name: "A4 page" }
|
|
101316
102179
|
};
|
|
101317
102180
|
if (command === "version" || command === "--version" || command === "-v") {
|
|
101318
|
-
|
|
102181
|
+
const LICENCE_FLAGS = /* @__PURE__ */ new Set(["--licenses", "--licences"]);
|
|
102182
|
+
const unknown = args.slice(1).filter((arg) => arg.startsWith("-") && !LICENCE_FLAGS.has(arg));
|
|
102183
|
+
if (unknown.length) {
|
|
102184
|
+
console.error(
|
|
102185
|
+
`unknown flag${unknown.length > 1 ? "s" : ""} for \`cairn version\`: ${unknown.join(", ")}
|
|
102186
|
+
the only one it takes is \`--licenses\` (third-party notices for this build)`
|
|
102187
|
+
);
|
|
102188
|
+
process.exit(2);
|
|
102189
|
+
}
|
|
102190
|
+
if (args.some((arg) => LICENCE_FLAGS.has(arg))) {
|
|
102191
|
+
console.log(`cairn v${version}
|
|
102192
|
+
`);
|
|
102193
|
+
console.log(notice());
|
|
102194
|
+
} else {
|
|
102195
|
+
console.log(`cairn v${version}`);
|
|
102196
|
+
if (process.stdout.isTTY)
|
|
102197
|
+
console.log("Apache-2.0, and bundles third-party code \u2014 `cairn version --licenses`");
|
|
102198
|
+
}
|
|
101319
102199
|
} else if (command === "validate") {
|
|
101320
102200
|
const file = positionalFile();
|
|
101321
102201
|
if (!file) usage();
|
|
@@ -101332,12 +102212,16 @@ APP -> DB : "Read/write" (TLS1.3)
|
|
|
101332
102212
|
} else if (command === "build") {
|
|
101333
102213
|
const file = positionalFile();
|
|
101334
102214
|
if (!file) usage();
|
|
102215
|
+
const themeOverride = themeFromArgs();
|
|
101335
102216
|
const outFile = resolveOutputPath(file, ".svg");
|
|
101336
102217
|
const { src, model, diagnostics } = loadAndCheck(file);
|
|
101337
102218
|
exitIfErrors(file, src, diagnostics);
|
|
102219
|
+
if (themeOverride) model.style.theme = themeOverride;
|
|
101338
102220
|
const view = views[model.type];
|
|
101339
102221
|
layout(model, view).then((scene) => {
|
|
101340
|
-
const {
|
|
102222
|
+
const { logos, diagnostics: logoDiagnostics } = resolveLogoFiles(model, file);
|
|
102223
|
+
diagnostics.push(...logoDiagnostics);
|
|
102224
|
+
const { svg, overlapsBefore, overlapsAfter } = render(model, view, scene, { logos });
|
|
101341
102225
|
writeFileSync2(outFile, svg);
|
|
101342
102226
|
const { fitInfo, diagnostic } = densityReport(
|
|
101343
102227
|
model.style.disposition,
|
|
@@ -101360,6 +102244,7 @@ APP -> DB : "Read/write" (TLS1.3)
|
|
|
101360
102244
|
} else if (command === "matrix") {
|
|
101361
102245
|
const file = positionalFile();
|
|
101362
102246
|
if (!file) usage();
|
|
102247
|
+
const themeOverride = themeFromArgs();
|
|
101363
102248
|
const formatIndex = args.indexOf("--format");
|
|
101364
102249
|
const format = formatIndex >= 0 ? args[formatIndex + 1] : "csv";
|
|
101365
102250
|
if (!["csv", "md", "svg"].includes(format)) {
|
|
@@ -101372,6 +102257,7 @@ APP -> DB : "Read/write" (TLS1.3)
|
|
|
101372
102257
|
console.error(`error: \`${file}\` declares no flows \u2014 nothing to tabulate`);
|
|
101373
102258
|
process.exit(1);
|
|
101374
102259
|
}
|
|
102260
|
+
if (themeOverride) model.style.theme = themeOverride;
|
|
101375
102261
|
const ext = format === "svg" ? "svg" : format === "md" ? "md" : "csv";
|
|
101376
102262
|
const outFile = resolveOutputPath(file, ".flow." + ext);
|
|
101377
102263
|
const lang = model.style.lang;
|
|
@@ -101384,7 +102270,7 @@ APP -> DB : "Read/write" (TLS1.3)
|
|
|
101384
102270
|
} else if (command === "watch") {
|
|
101385
102271
|
const file = positionalFile();
|
|
101386
102272
|
if (!file) usage();
|
|
101387
|
-
watchCommand(file, resolveOutputPath(file, ".svg"));
|
|
102273
|
+
watchCommand(file, resolveOutputPath(file, ".svg"), themeFromArgs());
|
|
101388
102274
|
} else if (command === "new") {
|
|
101389
102275
|
const type = args.map((arg) => TYPE_FLAGS[arg]).find(Boolean);
|
|
101390
102276
|
const file = positionalFile();
|
|
@@ -101408,6 +102294,25 @@ APP -> DB : "Read/write" (TLS1.3)
|
|
|
101408
102294
|
console.log(
|
|
101409
102295
|
`\u2713 ${file} created (${type} view) \u2014 fill in the sections, then run \`cairn validate ${file}\``
|
|
101410
102296
|
);
|
|
102297
|
+
} else if (command === "logos") {
|
|
102298
|
+
const width = LOGO_NAMES.reduce((widest, name) => Math.max(widest, name.length), 0) + 2;
|
|
102299
|
+
const perLine = Math.max(1, Math.floor(78 / width));
|
|
102300
|
+
console.log(`${LOGO_NAMES.length} built-in logos \u2014 use as \`logo: <name>\` on an element:
|
|
102301
|
+
`);
|
|
102302
|
+
for (let index = 0; index < LOGO_NAMES.length; index += perLine)
|
|
102303
|
+
console.log(
|
|
102304
|
+
" " + LOGO_NAMES.slice(index, index + perLine).map((n) => n.padEnd(width)).join("").trimEnd()
|
|
102305
|
+
);
|
|
102306
|
+
console.log('\nAnything else: point at a file \u2014 `logo: "./logos/name.svg"`.');
|
|
102307
|
+
} else if (command === "themes") {
|
|
102308
|
+
console.log(
|
|
102309
|
+
`${themeNames.length} built-in themes \u2014 \`--theme <name>\`, or \`style { theme: \u2026 }\`:
|
|
102310
|
+
`
|
|
102311
|
+
);
|
|
102312
|
+
for (const name of themeNames) console.log(` ${name}`);
|
|
102313
|
+
console.log(
|
|
102314
|
+
'\nFor your own colours, pass a JSON file instead \u2014 `--theme ./my-theme.json`.\nIt extends a built-in and overrides only what it names:\n\n { "extends": "dark", "pal": { "bg": "#0d1117" } }\n'
|
|
102315
|
+
);
|
|
101411
102316
|
} else if (command === "explain") {
|
|
101412
102317
|
const code = args[1];
|
|
101413
102318
|
if (!code) usage();
|