@buun_group/plotwork-mcp 0.1.0-beta.5 → 0.1.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/package.json +1 -1
- package/plotwork-mcp.mjs +2318 -1151
package/plotwork-mcp.mjs
CHANGED
|
@@ -51,7 +51,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
51
51
|
var package_default;
|
|
52
52
|
var init_package = __esm({
|
|
53
53
|
"package.json"() {
|
|
54
|
-
package_default = { version: "0.1.0-beta.
|
|
54
|
+
package_default = { version: "0.1.0-beta.6" };
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
|
|
@@ -643,7 +643,7 @@ var init_view_links = __esm({
|
|
|
643
643
|
};
|
|
644
644
|
CLI_RELEASE = {
|
|
645
645
|
packageName: "@buun_group/plotwork",
|
|
646
|
-
version: "0.1.0-beta.
|
|
646
|
+
version: "0.1.0-beta.7",
|
|
647
647
|
onNpm: true
|
|
648
648
|
};
|
|
649
649
|
}
|
|
@@ -662,7 +662,7 @@ var init_mcp_release = __esm({
|
|
|
662
662
|
"use strict";
|
|
663
663
|
MCP_RELEASE = {
|
|
664
664
|
packageName: "@buun_group/plotwork-mcp",
|
|
665
|
-
version: "0.1.0-beta.
|
|
665
|
+
version: "0.1.0-beta.5"
|
|
666
666
|
};
|
|
667
667
|
}
|
|
668
668
|
});
|
|
@@ -6919,6 +6919,53 @@ var init_icons = __esm({
|
|
|
6919
6919
|
}
|
|
6920
6920
|
});
|
|
6921
6921
|
|
|
6922
|
+
// ../../packages/diagrams/src/importers/guide.ts
|
|
6923
|
+
function importFormatGuide(formats) {
|
|
6924
|
+
return formats.map((format) => ({ format, ...GUIDE[format] }));
|
|
6925
|
+
}
|
|
6926
|
+
var GUIDE;
|
|
6927
|
+
var init_guide = __esm({
|
|
6928
|
+
"../../packages/diagrams/src/importers/guide.ts"() {
|
|
6929
|
+
"use strict";
|
|
6930
|
+
GUIDE = {
|
|
6931
|
+
sql: { reads: "CREATE TABLE and ALTER TABLE of Postgres, MySQL, and SQLite; a migration history is applied in order.", draws: "schema", options: "tables: names or prefix* to draw." },
|
|
6932
|
+
prisma: { reads: "schema.prisma models and their relations.", draws: "schema", options: "tables." },
|
|
6933
|
+
drizzle: { reads: "pgTable, sqliteTable, and mysqlTable calls, as text.", draws: "schema", options: "tables." },
|
|
6934
|
+
openapi: { reads: "An OpenAPI 3 document in JSON or YAML.", draws: "matrix of endpoints against schemes, scopes, and roles (view endpoints), tree by tag (view map), or sequence of one operation (view sequence)", options: "view; operationId for view sequence; paths and tags to read part of it." },
|
|
6935
|
+
terraform: { reads: "The .tf and .tfvars files of a stack with its local modules and environments; send every file in files.", draws: "flow framed by module, nested in groups, networks, and subnets", options: "groupBy module, network, or file; root: the root module of several (envs/prod); varFiles." },
|
|
6936
|
+
"terraform-plan": { reads: "The JSON of terraform show -json for a plan or a state, or a raw terraform.tfstate.", draws: "flow as terraform, with planned changes as tones and words", options: "groupBy." },
|
|
6937
|
+
bicep: { reads: ".bicep files with their modules, and .bicepparam values.", draws: "flow as terraform", options: "groupBy; root; varFiles: the .bicepparam file." },
|
|
6938
|
+
arm: { reads: "An ARM template and its parameters file.", draws: "flow as terraform", options: "groupBy; varFiles: the parameters file." },
|
|
6939
|
+
pulumi: { reads: "A Pulumi YAML program with Pulumi.<stack>.yaml, or pulumi stack export or pulumi preview --json of any language.", draws: "flow as terraform, components as frames", options: "groupBy; root; varFiles: the stack file." },
|
|
6940
|
+
cloudformation: { reads: "A CloudFormation or SAM template in YAML or JSON.", draws: "flow as terraform", options: "groupBy; root: one template of several." },
|
|
6941
|
+
cdk: { reads: "The cdk.out folder cdk synth writes (manifest.json, tree.json, templates, nested stacks), or one template it prints.", draws: "flow as cloudformation, stacks, nested stacks, and constructs as frames", options: "root: one stack of several." },
|
|
6942
|
+
compose: { reads: "A Docker Compose file.", draws: "flow of services, networks, and named volumes", options: "none." },
|
|
6943
|
+
kubernetes: { reads: "Multi-document manifests; send a folder of them in files.", draws: "flow of workloads, Services, Ingresses, ConfigMaps, Secrets, and claims, namespaces as frames", options: "none." },
|
|
6944
|
+
helm: { reads: "The output of helm template, or a chart folder (Chart.yaml, charts/, Chart.lock, values.yaml).", draws: "flow as kubernetes framed by release and chart, or a flow of charts and their dependencies", options: "none." },
|
|
6945
|
+
kustomize: { reads: "The output of kustomize build, or a folder of kustomization.yaml files with what they list.", draws: "flow as kubernetes, or a flow of overlays, bases, and components", options: "none." },
|
|
6946
|
+
backstage: { reads: "Backstage catalog descriptors (catalog-info.yaml), one file or a folder.", draws: "flow of components, APIs, and resources in systems and domains", options: "groupBy owner: frame by the owning group instead." },
|
|
6947
|
+
"github-actions": { reads: "A GitHub Actions workflow file.", draws: "flow of the trigger, the jobs in needs order, and their steps", options: "none." },
|
|
6948
|
+
csv: { reads: "A CSV, TSV, or semicolon-separated table.", draws: "the chart its shape suits: xychart, pie, sankey, treemap, or matrix", options: "chart: auto or one of those." },
|
|
6949
|
+
json: { reads: "Records, rows, a name to number object, or nested objects of numbers.", draws: "the same charts as csv", options: "chart." },
|
|
6950
|
+
tree: { reads: "tree output, a list of paths, or an indented outline.", draws: "tree", options: "none." },
|
|
6951
|
+
"git-log": { reads: "git log --oneline --graph --decorate, plain git log, or --oneline.", draws: "git graph (view git) or timeline (view timeline)", options: "view." }
|
|
6952
|
+
};
|
|
6953
|
+
}
|
|
6954
|
+
});
|
|
6955
|
+
|
|
6956
|
+
// ../../packages/diagrams/src/importers/types.ts
|
|
6957
|
+
var IMPORT_FORMATS, IMPORT_VIEWS, IMPORT_CHARTS, IMPORT_GROUP_BY, NO_STATS;
|
|
6958
|
+
var init_types2 = __esm({
|
|
6959
|
+
"../../packages/diagrams/src/importers/types.ts"() {
|
|
6960
|
+
"use strict";
|
|
6961
|
+
IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "cdk", "compose", "kubernetes", "helm", "kustomize", "backstage", "github-actions", "csv", "json", "tree", "git-log"];
|
|
6962
|
+
IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline"];
|
|
6963
|
+
IMPORT_CHARTS = ["auto", "xychart", "pie", "sankey", "treemap", "matrix"];
|
|
6964
|
+
IMPORT_GROUP_BY = ["module", "network", "file", "owner"];
|
|
6965
|
+
NO_STATS = { items: 0, links: 0, groups: 0, dropped: 0 };
|
|
6966
|
+
}
|
|
6967
|
+
});
|
|
6968
|
+
|
|
6922
6969
|
// ../../packages/diagrams/src/parse/layout-budget.ts
|
|
6923
6970
|
function checkLayoutBudget(diagram, at3) {
|
|
6924
6971
|
const { maxFlowNodes, maxLayerCrossings } = LAYOUT_LIMITS;
|
|
@@ -115955,9 +116002,9 @@ function readAttributes(text3, startAt) {
|
|
|
115955
116002
|
let colon = end;
|
|
115956
116003
|
while (colon < text3.length && isSpace3(text3.charAt(colon))) colon += 1;
|
|
115957
116004
|
if (end === at3 || text3.charAt(colon) !== ":") return { attributes: attributes2, leftover: text3.slice(at3).trim(), leftoverAt: at3 };
|
|
115958
|
-
let
|
|
115959
|
-
while (
|
|
115960
|
-
const read = readValue(text3,
|
|
116005
|
+
let valueAt3 = colon + 1;
|
|
116006
|
+
while (valueAt3 < text3.length && isSpace3(text3.charAt(valueAt3))) valueAt3 += 1;
|
|
116007
|
+
const read = readValue(text3, valueAt3);
|
|
115961
116008
|
attributes2.push({ key: text3.slice(at3, end).toLowerCase(), value: read.value, column: at3 + 1 });
|
|
115962
116009
|
at3 = read.end;
|
|
115963
116010
|
}
|
|
@@ -139121,8 +139168,19 @@ function kindOf(full, detail) {
|
|
|
139121
139168
|
examples: full.examples.filter((example) => example.kind === detail.kind)
|
|
139122
139169
|
};
|
|
139123
139170
|
}
|
|
139124
|
-
function
|
|
139171
|
+
function importFormatsOf(full) {
|
|
139172
|
+
return {
|
|
139173
|
+
answer: "import-formats",
|
|
139174
|
+
howToGetAKind: "This is the topic import-formats: every format import_source reads, what it reads, the diagram it draws, and the options it takes. Send a file's text, or every file of a folder in files, to import_source with its format. Call get_diagram_syntax with no kind and no topic for the language.",
|
|
139175
|
+
kinds: full.kinds,
|
|
139176
|
+
kindDetails: [],
|
|
139177
|
+
examples: [],
|
|
139178
|
+
importFormats: importFormatGuide(IMPORT_FORMATS)
|
|
139179
|
+
};
|
|
139180
|
+
}
|
|
139181
|
+
function buildSyntax(kind, topic) {
|
|
139125
139182
|
const full = buildVocabulary();
|
|
139183
|
+
if (topic === "import-formats") return importFormatsOf(full);
|
|
139126
139184
|
const detail = full.kindDetails.find((entry2) => entry2.kind === kind);
|
|
139127
139185
|
return detail === void 0 ? overviewOf(full) : kindOf(full, detail);
|
|
139128
139186
|
}
|
|
@@ -139133,6 +139191,8 @@ var init_build_vocabulary = __esm({
|
|
|
139133
139191
|
init_constants();
|
|
139134
139192
|
init_core();
|
|
139135
139193
|
init_icons();
|
|
139194
|
+
init_guide();
|
|
139195
|
+
init_types2();
|
|
139136
139196
|
init_registry2();
|
|
139137
139197
|
init_theme();
|
|
139138
139198
|
init_examples_generated();
|
|
@@ -178041,19 +178101,6 @@ var init_schema3 = __esm({
|
|
|
178041
178101
|
}
|
|
178042
178102
|
});
|
|
178043
178103
|
|
|
178044
|
-
// ../../packages/diagrams/src/importers/types.ts
|
|
178045
|
-
var IMPORT_FORMATS, IMPORT_VIEWS, IMPORT_CHARTS, IMPORT_GROUP_BY, NO_STATS;
|
|
178046
|
-
var init_types2 = __esm({
|
|
178047
|
-
"../../packages/diagrams/src/importers/types.ts"() {
|
|
178048
|
-
"use strict";
|
|
178049
|
-
IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "csv", "json", "tree", "git-log"];
|
|
178050
|
-
IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline"];
|
|
178051
|
-
IMPORT_CHARTS = ["auto", "xychart", "pie", "sankey", "treemap", "matrix"];
|
|
178052
|
-
IMPORT_GROUP_BY = ["module", "network", "file"];
|
|
178053
|
-
NO_STATS = { items: 0, links: 0, groups: 0, dropped: 0 };
|
|
178054
|
-
}
|
|
178055
|
-
});
|
|
178056
|
-
|
|
178057
178104
|
// ../../packages/diagrams/src/settings/sources.ts
|
|
178058
178105
|
var repositoryPath, pattern2, outPath, SourceOptionsSchema, SourcePublishSchema, SourceSchema;
|
|
178059
178106
|
var init_sources = __esm({
|
|
@@ -178074,9 +178121,9 @@ var init_sources = __esm({
|
|
|
178074
178121
|
tables: external_exports.array(external_exports.string().min(1).max(200)).max(200).optional().describe("sql, prisma and drizzle: the tables to draw, each a name or a prefix ending in * (org_*)."),
|
|
178075
178122
|
paths: external_exports.array(external_exports.string().min(1).max(200)).max(200).optional().describe("openapi: the path prefixes to read, such as /orders."),
|
|
178076
178123
|
tags: external_exports.array(external_exports.string().min(1).max(200)).max(200).optional().describe("openapi: the tags to read."),
|
|
178077
|
-
groupBy: external_exports.enum(IMPORT_GROUP_BY).optional().describe("terraform, bicep, arm, pulumi, cloudformation: module (the default) frames each module's resources and nests them by what they name; network nests by what they name alone; file (terraform) frames them by their .tf file."),
|
|
178124
|
+
groupBy: external_exports.enum(IMPORT_GROUP_BY).optional().describe("terraform, bicep, arm, pulumi, cloudformation, cdk: module (the default) frames each module's resources and nests them by what they name; network nests by what they name alone; file (terraform) frames them by their .tf file; owner (backstage) frames a catalog by the group that owns each entity."),
|
|
178078
178125
|
varFiles: external_exports.array(repositoryPath).max(20).optional().describe("terraform: the variables files to apply, as -var-file would; bicep: the .bicepparam file; arm: the parameters file; pulumi: the Pulumi.<stack>.yaml file."),
|
|
178079
|
-
root: repositoryPath.optional().describe("terraform, bicep, pulumi, cloudformation: the root module, deployment, program, or
|
|
178126
|
+
root: repositoryPath.optional().describe("terraform, bicep, pulumi, cloudformation, cdk: the root module, deployment, program, template, or stack to draw when the files hold several, such as envs/prod; each is a part of its own when left out.")
|
|
178080
178127
|
}).meta({ id: "SourceOptions", description: "The reader options of one source, as import_source takes them." });
|
|
178081
178128
|
SourcePublishSchema = external_exports.strictObject({
|
|
178082
178129
|
alias: external_exports.string().min(1).max(60).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "An alias is lower-case words joined by single hyphens, such as checkout-flow").optional().describe("A stable link of a personal key: one address that always shows the latest version."),
|
|
@@ -178418,7 +178465,7 @@ var init_icons2 = __esm({
|
|
|
178418
178465
|
});
|
|
178419
178466
|
|
|
178420
178467
|
// ../../packages/diagrams/src/schemas/vocabulary.ts
|
|
178421
|
-
var NodeTypeSchema, StatusIconSchema, ExampleSchema, GroupTypeSchema, GroupSchema, OverlaySchema, IconProviderSchema, LabelIconSchema, AutoIconsSchema, ArrowSchema, LineOptionSchema, KindStatementSchema, KindLimitSchema, KindDetailsSchema, DiagnosticCodeEntrySchema, VocabularyResponseSchema, SyntaxKindSchema, SyntaxQuerySchema, SyntaxInputSchema, SyntaxKindDetailsSchema, SyntaxTablesSchema, SyntaxResponseSchema;
|
|
178468
|
+
var NodeTypeSchema, StatusIconSchema, ExampleSchema, GroupTypeSchema, GroupSchema, OverlaySchema, IconProviderSchema, LabelIconSchema, AutoIconsSchema, ArrowSchema, LineOptionSchema, KindStatementSchema, KindLimitSchema, KindDetailsSchema, DiagnosticCodeEntrySchema, VocabularyResponseSchema, SyntaxKindSchema, SYNTAX_TOPICS, SyntaxTopicSchema, SyntaxQuerySchema, SyntaxInputSchema, SyntaxKindDetailsSchema, SyntaxTablesSchema, SyntaxResponseSchema;
|
|
178422
178469
|
var init_vocabulary18 = __esm({
|
|
178423
178470
|
"../../packages/diagrams/src/schemas/vocabulary.ts"() {
|
|
178424
178471
|
"use strict";
|
|
@@ -178557,21 +178604,24 @@ var init_vocabulary18 = __esm({
|
|
|
178557
178604
|
examples: external_exports.array(ExampleSchema)
|
|
178558
178605
|
}).meta({ id: "VocabularyResponse", description: "The diagram language: kinds, node types, arrows, flags, error codes, limits, and examples." });
|
|
178559
178606
|
SyntaxKindSchema = external_exports.enum(BUILT_KINDS).optional().describe("The one kind to read in full. Omit it for the overview: the language every kind shares and one line about each kind.");
|
|
178560
|
-
|
|
178561
|
-
|
|
178607
|
+
SYNTAX_TOPICS = ["import-formats"];
|
|
178608
|
+
SyntaxTopicSchema = external_exports.enum(SYNTAX_TOPICS).optional().describe("import-formats: what import_source reads, draws, and takes, a line each.");
|
|
178609
|
+
SyntaxQuerySchema = external_exports.object({ kind: SyntaxKindSchema, topic: SyntaxTopicSchema }).meta({ id: "SyntaxQuery", description: "The kind to read in full, or none for the overview, or a topic." });
|
|
178610
|
+
SyntaxInputSchema = external_exports.object({ kind: SyntaxKindSchema, topic: SyntaxTopicSchema }).strict();
|
|
178562
178611
|
SyntaxKindDetailsSchema = KindDetailsSchema.partial({ statements: true, limits: true }).extend({
|
|
178563
178612
|
more: external_exports.string().optional().describe("Only in the overview, where statements and limits are left out: what a call with this kind returns that the overview does not, and how to ask for it.")
|
|
178564
178613
|
});
|
|
178565
178614
|
SyntaxTablesSchema = VocabularyResponseSchema.omit({ kinds: true, kindDetails: true, examples: true }).partial();
|
|
178566
178615
|
SyntaxResponseSchema = external_exports.object({
|
|
178567
178616
|
answer: openKindSchema(
|
|
178568
|
-
`What this answer is: overview, or the kind it describes in full (${joinWords(BUILT_KINDS, "or")} today; later versions add kinds, so expect others).`
|
|
178617
|
+
`What this answer is: overview, a topic (import-formats), or the kind it describes in full (${joinWords(BUILT_KINDS, "or")} today; later versions add kinds, so expect others).`
|
|
178569
178618
|
),
|
|
178570
178619
|
howToGetAKind: external_exports.string().describe("In plain words: what this answer holds and how to get the rest."),
|
|
178571
178620
|
kinds: VocabularyResponseSchema.shape.kinds,
|
|
178572
178621
|
kindDetails: external_exports.array(SyntaxKindDetailsSchema).describe("The overview lists every kind in the order of kinds, with its header, noun, and summary, and a pointer in more. A kind answer holds that kind alone, in full."),
|
|
178573
178622
|
...SyntaxTablesSchema.shape,
|
|
178574
|
-
examples: VocabularyResponseSchema.shape.examples.describe("Tested examples: the overview holds the ones for the kinds the shared tables describe in full, a kind answer holds its own.")
|
|
178623
|
+
examples: VocabularyResponseSchema.shape.examples.describe("Tested examples: the overview holds the ones for the kinds the shared tables describe in full, a kind answer holds its own."),
|
|
178624
|
+
importFormats: external_exports.array(external_exports.object({ format: external_exports.string().describe("The format, as import_source takes it."), reads: external_exports.string().describe("What it reads."), draws: external_exports.string().describe("The diagram it draws."), options: external_exports.string().describe("The options it takes.") })).optional().describe("Only for topic import-formats: every format import_source reads, a line each.")
|
|
178575
178625
|
}).meta({ id: "SyntaxResponse", description: "The diagram language for one scope: the overview, or one kind in full." });
|
|
178576
178626
|
}
|
|
178577
178627
|
});
|
|
@@ -178660,7 +178710,7 @@ var init_import_source = __esm({
|
|
|
178660
178710
|
init_kinds2();
|
|
178661
178711
|
init_workflows();
|
|
178662
178712
|
ImportSourceInputSchema = external_exports.object({
|
|
178663
|
-
format: external_exports.enum(IMPORT_FORMATS).describe("What the text is
|
|
178713
|
+
format: external_exports.enum(IMPORT_FORMATS).describe("What the text is; get_diagram_syntax with topic import-formats describes each."),
|
|
178664
178714
|
// Neither text nor files has a length here: a call over the limits is answered with I102 and a hint, as data.
|
|
178665
178715
|
text: external_exports.string().optional().describe("The file content, as text. Send text or files, not both."),
|
|
178666
178716
|
files: external_exports.array(
|
|
@@ -178668,19 +178718,19 @@ var init_import_source = __esm({
|
|
|
178668
178718
|
path: external_exports.string().min(1).max(WORKFLOW_LIMITS.maxPathLength).describe("The file path, such as infra/network.tf; diagnostics name it."),
|
|
178669
178719
|
text: external_exports.string().describe("The file content, as text.")
|
|
178670
178720
|
})
|
|
178671
|
-
).optional().describe("The files of a folder, for a format that spans files
|
|
178721
|
+
).optional().describe("The files of a folder, for a format that spans files; the others read the first."),
|
|
178672
178722
|
title: external_exports.string().max(200).optional().describe("The diagram title; taken from the file when left out."),
|
|
178673
178723
|
partsPage: external_exports.number().int().min(1).max(1e5).optional().describe(`Which page of parts to return when a split import has more than ${WORKFLOW_LIMITS.maxImportParts} diagrams: 1 (default) is the first ${WORKFLOW_LIMITS.maxImportParts}.`),
|
|
178674
178724
|
options: external_exports.object({
|
|
178675
|
-
view: external_exports.enum(IMPORT_VIEWS).optional().describe("
|
|
178676
|
-
operationId: external_exports.string().max(200).optional().describe("openapi sequence: the operation
|
|
178677
|
-
chart: external_exports.enum(IMPORT_CHARTS).optional().describe("csv, json:
|
|
178678
|
-
tables: external_exports.array(external_exports.string().min(1).max(80)).max(40).optional().describe("
|
|
178679
|
-
paths: external_exports.array(external_exports.string().min(1).max(200)).max(40).optional().describe("openapi: path prefixes to read
|
|
178680
|
-
tags: external_exports.array(external_exports.string().min(1).max(80)).max(40).optional().describe("openapi: tags to read
|
|
178681
|
-
varFiles: external_exports.array(external_exports.string().min(1).max(WORKFLOW_LIMITS.maxPathLength)).max(20).optional().describe("Variables files
|
|
178682
|
-
groupBy: external_exports.enum(IMPORT_GROUP_BY).optional().describe("
|
|
178683
|
-
root: external_exports.string().max(WORKFLOW_LIMITS.maxPathLength).optional().describe("The root
|
|
178725
|
+
view: external_exports.enum(IMPORT_VIEWS).optional().describe("The picture of a format drawn several ways."),
|
|
178726
|
+
operationId: external_exports.string().max(200).optional().describe("openapi sequence: the operation."),
|
|
178727
|
+
chart: external_exports.enum(IMPORT_CHARTS).optional().describe("csv, json: the chart; auto picks."),
|
|
178728
|
+
tables: external_exports.array(external_exports.string().min(1).max(80)).max(40).optional().describe("Tables to draw, by name or prefix*."),
|
|
178729
|
+
paths: external_exports.array(external_exports.string().min(1).max(200)).max(40).optional().describe("openapi: path prefixes to read."),
|
|
178730
|
+
tags: external_exports.array(external_exports.string().min(1).max(80)).max(40).optional().describe("openapi: tags to read."),
|
|
178731
|
+
varFiles: external_exports.array(external_exports.string().min(1).max(WORKFLOW_LIMITS.maxPathLength)).max(20).optional().describe("Variables files to apply."),
|
|
178732
|
+
groupBy: external_exports.enum(IMPORT_GROUP_BY).optional().describe("How things are framed; module is the default."),
|
|
178733
|
+
root: external_exports.string().max(WORKFLOW_LIMITS.maxPathLength).optional().describe("The root, stack, or template of several to draw.")
|
|
178684
178734
|
}).strict().default({})
|
|
178685
178735
|
}).meta({ id: "ImportSourceInput", description: "A file of another format to turn into Plotwork source." });
|
|
178686
178736
|
StatsSchema2 = external_exports.object({
|
|
@@ -181110,204 +181160,6 @@ var init_patterns3 = __esm({
|
|
|
181110
181160
|
}
|
|
181111
181161
|
});
|
|
181112
181162
|
|
|
181113
|
-
// ../../packages/diagrams/src/importers/detect.ts
|
|
181114
|
-
function graphCommits(text3) {
|
|
181115
|
-
let count3 = 0;
|
|
181116
|
-
for (const line3 of text3.split("\n")) {
|
|
181117
|
-
let index2 = 0;
|
|
181118
|
-
while (index2 < line3.length && "*|\\/ _".includes(line3.charAt(index2))) index2 += 1;
|
|
181119
|
-
if (line3.slice(0, index2).includes("*") && /^[0-9a-f]{7,40}\s/.test(line3.slice(index2))) count3 += 1;
|
|
181120
|
-
}
|
|
181121
|
-
return count3;
|
|
181122
|
-
}
|
|
181123
|
-
function everyLine(text3, test) {
|
|
181124
|
-
const lines = filled(text3);
|
|
181125
|
-
return lines.length >= 3 && lines.every((line3) => test(line3.trim()));
|
|
181126
|
-
}
|
|
181127
|
-
function isOutline(text3) {
|
|
181128
|
-
const lines = filled(text3);
|
|
181129
|
-
return lines.length >= 3 && lines.every((line3) => /^\s*[-*+] \S/.test(line3)) && lines.some((line3) => /^\s+[-*+] /.test(line3));
|
|
181130
|
-
}
|
|
181131
|
-
function separators(line3, separator) {
|
|
181132
|
-
let count3 = 0;
|
|
181133
|
-
let quoted5 = false;
|
|
181134
|
-
for (const char of line3) {
|
|
181135
|
-
if (char === '"') quoted5 = !quoted5;
|
|
181136
|
-
else if (char === separator && !quoted5) count3 += 1;
|
|
181137
|
-
}
|
|
181138
|
-
return count3;
|
|
181139
|
-
}
|
|
181140
|
-
function isTable(text3) {
|
|
181141
|
-
const lines = filled(text3).slice(0, 6);
|
|
181142
|
-
if (lines.length < 2) return false;
|
|
181143
|
-
for (const separator of [",", " ", ";"]) {
|
|
181144
|
-
const counts = lines.map((line3) => separators(line3, separator));
|
|
181145
|
-
if ((counts[0] ?? 0) > 0 && counts.every((count3) => count3 === counts[0])) return true;
|
|
181146
|
-
}
|
|
181147
|
-
return false;
|
|
181148
|
-
}
|
|
181149
|
-
function importFormatFor(request, data) {
|
|
181150
|
-
const fromData = detectImportFormat(data);
|
|
181151
|
-
if (fromData !== null && SURE_FROM_DATA.has(fromData)) return fromData;
|
|
181152
|
-
return NAMES.find((name2) => name2.words.test(request.slice(0, SNIFF_LENGTH)))?.format ?? null;
|
|
181153
|
-
}
|
|
181154
|
-
function detectImportFormat(text3) {
|
|
181155
|
-
const head = text3.slice(0, SNIFF_LENGTH);
|
|
181156
|
-
if (head.trim() === "") return null;
|
|
181157
|
-
return SIGNS.find((sign) => sign.test(head))?.format ?? null;
|
|
181158
|
-
}
|
|
181159
|
-
var SNIFF_LENGTH, SIGNS, filled, NAMES, SURE_FROM_DATA;
|
|
181160
|
-
var init_detect = __esm({
|
|
181161
|
-
"../../packages/diagrams/src/importers/detect.ts"() {
|
|
181162
|
-
"use strict";
|
|
181163
|
-
SNIFF_LENGTH = 2e4;
|
|
181164
|
-
SIGNS = [
|
|
181165
|
-
{ format: "sql", test: (text3) => /^\s*create\s+(?:or\s+replace\s+)?(?:temporary\s+|temp\s+|unlogged\s+)?table\b/im.test(text3) },
|
|
181166
|
-
{ format: "prisma", test: (text3) => /^\s*model\s+\w+\s*\{/m.test(text3) && /@id\b|@relation\b|^\s*datasource\s+\w+\s*\{/m.test(text3) },
|
|
181167
|
-
{ format: "drizzle", test: (text3) => /\b(?:pgTable|sqliteTable|mysqlTable)\s*\(/.test(text3) },
|
|
181168
|
-
{ format: "openapi", test: (text3) => /^\s*["']?openapi["']?\s*:\s*["']?3\./m.test(text3) || /"openapi"\s*:\s*"3\./.test(text3) },
|
|
181169
|
-
{ format: "terraform-plan", test: (text3) => /^\s*\{\s*"format_version"\s*:/.test(text3) && /"terraform_version"\s*:/.test(text3) && /"(?:planned_values|resource_changes|root_module)"\s*:/.test(text3) },
|
|
181170
|
-
{ format: "terraform", test: (text3) => /^\s*resource\s+"[A-Za-z0-9_]+"\s+"[^"]+"\s*\{/m.test(text3) },
|
|
181171
|
-
{ format: "bicep", test: (text3) => /^\s*(?:resource|module)\s+[A-Za-z_]\w*\s+'[^'\n]+'\s*(?:existing\s*)?=/m.test(text3) || /^\s*targetScope\s*=\s*'/m.test(text3) },
|
|
181172
|
-
{ format: "arm", test: (text3) => /"\$schema"\s*:\s*"https?:\/\/schema\.management\.azure\.com\/schemas\/[^"]*(?:deploymentTemplate|DeploymentTemplate)/.test(text3) },
|
|
181173
|
-
{ format: "pulumi", test: (text3) => /^runtime\s*:\s*(?:yaml|\{\s*name\s*:\s*yaml)/m.test(text3) && /^resources\s*:/m.test(text3) || /"urn"\s*:\s*"urn:pulumi:/.test(text3) },
|
|
181174
|
-
{ format: "cloudformation", test: (text3) => /^\s*"?AWSTemplateFormatVersion"?\s*:/m.test(text3) || /^Transform\s*:\s*AWS::Serverless/m.test(text3) || /^\s*"?Resources"?\s*:/m.test(text3) && /"?Type"?\s*:\s*["']?AWS::[A-Za-z0-9]+::/.test(text3) },
|
|
181175
|
-
{ format: "kubernetes", test: (text3) => /^\s*apiVersion\s*:/m.test(text3) && /^\s*kind\s*:\s*\w+/m.test(text3) },
|
|
181176
|
-
{ format: "github-actions", test: (text3) => /^jobs\s*:/m.test(text3) && (/^\s*runs-on\s*:/m.test(text3) || /^["']?on["']?\s*:/m.test(text3)) },
|
|
181177
|
-
{ format: "compose", test: (text3) => /^services\s*:/m.test(text3) && /^\s+(?:image|build)\s*:/m.test(text3) },
|
|
181178
|
-
{ format: "tree", test: (text3) => /(?:├──|└──|\|-- |`-- )/.test(text3) || everyLine(text3, (line3) => /^[^\s/]+(?:\/[^\s/]+)+\/?$/.test(line3)) || isOutline(text3) },
|
|
181179
|
-
{ format: "git-log", test: (text3) => /^commit [0-9a-f]{7,40}\b/m.test(text3) || graphCommits(text3) >= 2 || everyLine(text3, (line3) => /^[0-9a-f]{7,40} \S/.test(line3)) },
|
|
181180
|
-
{ format: "json", test: (text3) => /^\s*[[{]/.test(text3) && /[\]}]\s*$/.test(text3) },
|
|
181181
|
-
{ format: "csv", test: (text3) => isTable(text3) }
|
|
181182
|
-
];
|
|
181183
|
-
filled = (text3) => text3.split("\n", 200).map((line3) => line3.trimEnd()).filter((line3) => line3.trim() !== "");
|
|
181184
|
-
NAMES = [
|
|
181185
|
-
{ format: "compose", words: /\b(?:docker[- ]compose|compose (?:file|yaml|yml|stack))\b/i },
|
|
181186
|
-
{ format: "kubernetes", words: /\b(?:kubernetes|k8s)\b/i },
|
|
181187
|
-
{ format: "github-actions", words: /\b(?:github actions?|workflow (?:file|yaml|yml)|ci workflow)\b/i },
|
|
181188
|
-
{ format: "terraform-plan", words: /\b(?:terraform|tofu) (?:plan|state|show -json)\b|\bplan\.json\b/i },
|
|
181189
|
-
{ format: "terraform", words: /\b(?:terraform|opentofu|hcl|\.tf files?)\b/i },
|
|
181190
|
-
{ format: "bicep", words: /\b(?:bicep|\.bicep files?)\b/i },
|
|
181191
|
-
{ format: "arm", words: /\b(?:arm templates?|azure resource manager|azuredeploy\.json)\b/i },
|
|
181192
|
-
{ format: "pulumi", words: /\bpulumi\b/i },
|
|
181193
|
-
{ format: "cloudformation", words: /\b(?:cloudformation|cfn templates?|sam templates?|serverless application model)\b/i },
|
|
181194
|
-
{ format: "openapi", words: /\b(?:openapi|swagger|api spec(?:ification)?)\b/i },
|
|
181195
|
-
{ format: "prisma", words: /\bprisma\b/i },
|
|
181196
|
-
{ format: "drizzle", words: /\bdrizzle\b/i },
|
|
181197
|
-
{ format: "sql", words: /\b(?:sql|ddl|create table|database schema dump)\b/i },
|
|
181198
|
-
{ format: "git-log", words: /\bgit (?:log|history)\b/i },
|
|
181199
|
-
{ format: "csv", words: /\b(?:csv|tsv|spreadsheet export)\b/i },
|
|
181200
|
-
{ format: "json", words: /\bjson (?:data|file|records|export)\b/i },
|
|
181201
|
-
{ format: "tree", words: /\b(?:tree output|folder (?:structure|tree|listing)|directory (?:tree|listing))\b/i }
|
|
181202
|
-
];
|
|
181203
|
-
SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "git-log"]);
|
|
181204
|
-
}
|
|
181205
|
-
});
|
|
181206
|
-
|
|
181207
|
-
// ../../packages/diagrams/src/importers/terraform/azure-families.ts
|
|
181208
|
-
function azureFamilyIcon(type) {
|
|
181209
|
-
if (!type.startsWith("azurerm_")) return null;
|
|
181210
|
-
const name2 = type.slice("azurerm_".length);
|
|
181211
|
-
let best;
|
|
181212
|
-
for (const family of AZURE_FAMILIES) if (name2.startsWith(family[0]) && family[0].length > (best?.[0].length ?? -1)) best = family;
|
|
181213
|
-
return best?.[1] ?? null;
|
|
181214
|
-
}
|
|
181215
|
-
var AZURE_FAMILIES;
|
|
181216
|
-
var init_azure_families = __esm({
|
|
181217
|
-
"../../packages/diagrams/src/importers/terraform/azure-families.ts"() {
|
|
181218
|
-
"use strict";
|
|
181219
|
-
AZURE_FAMILIES = [
|
|
181220
|
-
["aadb2c_", "azure:ad-b2c"],
|
|
181221
|
-
["active_directory_domain_service", "azure:entra-domain-services"],
|
|
181222
|
-
["advanced_threat_protection", "azure:defender-for-cloud"],
|
|
181223
|
-
["attestation_", "azure:azureattestation"],
|
|
181224
|
-
["automanage_", "azure:automanaged-vm"],
|
|
181225
|
-
["automation_", "azure:automation-accounts"],
|
|
181226
|
-
["backup_", "azure:recovery-services-vaults"],
|
|
181227
|
-
["batch_", "azure:batch-accounts"],
|
|
181228
|
-
["bot_", "azure:bot-services"],
|
|
181229
|
-
["cognitive_", "azure:cognitive-services"],
|
|
181230
|
-
["container_connected_registry", "azure:container-registries"],
|
|
181231
|
-
["container_group", "azure:container-instances"],
|
|
181232
|
-
["cosmosdb_postgresql_", "azure:database-postgresql-server-group"],
|
|
181233
|
-
["cosmosdb_", "azure:cosmos-db"],
|
|
181234
|
-
["custom_provider", "azure:resource-groups"],
|
|
181235
|
-
["data_protection_", "azure:backup-vault"],
|
|
181236
|
-
["database_migration_", "azure:database-migration-services"],
|
|
181237
|
-
["dev_center", "azure:dev-box"],
|
|
181238
|
-
["dev_test_", "azure:devtest-labs"],
|
|
181239
|
-
["elastic_cloud_", "simple:elasticsearch"],
|
|
181240
|
-
["eventgrid_domain", "azure:event-grid-domains"],
|
|
181241
|
-
["eventgrid_", "azure:event-grid"],
|
|
181242
|
-
["eventhub_cluster", "azure:event-hub-clusters"],
|
|
181243
|
-
["eventhub", "azure:event-hubs"],
|
|
181244
|
-
["express_route_", "azure:expressroute-circuits"],
|
|
181245
|
-
["fabric_", "azure:power-bi-embedded"],
|
|
181246
|
-
["federated_identity_credential", "azure:managed-identities"],
|
|
181247
|
-
["frontdoor", "azure:front-door"],
|
|
181248
|
-
["gallery_application", "azure:image-definitions"],
|
|
181249
|
-
["graph_services_", "azure:resource-graph-explorer"],
|
|
181250
|
-
["hdinsight_", "azure:hd-insight-clusters"],
|
|
181251
|
-
["healthbot", "azure:bot-services"],
|
|
181252
|
-
["healthcare_", "azure:fhir-service"],
|
|
181253
|
-
["iotcentral_", "azure:iot-central-applications"],
|
|
181254
|
-
["iothub", "azure:iot-hub"],
|
|
181255
|
-
["kubernetes_automatic", "azure:aks-automatic"],
|
|
181256
|
-
["kubernetes_fleet", "azure:kubernetes-fleet-manager"],
|
|
181257
|
-
["kubernetes_", "azure:kubernetes-services"],
|
|
181258
|
-
["kusto_", "azure:data-explorer-clusters"],
|
|
181259
|
-
["maintenance_", "azure:maintenance-configuration"],
|
|
181260
|
-
["managed_application", "azure:managed-applications-center"],
|
|
181261
|
-
["management_lock", "azure:resource-groups"],
|
|
181262
|
-
["mongo_cluster", "azure:cosmos-db"],
|
|
181263
|
-
["mssql_elasticpool", "azure:sql-elastic-pools"],
|
|
181264
|
-
["mssql_job", "azure:elastic-job-agents"],
|
|
181265
|
-
["mssql_managed", "azure:sql-managed-instance"],
|
|
181266
|
-
["mssql_", "azure:sql-database"],
|
|
181267
|
-
["mysql_", "azure:database-for-mysql"],
|
|
181268
|
-
["netapp_", "azure:netapp-files"],
|
|
181269
|
-
["network_function_", "azure:network-function-manager"],
|
|
181270
|
-
["network_profile", "azure:virtual-network"],
|
|
181271
|
-
["nginx_", "simple:nginx"],
|
|
181272
|
-
["oracle_", "azure:oracle-database"],
|
|
181273
|
-
["pim_", "azure:entra-identity-roles-and-administrators"],
|
|
181274
|
-
["playwright_", "azure:load-testing"],
|
|
181275
|
-
["point_to_site_vpn_gateway", "azure:virtual-network-gateways"],
|
|
181276
|
-
["policy_", "azure:policy"],
|
|
181277
|
-
["portal_", "azure:management-portal"],
|
|
181278
|
-
["powerbi_", "azure:power-bi-embedded"],
|
|
181279
|
-
["purview_", "azure:identity-governance"],
|
|
181280
|
-
["redhat_openshift", "azure:red-hat-openshift"],
|
|
181281
|
-
["redis_", "azure:cache-redis"],
|
|
181282
|
-
["resource_deployment_script", "azure:templates"],
|
|
181283
|
-
["resource_policy", "azure:policy"],
|
|
181284
|
-
["resource_provider_", "azure:subscriptions"],
|
|
181285
|
-
["role_definition", "azure:entra-identity-custom-roles"],
|
|
181286
|
-
["role_management", "azure:entra-identity-roles-and-administrators"],
|
|
181287
|
-
["route_map", "azure:virtual-router"],
|
|
181288
|
-
["route_server", "azure:virtual-router"],
|
|
181289
|
-
["route", "azure:route-tables"],
|
|
181290
|
-
["service_fabric", "azure:service-fabric-clusters"],
|
|
181291
|
-
["site_recovery_", "azure:recovery-services-vaults"],
|
|
181292
|
-
["snapshot", "azure:disks-snapshots"],
|
|
181293
|
-
["spring_cloud_", "azure:spring-apps"],
|
|
181294
|
-
["ssh_public_key", "azure:ssh-keys"],
|
|
181295
|
-
["stack_hci_", "azure:stack-hci-premium"],
|
|
181296
|
-
["storage_blob", "azure:blob-storage"],
|
|
181297
|
-
["storage_sync", "azure:storage-sync-services"],
|
|
181298
|
-
["storage_", "azure:storage-accounts"],
|
|
181299
|
-
["stream_analytics_", "azure:stream-analytics-jobs"],
|
|
181300
|
-
["traffic_manager_", "azure:traffic-manager-profiles"],
|
|
181301
|
-
["trusted_signing_", "azure:key-vaults"],
|
|
181302
|
-
["virtual_hub", "azure:virtual-wan-hub"],
|
|
181303
|
-
["vmware_", "azure:vmware-solution"],
|
|
181304
|
-
["vpn_", "azure:virtual-network-gateways"],
|
|
181305
|
-
["web_app", "azure:app-service"],
|
|
181306
|
-
["workloads_sap_", "azure:virtual-instance-for-sap"]
|
|
181307
|
-
];
|
|
181308
|
-
}
|
|
181309
|
-
});
|
|
181310
|
-
|
|
181311
181163
|
// ../../packages/diagrams/src/importers/shared/direction.ts
|
|
181312
181164
|
function longestChain(keys, edges) {
|
|
181313
181165
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -182243,6 +182095,1345 @@ var init_shared2 = __esm({
|
|
|
182243
182095
|
}
|
|
182244
182096
|
});
|
|
182245
182097
|
|
|
182098
|
+
// ../../packages/diagrams/src/importers/shared/yaml/access.ts
|
|
182099
|
+
function get(node3, key) {
|
|
182100
|
+
if (node3?.kind !== "map") return void 0;
|
|
182101
|
+
return node3.entries.find((entry2) => entry2.key === key)?.value;
|
|
182102
|
+
}
|
|
182103
|
+
function text(node3) {
|
|
182104
|
+
return node3?.kind === "scalar" && !node3.isNull ? node3.value : null;
|
|
182105
|
+
}
|
|
182106
|
+
function items(node3) {
|
|
182107
|
+
if (node3 === null || node3 === void 0) return [];
|
|
182108
|
+
if (node3.kind === "seq") return node3.items;
|
|
182109
|
+
if (node3.kind === "scalar" && node3.isNull) return [];
|
|
182110
|
+
return [node3];
|
|
182111
|
+
}
|
|
182112
|
+
function names5(node3) {
|
|
182113
|
+
if (node3?.kind === "map") return node3.entries.map((entry2) => entry2.key);
|
|
182114
|
+
return items(node3).map((item) => text(item)).filter((value) => value !== null && value !== "");
|
|
182115
|
+
}
|
|
182116
|
+
function entries(node3) {
|
|
182117
|
+
return node3?.kind === "map" ? node3.entries : [];
|
|
182118
|
+
}
|
|
182119
|
+
var init_access = __esm({
|
|
182120
|
+
"../../packages/diagrams/src/importers/shared/yaml/access.ts"() {
|
|
182121
|
+
"use strict";
|
|
182122
|
+
}
|
|
182123
|
+
});
|
|
182124
|
+
|
|
182125
|
+
// ../../packages/diagrams/src/importers/shared/yaml/lines.ts
|
|
182126
|
+
function opensQuote(text3, index2) {
|
|
182127
|
+
if (index2 === 0) return true;
|
|
182128
|
+
const before = text3.charAt(index2 - 1);
|
|
182129
|
+
return before === " " || before === " " || before === "[" || before === "{" || before === ",";
|
|
182130
|
+
}
|
|
182131
|
+
function cutComment(text3) {
|
|
182132
|
+
let quote3 = null;
|
|
182133
|
+
for (let index2 = 0; index2 < text3.length; index2 += 1) {
|
|
182134
|
+
const char = text3.charAt(index2);
|
|
182135
|
+
if (quote3 === '"') {
|
|
182136
|
+
if (char === "\\") index2 += 1;
|
|
182137
|
+
else if (char === '"') quote3 = null;
|
|
182138
|
+
} else if (quote3 === "'") {
|
|
182139
|
+
if (char === "'" && text3.charAt(index2 + 1) === "'") index2 += 1;
|
|
182140
|
+
else if (char === "'") quote3 = null;
|
|
182141
|
+
} else if ((char === '"' || char === "'") && opensQuote(text3, index2)) {
|
|
182142
|
+
quote3 = char;
|
|
182143
|
+
} else if (char === "#" && (index2 === 0 || text3.charAt(index2 - 1) === " " || text3.charAt(index2 - 1) === " ")) {
|
|
182144
|
+
return text3.slice(0, index2);
|
|
182145
|
+
}
|
|
182146
|
+
}
|
|
182147
|
+
return text3;
|
|
182148
|
+
}
|
|
182149
|
+
function blockIndicator(text3) {
|
|
182150
|
+
const lastSpace = text3.lastIndexOf(" ");
|
|
182151
|
+
const tail = text3.slice(lastSpace + 1);
|
|
182152
|
+
if (!/^[|>][-+0-9]{0,2}$/.test(tail)) return null;
|
|
182153
|
+
const words2 = text3.slice(0, lastSpace + 1).trim().split(" ").filter((part) => part !== "");
|
|
182154
|
+
while (words2.length > 0 && /^[&!]/.test(words2[words2.length - 1] ?? "")) words2.pop();
|
|
182155
|
+
const head = words2.join(" ");
|
|
182156
|
+
if (head !== "" && !head.endsWith(":") && head !== "-") return null;
|
|
182157
|
+
return { folded: tail.startsWith(">"), keep: tail.includes("+"), strip: tail.includes("-") };
|
|
182158
|
+
}
|
|
182159
|
+
function fold4(lines) {
|
|
182160
|
+
let out = "";
|
|
182161
|
+
for (const line3 of lines) {
|
|
182162
|
+
if (line3 === "") out += "\n";
|
|
182163
|
+
else out += out === "" || out.endsWith("\n") ? line3 : ` ${line3}`;
|
|
182164
|
+
}
|
|
182165
|
+
return out;
|
|
182166
|
+
}
|
|
182167
|
+
function splitDocuments(text3) {
|
|
182168
|
+
const raw = text3.split("\n");
|
|
182169
|
+
const documents = [];
|
|
182170
|
+
let current = { lines: [], line: 1 };
|
|
182171
|
+
let started = false;
|
|
182172
|
+
for (let index2 = 0; index2 < raw.length; index2 += 1) {
|
|
182173
|
+
const full = (raw[index2] ?? "").replace(/\r$/, "");
|
|
182174
|
+
const lineNumber = index2 + 1;
|
|
182175
|
+
if (/^---(\s|$)/.test(full) || /^\.\.\.\s*$/.test(full)) {
|
|
182176
|
+
if (started || current.lines.length > 0) documents.push(current);
|
|
182177
|
+
current = { lines: [], line: lineNumber };
|
|
182178
|
+
started = full.startsWith("---");
|
|
182179
|
+
const rest = cutComment(full.slice(3)).trim();
|
|
182180
|
+
if (full.startsWith("---") && rest !== "" && !/^![^\s]*$/.test(rest)) current.lines.push({ indent: 0, text: rest.replace(/^![^\s]*\s+/, ""), line: lineNumber, block: null });
|
|
182181
|
+
continue;
|
|
182182
|
+
}
|
|
182183
|
+
if (full.startsWith("%") && current.lines.length === 0) continue;
|
|
182184
|
+
const indent = full.length - full.replace(/^ +/, "").length;
|
|
182185
|
+
if (full.charAt(indent) === " " && full.trim() !== "") {
|
|
182186
|
+
return { documents, problem: { line: lineNumber, column: indent + 1, message: "A tab is used to indent this line.", hint: "YAML indents with spaces only. Replace the tab with spaces." } };
|
|
182187
|
+
}
|
|
182188
|
+
const textPart = cutComment(full.slice(indent)).trimEnd();
|
|
182189
|
+
if (textPart === "") continue;
|
|
182190
|
+
const indicator = blockIndicator(textPart);
|
|
182191
|
+
let block = null;
|
|
182192
|
+
if (indicator !== null) {
|
|
182193
|
+
const body6 = [];
|
|
182194
|
+
let bodyIndent = -1;
|
|
182195
|
+
while (index2 + 1 < raw.length) {
|
|
182196
|
+
const next = (raw[index2 + 1] ?? "").replace(/\r$/, "");
|
|
182197
|
+
const nextIndent = next.length - next.replace(/^ +/, "").length;
|
|
182198
|
+
if (next.trim() !== "" && nextIndent <= indent) break;
|
|
182199
|
+
if (next.trim() !== "" && bodyIndent === -1) bodyIndent = nextIndent;
|
|
182200
|
+
body6.push(next.trim() === "" ? "" : next.slice(Math.max(0, bodyIndent)));
|
|
182201
|
+
index2 += 1;
|
|
182202
|
+
}
|
|
182203
|
+
while (!indicator.keep && body6.length > 0 && body6[body6.length - 1] === "") body6.pop();
|
|
182204
|
+
const joined2 = indicator.folded ? fold4(body6) : body6.join("\n");
|
|
182205
|
+
block = indicator.strip || joined2 === "" ? joined2 : `${joined2}
|
|
182206
|
+
`;
|
|
182207
|
+
}
|
|
182208
|
+
current.lines.push({ indent, text: indicator === null ? textPart : textPart.replace(/[|>][-+0-9]*$/, "").trimEnd(), line: lineNumber, block });
|
|
182209
|
+
}
|
|
182210
|
+
if (started || current.lines.length > 0) documents.push(current);
|
|
182211
|
+
return { documents, problem: null };
|
|
182212
|
+
}
|
|
182213
|
+
var init_lines = __esm({
|
|
182214
|
+
"../../packages/diagrams/src/importers/shared/yaml/lines.ts"() {
|
|
182215
|
+
"use strict";
|
|
182216
|
+
}
|
|
182217
|
+
});
|
|
182218
|
+
|
|
182219
|
+
// ../../packages/diagrams/src/importers/shared/yaml/scalars.ts
|
|
182220
|
+
function scalar(value, quoted5, line3, column) {
|
|
182221
|
+
const isNull = !quoted5 && (value === "" || value === "~" || value === "null" || value === "Null" || value === "NULL");
|
|
182222
|
+
return { kind: "scalar", value: isNull ? "" : value, quoted: quoted5, isNull, line: line3, column };
|
|
182223
|
+
}
|
|
182224
|
+
function readQuoted(text3, start2) {
|
|
182225
|
+
const quote3 = text3.charAt(start2);
|
|
182226
|
+
let value = "";
|
|
182227
|
+
for (let index2 = start2 + 1; index2 < text3.length; index2 += 1) {
|
|
182228
|
+
const char = text3.charAt(index2);
|
|
182229
|
+
if (quote3 === "'") {
|
|
182230
|
+
if (char !== "'") value += char;
|
|
182231
|
+
else if (text3.charAt(index2 + 1) === "'") {
|
|
182232
|
+
value += "'";
|
|
182233
|
+
index2 += 1;
|
|
182234
|
+
} else return { value, end: index2 + 1 };
|
|
182235
|
+
} else if (char === '"') {
|
|
182236
|
+
return { value, end: index2 + 1 };
|
|
182237
|
+
} else if (char === "\\") {
|
|
182238
|
+
const next = text3.charAt(index2 + 1);
|
|
182239
|
+
const width = next === "u" ? 4 : next === "x" ? 2 : next === "U" ? 8 : 0;
|
|
182240
|
+
if (width > 0) {
|
|
182241
|
+
const code = Number.parseInt(text3.slice(index2 + 2, index2 + 2 + width), 16);
|
|
182242
|
+
value += Number.isFinite(code) && code <= 1114111 ? String.fromCodePoint(code) : "";
|
|
182243
|
+
index2 += 1 + width;
|
|
182244
|
+
} else {
|
|
182245
|
+
value += ESCAPES[next] ?? next;
|
|
182246
|
+
index2 += 1;
|
|
182247
|
+
}
|
|
182248
|
+
} else {
|
|
182249
|
+
value += char;
|
|
182250
|
+
}
|
|
182251
|
+
}
|
|
182252
|
+
return null;
|
|
182253
|
+
}
|
|
182254
|
+
function stripProperties(text3) {
|
|
182255
|
+
let rest = text3;
|
|
182256
|
+
let anchor2 = null;
|
|
182257
|
+
let tag = null;
|
|
182258
|
+
let offset = 0;
|
|
182259
|
+
for (let round2 = 0; round2 < 2; round2 += 1) {
|
|
182260
|
+
const match = /^([!&])([^\s,[\]{}]*)\s*/.exec(rest);
|
|
182261
|
+
if (match === null) break;
|
|
182262
|
+
if (match[1] === "&") anchor2 = match[2] ?? null;
|
|
182263
|
+
else tag = `!${match[2] ?? ""}`;
|
|
182264
|
+
offset += match[0].length;
|
|
182265
|
+
rest = rest.slice(match[0].length);
|
|
182266
|
+
}
|
|
182267
|
+
return { text: rest, anchor: anchor2, tag, offset };
|
|
182268
|
+
}
|
|
182269
|
+
function tagged(node3, tag) {
|
|
182270
|
+
return tag === null || tag.startsWith("!!") ? node3 : { ...node3, tag };
|
|
182271
|
+
}
|
|
182272
|
+
function readFlow2(text3, line3, column, resolveAlias) {
|
|
182273
|
+
const reader = new FlowReader(text3, line3, column, resolveAlias);
|
|
182274
|
+
const node3 = reader.value(0);
|
|
182275
|
+
if (!reader.done()) throw new FlowError("Text follows the end of the flow collection.");
|
|
182276
|
+
return node3;
|
|
182277
|
+
}
|
|
182278
|
+
function flowClosed(text3) {
|
|
182279
|
+
let depth = 0;
|
|
182280
|
+
let quote3 = null;
|
|
182281
|
+
for (let index2 = 0; index2 < text3.length; index2 += 1) {
|
|
182282
|
+
const char = text3.charAt(index2);
|
|
182283
|
+
if (quote3 !== null) {
|
|
182284
|
+
if (quote3 === '"' && char === "\\") index2 += 1;
|
|
182285
|
+
else if (char === quote3) quote3 = null;
|
|
182286
|
+
} else if (char === '"' || char === "'") quote3 = char;
|
|
182287
|
+
else if (char === "[" || char === "{") depth += 1;
|
|
182288
|
+
else if (char === "]" || char === "}") depth -= 1;
|
|
182289
|
+
}
|
|
182290
|
+
return depth <= 0 && quote3 === null;
|
|
182291
|
+
}
|
|
182292
|
+
var MAX_FLOW_DEPTH, ESCAPES, FlowReader, FlowError;
|
|
182293
|
+
var init_scalars = __esm({
|
|
182294
|
+
"../../packages/diagrams/src/importers/shared/yaml/scalars.ts"() {
|
|
182295
|
+
"use strict";
|
|
182296
|
+
MAX_FLOW_DEPTH = 32;
|
|
182297
|
+
ESCAPES = { n: "\n", t: " ", r: "\r", '"': '"', "\\": "\\", "/": "/", "0": "\0", " ": " ", e: "\x1B", N: "\x85", _: "\xA0" };
|
|
182298
|
+
FlowReader = class {
|
|
182299
|
+
constructor(text3, line3, column, resolveAlias) {
|
|
182300
|
+
this.text = text3;
|
|
182301
|
+
this.line = line3;
|
|
182302
|
+
this.column = column;
|
|
182303
|
+
this.resolveAlias = resolveAlias;
|
|
182304
|
+
}
|
|
182305
|
+
text;
|
|
182306
|
+
line;
|
|
182307
|
+
column;
|
|
182308
|
+
resolveAlias;
|
|
182309
|
+
index = 0;
|
|
182310
|
+
skipSpace() {
|
|
182311
|
+
while (this.index < this.text.length && /\s/.test(this.text.charAt(this.index))) this.index += 1;
|
|
182312
|
+
}
|
|
182313
|
+
/** The column in the file of the reader's position, for a node it reads. */
|
|
182314
|
+
at() {
|
|
182315
|
+
return this.column + this.index;
|
|
182316
|
+
}
|
|
182317
|
+
/** One value: a collection, a quoted scalar, an alias, or a plain scalar up to `,`, `]`, `}`, or `: `. */
|
|
182318
|
+
value(depth) {
|
|
182319
|
+
if (depth > MAX_FLOW_DEPTH) throw new FlowError("The flow collection is nested too deep.");
|
|
182320
|
+
this.skipSpace();
|
|
182321
|
+
const char = this.text.charAt(this.index);
|
|
182322
|
+
const column = this.at();
|
|
182323
|
+
if (char === "[") return this.sequence(depth);
|
|
182324
|
+
if (char === "{") return this.mapping(depth);
|
|
182325
|
+
if (char === '"' || char === "'") {
|
|
182326
|
+
const read = readQuoted(this.text, this.index);
|
|
182327
|
+
if (read === null) throw new FlowError("A quoted string is never closed.");
|
|
182328
|
+
this.index = read.end;
|
|
182329
|
+
return scalar(read.value, true, this.line, column);
|
|
182330
|
+
}
|
|
182331
|
+
const start2 = this.index;
|
|
182332
|
+
while (this.index < this.text.length) {
|
|
182333
|
+
const next = this.text.charAt(this.index);
|
|
182334
|
+
if (next === "," || next === "]" || next === "}") break;
|
|
182335
|
+
if (next === ":" && /[\s,\]}]/.test(this.text.charAt(this.index + 1) || " ")) break;
|
|
182336
|
+
this.index += 1;
|
|
182337
|
+
}
|
|
182338
|
+
const word2 = this.text.slice(start2, this.index).trim();
|
|
182339
|
+
if (word2.startsWith("*")) return this.resolveAlias(word2.slice(1)) ?? scalar("", false, this.line, column);
|
|
182340
|
+
const props = stripProperties(word2);
|
|
182341
|
+
return tagged(scalar(props.text, false, this.line, column), props.tag);
|
|
182342
|
+
}
|
|
182343
|
+
sequence(depth) {
|
|
182344
|
+
const column = this.at();
|
|
182345
|
+
this.index += 1;
|
|
182346
|
+
const items2 = [];
|
|
182347
|
+
for (; ; ) {
|
|
182348
|
+
this.skipSpace();
|
|
182349
|
+
if (this.index >= this.text.length) throw new FlowError("A [ list is never closed with ].");
|
|
182350
|
+
if (this.text.charAt(this.index) === "]") {
|
|
182351
|
+
this.index += 1;
|
|
182352
|
+
return { kind: "seq", items: items2, line: this.line, column };
|
|
182353
|
+
}
|
|
182354
|
+
items2.push(this.value(depth + 1));
|
|
182355
|
+
this.skipSpace();
|
|
182356
|
+
if (this.text.charAt(this.index) === ",") this.index += 1;
|
|
182357
|
+
else if (this.text.charAt(this.index) !== "]") throw new FlowError("Items of a [ list are separated by commas.");
|
|
182358
|
+
}
|
|
182359
|
+
}
|
|
182360
|
+
mapping(depth) {
|
|
182361
|
+
const column = this.at();
|
|
182362
|
+
this.index += 1;
|
|
182363
|
+
const entries2 = [];
|
|
182364
|
+
for (; ; ) {
|
|
182365
|
+
this.skipSpace();
|
|
182366
|
+
if (this.index >= this.text.length) throw new FlowError("A { mapping is never closed with }.");
|
|
182367
|
+
if (this.text.charAt(this.index) === "}") {
|
|
182368
|
+
this.index += 1;
|
|
182369
|
+
return { kind: "map", entries: entries2, line: this.line, column };
|
|
182370
|
+
}
|
|
182371
|
+
const keyColumn = this.at();
|
|
182372
|
+
const key = this.value(depth + 1);
|
|
182373
|
+
this.skipSpace();
|
|
182374
|
+
let value = scalar("", false, this.line, this.at());
|
|
182375
|
+
if (this.text.charAt(this.index) === ":") {
|
|
182376
|
+
this.index += 1;
|
|
182377
|
+
value = this.value(depth + 1);
|
|
182378
|
+
}
|
|
182379
|
+
entries2.push({ key: key.kind === "scalar" ? key.value : "", value, line: this.line, column: keyColumn });
|
|
182380
|
+
this.skipSpace();
|
|
182381
|
+
if (this.text.charAt(this.index) === ",") this.index += 1;
|
|
182382
|
+
else if (this.text.charAt(this.index) !== "}") throw new FlowError("Entries of a { mapping are separated by commas.");
|
|
182383
|
+
}
|
|
182384
|
+
}
|
|
182385
|
+
/** True when only spaces are left. */
|
|
182386
|
+
done() {
|
|
182387
|
+
this.skipSpace();
|
|
182388
|
+
return this.index >= this.text.length;
|
|
182389
|
+
}
|
|
182390
|
+
};
|
|
182391
|
+
FlowError = class extends Error {
|
|
182392
|
+
};
|
|
182393
|
+
}
|
|
182394
|
+
});
|
|
182395
|
+
|
|
182396
|
+
// ../../packages/diagrams/src/importers/shared/yaml/parse.ts
|
|
182397
|
+
function splitKey(text3) {
|
|
182398
|
+
if (text3.startsWith('"') || text3.startsWith("'")) {
|
|
182399
|
+
const read = readQuoted(text3, 0);
|
|
182400
|
+
if (read === null) return null;
|
|
182401
|
+
const after = text3.slice(read.end).trimStart();
|
|
182402
|
+
if (!after.startsWith(":")) return null;
|
|
182403
|
+
const colon = text3.length - after.length;
|
|
182404
|
+
return /^:(\s|$)/.test(text3.slice(colon)) ? { key: read.value, colon } : null;
|
|
182405
|
+
}
|
|
182406
|
+
if (/^[[{]/.test(text3) || text3.startsWith("- ") || text3 === "-") return null;
|
|
182407
|
+
for (let index2 = text3.indexOf(":"); index2 !== -1; index2 = text3.indexOf(":", index2 + 1)) {
|
|
182408
|
+
const next = text3.charAt(index2 + 1);
|
|
182409
|
+
if (next === "" || next === " " || next === " ") return { key: text3.slice(0, index2).trim(), colon: index2 };
|
|
182410
|
+
}
|
|
182411
|
+
return null;
|
|
182412
|
+
}
|
|
182413
|
+
function parseYaml(text3) {
|
|
182414
|
+
const split = splitDocuments(text3);
|
|
182415
|
+
if (split.problem !== null) return { documents: [], error: split.problem };
|
|
182416
|
+
const documents = [];
|
|
182417
|
+
for (const document2 of split.documents) {
|
|
182418
|
+
try {
|
|
182419
|
+
documents.push({ root: new BlockReader(document2.lines).document(), line: document2.line });
|
|
182420
|
+
} catch (error62) {
|
|
182421
|
+
if (!(error62 instanceof YamlProblem)) throw error62;
|
|
182422
|
+
const problem = { line: error62.line, column: error62.column, message: error62.message, hint: error62.hint };
|
|
182423
|
+
return { documents, error: problem };
|
|
182424
|
+
}
|
|
182425
|
+
}
|
|
182426
|
+
return { documents, error: null };
|
|
182427
|
+
}
|
|
182428
|
+
var MAX_DEPTH2, MAX_JOINED_LINES, YamlProblem, isItem, BlockReader;
|
|
182429
|
+
var init_parse21 = __esm({
|
|
182430
|
+
"../../packages/diagrams/src/importers/shared/yaml/parse.ts"() {
|
|
182431
|
+
"use strict";
|
|
182432
|
+
init_lines();
|
|
182433
|
+
init_scalars();
|
|
182434
|
+
MAX_DEPTH2 = 64;
|
|
182435
|
+
MAX_JOINED_LINES = 200;
|
|
182436
|
+
YamlProblem = class extends Error {
|
|
182437
|
+
constructor(line3, column, message2, hint2) {
|
|
182438
|
+
super(message2);
|
|
182439
|
+
this.line = line3;
|
|
182440
|
+
this.column = column;
|
|
182441
|
+
this.hint = hint2;
|
|
182442
|
+
}
|
|
182443
|
+
line;
|
|
182444
|
+
column;
|
|
182445
|
+
hint;
|
|
182446
|
+
};
|
|
182447
|
+
isItem = (text3) => text3 === "-" || text3.startsWith("- ");
|
|
182448
|
+
BlockReader = class {
|
|
182449
|
+
constructor(lines) {
|
|
182450
|
+
this.lines = lines;
|
|
182451
|
+
}
|
|
182452
|
+
lines;
|
|
182453
|
+
index = 0;
|
|
182454
|
+
anchors = /* @__PURE__ */ new Map();
|
|
182455
|
+
problem(line3, message2, hint2) {
|
|
182456
|
+
return new YamlProblem(line3.line, line3.indent + 1, message2, hint2);
|
|
182457
|
+
}
|
|
182458
|
+
/** The whole document: one block, and nothing left over. */
|
|
182459
|
+
document() {
|
|
182460
|
+
const first = this.lines[0];
|
|
182461
|
+
if (first === void 0) return null;
|
|
182462
|
+
const root = this.block(first.indent, 0);
|
|
182463
|
+
const extra = this.lines[this.index];
|
|
182464
|
+
if (extra !== void 0) throw this.problem(extra, "This line is indented less than the block it follows, or not like the lines before it.", "Line it up with the other keys at its level.");
|
|
182465
|
+
return root;
|
|
182466
|
+
}
|
|
182467
|
+
/** A block that starts at the current line, indented `indent` spaces: a sequence, a mapping, or a scalar. */
|
|
182468
|
+
block(indent, depth) {
|
|
182469
|
+
const line3 = this.lines[this.index];
|
|
182470
|
+
if (depth > MAX_DEPTH2) throw this.problem(line3, "The YAML is nested too deep.", `Keep nesting under ${MAX_DEPTH2} levels.`);
|
|
182471
|
+
if (isItem(line3.text)) return this.sequence(indent, depth);
|
|
182472
|
+
if (splitKey(line3.text) !== null) return this.mapping(indent, depth);
|
|
182473
|
+
this.index += 1;
|
|
182474
|
+
return this.value(line3.text, line3, indent, depth, line3.indent + 1);
|
|
182475
|
+
}
|
|
182476
|
+
mapping(indent, depth) {
|
|
182477
|
+
const first = this.lines[this.index];
|
|
182478
|
+
const entries2 = [];
|
|
182479
|
+
const merges = [];
|
|
182480
|
+
while (this.index < this.lines.length) {
|
|
182481
|
+
const line3 = this.lines[this.index];
|
|
182482
|
+
if (line3.indent < indent) break;
|
|
182483
|
+
if (line3.indent > indent) throw this.problem(line3, "This line is indented more than the keys around it.", "Indent it like the other keys of the same mapping.");
|
|
182484
|
+
if (isItem(line3.text)) break;
|
|
182485
|
+
const split = splitKey(line3.text);
|
|
182486
|
+
if (split === null) throw this.problem(line3, "Expected a key followed by a colon.", "Write it as key: value, with a space after the colon.");
|
|
182487
|
+
this.index += 1;
|
|
182488
|
+
const rest = line3.text.slice(split.colon + 1).trim();
|
|
182489
|
+
const value = this.entryValue(rest, line3, indent, depth, line3.indent + split.colon + 2);
|
|
182490
|
+
if (split.key === "<<") merges.push(value);
|
|
182491
|
+
else entries2.push({ key: split.key, value, line: line3.line, column: line3.indent + 1 });
|
|
182492
|
+
}
|
|
182493
|
+
for (const merge3 of merges) {
|
|
182494
|
+
const sources = merge3.kind === "seq" ? merge3.items : [merge3];
|
|
182495
|
+
for (const source of sources) {
|
|
182496
|
+
if (source.kind !== "map") continue;
|
|
182497
|
+
for (const entry2 of source.entries) if (!entries2.some((own2) => own2.key === entry2.key)) entries2.push(entry2);
|
|
182498
|
+
}
|
|
182499
|
+
}
|
|
182500
|
+
return { kind: "map", entries: entries2, line: first.line, column: first.indent + 1 };
|
|
182501
|
+
}
|
|
182502
|
+
/** The value of a mapping entry: on its own line, in a block below it, or a sequence at the same indent. */
|
|
182503
|
+
entryValue(rest, line3, indent, depth, column) {
|
|
182504
|
+
const next = this.lines[this.index];
|
|
182505
|
+
const props = stripProperties(rest);
|
|
182506
|
+
if (props.text === "" && line3.block === null && next !== void 0 && (next.indent > indent || next.indent === indent && isItem(next.text))) {
|
|
182507
|
+
const node3 = tagged(this.block(next.indent, depth + 1), props.tag);
|
|
182508
|
+
if (props.anchor !== null) this.anchors.set(props.anchor, node3);
|
|
182509
|
+
return node3;
|
|
182510
|
+
}
|
|
182511
|
+
return this.value(rest, line3, indent, depth, column, true);
|
|
182512
|
+
}
|
|
182513
|
+
sequence(indent, depth) {
|
|
182514
|
+
const first = this.lines[this.index];
|
|
182515
|
+
const items2 = [];
|
|
182516
|
+
while (this.index < this.lines.length) {
|
|
182517
|
+
const line3 = this.lines[this.index];
|
|
182518
|
+
if (line3.indent !== indent || !isItem(line3.text)) {
|
|
182519
|
+
if (line3.indent > indent) throw this.problem(line3, "This line is indented more than the items around it.", "Indent it like the other items, or under the item it belongs to.");
|
|
182520
|
+
break;
|
|
182521
|
+
}
|
|
182522
|
+
const rest = line3.text.slice(1).trimStart();
|
|
182523
|
+
const restColumn = line3.indent + (line3.text.length - rest.length);
|
|
182524
|
+
if (rest === "" && line3.block === null) {
|
|
182525
|
+
this.index += 1;
|
|
182526
|
+
const next = this.lines[this.index];
|
|
182527
|
+
items2.push(next !== void 0 && next.indent > indent ? this.block(next.indent, depth + 1) : scalar("", false, line3.line, restColumn + 1));
|
|
182528
|
+
} else if (line3.block === null && /^![A-Za-z:]+$/.test(rest) && this.lines[this.index + 1] !== void 0 && this.lines[this.index + 1].indent > indent) {
|
|
182529
|
+
const tag = rest;
|
|
182530
|
+
this.index += 1;
|
|
182531
|
+
items2.push(tagged(this.block(this.lines[this.index].indent, depth + 1), tag));
|
|
182532
|
+
} else if (line3.block === null && (isItem(rest) || splitKey(stripProperties(rest).text) !== null)) {
|
|
182533
|
+
const props = stripProperties(rest);
|
|
182534
|
+
line3.indent = restColumn + props.offset;
|
|
182535
|
+
line3.text = props.text;
|
|
182536
|
+
const node3 = this.block(line3.indent, depth + 1);
|
|
182537
|
+
if (props.anchor !== null) this.anchors.set(props.anchor, node3);
|
|
182538
|
+
items2.push(node3);
|
|
182539
|
+
} else {
|
|
182540
|
+
this.index += 1;
|
|
182541
|
+
items2.push(this.value(rest, line3, indent, depth, restColumn + 1));
|
|
182542
|
+
}
|
|
182543
|
+
}
|
|
182544
|
+
return { kind: "seq", items: items2, line: first.line, column: first.indent + 1 };
|
|
182545
|
+
}
|
|
182546
|
+
/** A value written on a line: a block scalar, an alias, a flow collection, a quoted scalar, or a plain scalar that may run on. */
|
|
182547
|
+
value(text3, line3, indent, depth, column, ofKey = false) {
|
|
182548
|
+
const props = stripProperties(text3);
|
|
182549
|
+
const body6 = props.text;
|
|
182550
|
+
let node3;
|
|
182551
|
+
if (line3.block !== null) {
|
|
182552
|
+
node3 = scalar(line3.block, true, line3.line, column);
|
|
182553
|
+
} else if (body6.startsWith("*")) {
|
|
182554
|
+
const target = this.anchors.get(body6.slice(1).trim());
|
|
182555
|
+
if (target === void 0) throw this.problem(line3, `The alias ${body6} names no anchor written before it.`, "Write the anchor (&name) before the alias that uses it.");
|
|
182556
|
+
node3 = target;
|
|
182557
|
+
} else if (body6.startsWith("[") || body6.startsWith("{")) {
|
|
182558
|
+
node3 = this.flow(this.joined(body6, flowClosed), line3, column + props.offset);
|
|
182559
|
+
} else if (body6.startsWith('"') || body6.startsWith("'")) {
|
|
182560
|
+
const whole2 = this.joined(body6, (joined2) => readQuoted(joined2, 0) !== null);
|
|
182561
|
+
const read = readQuoted(whole2, 0);
|
|
182562
|
+
if (read === null) throw this.problem(line3, "A quoted string is never closed.", "Close it with the same quote it opened with.");
|
|
182563
|
+
node3 = scalar(read.value, true, line3.line, column + props.offset);
|
|
182564
|
+
} else {
|
|
182565
|
+
let plain3 = body6;
|
|
182566
|
+
while (this.index < this.lines.length) {
|
|
182567
|
+
const more = this.lines[this.index];
|
|
182568
|
+
if (more.indent < indent || more.indent === indent && !ofKey) break;
|
|
182569
|
+
if (splitKey(more.text) !== null || isItem(more.text)) break;
|
|
182570
|
+
plain3 = `${plain3} ${more.text}`;
|
|
182571
|
+
this.index += 1;
|
|
182572
|
+
}
|
|
182573
|
+
node3 = scalar(plain3.trim(), false, line3.line, column + props.offset);
|
|
182574
|
+
}
|
|
182575
|
+
node3 = tagged(node3, props.tag);
|
|
182576
|
+
if (props.anchor !== null) this.anchors.set(props.anchor, node3);
|
|
182577
|
+
return node3;
|
|
182578
|
+
}
|
|
182579
|
+
/** The text of a value that runs over several lines until `complete` says it is whole, consuming those lines. */
|
|
182580
|
+
joined(start2, complete) {
|
|
182581
|
+
let text3 = start2;
|
|
182582
|
+
for (let count3 = 0; !complete(text3) && count3 < MAX_JOINED_LINES && this.index < this.lines.length; count3 += 1) {
|
|
182583
|
+
text3 = `${text3} ${this.lines[this.index].text}`;
|
|
182584
|
+
this.index += 1;
|
|
182585
|
+
}
|
|
182586
|
+
return text3;
|
|
182587
|
+
}
|
|
182588
|
+
flow(text3, line3, column) {
|
|
182589
|
+
try {
|
|
182590
|
+
return readFlow2(text3, line3.line, column, (name2) => this.anchors.get(name2) ?? null);
|
|
182591
|
+
} catch (error62) {
|
|
182592
|
+
if (error62 instanceof FlowError) throw this.problem(line3, error62.message, "Close every [ and { on the line it opens, and separate items with commas.");
|
|
182593
|
+
throw error62;
|
|
182594
|
+
}
|
|
182595
|
+
}
|
|
182596
|
+
};
|
|
182597
|
+
}
|
|
182598
|
+
});
|
|
182599
|
+
|
|
182600
|
+
// ../../packages/diagrams/src/importers/shared/yaml/index.ts
|
|
182601
|
+
var init_yaml = __esm({
|
|
182602
|
+
"../../packages/diagrams/src/importers/shared/yaml/index.ts"() {
|
|
182603
|
+
"use strict";
|
|
182604
|
+
init_access();
|
|
182605
|
+
init_parse21();
|
|
182606
|
+
}
|
|
182607
|
+
});
|
|
182608
|
+
|
|
182609
|
+
// ../../packages/diagrams/src/importers/helm/chart.ts
|
|
182610
|
+
function isChartFile(textIn) {
|
|
182611
|
+
return /^apiVersion\s*:\s*["']?v[12]["']?\s*$/m.test(textIn) && /^name\s*:/m.test(textIn) && /^version\s*:/m.test(textIn) && !/^kind\s*:/m.test(textIn);
|
|
182612
|
+
}
|
|
182613
|
+
function dependenciesOf(node3) {
|
|
182614
|
+
return items(node3).flatMap((entry2) => {
|
|
182615
|
+
const name2 = text(get(entry2, "name"));
|
|
182616
|
+
return name2 === null ? [] : [{ name: name2, alias: text(get(entry2, "alias")), version: text(get(entry2, "version")), repository: text(get(entry2, "repository")), condition: text(get(entry2, "condition")) }];
|
|
182617
|
+
});
|
|
182618
|
+
}
|
|
182619
|
+
function valueAt(values, path) {
|
|
182620
|
+
let node3 = values ?? void 0;
|
|
182621
|
+
for (const key of path.split(".")) node3 = get(node3, key);
|
|
182622
|
+
return text(node3);
|
|
182623
|
+
}
|
|
182624
|
+
function drawCharts(files, context, index2) {
|
|
182625
|
+
const charts = [];
|
|
182626
|
+
const byFolder = (folder, name2) => files.find((file2) => folderOf(file2.path) === folder && baseName(file2.path) === name2);
|
|
182627
|
+
const parsed = (file2) => {
|
|
182628
|
+
if (file2 === void 0) return null;
|
|
182629
|
+
const read = parseYaml(file2.text);
|
|
182630
|
+
if (read.error !== null) {
|
|
182631
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(file2.start), `${cleanText(file2.path, "A file")} is not read: ${read.error.message}`, read.error.hint);
|
|
182632
|
+
return null;
|
|
182633
|
+
}
|
|
182634
|
+
return read.documents[0]?.root ?? null;
|
|
182635
|
+
};
|
|
182636
|
+
const templates = files.filter((file2) => /(?:^|\/)templates\//.test(file2.path));
|
|
182637
|
+
for (const file2 of files.filter((entry2) => baseName(entry2.path) === "Chart.yaml" || entry2.path === "" && isChartFile(entry2.text))) {
|
|
182638
|
+
const root2 = parsed(file2);
|
|
182639
|
+
const name2 = text(get(root2, "name"));
|
|
182640
|
+
if (root2 === null || name2 === null) continue;
|
|
182641
|
+
const folder = folderOf(file2.path);
|
|
182642
|
+
const requirements = parsed(byFolder(folder, "requirements.yaml"));
|
|
182643
|
+
const lock = parsed(byFolder(folder, "Chart.lock")) ?? parsed(byFolder(folder, "requirements.lock"));
|
|
182644
|
+
const locked = /* @__PURE__ */ new Map();
|
|
182645
|
+
for (const entry2 of items(get(lock, "dependencies"))) {
|
|
182646
|
+
const lockedName = text(get(entry2, "name"));
|
|
182647
|
+
const version2 = text(get(entry2, "version"));
|
|
182648
|
+
if (lockedName !== null && version2 !== null) locked.set(lockedName, version2);
|
|
182649
|
+
}
|
|
182650
|
+
charts.push({
|
|
182651
|
+
name: name2,
|
|
182652
|
+
version: text(get(root2, "version")),
|
|
182653
|
+
appVersion: text(get(root2, "appVersion")),
|
|
182654
|
+
library: text(get(root2, "type")) === "library",
|
|
182655
|
+
folder,
|
|
182656
|
+
start: file2.start,
|
|
182657
|
+
dependencies: [...dependenciesOf(get(root2, "dependencies")), ...dependenciesOf(get(requirements, "dependencies"))],
|
|
182658
|
+
values: parsed(byFolder(folder, "values.yaml")),
|
|
182659
|
+
locked
|
|
182660
|
+
});
|
|
182661
|
+
}
|
|
182662
|
+
if (charts.length === 0) {
|
|
182663
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "No Chart.yaml with a name was found.", "Send the chart folder with its Chart.yaml, or the output of helm template.");
|
|
182664
|
+
return null;
|
|
182665
|
+
}
|
|
182666
|
+
if (templates.length > 0) {
|
|
182667
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(templates[0]?.start ?? 0), `${countOf2(templates.length, "template")} of the chart ${templates.length === 1 ? "is" : "are"} not rendered, so the objects ${templates.length === 1 ? "it makes are" : "they make are"} not drawn.`, "Run helm template with the values to deploy, and import its output as helm to draw the objects.");
|
|
182668
|
+
}
|
|
182669
|
+
charts.sort((a, b) => a.folder.split("/").length - b.folder.split("/").length || (a.folder < b.folder ? -1 : 1));
|
|
182670
|
+
const chartKey = (chart) => `chart:${chart.folder === "" ? chart.name : chart.folder}`;
|
|
182671
|
+
const nodes = [];
|
|
182672
|
+
const edges = [];
|
|
182673
|
+
const repositories = new Set(charts.flatMap((chart) => chart.dependencies.map((dependency) => dependency.repository)).filter((repository) => repository !== null && repository !== "" && !repository.startsWith("file://")));
|
|
182674
|
+
const framed = repositories.size > 1;
|
|
182675
|
+
const groups = framed ? [...repositories].sort().map((repository) => ({ key: `repository:${repository}`, label: repositoryLabel(repository), sub: "Chart repository", icon: "simple:helm", idHint: repositoryLabel(repository).split("/").pop() ?? "repository" })) : [];
|
|
182676
|
+
for (const chart of charts) {
|
|
182677
|
+
const look = imageLook(chart.name);
|
|
182678
|
+
nodes.push({ key: chartKey(chart), type: look?.type ?? "service", label: chart.name, sub: cleanText([[chart.library ? "Library chart" : "Chart", chart.version].filter((part) => part !== null).join(" "), chart.appVersion === null ? null : `app ${chart.appVersion}`].filter((part) => part !== null).join(", ")), icon: look?.icon ?? "simple:helm", idHint: chart.name });
|
|
182679
|
+
}
|
|
182680
|
+
for (const chart of charts) {
|
|
182681
|
+
for (const dependency of chart.dependencies) {
|
|
182682
|
+
const shown = dependency.alias ?? dependency.name;
|
|
182683
|
+
const vendored = charts.find((other) => other.folder === `${chart.folder === "" ? "" : `${chart.folder}/`}charts/${dependency.name}`) ?? (dependency.repository?.startsWith("file://") === true ? charts.find((other) => other.name === dependency.name) : void 0);
|
|
182684
|
+
const key = vendored === void 0 ? `dependency:${chart.name}/${shown}` : chartKey(vendored);
|
|
182685
|
+
const setting = dependency.condition === null ? null : dependency.condition.split(",").map((path) => valueAt(chart.values, path.trim())).find((value) => value !== null) ?? null;
|
|
182686
|
+
const off = setting === "false";
|
|
182687
|
+
if (vendored === void 0) {
|
|
182688
|
+
const look = imageLook(dependency.name);
|
|
182689
|
+
const repository = dependency.repository !== null && repositories.has(dependency.repository) && framed ? `repository:${dependency.repository}` : null;
|
|
182690
|
+
nodes.push({ key, type: look?.type ?? "service", label: shown, sub: cleanText([shown === dependency.name ? "Chart" : `Chart ${dependency.name}`, off ? "off in values" : dependency.condition !== null && setting !== "true" ? "optional" : null].filter((part) => part !== null).join(", ")), icon: look?.icon ?? iconForName(dependency.name, look?.type ?? "service") ?? "simple:helm", group: repository, idHint: shown });
|
|
182691
|
+
}
|
|
182692
|
+
const version2 = chart.locked.get(dependency.name) ?? dependency.version;
|
|
182693
|
+
edges.push({ from: chartKey(chart), to: key, label: version2, ...off ? { arrow: "-->" } : {} });
|
|
182694
|
+
}
|
|
182695
|
+
}
|
|
182696
|
+
const root = charts[0];
|
|
182697
|
+
const dependencies = charts.reduce((total, chart) => total + chart.dependencies.length, 0);
|
|
182698
|
+
return writeFlow(
|
|
182699
|
+
{
|
|
182700
|
+
title: context.title ?? `Helm chart ${root.name}`,
|
|
182701
|
+
desc: `${countOf2(charts.length, "chart")} and the ${countOf2(dependencies, "dependency", "dependencies")} they declare, imported from a Helm chart folder. An arrow points from a chart to a chart it depends on, labelled with the version it gets; a dashed one is switched off in values.yaml.`,
|
|
182702
|
+
direction: "down",
|
|
182703
|
+
nodes,
|
|
182704
|
+
groups,
|
|
182705
|
+
edges,
|
|
182706
|
+
noun: "charts",
|
|
182707
|
+
capSpan: (key) => index2.span(charts.find((chart) => chartKey(chart) === key)?.start ?? 0),
|
|
182708
|
+
advice: "Import the output of helm template as helm to draw the objects each chart makes."
|
|
182709
|
+
},
|
|
182710
|
+
context.report
|
|
182711
|
+
);
|
|
182712
|
+
}
|
|
182713
|
+
var baseName, folderOf, repositoryLabel;
|
|
182714
|
+
var init_chart = __esm({
|
|
182715
|
+
"../../packages/diagrams/src/importers/helm/chart.ts"() {
|
|
182716
|
+
"use strict";
|
|
182717
|
+
init_core();
|
|
182718
|
+
init_shared2();
|
|
182719
|
+
init_yaml();
|
|
182720
|
+
baseName = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
182721
|
+
folderOf = (path) => path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
|
|
182722
|
+
repositoryLabel = (repository) => repository.replace(/^[a-z]+:\/\//i, "").replace(/\/+$/, "") || repository;
|
|
182723
|
+
}
|
|
182724
|
+
});
|
|
182725
|
+
|
|
182726
|
+
// ../../packages/diagrams/src/importers/kubernetes/manifests.ts
|
|
182727
|
+
function valuesOf(kind, root, podSpec) {
|
|
182728
|
+
const raw = kind === "ConfigMap" ? entries(get(root, "data")).map((entry2) => text(entry2.value)) : items(get(podSpec, "containers")).flatMap((container) => items(get(container, "env")).map((variable) => text(get(variable, "value"))));
|
|
182729
|
+
return raw.filter((value) => value !== null && value.length <= MAX_VALUE_LENGTH);
|
|
182730
|
+
}
|
|
182731
|
+
function stringMap(node3) {
|
|
182732
|
+
const out = /* @__PURE__ */ new Map();
|
|
182733
|
+
if (node3?.kind === "map") for (const entry2 of node3.entries) out.set(entry2.key, text(entry2.value) ?? "");
|
|
182734
|
+
return out;
|
|
182735
|
+
}
|
|
182736
|
+
function podUses(spec) {
|
|
182737
|
+
const uses = [];
|
|
182738
|
+
const add2 = (kind, name2) => {
|
|
182739
|
+
if (name2 !== null && name2 !== "" && !uses.some((use) => use.kind === kind && use.name === name2)) uses.push({ kind, name: name2 });
|
|
182740
|
+
};
|
|
182741
|
+
for (const container of [...items(get(spec, "initContainers")), ...items(get(spec, "containers"))]) {
|
|
182742
|
+
for (const source of items(get(container, "envFrom"))) {
|
|
182743
|
+
add2("ConfigMap", text(at2(source, ["configMapRef", "name"])));
|
|
182744
|
+
add2("Secret", text(at2(source, ["secretRef", "name"])));
|
|
182745
|
+
}
|
|
182746
|
+
for (const variable of items(get(container, "env"))) {
|
|
182747
|
+
add2("ConfigMap", text(at2(variable, ["valueFrom", "configMapKeyRef", "name"])));
|
|
182748
|
+
add2("Secret", text(at2(variable, ["valueFrom", "secretKeyRef", "name"])));
|
|
182749
|
+
}
|
|
182750
|
+
}
|
|
182751
|
+
for (const volume of items(get(spec, "volumes"))) {
|
|
182752
|
+
add2("ConfigMap", text(at2(volume, ["configMap", "name"])));
|
|
182753
|
+
add2("Secret", text(at2(volume, ["secret", "secretName"])));
|
|
182754
|
+
add2("PersistentVolumeClaim", text(at2(volume, ["persistentVolumeClaim", "claimName"])));
|
|
182755
|
+
}
|
|
182756
|
+
return uses;
|
|
182757
|
+
}
|
|
182758
|
+
function ingressRoutes(spec) {
|
|
182759
|
+
const routes = [];
|
|
182760
|
+
const backend = (node3) => text(at2(node3, ["service", "name"])) ?? text(get(node3, "serviceName"));
|
|
182761
|
+
const add2 = (service, label) => {
|
|
182762
|
+
if (service !== null && !routes.some((route) => route.service === service)) routes.push({ service, label });
|
|
182763
|
+
};
|
|
182764
|
+
add2(backend(get(spec, "defaultBackend") ?? get(spec, "backend")), null);
|
|
182765
|
+
for (const rule of items(get(spec, "rules"))) {
|
|
182766
|
+
for (const path of items(at2(rule, ["http", "paths"]))) {
|
|
182767
|
+
const route = text(get(path, "path"));
|
|
182768
|
+
add2(backend(get(path, "backend")), route === null || route === "/" ? text(get(rule, "host")) : route);
|
|
182769
|
+
}
|
|
182770
|
+
}
|
|
182771
|
+
return routes;
|
|
182772
|
+
}
|
|
182773
|
+
function detailOf(kind, spec) {
|
|
182774
|
+
if (kind === "Service") {
|
|
182775
|
+
const ports = items(get(spec, "ports")).map((port) => text(get(port, "port"))).filter((port) => port !== null);
|
|
182776
|
+
return [text(get(spec, "type")) ?? "ClusterIP", ports.length === 0 ? "" : `port ${ports.slice(0, 3).join(", ")}`].filter((part) => part !== "").join(", ");
|
|
182777
|
+
}
|
|
182778
|
+
if (kind === "Ingress") return text(get(items(get(spec, "rules"))[0], "host")) ?? names5(get(items(get(spec, "tls"))[0], "hosts"))[0] ?? null;
|
|
182779
|
+
if (kind === "PersistentVolumeClaim") return text(at2(spec, ["resources", "requests", "storage"]));
|
|
182780
|
+
return null;
|
|
182781
|
+
}
|
|
182782
|
+
function readManifest(root) {
|
|
182783
|
+
const kind = text(get(root, "kind"));
|
|
182784
|
+
const name2 = text(at2(root, ["metadata", "name"]));
|
|
182785
|
+
if (kind === null || name2 === null) return null;
|
|
182786
|
+
const spec = get(root, "spec");
|
|
182787
|
+
const templatePath = WORKLOAD_TEMPLATES[kind];
|
|
182788
|
+
const template = templatePath === void 0 ? kind === "Pod" ? root : void 0 : at2(root, templatePath);
|
|
182789
|
+
const podSpec = get(template, "spec");
|
|
182790
|
+
const firstContainer = items(get(podSpec, "containers"))[0];
|
|
182791
|
+
return {
|
|
182792
|
+
kind,
|
|
182793
|
+
name: name2,
|
|
182794
|
+
namespace: text(at2(root, ["metadata", "namespace"])) ?? "default",
|
|
182795
|
+
line: root.line,
|
|
182796
|
+
column: root.column,
|
|
182797
|
+
labels: template !== void 0 ? stringMap(at2(template, ["metadata", "labels"])) : kind === "Service" ? stringMap(get(spec, "selector")) : /* @__PURE__ */ new Map(),
|
|
182798
|
+
meta: stringMap(at2(root, ["metadata", "labels"])),
|
|
182799
|
+
image: text(get(firstContainer, "image")),
|
|
182800
|
+
replicas: text(get(spec, "replicas")),
|
|
182801
|
+
uses: podSpec === void 0 ? [] : podUses(podSpec),
|
|
182802
|
+
routes: kind === "Ingress" ? ingressRoutes(spec) : [],
|
|
182803
|
+
detail: detailOf(kind, spec),
|
|
182804
|
+
values: valuesOf(kind, root, podSpec)
|
|
182805
|
+
};
|
|
182806
|
+
}
|
|
182807
|
+
function manifestRoots(roots) {
|
|
182808
|
+
const out = [];
|
|
182809
|
+
for (const root of roots) {
|
|
182810
|
+
if (text(get(root, "kind")) === "List") out.push(...items(get(root, "items")));
|
|
182811
|
+
else out.push(root);
|
|
182812
|
+
}
|
|
182813
|
+
return out;
|
|
182814
|
+
}
|
|
182815
|
+
var WORKLOAD_TEMPLATES, DRAWN_KINDS, QUIET_KINDS, MAX_VALUE_LENGTH, at2;
|
|
182816
|
+
var init_manifests = __esm({
|
|
182817
|
+
"../../packages/diagrams/src/importers/kubernetes/manifests.ts"() {
|
|
182818
|
+
"use strict";
|
|
182819
|
+
init_yaml();
|
|
182820
|
+
WORKLOAD_TEMPLATES = {
|
|
182821
|
+
Deployment: ["spec", "template"],
|
|
182822
|
+
StatefulSet: ["spec", "template"],
|
|
182823
|
+
DaemonSet: ["spec", "template"],
|
|
182824
|
+
ReplicaSet: ["spec", "template"],
|
|
182825
|
+
Job: ["spec", "template"],
|
|
182826
|
+
CronJob: ["spec", "jobTemplate", "spec", "template"]
|
|
182827
|
+
};
|
|
182828
|
+
DRAWN_KINDS = /* @__PURE__ */ new Set([...Object.keys(WORKLOAD_TEMPLATES), "Pod", "Service", "Ingress", "ConfigMap", "Secret", "PersistentVolumeClaim"]);
|
|
182829
|
+
QUIET_KINDS = /* @__PURE__ */ new Set([
|
|
182830
|
+
"Namespace",
|
|
182831
|
+
"ServiceAccount",
|
|
182832
|
+
"Role",
|
|
182833
|
+
"ClusterRole",
|
|
182834
|
+
"RoleBinding",
|
|
182835
|
+
"ClusterRoleBinding",
|
|
182836
|
+
"HorizontalPodAutoscaler",
|
|
182837
|
+
"PodDisruptionBudget",
|
|
182838
|
+
"NetworkPolicy",
|
|
182839
|
+
"LimitRange",
|
|
182840
|
+
"ResourceQuota",
|
|
182841
|
+
"PriorityClass",
|
|
182842
|
+
"ServiceMonitor",
|
|
182843
|
+
"PodMonitor",
|
|
182844
|
+
"VerticalPodAutoscaler",
|
|
182845
|
+
"Certificate",
|
|
182846
|
+
"IngressClass",
|
|
182847
|
+
"StorageClass"
|
|
182848
|
+
]);
|
|
182849
|
+
MAX_VALUE_LENGTH = 500;
|
|
182850
|
+
at2 = (node3, path) => path.reduce((current, key) => get(current, key), node3);
|
|
182851
|
+
}
|
|
182852
|
+
});
|
|
182853
|
+
|
|
182854
|
+
// ../../packages/diagrams/src/importers/kubernetes/index.ts
|
|
182855
|
+
function kindLook(kind) {
|
|
182856
|
+
const look = LOOKS[kind];
|
|
182857
|
+
return look === void 0 ? { type: "service", icon: null } : { type: look.type, icon: look.icon };
|
|
182858
|
+
}
|
|
182859
|
+
function namespaceType(name2) {
|
|
182860
|
+
const phrase2 = name2.toLowerCase().replace(/[-_]+/g, " ").trim();
|
|
182861
|
+
const matches3 = GROUP_TYPES.filter((type) => GROUP_TYPE_SPECS[type].phrases.includes(phrase2));
|
|
182862
|
+
return matches3.length === 1 ? matches3[0] : null;
|
|
182863
|
+
}
|
|
182864
|
+
function nodeOf(manifest, grouped, serviceDetail) {
|
|
182865
|
+
const look = LOOKS[manifest.kind] ?? { type: "service", icon: null, rank: 2 };
|
|
182866
|
+
const image = manifest.image === null ? null : imageLook(manifest.image);
|
|
182867
|
+
const replicas = manifest.replicas !== null && manifest.replicas !== "1" ? `, ${manifest.replicas} replicas` : "";
|
|
182868
|
+
const detail = (serviceDetail ?? manifest.detail) === null ? "" : `, ${serviceDetail ?? manifest.detail}`;
|
|
182869
|
+
return {
|
|
182870
|
+
key: keyOf(manifest.kind, manifest.namespace, manifest.name),
|
|
182871
|
+
type: image?.type ?? look.type,
|
|
182872
|
+
label: manifest.name,
|
|
182873
|
+
sub: `${manifest.kind}${replicas}${detail}`,
|
|
182874
|
+
// A workload whose image this reader does not know may still be named after a product, such as kafka; lint's own rule finds it.
|
|
182875
|
+
icon: image?.icon ?? look.icon ?? iconForName(manifest.name, image?.type ?? look.type),
|
|
182876
|
+
group: grouped ? `ns:${manifest.namespace}` : null,
|
|
182877
|
+
idHint: manifest.name
|
|
182878
|
+
};
|
|
182879
|
+
}
|
|
182880
|
+
function namesHost(value, host) {
|
|
182881
|
+
if (host === "") return false;
|
|
182882
|
+
for (let index2 = value.indexOf(host); index2 !== -1; index2 = value.indexOf(host, index2 + 1)) {
|
|
182883
|
+
const before = index2 === 0 ? "" : value.charAt(index2 - 1);
|
|
182884
|
+
const after = value.charAt(index2 + host.length);
|
|
182885
|
+
if (!/[A-Za-z0-9.-]/.test(before) && !/[A-Za-z0-9_-]/.test(after)) return true;
|
|
182886
|
+
}
|
|
182887
|
+
return false;
|
|
182888
|
+
}
|
|
182889
|
+
function foldedServices(drawn) {
|
|
182890
|
+
const folded = /* @__PURE__ */ new Map();
|
|
182891
|
+
for (const service of drawn) {
|
|
182892
|
+
if (service.kind !== "Service") continue;
|
|
182893
|
+
const workloads = selected(service, drawn);
|
|
182894
|
+
const only = workloads[0];
|
|
182895
|
+
if (workloads.length === 1 && only !== void 0) folded.set(keyOf("Service", service.namespace, service.name), keyOf(only.kind, only.namespace, only.name));
|
|
182896
|
+
}
|
|
182897
|
+
return folded;
|
|
182898
|
+
}
|
|
182899
|
+
function edgesOf(drawn, folded, context) {
|
|
182900
|
+
const edges = [];
|
|
182901
|
+
const has = (kind, namespace, name2) => drawn.some((other) => other.kind === kind && other.namespace === namespace && other.name === name2);
|
|
182902
|
+
const unresolved = (manifest, what) => {
|
|
182903
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(manifest.line, manifest.column), `${manifest.kind} ${manifest.name} names the ${what}, which is not in the text.`, "Include its manifest, or leave it out if it is created elsewhere; the arrow was not drawn.");
|
|
182904
|
+
};
|
|
182905
|
+
for (const manifest of drawn) {
|
|
182906
|
+
const from = keyOf(manifest.kind, manifest.namespace, manifest.name);
|
|
182907
|
+
for (const route of manifest.routes) {
|
|
182908
|
+
const service = keyOf("Service", manifest.namespace, route.service);
|
|
182909
|
+
if (has("Service", manifest.namespace, route.service)) edges.push({ from, to: folded.get(service) ?? service, label: route.label });
|
|
182910
|
+
else unresolved(manifest, `Service ${route.service}`);
|
|
182911
|
+
}
|
|
182912
|
+
if (manifest.kind === "Service" && !folded.has(from)) {
|
|
182913
|
+
for (const workload of selected(manifest, drawn)) edges.push({ from, to: keyOf(workload.kind, workload.namespace, workload.name) });
|
|
182914
|
+
}
|
|
182915
|
+
if (manifest.image !== null) {
|
|
182916
|
+
const read = drawn.filter((other) => other.kind === "ConfigMap" && other.namespace === manifest.namespace && manifest.uses.some((use) => use.kind === "ConfigMap" && use.name === other.name));
|
|
182917
|
+
const values = [...manifest.values, ...read.flatMap((config2) => config2.values)];
|
|
182918
|
+
for (const service of drawn) {
|
|
182919
|
+
const host = service.namespace === manifest.namespace ? service.name : `${service.name}.${service.namespace}`;
|
|
182920
|
+
if (service.kind !== "Service" || !values.some((value) => namesHost(value, host))) continue;
|
|
182921
|
+
const key = keyOf("Service", service.namespace, service.name);
|
|
182922
|
+
const to = folded.get(key) ?? key;
|
|
182923
|
+
if (to !== from) edges.push({ from, to });
|
|
182924
|
+
}
|
|
182925
|
+
}
|
|
182926
|
+
for (const use of manifest.uses) {
|
|
182927
|
+
if (has(use.kind, manifest.namespace, use.name)) edges.push({ from, to: keyOf(use.kind, manifest.namespace, use.name), arrow: use.kind === "PersistentVolumeClaim" ? "->" : "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads" });
|
|
182928
|
+
else unresolved(manifest, `${use.kind} ${use.name}`);
|
|
182929
|
+
}
|
|
182930
|
+
}
|
|
182931
|
+
return edges;
|
|
182932
|
+
}
|
|
182933
|
+
function readKubernetes(textIn, context) {
|
|
182934
|
+
const read = parseYaml(textIn);
|
|
182935
|
+
if (read.error !== null) {
|
|
182936
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
182937
|
+
return null;
|
|
182938
|
+
}
|
|
182939
|
+
return drawManifests(read.documents.map((document2) => document2.root).filter((root) => root !== null), context, null);
|
|
182940
|
+
}
|
|
182941
|
+
function drawManifests(documents, context, framing) {
|
|
182942
|
+
const roots = manifestRoots(documents);
|
|
182943
|
+
const drawn = [];
|
|
182944
|
+
const unknown2 = [];
|
|
182945
|
+
for (const root of roots) {
|
|
182946
|
+
const manifest = readManifest(root);
|
|
182947
|
+
if (manifest === null || QUIET_KINDS.has(manifest.kind)) continue;
|
|
182948
|
+
if (DRAWN_KINDS.has(manifest.kind)) {
|
|
182949
|
+
if (!drawn.some((other) => other.kind === manifest.kind && other.namespace === manifest.namespace && other.name === manifest.name)) drawn.push(manifest);
|
|
182950
|
+
} else unknown2.push(manifest);
|
|
182951
|
+
}
|
|
182952
|
+
const firstUnknown = unknown2[0];
|
|
182953
|
+
if (firstUnknown !== void 0) {
|
|
182954
|
+
const kinds2 = [...new Set(unknown2.map((manifest) => manifest.kind))];
|
|
182955
|
+
context.report.add(
|
|
182956
|
+
DIAGNOSTIC_CODES.importSkipped,
|
|
182957
|
+
spanAt3(firstUnknown.line, firstUnknown.column),
|
|
182958
|
+
`${countOf2(unknown2.length, "object")} of a kind this reader does not draw ${unknown2.length === 1 ? "was" : "were"} left out: ${kinds2.slice(0, 6).join(", ")}.`,
|
|
182959
|
+
"The reader draws workloads, Services, Ingresses, ConfigMaps, Secrets, and PersistentVolumeClaims. Add the others by hand if they matter."
|
|
182960
|
+
);
|
|
182961
|
+
}
|
|
182962
|
+
if (drawn.length === 0) {
|
|
182963
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, spanAt3(1, 1), "No workload, Service, Ingress, ConfigMap, Secret, or claim was found.", "Send manifests with apiVersion, kind, and metadata.name, separated by ---.");
|
|
182964
|
+
return null;
|
|
182965
|
+
}
|
|
182966
|
+
const ordered = [...drawn].sort((a, b) => (LOOKS[a.kind]?.rank ?? 2) - (LOOKS[b.kind]?.rank ?? 2));
|
|
182967
|
+
const namespaces = [...new Set(ordered.map((manifest) => manifest.namespace))];
|
|
182968
|
+
const grouped = namespaces.length > 1;
|
|
182969
|
+
const groups = grouped ? namespaces.map((namespace) => ({ key: `ns:${namespace}`, label: namespace, type: namespaceType(namespace), sub: "Namespace", idHint: `ns_${namespace}` })) : [];
|
|
182970
|
+
const framed = /* @__PURE__ */ new Map();
|
|
182971
|
+
for (const manifest of framing === null ? [] : ordered) {
|
|
182972
|
+
let parent = grouped ? `ns:${manifest.namespace}` : null;
|
|
182973
|
+
for (const frame of framing?.framesOf(manifest) ?? []) {
|
|
182974
|
+
const key = grouped ? `${manifest.namespace}/${frame.key}` : frame.key;
|
|
182975
|
+
if (!groups.some((group2) => group2.key === key)) groups.push({ key, label: frame.label, sub: frame.sub, icon: frame.icon, parent, idHint: frame.idHint });
|
|
182976
|
+
parent = key;
|
|
182977
|
+
}
|
|
182978
|
+
if (parent !== null) framed.set(manifest, parent);
|
|
182979
|
+
}
|
|
182980
|
+
const only = namespaces[0] ?? "default";
|
|
182981
|
+
const folded = foldedServices(ordered);
|
|
182982
|
+
const servicePorts = /* @__PURE__ */ new Map();
|
|
182983
|
+
for (const manifest of ordered) {
|
|
182984
|
+
const workload = folded.get(keyOf(manifest.kind, manifest.namespace, manifest.name));
|
|
182985
|
+
const ports = manifest.detail?.replace(/^ClusterIP(, )?/, "") ?? "";
|
|
182986
|
+
if (workload !== void 0 && ports !== "" && !servicePorts.has(workload)) servicePorts.set(workload, ports);
|
|
182987
|
+
}
|
|
182988
|
+
const boxes2 = ordered.filter((manifest) => !folded.has(keyOf(manifest.kind, manifest.namespace, manifest.name)));
|
|
182989
|
+
const workloads = boxes2.filter((manifest) => manifest.image !== null).length;
|
|
182990
|
+
const others = boxes2.length - workloads;
|
|
182991
|
+
return writeFlow(
|
|
182992
|
+
{
|
|
182993
|
+
title: context.title ?? framing?.title ?? (grouped || only === "default" ? "Kubernetes workloads" : `Kubernetes namespace ${only}`),
|
|
182994
|
+
desc: `${countOf2(workloads, "workload")}${others > 0 ? ` and ${countOf2(others, "object")} around ${workloads === 1 ? "it" : "them"}` : ""}${grouped ? ` in ${countOf2(namespaces.length, "namespace")}` : ""}, imported from ${framing?.source ?? "Kubernetes manifests"}. ${boxes2.some((manifest) => manifest.kind === "Ingress") ? "Traffic flows from each Ingress to the pods behind its Services" : "Solid arrows are calls to a Service"}, and dashed arrows are configuration the pods read.`,
|
|
182995
|
+
direction: "down",
|
|
182996
|
+
nodes: boxes2.map((manifest) => {
|
|
182997
|
+
const node3 = nodeOf(manifest, grouped, servicePorts.get(keyOf(manifest.kind, manifest.namespace, manifest.name)) ?? null);
|
|
182998
|
+
return framed.has(manifest) ? { ...node3, group: framed.get(manifest) ?? null } : node3;
|
|
182999
|
+
}),
|
|
183000
|
+
groups,
|
|
183001
|
+
edges: edgesOf(ordered, folded, context),
|
|
183002
|
+
noun: "objects",
|
|
183003
|
+
capSpan: (key) => {
|
|
183004
|
+
const manifest = ordered.find((candidate2) => keyOf(candidate2.kind, candidate2.namespace, candidate2.name) === key);
|
|
183005
|
+
return spanAt3(manifest?.line ?? 1, manifest?.column ?? 1);
|
|
183006
|
+
},
|
|
183007
|
+
advice: "Check the arrows from each Service: they follow its selector, so a selector that matches no pod template draws none. Label the Ingress arrows with their paths if they carry none."
|
|
183008
|
+
},
|
|
183009
|
+
context.report
|
|
183010
|
+
);
|
|
183011
|
+
}
|
|
183012
|
+
var LOOKS, keyOf, selects, selected, kubernetesImporter;
|
|
183013
|
+
var init_kubernetes = __esm({
|
|
183014
|
+
"../../packages/diagrams/src/importers/kubernetes/index.ts"() {
|
|
183015
|
+
"use strict";
|
|
183016
|
+
init_constants();
|
|
183017
|
+
init_core();
|
|
183018
|
+
init_shared2();
|
|
183019
|
+
init_yaml();
|
|
183020
|
+
init_manifests();
|
|
183021
|
+
LOOKS = {
|
|
183022
|
+
Ingress: { type: "gateway", icon: "lucide:globe", rank: 0 },
|
|
183023
|
+
Service: { type: "gateway", icon: "lucide:network", rank: 1 },
|
|
183024
|
+
Deployment: { type: "service", icon: null, rank: 2 },
|
|
183025
|
+
StatefulSet: { type: "service", icon: null, rank: 2 },
|
|
183026
|
+
DaemonSet: { type: "service", icon: null, rank: 2 },
|
|
183027
|
+
ReplicaSet: { type: "service", icon: null, rank: 2 },
|
|
183028
|
+
Pod: { type: "service", icon: null, rank: 2 },
|
|
183029
|
+
Job: { type: "function", icon: "lucide:play", rank: 3 },
|
|
183030
|
+
CronJob: { type: "function", icon: "lucide:calendar-clock", rank: 3 },
|
|
183031
|
+
PersistentVolumeClaim: { type: "storage", icon: "lucide:hard-drive", rank: 4 },
|
|
183032
|
+
ConfigMap: { type: "storage", icon: "lucide:settings-2", rank: 5 },
|
|
183033
|
+
Secret: { type: "secret", icon: "lucide:key-round", rank: 5 }
|
|
183034
|
+
};
|
|
183035
|
+
keyOf = (kind, namespace, name2) => `${namespace}/${kind}/${name2}`;
|
|
183036
|
+
selects = (selector, labels2) => selector.size > 0 && [...selector].every(([key, value]) => labels2.get(key) === value);
|
|
183037
|
+
selected = (service, drawn) => drawn.filter((workload) => workload.namespace === service.namespace && workload.kind !== "Service" && workload.image !== null && selects(service.labels, workload.labels));
|
|
183038
|
+
kubernetesImporter = { format: "kubernetes", kinds: ["flow"], joins: "\n---\n", extensions: [".yaml", ".yml"], read: readKubernetes };
|
|
183039
|
+
}
|
|
183040
|
+
});
|
|
183041
|
+
|
|
183042
|
+
// ../../packages/diagrams/src/importers/kustomize/folder.ts
|
|
183043
|
+
function resolvePath(folder, path) {
|
|
183044
|
+
const parts = folder === "" ? [] : folder.split("/");
|
|
183045
|
+
for (const part of path.split("/")) {
|
|
183046
|
+
if (part === "" || part === ".") continue;
|
|
183047
|
+
if (part === "..") {
|
|
183048
|
+
if (parts.length === 0) return null;
|
|
183049
|
+
parts.pop();
|
|
183050
|
+
} else parts.push(part);
|
|
183051
|
+
}
|
|
183052
|
+
return parts.join("/");
|
|
183053
|
+
}
|
|
183054
|
+
function kustomizationOf(root, folder, start2) {
|
|
183055
|
+
const patches = [];
|
|
183056
|
+
for (const entry2 of items(get(root, "patches"))) {
|
|
183057
|
+
const target = get(entry2, "target");
|
|
183058
|
+
patches.push({ path: text(entry2) ?? text(get(entry2, "path")), target: target === void 0 ? null : { kind: text(get(target, "kind")), name: text(get(target, "name")) } });
|
|
183059
|
+
}
|
|
183060
|
+
for (const key of ["patchesStrategicMerge", "patchesJson6902"]) {
|
|
183061
|
+
for (const entry2 of items(get(root, key))) {
|
|
183062
|
+
const target = get(entry2, "target");
|
|
183063
|
+
patches.push({ path: text(entry2) ?? text(get(entry2, "path")), target: target === void 0 ? null : { kind: text(get(target, "kind")), name: text(get(target, "name")) } });
|
|
183064
|
+
}
|
|
183065
|
+
}
|
|
183066
|
+
const generators = [
|
|
183067
|
+
...items(get(root, "configMapGenerator")).map((entry2) => ({ name: text(get(entry2, "name")), kind: "ConfigMap" })),
|
|
183068
|
+
...items(get(root, "secretGenerator")).map((entry2) => ({ name: text(get(entry2, "name")), kind: "Secret" }))
|
|
183069
|
+
].filter((entry2) => entry2.name !== null);
|
|
183070
|
+
const images = items(get(root, "images")).map((entry2) => {
|
|
183071
|
+
const name2 = text(get(entry2, "name"));
|
|
183072
|
+
const tag = text(get(entry2, "newTag")) ?? text(get(entry2, "digest"));
|
|
183073
|
+
return name2 === null ? null : `${baseName2(text(get(entry2, "newName")) ?? name2)}${tag === null ? "" : `:${tag}`}`;
|
|
183074
|
+
}).filter((entry2) => entry2 !== null);
|
|
183075
|
+
const replicas = items(get(root, "replicas")).map((entry2) => `${text(get(entry2, "name")) ?? ""} ${text(get(entry2, "count")) ?? "?"} replicas`);
|
|
183076
|
+
const namespace = text(get(root, "namespace"));
|
|
183077
|
+
const prefix = text(get(root, "namePrefix"));
|
|
183078
|
+
const suffix = text(get(root, "nameSuffix"));
|
|
183079
|
+
const details = [namespace === null ? null : `namespace ${namespace}`, prefix === null ? null : `prefix ${prefix}`, suffix === null ? null : `suffix ${suffix}`, ...images, ...replicas].filter((entry2) => entry2 !== null && entry2 !== "");
|
|
183080
|
+
return { folder, start: start2, component: text(get(root, "kind")) === "Component", resources: [...names5(get(root, "resources")), ...names5(get(root, "bases"))], components: names5(get(root, "components")), patches, generators, details };
|
|
183081
|
+
}
|
|
183082
|
+
function drawFolder(files, context, index2) {
|
|
183083
|
+
const read = (file2) => {
|
|
183084
|
+
const parsed = parseYaml(file2.text);
|
|
183085
|
+
if (parsed.error !== null) {
|
|
183086
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(file2.start), `${cleanText(file2.path, "A file")} is not read: ${parsed.error.message}`, parsed.error.hint);
|
|
183087
|
+
return null;
|
|
183088
|
+
}
|
|
183089
|
+
return parsed.documents.map((document2) => document2.root).filter((root) => root !== null);
|
|
183090
|
+
};
|
|
183091
|
+
const kustomizations = [];
|
|
183092
|
+
const objects = /* @__PURE__ */ new Map();
|
|
183093
|
+
for (const file2 of files) {
|
|
183094
|
+
const roots = read(file2);
|
|
183095
|
+
if (roots === null) continue;
|
|
183096
|
+
const isOwn = KUSTOMIZATION_NAMES.has(baseName2(file2.path)) || file2.path === "" && isKustomization(file2.text);
|
|
183097
|
+
if (isOwn && roots[0] !== void 0) kustomizations.push(kustomizationOf(roots[0], folderOf2(file2.path), file2.start));
|
|
183098
|
+
else objects.set(file2.path, objectsOf(roots));
|
|
183099
|
+
}
|
|
183100
|
+
if (kustomizations.length === 0) {
|
|
183101
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "No kustomization.yaml was found.", "Send the folder with its kustomization.yaml files, or the output of kustomize build.");
|
|
183102
|
+
return null;
|
|
183103
|
+
}
|
|
183104
|
+
const byFolder = new Map(kustomizations.map((entry2) => [entry2.folder, entry2]));
|
|
183105
|
+
const missing = [];
|
|
183106
|
+
const roleOf3 = (entry2) => entry2.component ? "Component" : entry2.resources.some((resource) => isRemote(resource) || byFolder.has(resolvePath(entry2.folder, resource) ?? "\0")) ? "Overlay" : "Base";
|
|
183107
|
+
const rank = { Overlay: 0, Component: 1, Base: 2 };
|
|
183108
|
+
const ordered = [...kustomizations].sort((a, b) => rank[roleOf3(a)] - rank[roleOf3(b)] || (a.folder < b.folder ? -1 : 1));
|
|
183109
|
+
const firstParts = (kustomizations[0]?.folder ?? "").split("/");
|
|
183110
|
+
let shared = 0;
|
|
183111
|
+
while (shared < firstParts.length && kustomizations.every((entry2) => entry2.folder.split("/")[shared] === firstParts[shared] && entry2.folder.split("/").length > shared + 1)) shared += 1;
|
|
183112
|
+
const common = shared === 0 ? "" : `${firstParts.slice(0, shared).join("/")}/`;
|
|
183113
|
+
const groups = [];
|
|
183114
|
+
const nodes = [];
|
|
183115
|
+
const edges = [];
|
|
183116
|
+
const own2 = (entry2) => `kustomization:${entry2.folder}`;
|
|
183117
|
+
const fileOf2 = (entry2, kind, name2, depth = 0) => {
|
|
183118
|
+
if (depth > 16) return null;
|
|
183119
|
+
for (const resource of entry2.resources) {
|
|
183120
|
+
const path = isRemote(resource) ? null : resolvePath(entry2.folder, resource);
|
|
183121
|
+
if (path === null) continue;
|
|
183122
|
+
const inner = byFolder.get(path);
|
|
183123
|
+
if (inner !== void 0) {
|
|
183124
|
+
const found = fileOf2(inner, kind, name2, depth + 1);
|
|
183125
|
+
if (found !== null) return found;
|
|
183126
|
+
} else if ((objects.get(path) ?? []).some((object2) => (kind === null || object2.kind === kind) && (name2 === null || object2.name === name2))) return path;
|
|
183127
|
+
}
|
|
183128
|
+
return null;
|
|
183129
|
+
};
|
|
183130
|
+
for (const entry2 of ordered) {
|
|
183131
|
+
const role = roleOf3(entry2);
|
|
183132
|
+
const frame = `frame:${entry2.folder}`;
|
|
183133
|
+
groups.push({ key: frame, label: entry2.folder.slice(common.length) || baseName2(entry2.folder) || "kustomization", sub: role, icon: "lucide:layers", idHint: entry2.folder.slice(common.length) || baseName2(entry2.folder) || "root" });
|
|
183134
|
+
nodes.push({ key: own2(entry2), type: "service", label: baseName2(entry2.folder) || "kustomization", sub: cleanText(entry2.details.length === 0 ? "kustomization.yaml" : entry2.details.slice(0, 4).join(", ")), icon: "lucide:layers", group: frame, idHint: `${baseName2(entry2.folder) || "kustomization"}_kustomization` });
|
|
183135
|
+
for (const resource of entry2.resources) {
|
|
183136
|
+
if (isRemote(resource)) {
|
|
183137
|
+
nodes.push({ key: `remote:${resource}`, type: "service", label: cleanText(resource.replace(/^https?:\/\//, "").replace(/\?.*$/, "").split("/").slice(-2).join("/")), sub: "Remote resource", icon: "lucide:globe", group: frame, idHint: "remote" });
|
|
183138
|
+
edges.push({ from: own2(entry2), to: `remote:${resource}`, label: "builds on" });
|
|
183139
|
+
continue;
|
|
183140
|
+
}
|
|
183141
|
+
const path = resolvePath(entry2.folder, resource);
|
|
183142
|
+
const inner = path === null ? void 0 : byFolder.get(path);
|
|
183143
|
+
if (inner !== void 0) {
|
|
183144
|
+
edges.push({ from: own2(entry2), to: own2(inner), label: "builds on" });
|
|
183145
|
+
continue;
|
|
183146
|
+
}
|
|
183147
|
+
const found = path === null ? void 0 : objects.get(path);
|
|
183148
|
+
if (path === null || found === void 0) {
|
|
183149
|
+
missing.push(`${entry2.folder === "" ? "" : `${entry2.folder}/`}${resource}`);
|
|
183150
|
+
continue;
|
|
183151
|
+
}
|
|
183152
|
+
const first = found[0];
|
|
183153
|
+
const look = kindLook(first?.kind ?? "");
|
|
183154
|
+
nodes.push({ key: `file:${path}`, type: look.type, label: first === void 0 ? baseName2(path) : first.name, sub: cleanText(found.length <= 1 ? `${first?.kind ?? "No object"}, ${baseName2(path)}` : `${countOf2(found.length, "object")}, ${baseName2(path)}`), icon: look.icon, group: frame, idHint: baseName2(path).replace(/\.ya?ml$/, "") });
|
|
183155
|
+
}
|
|
183156
|
+
for (const component of entry2.components) {
|
|
183157
|
+
const inner = byFolder.get(resolvePath(entry2.folder, component) ?? "\0");
|
|
183158
|
+
if (inner !== void 0) edges.push({ from: own2(entry2), to: own2(inner), label: "includes" });
|
|
183159
|
+
else missing.push(`${entry2.folder === "" ? "" : `${entry2.folder}/`}${component}`);
|
|
183160
|
+
}
|
|
183161
|
+
for (const generator of entry2.generators) {
|
|
183162
|
+
const look = kindLook(generator.kind);
|
|
183163
|
+
nodes.push({ key: `generator:${entry2.folder}/${generator.kind}/${generator.name}`, type: look.type, label: generator.name, sub: `${generator.kind} generator`, icon: look.icon, group: frame, idHint: generator.name });
|
|
183164
|
+
}
|
|
183165
|
+
for (const patch of entry2.patches) {
|
|
183166
|
+
const path = patch.path === null ? null : resolvePath(entry2.folder, patch.path);
|
|
183167
|
+
const named = path === null ? void 0 : objects.get(path)?.[0];
|
|
183168
|
+
const kind = patch.target?.kind ?? named?.kind ?? null;
|
|
183169
|
+
const name2 = patch.target?.name ?? named?.name ?? null;
|
|
183170
|
+
const key = `patch:${entry2.folder}/${patch.path ?? `${kind ?? "any"}/${name2 ?? "any"}`}`;
|
|
183171
|
+
nodes.push({ key, type: "service", label: patch.path === null ? `${kind ?? "object"} ${name2 ?? ""}`.trim() : baseName2(patch.path), sub: cleanText(`Patch${kind === null ? "" : ` of ${kind}${name2 === null ? "" : ` ${name2}`}`}`), icon: "lucide:file-code", group: frame, idHint: `${baseName2(patch.path ?? "patch").replace(/\.ya?ml$/, "")}_patch` });
|
|
183172
|
+
const target = kind === null && name2 === null ? null : fileOf2(entry2, kind, name2) ?? [...objects].find(([, inside]) => inside.some((object2) => (kind === null || object2.kind === kind) && (name2 === null || object2.name === name2)))?.[0] ?? null;
|
|
183173
|
+
if (target !== null) edges.push({ from: key, to: `file:${target}`, label: "patches" });
|
|
183174
|
+
}
|
|
183175
|
+
}
|
|
183176
|
+
const drawnFiles = [...objects].filter(([path]) => nodes.some((node3) => node3.key === `file:${path}`));
|
|
183177
|
+
for (const [path, manifests] of drawnFiles) {
|
|
183178
|
+
for (const manifest of manifests) {
|
|
183179
|
+
for (const use of manifest.uses) {
|
|
183180
|
+
for (const node3 of nodes) if (node3.key.startsWith("generator:") && node3.key.endsWith(`/${use.kind}/${use.name}`)) edges.push({ from: `file:${path}`, to: node3.key, arrow: "-->", label: "reads" });
|
|
183181
|
+
const holder = drawnFiles.find(([, others]) => others.some((other) => other.kind === use.kind && other.name === use.name));
|
|
183182
|
+
if (holder !== void 0 && holder[0] !== path) edges.push({ from: `file:${path}`, to: `file:${holder[0]}`, arrow: "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads" });
|
|
183183
|
+
}
|
|
183184
|
+
for (const [other, inside] of drawnFiles) {
|
|
183185
|
+
if (other === path) continue;
|
|
183186
|
+
if (manifest.kind === "Service" && inside.some((workload) => workload.image !== null && selects(manifest.labels, workload.labels))) edges.push({ from: `file:${path}`, to: `file:${other}` });
|
|
183187
|
+
if (manifest.image !== null && inside.some((service) => service.kind === "Service" && manifest.values.some((value) => namesHost(value, service.name)))) edges.push({ from: `file:${path}`, to: `file:${other}` });
|
|
183188
|
+
}
|
|
183189
|
+
}
|
|
183190
|
+
}
|
|
183191
|
+
if (missing.length > 0) {
|
|
183192
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, START, `${countOf2(missing.length, "entry", "entries")} of the kustomizations ${missing.length === 1 ? "names a file that was" : "name files that were"} not sent, so ${missing.length === 1 ? "it is" : "they are"} not drawn: ${missing.slice(0, 3).map((entry2) => cleanText(entry2)).join(", ")}.`, "Send every file of the folder, with each base and component.");
|
|
183193
|
+
}
|
|
183194
|
+
const overlays = ordered.filter((entry2) => roleOf3(entry2) === "Overlay").length;
|
|
183195
|
+
return writeFlow(
|
|
183196
|
+
{
|
|
183197
|
+
title: context.title ?? "Kustomize overlays",
|
|
183198
|
+
desc: `${countOf2(kustomizations.length, "kustomization")}, ${countOf2(overlays, "overlay")} among them, imported from a Kustomize folder. Each frame is a kustomization with the files, patches, and generators it lists; an arrow shows what an overlay builds on or includes, and what a patch changes.`,
|
|
183199
|
+
direction: "down",
|
|
183200
|
+
nodes,
|
|
183201
|
+
groups,
|
|
183202
|
+
edges,
|
|
183203
|
+
noun: "entries",
|
|
183204
|
+
capSpan: () => index2.span(ordered[0]?.start ?? 0),
|
|
183205
|
+
advice: "Import the output of kustomize build for an overlay as kustomize to draw the objects it makes."
|
|
183206
|
+
},
|
|
183207
|
+
context.report
|
|
183208
|
+
);
|
|
183209
|
+
}
|
|
183210
|
+
var KUSTOMIZATION_NAMES, isKustomization, baseName2, folderOf2, isRemote, objectsOf;
|
|
183211
|
+
var init_folder = __esm({
|
|
183212
|
+
"../../packages/diagrams/src/importers/kustomize/folder.ts"() {
|
|
183213
|
+
"use strict";
|
|
183214
|
+
init_core();
|
|
183215
|
+
init_kubernetes();
|
|
183216
|
+
init_manifests();
|
|
183217
|
+
init_shared2();
|
|
183218
|
+
init_yaml();
|
|
183219
|
+
KUSTOMIZATION_NAMES = /* @__PURE__ */ new Set(["kustomization.yaml", "kustomization.yml", "Kustomization"]);
|
|
183220
|
+
isKustomization = (textIn) => /^apiVersion\s*:\s*["']?kustomize\.config\.k8s\.io\//m.test(textIn);
|
|
183221
|
+
baseName2 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
183222
|
+
folderOf2 = (path) => path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
|
|
183223
|
+
isRemote = (entry2) => /^(?:https?:\/\/|git@|github\.com\/|gitlab\.com\/|bitbucket\.org\/|ssh:\/\/)/.test(entry2) || /\?ref=/.test(entry2);
|
|
183224
|
+
objectsOf = (roots) => manifestRoots(roots).flatMap((node3) => readManifest(node3) ?? []);
|
|
183225
|
+
}
|
|
183226
|
+
});
|
|
183227
|
+
|
|
183228
|
+
// ../../packages/diagrams/src/importers/detect.ts
|
|
183229
|
+
function graphCommits(text3) {
|
|
183230
|
+
let count3 = 0;
|
|
183231
|
+
for (const line3 of text3.split("\n")) {
|
|
183232
|
+
let index2 = 0;
|
|
183233
|
+
while (index2 < line3.length && "*|\\/ _".includes(line3.charAt(index2))) index2 += 1;
|
|
183234
|
+
if (line3.slice(0, index2).includes("*") && /^[0-9a-f]{7,40}\s/.test(line3.slice(index2))) count3 += 1;
|
|
183235
|
+
}
|
|
183236
|
+
return count3;
|
|
183237
|
+
}
|
|
183238
|
+
function everyLine(text3, test) {
|
|
183239
|
+
const lines = filled(text3);
|
|
183240
|
+
return lines.length >= 3 && lines.every((line3) => test(line3.trim()));
|
|
183241
|
+
}
|
|
183242
|
+
function isOutline(text3) {
|
|
183243
|
+
const lines = filled(text3);
|
|
183244
|
+
return lines.length >= 3 && lines.every((line3) => /^\s*[-*+] \S/.test(line3)) && lines.some((line3) => /^\s+[-*+] /.test(line3));
|
|
183245
|
+
}
|
|
183246
|
+
function separators(line3, separator) {
|
|
183247
|
+
let count3 = 0;
|
|
183248
|
+
let quoted5 = false;
|
|
183249
|
+
for (const char of line3) {
|
|
183250
|
+
if (char === '"') quoted5 = !quoted5;
|
|
183251
|
+
else if (char === separator && !quoted5) count3 += 1;
|
|
183252
|
+
}
|
|
183253
|
+
return count3;
|
|
183254
|
+
}
|
|
183255
|
+
function isTable(text3) {
|
|
183256
|
+
const lines = filled(text3).slice(0, 6);
|
|
183257
|
+
if (lines.length < 2) return false;
|
|
183258
|
+
for (const separator of [",", " ", ";"]) {
|
|
183259
|
+
const counts = lines.map((line3) => separators(line3, separator));
|
|
183260
|
+
if ((counts[0] ?? 0) > 0 && counts.every((count3) => count3 === counts[0])) return true;
|
|
183261
|
+
}
|
|
183262
|
+
return false;
|
|
183263
|
+
}
|
|
183264
|
+
function importFormatFor(request, data) {
|
|
183265
|
+
const fromData = detectImportFormat(data);
|
|
183266
|
+
if (fromData !== null && SURE_FROM_DATA.has(fromData)) return fromData;
|
|
183267
|
+
return NAMES.find((name2) => name2.words.test(request.slice(0, SNIFF_LENGTH)))?.format ?? null;
|
|
183268
|
+
}
|
|
183269
|
+
function detectImportFormat(text3) {
|
|
183270
|
+
const head = text3.slice(0, SNIFF_LENGTH);
|
|
183271
|
+
if (head.trim() === "") return null;
|
|
183272
|
+
return SIGNS.find((sign) => sign.test(head))?.format ?? null;
|
|
183273
|
+
}
|
|
183274
|
+
var SNIFF_LENGTH, SIGNS, filled, NAMES, SURE_FROM_DATA;
|
|
183275
|
+
var init_detect = __esm({
|
|
183276
|
+
"../../packages/diagrams/src/importers/detect.ts"() {
|
|
183277
|
+
"use strict";
|
|
183278
|
+
init_chart();
|
|
183279
|
+
init_folder();
|
|
183280
|
+
SNIFF_LENGTH = 2e4;
|
|
183281
|
+
SIGNS = [
|
|
183282
|
+
{ format: "sql", test: (text3) => /^\s*create\s+(?:or\s+replace\s+)?(?:temporary\s+|temp\s+|unlogged\s+)?table\b/im.test(text3) },
|
|
183283
|
+
{ format: "prisma", test: (text3) => /^\s*model\s+\w+\s*\{/m.test(text3) && /@id\b|@relation\b|^\s*datasource\s+\w+\s*\{/m.test(text3) },
|
|
183284
|
+
{ format: "drizzle", test: (text3) => /\b(?:pgTable|sqliteTable|mysqlTable)\s*\(/.test(text3) },
|
|
183285
|
+
{ format: "openapi", test: (text3) => /^\s*["']?openapi["']?\s*:\s*["']?3\./m.test(text3) || /"openapi"\s*:\s*"3\./.test(text3) },
|
|
183286
|
+
{ format: "terraform-plan", test: (text3) => /^\s*\{\s*"format_version"\s*:/.test(text3) && /"terraform_version"\s*:/.test(text3) && /"(?:planned_values|resource_changes|root_module)"\s*:/.test(text3) },
|
|
183287
|
+
{ format: "terraform", test: (text3) => /^\s*resource\s+"[A-Za-z0-9_]+"\s+"[^"]+"\s*\{/m.test(text3) },
|
|
183288
|
+
{ format: "bicep", test: (text3) => /^\s*(?:resource|module)\s+[A-Za-z_]\w*\s+'[^'\n]+'\s*(?:existing\s*)?=/m.test(text3) || /^\s*targetScope\s*=\s*'/m.test(text3) },
|
|
183289
|
+
{ format: "arm", test: (text3) => /"\$schema"\s*:\s*"https?:\/\/schema\.management\.azure\.com\/schemas\/[^"]*(?:deploymentTemplate|DeploymentTemplate)/.test(text3) },
|
|
183290
|
+
{ format: "pulumi", test: (text3) => /^runtime\s*:\s*(?:yaml|\{\s*name\s*:\s*yaml)/m.test(text3) && /^resources\s*:/m.test(text3) || /"urn"\s*:\s*"urn:pulumi:/.test(text3) },
|
|
183291
|
+
{ format: "cdk", test: (text3) => /"?aws:cdk:path"?\s*:/.test(text3) || /"artifacts"\s*:/.test(text3) && /"aws:cloudformation:stack"/.test(text3) },
|
|
183292
|
+
{ format: "cloudformation", test: (text3) => /^\s*"?AWSTemplateFormatVersion"?\s*:/m.test(text3) || /^Transform\s*:\s*AWS::Serverless/m.test(text3) || /^\s*"?Resources"?\s*:/m.test(text3) && /"?Type"?\s*:\s*["']?AWS::[A-Za-z0-9]+::/.test(text3) },
|
|
183293
|
+
{ format: "backstage", test: (text3) => /^apiVersion\s*:\s*["']?backstage\.io\//m.test(text3) },
|
|
183294
|
+
// A kustomization, or what kustomize build makes of one: a generated ConfigMap or Secret whose name ends in its hash.
|
|
183295
|
+
{ format: "kustomize", test: (text3) => isKustomization(text3) || /^kind\s*:\s*(?:ConfigMap|Secret)\s*$/m.test(text3) && /^\s+name\s*:\s*[\w.-]+-(?=[^-\s]*\d)[b-df-hj-np-tv-z0-9]{10}\s*$/m.test(text3) },
|
|
183296
|
+
{ format: "helm", test: (text3) => /^\s*apiVersion\s*:/m.test(text3) && /^\s*kind\s*:\s*\w+/m.test(text3) && (/^# Source: [^\n]*\/templates\//m.test(text3) || /^\s*helm\.sh\/chart\s*:/m.test(text3)) || isChartFile(text3) },
|
|
183297
|
+
{ format: "kubernetes", test: (text3) => /^\s*apiVersion\s*:/m.test(text3) && /^\s*kind\s*:\s*\w+/m.test(text3) },
|
|
183298
|
+
{ format: "github-actions", test: (text3) => /^jobs\s*:/m.test(text3) && (/^\s*runs-on\s*:/m.test(text3) || /^["']?on["']?\s*:/m.test(text3)) },
|
|
183299
|
+
{ format: "compose", test: (text3) => /^services\s*:/m.test(text3) && /^\s+(?:image|build)\s*:/m.test(text3) },
|
|
183300
|
+
{ format: "tree", test: (text3) => /(?:├──|└──|\|-- |`-- )/.test(text3) || everyLine(text3, (line3) => /^[^\s/]+(?:\/[^\s/]+)+\/?$/.test(line3)) || isOutline(text3) },
|
|
183301
|
+
{ format: "git-log", test: (text3) => /^commit [0-9a-f]{7,40}\b/m.test(text3) || graphCommits(text3) >= 2 || everyLine(text3, (line3) => /^[0-9a-f]{7,40} \S/.test(line3)) },
|
|
183302
|
+
{ format: "json", test: (text3) => /^\s*[[{]/.test(text3) && /[\]}]\s*$/.test(text3) },
|
|
183303
|
+
{ format: "csv", test: (text3) => isTable(text3) }
|
|
183304
|
+
];
|
|
183305
|
+
filled = (text3) => text3.split("\n", 200).map((line3) => line3.trimEnd()).filter((line3) => line3.trim() !== "");
|
|
183306
|
+
NAMES = [
|
|
183307
|
+
{ format: "compose", words: /\b(?:docker[- ]compose|compose (?:file|yaml|yml|stack))\b/i },
|
|
183308
|
+
{ format: "backstage", words: /\b(?:backstage|catalog-info(?:\.yaml)?|software catalog)\b/i },
|
|
183309
|
+
{ format: "kustomize", words: /\b(?:kustomize|kustomization(?:\.yaml)?)\b/i },
|
|
183310
|
+
{ format: "helm", words: /\b(?:helm (?:charts?|template|release)|chart\.yaml)\b/i },
|
|
183311
|
+
{ format: "kubernetes", words: /\b(?:kubernetes|k8s)\b/i },
|
|
183312
|
+
{ format: "github-actions", words: /\b(?:github actions?|workflow (?:file|yaml|yml)|ci workflow)\b/i },
|
|
183313
|
+
{ format: "terraform-plan", words: /\b(?:terraform|tofu) (?:plan|state|show -json)\b|\bplan\.json\b/i },
|
|
183314
|
+
{ format: "terraform", words: /\b(?:terraform|opentofu|hcl|\.tf files?)\b/i },
|
|
183315
|
+
{ format: "bicep", words: /\b(?:bicep|\.bicep files?)\b/i },
|
|
183316
|
+
{ format: "arm", words: /\b(?:arm templates?|azure resource manager|azuredeploy\.json)\b/i },
|
|
183317
|
+
{ format: "pulumi", words: /\bpulumi\b/i },
|
|
183318
|
+
{ format: "cdk", words: /\b(?:aws cdk|cdk (?:app|synth|stacks?)|cdk\.out|cloud assembly)\b/i },
|
|
183319
|
+
{ format: "cloudformation", words: /\b(?:cloudformation|cfn templates?|sam templates?|serverless application model)\b/i },
|
|
183320
|
+
{ format: "openapi", words: /\b(?:openapi|swagger|api spec(?:ification)?)\b/i },
|
|
183321
|
+
{ format: "prisma", words: /\bprisma\b/i },
|
|
183322
|
+
{ format: "drizzle", words: /\bdrizzle\b/i },
|
|
183323
|
+
{ format: "sql", words: /\b(?:sql|ddl|create table|database schema dump)\b/i },
|
|
183324
|
+
{ format: "git-log", words: /\bgit (?:log|history)\b/i },
|
|
183325
|
+
{ format: "csv", words: /\b(?:csv|tsv|spreadsheet export)\b/i },
|
|
183326
|
+
{ format: "json", words: /\bjson (?:data|file|records|export)\b/i },
|
|
183327
|
+
{ format: "tree", words: /\b(?:tree output|folder (?:structure|tree|listing)|directory (?:tree|listing))\b/i }
|
|
183328
|
+
];
|
|
183329
|
+
SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "cdk", "compose", "kubernetes", "helm", "kustomize", "backstage", "github-actions", "git-log"]);
|
|
183330
|
+
}
|
|
183331
|
+
});
|
|
183332
|
+
|
|
183333
|
+
// ../../packages/diagrams/src/importers/terraform/azure-families.ts
|
|
183334
|
+
function azureFamilyIcon(type) {
|
|
183335
|
+
if (!type.startsWith("azurerm_")) return null;
|
|
183336
|
+
const name2 = type.slice("azurerm_".length);
|
|
183337
|
+
let best;
|
|
183338
|
+
for (const family of AZURE_FAMILIES) if (name2.startsWith(family[0]) && family[0].length > (best?.[0].length ?? -1)) best = family;
|
|
183339
|
+
return best?.[1] ?? null;
|
|
183340
|
+
}
|
|
183341
|
+
var AZURE_FAMILIES;
|
|
183342
|
+
var init_azure_families = __esm({
|
|
183343
|
+
"../../packages/diagrams/src/importers/terraform/azure-families.ts"() {
|
|
183344
|
+
"use strict";
|
|
183345
|
+
AZURE_FAMILIES = [
|
|
183346
|
+
["aadb2c_", "azure:ad-b2c"],
|
|
183347
|
+
["active_directory_domain_service", "azure:entra-domain-services"],
|
|
183348
|
+
["advanced_threat_protection", "azure:defender-for-cloud"],
|
|
183349
|
+
["attestation_", "azure:azureattestation"],
|
|
183350
|
+
["automanage_", "azure:automanaged-vm"],
|
|
183351
|
+
["automation_", "azure:automation-accounts"],
|
|
183352
|
+
["backup_", "azure:recovery-services-vaults"],
|
|
183353
|
+
["batch_", "azure:batch-accounts"],
|
|
183354
|
+
["bot_", "azure:bot-services"],
|
|
183355
|
+
["cognitive_", "azure:cognitive-services"],
|
|
183356
|
+
["container_connected_registry", "azure:container-registries"],
|
|
183357
|
+
["container_group", "azure:container-instances"],
|
|
183358
|
+
["cosmosdb_postgresql_", "azure:database-postgresql-server-group"],
|
|
183359
|
+
["cosmosdb_", "azure:cosmos-db"],
|
|
183360
|
+
["custom_provider", "azure:resource-groups"],
|
|
183361
|
+
["data_protection_", "azure:backup-vault"],
|
|
183362
|
+
["database_migration_", "azure:database-migration-services"],
|
|
183363
|
+
["dev_center", "azure:dev-box"],
|
|
183364
|
+
["dev_test_", "azure:devtest-labs"],
|
|
183365
|
+
["elastic_cloud_", "simple:elasticsearch"],
|
|
183366
|
+
["eventgrid_domain", "azure:event-grid-domains"],
|
|
183367
|
+
["eventgrid_", "azure:event-grid"],
|
|
183368
|
+
["eventhub_cluster", "azure:event-hub-clusters"],
|
|
183369
|
+
["eventhub", "azure:event-hubs"],
|
|
183370
|
+
["express_route_", "azure:expressroute-circuits"],
|
|
183371
|
+
["fabric_", "azure:power-bi-embedded"],
|
|
183372
|
+
["federated_identity_credential", "azure:managed-identities"],
|
|
183373
|
+
["frontdoor", "azure:front-door"],
|
|
183374
|
+
["gallery_application", "azure:image-definitions"],
|
|
183375
|
+
["graph_services_", "azure:resource-graph-explorer"],
|
|
183376
|
+
["hdinsight_", "azure:hd-insight-clusters"],
|
|
183377
|
+
["healthbot", "azure:bot-services"],
|
|
183378
|
+
["healthcare_", "azure:fhir-service"],
|
|
183379
|
+
["iotcentral_", "azure:iot-central-applications"],
|
|
183380
|
+
["iothub", "azure:iot-hub"],
|
|
183381
|
+
["kubernetes_automatic", "azure:aks-automatic"],
|
|
183382
|
+
["kubernetes_fleet", "azure:kubernetes-fleet-manager"],
|
|
183383
|
+
["kubernetes_", "azure:kubernetes-services"],
|
|
183384
|
+
["kusto_", "azure:data-explorer-clusters"],
|
|
183385
|
+
["maintenance_", "azure:maintenance-configuration"],
|
|
183386
|
+
["managed_application", "azure:managed-applications-center"],
|
|
183387
|
+
["management_lock", "azure:resource-groups"],
|
|
183388
|
+
["mongo_cluster", "azure:cosmos-db"],
|
|
183389
|
+
["mssql_elasticpool", "azure:sql-elastic-pools"],
|
|
183390
|
+
["mssql_job", "azure:elastic-job-agents"],
|
|
183391
|
+
["mssql_managed", "azure:sql-managed-instance"],
|
|
183392
|
+
["mssql_", "azure:sql-database"],
|
|
183393
|
+
["mysql_", "azure:database-for-mysql"],
|
|
183394
|
+
["netapp_", "azure:netapp-files"],
|
|
183395
|
+
["network_function_", "azure:network-function-manager"],
|
|
183396
|
+
["network_profile", "azure:virtual-network"],
|
|
183397
|
+
["nginx_", "simple:nginx"],
|
|
183398
|
+
["oracle_", "azure:oracle-database"],
|
|
183399
|
+
["pim_", "azure:entra-identity-roles-and-administrators"],
|
|
183400
|
+
["playwright_", "azure:load-testing"],
|
|
183401
|
+
["point_to_site_vpn_gateway", "azure:virtual-network-gateways"],
|
|
183402
|
+
["policy_", "azure:policy"],
|
|
183403
|
+
["portal_", "azure:management-portal"],
|
|
183404
|
+
["powerbi_", "azure:power-bi-embedded"],
|
|
183405
|
+
["purview_", "azure:identity-governance"],
|
|
183406
|
+
["redhat_openshift", "azure:red-hat-openshift"],
|
|
183407
|
+
["redis_", "azure:cache-redis"],
|
|
183408
|
+
["resource_deployment_script", "azure:templates"],
|
|
183409
|
+
["resource_policy", "azure:policy"],
|
|
183410
|
+
["resource_provider_", "azure:subscriptions"],
|
|
183411
|
+
["role_definition", "azure:entra-identity-custom-roles"],
|
|
183412
|
+
["role_management", "azure:entra-identity-roles-and-administrators"],
|
|
183413
|
+
["route_map", "azure:virtual-router"],
|
|
183414
|
+
["route_server", "azure:virtual-router"],
|
|
183415
|
+
["route", "azure:route-tables"],
|
|
183416
|
+
["service_fabric", "azure:service-fabric-clusters"],
|
|
183417
|
+
["site_recovery_", "azure:recovery-services-vaults"],
|
|
183418
|
+
["snapshot", "azure:disks-snapshots"],
|
|
183419
|
+
["spring_cloud_", "azure:spring-apps"],
|
|
183420
|
+
["ssh_public_key", "azure:ssh-keys"],
|
|
183421
|
+
["stack_hci_", "azure:stack-hci-premium"],
|
|
183422
|
+
["storage_blob", "azure:blob-storage"],
|
|
183423
|
+
["storage_sync", "azure:storage-sync-services"],
|
|
183424
|
+
["storage_", "azure:storage-accounts"],
|
|
183425
|
+
["stream_analytics_", "azure:stream-analytics-jobs"],
|
|
183426
|
+
["traffic_manager_", "azure:traffic-manager-profiles"],
|
|
183427
|
+
["trusted_signing_", "azure:key-vaults"],
|
|
183428
|
+
["virtual_hub", "azure:virtual-wan-hub"],
|
|
183429
|
+
["vmware_", "azure:vmware-solution"],
|
|
183430
|
+
["vpn_", "azure:virtual-network-gateways"],
|
|
183431
|
+
["web_app", "azure:app-service"],
|
|
183432
|
+
["workloads_sap_", "azure:virtual-instance-for-sap"]
|
|
183433
|
+
];
|
|
183434
|
+
}
|
|
183435
|
+
});
|
|
183436
|
+
|
|
182246
183437
|
// ../../packages/diagrams/src/importers/terraform/tokens.ts
|
|
182247
183438
|
function stringEnd(text3, start2) {
|
|
182248
183439
|
const modes = ["string"];
|
|
@@ -182350,12 +183541,12 @@ function allAttributes(block) {
|
|
|
182350
183541
|
}
|
|
182351
183542
|
return out;
|
|
182352
183543
|
}
|
|
182353
|
-
var
|
|
182354
|
-
var
|
|
183544
|
+
var MAX_DEPTH3, HclReader;
|
|
183545
|
+
var init_parse22 = __esm({
|
|
182355
183546
|
"../../packages/diagrams/src/importers/terraform/parse.ts"() {
|
|
182356
183547
|
"use strict";
|
|
182357
183548
|
init_tokens();
|
|
182358
|
-
|
|
183549
|
+
MAX_DEPTH3 = 32;
|
|
182359
183550
|
HclReader = class {
|
|
182360
183551
|
constructor(text3, tokens) {
|
|
182361
183552
|
this.text = text3;
|
|
@@ -182417,7 +183608,7 @@ var init_parse21 = __esm({
|
|
|
182417
183608
|
/** A block: its type, its labels, and its body in braces. */
|
|
182418
183609
|
block(depth) {
|
|
182419
183610
|
const head = this.peek();
|
|
182420
|
-
if (depth >=
|
|
183611
|
+
if (depth >= MAX_DEPTH3) return { offset: head.start, message: "The blocks are nested too deep.", hint: `Keep nesting under ${MAX_DEPTH3} levels.` };
|
|
182421
183612
|
const labels2 = [];
|
|
182422
183613
|
this.index += 1;
|
|
182423
183614
|
for (; ; ) {
|
|
@@ -182537,7 +183728,7 @@ var init_labels = __esm({
|
|
|
182537
183728
|
"use strict";
|
|
182538
183729
|
init_constants();
|
|
182539
183730
|
init_shared2();
|
|
182540
|
-
|
|
183731
|
+
init_parse22();
|
|
182541
183732
|
GENERIC_NAMES = /* @__PURE__ */ new Set(["main", "this", "default", "example", "primary", "the", "it", "resource", "self"]);
|
|
182542
183733
|
NAME_ATTRIBUTES = ["name", "bucket", "identifier", "function_name", "cluster_identifier", "cluster_name", "domain_name"];
|
|
182543
183734
|
ACRONYMS = /* @__PURE__ */ new Set(["api", "db", "sql", "vpc", "cdn", "dns", "alb", "nlb", "lb", "vm", "ecs", "eks", "aks", "gke", "nat", "waf", "kms", "iam", "s3", "sns", "sqs", "ui", "id", "kv", "acr", "apim", "aca", "nsg", "pe", "url"]);
|
|
@@ -183027,13 +184218,13 @@ function itemsToStack(written3, modules) {
|
|
|
183027
184218
|
const byAttribute = /* @__PURE__ */ new Map();
|
|
183028
184219
|
const vars = /* @__PURE__ */ new Map();
|
|
183029
184220
|
const values = /* @__PURE__ */ new Map();
|
|
183030
|
-
const
|
|
184221
|
+
const readable3 = /* @__PURE__ */ new Map();
|
|
183031
184222
|
for (const attribute2 of item.attributes) {
|
|
183032
184223
|
const refs = attribute2.refs.map((ref) => keyOf5.get(ref)).filter((ref) => ref !== void 0 && ref !== key);
|
|
183033
184224
|
if (refs.length > 0) byAttribute.set(attribute2.name, [.../* @__PURE__ */ new Set([...byAttribute.get(attribute2.name) ?? [], ...refs])]);
|
|
183034
184225
|
if ((attribute2.vars ?? []).length > 0) vars.set(attribute2.name, [.../* @__PURE__ */ new Set([...vars.get(attribute2.name) ?? [], ...attribute2.vars ?? []])]);
|
|
183035
184226
|
if (attribute2.value !== null) values.set(attribute2.name, attribute2.value);
|
|
183036
|
-
else if (attribute2.readable !== void 0 && attribute2.readable !== null)
|
|
184227
|
+
else if (attribute2.readable !== void 0 && attribute2.readable !== null) readable3.set(attribute2.name, attribute2.readable);
|
|
183037
184228
|
}
|
|
183038
184229
|
if (item.source !== void 0) values.set("source", item.source);
|
|
183039
184230
|
const all = [...byAttribute];
|
|
@@ -183050,7 +184241,7 @@ function itemsToStack(written3, modules) {
|
|
|
183050
184241
|
byAttribute,
|
|
183051
184242
|
vars,
|
|
183052
184243
|
values,
|
|
183053
|
-
readable:
|
|
184244
|
+
readable: readable3,
|
|
183054
184245
|
local: item.type === "module" ? `module.${name2}` : `${item.type}.${name2}`,
|
|
183055
184246
|
scope: item.scope,
|
|
183056
184247
|
instance: item.copies?.kind === "instance",
|
|
@@ -183100,7 +184291,7 @@ function bundleArrows(nodes, groups, edges, ownBox, joinPairs = true) {
|
|
|
183100
184291
|
const typeOf = new Map(groups.map((group2) => [group2.key, group2.type ?? ""]));
|
|
183101
184292
|
const inside = (key, frame) => {
|
|
183102
184293
|
let current = frameOf3.get(key) ?? null;
|
|
183103
|
-
for (let depth = 0; current !== null && depth <
|
|
184294
|
+
for (let depth = 0; current !== null && depth < MAX_DEPTH4; depth += 1) {
|
|
183104
184295
|
if (current === frame) return true;
|
|
183105
184296
|
current = parents.get(current) ?? null;
|
|
183106
184297
|
}
|
|
@@ -183152,14 +184343,14 @@ function bundleArrows(nodes, groups, edges, ownBox, joinPairs = true) {
|
|
|
183152
184343
|
}
|
|
183153
184344
|
return { nodes: [...nodes, ...added], edges: out };
|
|
183154
184345
|
}
|
|
183155
|
-
var BUNDLE_AT, FEW, HOSTS2,
|
|
184346
|
+
var BUNDLE_AT, FEW, HOSTS2, MAX_DEPTH4;
|
|
183156
184347
|
var init_bundle = __esm({
|
|
183157
184348
|
"../../packages/diagrams/src/importers/terraform/bundle.ts"() {
|
|
183158
184349
|
"use strict";
|
|
183159
184350
|
BUNDLE_AT = 2;
|
|
183160
184351
|
FEW = 3;
|
|
183161
184352
|
HOSTS2 = /* @__PURE__ */ new Set(["service-plan", "cluster"]);
|
|
183162
|
-
|
|
184353
|
+
MAX_DEPTH4 = 32;
|
|
183163
184354
|
}
|
|
183164
184355
|
});
|
|
183165
184356
|
|
|
@@ -183178,14 +184369,14 @@ function listAt(map2, key) {
|
|
|
183178
184369
|
map2.set(key, made);
|
|
183179
184370
|
return made;
|
|
183180
184371
|
}
|
|
183181
|
-
var NOT_SCOPES, MAX_PLACEMENT_HOPS,
|
|
184372
|
+
var NOT_SCOPES, MAX_PLACEMENT_HOPS, MAX_DEPTH5, GROUP_RANK, SELF_BOXED, VARIABLE_WORDS, sameKind, familyOf, containerFrame, anchorOf, StackPlan;
|
|
183182
184373
|
var init_plan9 = __esm({
|
|
183183
184374
|
"../../packages/diagrams/src/importers/terraform/plan.ts"() {
|
|
183184
184375
|
"use strict";
|
|
183185
184376
|
init_resources();
|
|
183186
184377
|
NOT_SCOPES = /* @__PURE__ */ new Set(["count", "for_each", "depends_on", "provider", "lifecycle"]);
|
|
183187
184378
|
MAX_PLACEMENT_HOPS = 3;
|
|
183188
|
-
|
|
184379
|
+
MAX_DEPTH5 = 12;
|
|
183189
184380
|
GROUP_RANK = { account: 0, "resource-group": 1, network: 2, subnet: 4, "public-subnet": 4, "private-subnet": 4, "service-plan": 5, cluster: 6 };
|
|
183190
184381
|
SELF_BOXED = /* @__PURE__ */ new Set(["service-plan", "cluster"]);
|
|
183191
184382
|
VARIABLE_WORDS = { "resource-group": /resource_group|(?:^|_)rg(?:_|$)/, network: /vnet|vpc|network/, subnet: /subnet/ };
|
|
@@ -183296,7 +184487,7 @@ var init_plan9 = __esm({
|
|
|
183296
184487
|
if (holder === null) continue;
|
|
183297
184488
|
let current = holder;
|
|
183298
184489
|
let loops = false;
|
|
183299
|
-
for (let depth = 0; current !== void 0 && depth <
|
|
184490
|
+
for (let depth = 0; current !== void 0 && depth < MAX_DEPTH5; depth += 1) {
|
|
183300
184491
|
if (current === resource.key) loops = true;
|
|
183301
184492
|
current = this.holder.get(current);
|
|
183302
184493
|
}
|
|
@@ -183515,7 +184706,7 @@ var init_plan9 = __esm({
|
|
|
183515
184706
|
ancestors(key) {
|
|
183516
184707
|
const out = [];
|
|
183517
184708
|
let current = this.parents.get(key);
|
|
183518
|
-
for (let depth = 0; current !== void 0 && depth <
|
|
184709
|
+
for (let depth = 0; current !== void 0 && depth < MAX_DEPTH5 && !out.includes(current); depth += 1) {
|
|
183519
184710
|
out.push(current);
|
|
183520
184711
|
current = this.parents.get(current);
|
|
183521
184712
|
}
|
|
@@ -183802,7 +184993,7 @@ function layerNetworks(plan) {
|
|
|
183802
184993
|
const resource = plan.resources.get(key.replace(/^(?:frame|anchor):/, ""));
|
|
183803
184994
|
if (resource === void 0 || NETWORK_TYPE.test(resource.type)) continue;
|
|
183804
184995
|
let target = parent;
|
|
183805
|
-
for (let depth = 0; target !== void 0 && depth <
|
|
184996
|
+
for (let depth = 0; target !== void 0 && depth < MAX_DEPTH6; depth += 1) {
|
|
183806
184997
|
const type = plan.frameType(target);
|
|
183807
184998
|
if (type === null || !NETWORK_FRAMES.has(type)) break;
|
|
183808
184999
|
target = plan.parents.get(target);
|
|
@@ -183814,11 +185005,11 @@ function layerNetworks(plan) {
|
|
|
183814
185005
|
}
|
|
183815
185006
|
return moved3;
|
|
183816
185007
|
}
|
|
183817
|
-
var
|
|
185008
|
+
var MAX_DEPTH6, NETWORK_FRAMES, NETWORK_TYPE;
|
|
183818
185009
|
var init_network_layer = __esm({
|
|
183819
185010
|
"../../packages/diagrams/src/importers/terraform/network-layer.ts"() {
|
|
183820
185011
|
"use strict";
|
|
183821
|
-
|
|
185012
|
+
MAX_DEPTH6 = 16;
|
|
183822
185013
|
NETWORK_FRAMES = /* @__PURE__ */ new Set(["network", "subnet", "public-subnet", "private-subnet", "management-subnet", "isolated-subnet"]);
|
|
183823
185014
|
NETWORK_TYPE = /^(?:azurerm_(?:virtual_network|subnet|network_|route|nat_gateway|public_ip|firewall|application_gateway|lb$|lb_|private_dns)|aws_(?:vpc|subnet|security_group|network_acl|route|internet_gateway|nat_gateway|eip|egress_only)|google_compute_(?:network|subnetwork|firewall|router|route|address))/;
|
|
183824
185015
|
}
|
|
@@ -184145,7 +185336,7 @@ function drawStack(input2) {
|
|
|
184145
185336
|
const provider = providers.size === 1 ? [...providers][0] : providers.size === 0 ? input2.cloud ?? null : null;
|
|
184146
185337
|
const owner = provider === null ? null : SHORT_NAMES2[provider] ?? CLOUD_PROVIDER_SPECS[provider].title;
|
|
184147
185338
|
const where = owner === null ? "on more than one cloud" : `on ${owner}`;
|
|
184148
|
-
const nesting2 = context.options.groupBy === "file" ? "framed by the file that declares them" : plan.modules.size > 0 ?
|
|
185339
|
+
const nesting2 = context.options.groupBy === "file" ? "framed by the file that declares them" : plan.modules.size > 0 ? `framed by the ${input2.framing ?? "module"} that declares them and nested in the groups, networks, and subnets that hold them` : layered ? "nested in the groups that hold them, beside the network, with an arrow to the subnet each one sits in" : "nested in the groups, networks, and subnets that hold them";
|
|
184149
185340
|
const title = context.title ?? `${owner === null ? "Cloud infrastructure" : `${owner} infrastructure`}${input2.summary === void 0 ? "" : `: ${input2.summary}`}`;
|
|
184150
185341
|
const draft = {
|
|
184151
185342
|
title,
|
|
@@ -184441,14 +185632,14 @@ function lastPart(value) {
|
|
|
184441
185632
|
if (!value.includes("/")) return value;
|
|
184442
185633
|
return value.split("/").filter((part) => part !== "").pop() ?? value;
|
|
184443
185634
|
}
|
|
184444
|
-
var
|
|
185635
|
+
var MAX_DEPTH7, MAX_VALUE_LENGTH2, MAX_ENTRIES, ValueResolver;
|
|
184445
185636
|
var init_values2 = __esm({
|
|
184446
185637
|
"../../packages/diagrams/src/importers/terraform/values.ts"() {
|
|
184447
185638
|
"use strict";
|
|
184448
185639
|
init_expressions();
|
|
184449
|
-
|
|
184450
|
-
|
|
184451
|
-
|
|
185640
|
+
init_parse22();
|
|
185641
|
+
MAX_DEPTH7 = 8;
|
|
185642
|
+
MAX_VALUE_LENGTH2 = 600;
|
|
184452
185643
|
MAX_ENTRIES = 64;
|
|
184453
185644
|
ValueResolver = class _ValueResolver {
|
|
184454
185645
|
constructor(variables, assigned, locals, inputs = /* @__PURE__ */ new Map(), binding = null, site = "") {
|
|
@@ -184505,13 +185696,13 @@ var init_values2 = __esm({
|
|
|
184505
185696
|
}
|
|
184506
185697
|
/** The value of an expression as written, or null when it cannot be known from the text. */
|
|
184507
185698
|
value(raw, depth = 0) {
|
|
184508
|
-
if (depth >
|
|
185699
|
+
if (depth > MAX_DEPTH7) return null;
|
|
184509
185700
|
const text3 = raw.trim();
|
|
184510
185701
|
const memoKey = `${depth}\0${text3}`;
|
|
184511
185702
|
if (this.memo.has(memoKey)) return this.memo.get(memoKey) ?? null;
|
|
184512
185703
|
this.memo.set(memoKey, null);
|
|
184513
185704
|
const found = this.evaluate(text3, depth);
|
|
184514
|
-
const kept2 = found === null || found.length >
|
|
185705
|
+
const kept2 = found === null || found.length > MAX_VALUE_LENGTH2 ? null : found;
|
|
184515
185706
|
this.memo.set(memoKey, kept2);
|
|
184516
185707
|
return kept2;
|
|
184517
185708
|
}
|
|
@@ -184526,7 +185717,7 @@ var init_values2 = __esm({
|
|
|
184526
185717
|
const part = (expression2) => this.value(expression2, depth + 1) ?? this.readable(expression2, depth + 1) ?? `{${shortName(expression2)}}`;
|
|
184527
185718
|
if (text3.startsWith('"') && text3.endsWith('"') && text3.length >= 2 && interpolationsClosed(text3)) return this.template(text3.slice(1, -1), depth, part);
|
|
184528
185719
|
const call = /^(format|join|lower|upper)\(([\s\S]*)\)$/.exec(text3);
|
|
184529
|
-
if (call === null || depth >
|
|
185720
|
+
if (call === null || depth > MAX_DEPTH7) return null;
|
|
184530
185721
|
const args = argumentsOf(call[2] ?? "");
|
|
184531
185722
|
if (args === null || args.length === 0) return null;
|
|
184532
185723
|
if (call[1] === "format") {
|
|
@@ -184552,7 +185743,7 @@ var init_values2 = __esm({
|
|
|
184552
185743
|
* `toset`, `tolist`, `keys`, `values`, `merge`, `each.value`, and a `for` over a known map or list. Null when unknown.
|
|
184553
185744
|
*/
|
|
184554
185745
|
collection(raw, depth = 0) {
|
|
184555
|
-
if (depth >
|
|
185746
|
+
if (depth > MAX_DEPTH7) return null;
|
|
184556
185747
|
const text3 = raw.trim();
|
|
184557
185748
|
if (text3.startsWith("{") && text3.endsWith("}")) {
|
|
184558
185749
|
const forMap = /^\{\s*for\s+([A-Za-z_]\w*)\s*(?:,\s*([A-Za-z_]\w*)\s*)?in\s+([^:]+):\s*([A-Za-z_]\w*)\s*=>/.exec(text3);
|
|
@@ -184646,7 +185837,7 @@ var init_values2 = __esm({
|
|
|
184646
185837
|
fieldOf(base, fields, depth) {
|
|
184647
185838
|
let current = base;
|
|
184648
185839
|
for (const field of fields) {
|
|
184649
|
-
if (current === null || depth >
|
|
185840
|
+
if (current === null || depth > MAX_DEPTH7) return null;
|
|
184650
185841
|
const map2 = current.scope.collection(current.raw, depth + 1);
|
|
184651
185842
|
if (map2?.kind !== "map") return null;
|
|
184652
185843
|
current = map2.entries.find(([key]) => key === field)?.[1] ?? null;
|
|
@@ -184815,7 +186006,7 @@ function pathOf2(block, files) {
|
|
|
184815
186006
|
function foldersOf(blocks2, files) {
|
|
184816
186007
|
const byFolder = /* @__PURE__ */ new Map();
|
|
184817
186008
|
for (const block of blocks2) {
|
|
184818
|
-
const folder =
|
|
186009
|
+
const folder = folderOf3(pathOf2(block, files));
|
|
184819
186010
|
byFolder.set(folder, [...byFolder.get(folder) ?? [], block]);
|
|
184820
186011
|
}
|
|
184821
186012
|
const targets = /* @__PURE__ */ new Map();
|
|
@@ -184831,7 +186022,7 @@ function foldersOf(blocks2, files) {
|
|
|
184831
186022
|
called.add(target);
|
|
184832
186023
|
}
|
|
184833
186024
|
}
|
|
184834
|
-
const roots = [...byFolder.keys()].filter((folder) => !called.has(folder) && (byFolder.get(folder) ?? []).some(
|
|
186025
|
+
const roots = [...byFolder.keys()].filter((folder) => !called.has(folder) && (byFolder.get(folder) ?? []).some(isItem2)).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
184835
186026
|
return { blocks: byFolder, targets, roots };
|
|
184836
186027
|
}
|
|
184837
186028
|
function outputsOf(blocks2) {
|
|
@@ -184890,7 +186081,7 @@ function allScopes(root) {
|
|
|
184890
186081
|
}
|
|
184891
186082
|
return out;
|
|
184892
186083
|
}
|
|
184893
|
-
var MAX_MODULE_DEPTH, CALL_SETTINGS,
|
|
186084
|
+
var MAX_MODULE_DEPTH, CALL_SETTINGS, folderOf3, isItem2;
|
|
184894
186085
|
var init_modules2 = __esm({
|
|
184895
186086
|
"../../packages/diagrams/src/importers/terraform/modules.ts"() {
|
|
184896
186087
|
"use strict";
|
|
@@ -184898,12 +186089,12 @@ var init_modules2 = __esm({
|
|
|
184898
186089
|
init_values2();
|
|
184899
186090
|
MAX_MODULE_DEPTH = 6;
|
|
184900
186091
|
CALL_SETTINGS = /* @__PURE__ */ new Set(["source", "version", "providers", "count", "for_each", "depends_on"]);
|
|
184901
|
-
|
|
186092
|
+
folderOf3 = (path) => {
|
|
184902
186093
|
const parts = path.split(/[\\/]/);
|
|
184903
186094
|
parts.pop();
|
|
184904
186095
|
return parts.join("/");
|
|
184905
186096
|
};
|
|
184906
|
-
|
|
186097
|
+
isItem2 = (block) => block.type === "resource" || block.type === "data" || block.type === "module";
|
|
184907
186098
|
}
|
|
184908
186099
|
});
|
|
184909
186100
|
|
|
@@ -184973,21 +186164,21 @@ function readResources(root) {
|
|
|
184973
186164
|
const vars = /* @__PURE__ */ new Map();
|
|
184974
186165
|
for (const attribute2 of attributes2) {
|
|
184975
186166
|
const found = reader.read(attribute2.raw).filter((ref) => ref !== key && ref !== base);
|
|
184976
|
-
const items2 = found.filter(
|
|
184977
|
-
const named = found.filter((ref) => !
|
|
186167
|
+
const items2 = found.filter(isItem3);
|
|
186168
|
+
const named = found.filter((ref) => !isItem3(ref)).map((ref) => ref.slice("var.".length));
|
|
184978
186169
|
if (items2.length > 0) byAttribute.set(attribute2.name, unique([...byAttribute.get(attribute2.name) ?? [], ...items2]));
|
|
184979
186170
|
if (named.length > 0) vars.set(attribute2.name, unique([...vars.get(attribute2.name) ?? [], ...named]));
|
|
184980
186171
|
}
|
|
184981
186172
|
const from = (keep) => unique(attributes2.filter(keep).flatMap((attribute2) => byAttribute.get(attribute2.name) ?? []));
|
|
184982
186173
|
const role = id.kind === "module" ? { role: "node", type: "service", icon: "lucide:package", product: "Module" } : roleOf2(id.type);
|
|
184983
186174
|
const values = /* @__PURE__ */ new Map();
|
|
184984
|
-
const
|
|
186175
|
+
const readable3 = /* @__PURE__ */ new Map();
|
|
184985
186176
|
for (const attribute2 of block.attributes) {
|
|
184986
186177
|
const value = attribute2.literal ?? resolver.value(attribute2.raw);
|
|
184987
186178
|
if (value !== null) values.set(attribute2.name, value);
|
|
184988
186179
|
else if (NAMED.includes(attribute2.name)) {
|
|
184989
186180
|
const partly = resolver.readable(attribute2.raw);
|
|
184990
|
-
if (partly !== null)
|
|
186181
|
+
if (partly !== null) readable3.set(attribute2.name, partly);
|
|
184991
186182
|
}
|
|
184992
186183
|
}
|
|
184993
186184
|
const tags = block.attributes.find((attribute2) => attribute2.name === "tags");
|
|
@@ -185005,7 +186196,7 @@ function readResources(root) {
|
|
|
185005
186196
|
byAttribute,
|
|
185006
186197
|
vars,
|
|
185007
186198
|
values,
|
|
185008
|
-
readable:
|
|
186199
|
+
readable: readable3,
|
|
185009
186200
|
local: id.local,
|
|
185010
186201
|
scope: scope.prefix,
|
|
185011
186202
|
instance: copy.key !== null,
|
|
@@ -185039,7 +186230,7 @@ function readResources(root) {
|
|
|
185039
186230
|
}
|
|
185040
186231
|
return { resources, modules, empty };
|
|
185041
186232
|
}
|
|
185042
|
-
var
|
|
186233
|
+
var MAX_DEPTH8, TYPE, unique, ScopeReader, isItem3, PLAIN_NAMES, NAMED;
|
|
185043
186234
|
var init_graph4 = __esm({
|
|
185044
186235
|
"../../packages/diagrams/src/importers/terraform/graph.ts"() {
|
|
185045
186236
|
"use strict";
|
|
@@ -185047,9 +186238,9 @@ var init_graph4 = __esm({
|
|
|
185047
186238
|
init_generic();
|
|
185048
186239
|
init_instances();
|
|
185049
186240
|
init_modules2();
|
|
185050
|
-
|
|
186241
|
+
init_parse22();
|
|
185051
186242
|
init_resources();
|
|
185052
|
-
|
|
186243
|
+
MAX_DEPTH8 = 6;
|
|
185053
186244
|
TYPE = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
|
|
185054
186245
|
unique = (values) => [...new Set(values)];
|
|
185055
186246
|
ScopeReader = class {
|
|
@@ -185069,7 +186260,7 @@ var init_graph4 = __esm({
|
|
|
185069
186260
|
}
|
|
185070
186261
|
/** Every address a text names, with `var.` names for the variables that name no item: `aws_vpc.main`, `module.network.azurerm_subnet.this["app"]`, `var.region`. */
|
|
185071
186262
|
read(text3, depth = 0) {
|
|
185072
|
-
if (depth >
|
|
186263
|
+
if (depth > MAX_DEPTH8) return [];
|
|
185073
186264
|
const out = [];
|
|
185074
186265
|
for (const steps of references(text3)) out.push(...this.interpret(steps, depth));
|
|
185075
186266
|
return out;
|
|
@@ -185150,7 +186341,7 @@ var init_graph4 = __esm({
|
|
|
185150
186341
|
return out;
|
|
185151
186342
|
}
|
|
185152
186343
|
};
|
|
185153
|
-
|
|
186344
|
+
isItem3 = (ref) => !ref.startsWith("var.");
|
|
185154
186345
|
PLAIN_NAMES = /* @__PURE__ */ new Set(["this", "main", "default", "these", "each", "all", "items"]);
|
|
185155
186346
|
NAMED = ["name", "bucket", "identifier", "function_name", "cluster_name", "domain_name"];
|
|
185156
186347
|
}
|
|
@@ -185158,28 +186349,28 @@ var init_graph4 = __esm({
|
|
|
185158
186349
|
|
|
185159
186350
|
// ../../packages/diagrams/src/importers/terraform/json-syntax.ts
|
|
185160
186351
|
function expression(value, depth) {
|
|
185161
|
-
if (depth >
|
|
186352
|
+
if (depth > MAX_DEPTH9) return "null";
|
|
185162
186353
|
if (typeof value === "string") return JSON.stringify(value);
|
|
185163
186354
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
185164
186355
|
if (value === null) return "null";
|
|
185165
186356
|
if (Array.isArray(value)) return `[${value.map((item) => expression(item, depth + 1)).join(", ")}]`;
|
|
185166
|
-
return `{ ${Object.entries(value).map(([key, item]) => `${
|
|
186357
|
+
return `{ ${Object.entries(value).map(([key, item]) => `${keyOf2(key)} = ${expression(item, depth + 1)}`).join(", ")} }`;
|
|
185167
186358
|
}
|
|
185168
186359
|
function body5(object2, depth, lines) {
|
|
185169
186360
|
for (const [key, value] of Object.entries(object2)) {
|
|
185170
186361
|
const isObject5 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
|
|
185171
|
-
if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth >
|
|
186362
|
+
if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth > MAX_DEPTH9) lines.push(`${keyOf2(key)} = ${expression(value, depth)}`);
|
|
185172
186363
|
else if (isObject5(value)) {
|
|
185173
|
-
lines.push(`${
|
|
186364
|
+
lines.push(`${keyOf2(key)} {`);
|
|
185174
186365
|
body5(value, depth + 1, lines);
|
|
185175
186366
|
lines.push("}");
|
|
185176
186367
|
} else if (Array.isArray(value) && value.length > 0 && value.every(isObject5)) {
|
|
185177
186368
|
for (const item of value) {
|
|
185178
|
-
lines.push(`${
|
|
186369
|
+
lines.push(`${keyOf2(key)} {`);
|
|
185179
186370
|
body5(item, depth + 1, lines);
|
|
185180
186371
|
lines.push("}");
|
|
185181
186372
|
}
|
|
185182
|
-
} else lines.push(`${
|
|
186373
|
+
} else lines.push(`${keyOf2(key)} = ${expression(value, depth)}`);
|
|
185183
186374
|
}
|
|
185184
186375
|
}
|
|
185185
186376
|
function blocks(kind, value, labels2, depth, lines) {
|
|
@@ -185210,7 +186401,7 @@ function jsonToHcl(text3) {
|
|
|
185210
186401
|
for (const entry2 of Array.isArray(value) ? value : [value]) {
|
|
185211
186402
|
if (typeof entry2 !== "object" || entry2 === null || Array.isArray(entry2)) continue;
|
|
185212
186403
|
lines.push("locals {");
|
|
185213
|
-
for (const [name2, item] of Object.entries(entry2)) lines.push(`${
|
|
186404
|
+
for (const [name2, item] of Object.entries(entry2)) lines.push(`${keyOf2(name2)} = ${expression(item, 1)}`);
|
|
185214
186405
|
lines.push("}");
|
|
185215
186406
|
}
|
|
185216
186407
|
} else if (kind in LABELS) blocks(kind, value, [], 0, lines);
|
|
@@ -185234,15 +186425,15 @@ function readJsonFiles(text3, context, index2) {
|
|
|
185234
186425
|
}
|
|
185235
186426
|
return { text: blanked, blocks: out };
|
|
185236
186427
|
}
|
|
185237
|
-
var
|
|
186428
|
+
var MAX_DEPTH9, LABELS, keyOf2;
|
|
185238
186429
|
var init_json_syntax = __esm({
|
|
185239
186430
|
"../../packages/diagrams/src/importers/terraform/json-syntax.ts"() {
|
|
185240
186431
|
"use strict";
|
|
185241
186432
|
init_core();
|
|
185242
|
-
|
|
185243
|
-
|
|
186433
|
+
init_parse22();
|
|
186434
|
+
MAX_DEPTH9 = 24;
|
|
185244
186435
|
LABELS = { resource: 2, data: 2, module: 1, variable: 1, output: 1, provider: 1 };
|
|
185245
|
-
|
|
186436
|
+
keyOf2 = (key) => /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key) ? key : JSON.stringify(key);
|
|
185246
186437
|
}
|
|
185247
186438
|
});
|
|
185248
186439
|
|
|
@@ -185274,7 +186465,7 @@ function readVariableFiles(text3, files, context, index2, folder = null) {
|
|
|
185274
186465
|
const all = variableSpansOf(text3, files);
|
|
185275
186466
|
const variableSpans = all.filter((span) => inFolder(span.path, folder));
|
|
185276
186467
|
if (all.length === 0) return { assigned: /* @__PURE__ */ new Map(), applied: [] };
|
|
185277
|
-
const loaded = variableSpans.filter((span) => isLoaded(span.path)).sort((a, b) => Number(!/^terraform\./i.test(
|
|
186468
|
+
const loaded = variableSpans.filter((span) => isLoaded(span.path)).sort((a, b) => Number(!/^terraform\./i.test(baseName3(a.path))) - Number(!/^terraform\./i.test(baseName3(b.path))) || a.path.localeCompare(b.path));
|
|
185278
186469
|
const others = variableSpans.filter((span) => !isLoaded(span.path));
|
|
185279
186470
|
const chosenNames = context.options.varFiles ?? [];
|
|
185280
186471
|
let chosen;
|
|
@@ -185322,23 +186513,23 @@ function readVariableFiles(text3, files, context, index2, folder = null) {
|
|
|
185322
186513
|
}
|
|
185323
186514
|
return { assigned, applied };
|
|
185324
186515
|
}
|
|
185325
|
-
var LISTED5, isVariableFile,
|
|
186516
|
+
var LISTED5, isVariableFile, baseName3, isLoaded, inFolder, picks;
|
|
185326
186517
|
var init_tfvars = __esm({
|
|
185327
186518
|
"../../packages/diagrams/src/importers/terraform/tfvars.ts"() {
|
|
185328
186519
|
"use strict";
|
|
185329
186520
|
init_core();
|
|
185330
186521
|
init_shared2();
|
|
185331
|
-
|
|
186522
|
+
init_parse22();
|
|
185332
186523
|
LISTED5 = 5;
|
|
185333
186524
|
isVariableFile = (path) => /\.tfvars(?:\.json)?$/i.test(path);
|
|
185334
|
-
|
|
185335
|
-
isLoaded = (path) => /^terraform\.tfvars(?:\.json)?$/i.test(
|
|
186525
|
+
baseName3 = (path) => path.split(/[\\/]/).pop() ?? path;
|
|
186526
|
+
isLoaded = (path) => /^terraform\.tfvars(?:\.json)?$/i.test(baseName3(path)) || /\.auto\.tfvars(?:\.json)?$/i.test(path);
|
|
185336
186527
|
inFolder = (path, folder) => {
|
|
185337
186528
|
if (folder === null) return true;
|
|
185338
186529
|
const own2 = path.split(/[\\/]/).slice(0, -1).join("/");
|
|
185339
186530
|
return own2 === folder || folder !== "" && own2.startsWith(`${folder}/`);
|
|
185340
186531
|
};
|
|
185341
|
-
picks = (chosen, path) => path === chosen || path.endsWith(`/${chosen.replace(/^\.?\//, "")}`) ||
|
|
186532
|
+
picks = (chosen, path) => path === chosen || path.endsWith(`/${chosen.replace(/^\.?\//, "")}`) || baseName3(path) === chosen;
|
|
185342
186533
|
}
|
|
185343
186534
|
});
|
|
185344
186535
|
|
|
@@ -185464,7 +186655,7 @@ function readTerraform(text3, context) {
|
|
|
185464
186655
|
}
|
|
185465
186656
|
const blocks2 = [...read.blocks, ...json2.blocks];
|
|
185466
186657
|
const folders = foldersOf(blocks2, context.files);
|
|
185467
|
-
const roots = folders.roots.length === 0 ? [
|
|
186658
|
+
const roots = folders.roots.length === 0 ? [folderOf3(context.files[0]?.path ?? "")] : folders.roots;
|
|
185468
186659
|
let chosen = roots;
|
|
185469
186660
|
if (context.options.root !== void 0 && context.options.root !== "") {
|
|
185470
186661
|
const root = chosenRoot(roots, context.options.root);
|
|
@@ -185491,7 +186682,7 @@ var init_terraform = __esm({
|
|
|
185491
186682
|
init_graph4();
|
|
185492
186683
|
init_labels();
|
|
185493
186684
|
init_modules2();
|
|
185494
|
-
|
|
186685
|
+
init_parse22();
|
|
185495
186686
|
init_resources();
|
|
185496
186687
|
init_json_syntax();
|
|
185497
186688
|
init_tfvars();
|
|
@@ -185570,13 +186761,13 @@ function bodyObject(value) {
|
|
|
185570
186761
|
if (value.kind === "if" || value.kind === "for") return bodyObject(value.body);
|
|
185571
186762
|
return null;
|
|
185572
186763
|
}
|
|
185573
|
-
var
|
|
186764
|
+
var MAX_DEPTH10, MAX_ITEMS, Env, Evaluator;
|
|
185574
186765
|
var init_evaluate = __esm({
|
|
185575
186766
|
"../../packages/diagrams/src/importers/bicep/evaluate.ts"() {
|
|
185576
186767
|
"use strict";
|
|
185577
186768
|
init_value();
|
|
185578
186769
|
init_value();
|
|
185579
|
-
|
|
186770
|
+
MAX_DEPTH10 = 24;
|
|
185580
186771
|
MAX_ITEMS = 256;
|
|
185581
186772
|
Env = class _Env {
|
|
185582
186773
|
constructor(unit3, inputs, loop, prefix, children) {
|
|
@@ -185599,7 +186790,7 @@ var init_evaluate = __esm({
|
|
|
185599
186790
|
Evaluator = class {
|
|
185600
186791
|
memo = /* @__PURE__ */ new Map();
|
|
185601
186792
|
evaluate(expr, env, depth = 0) {
|
|
185602
|
-
if (depth >
|
|
186793
|
+
if (depth > MAX_DEPTH10) return new Unknown(shortOf(expr));
|
|
185603
186794
|
switch (expr.kind) {
|
|
185604
186795
|
case "literal":
|
|
185605
186796
|
return expr.value;
|
|
@@ -186138,7 +187329,7 @@ var init_azure_roles = __esm({
|
|
|
186138
187329
|
});
|
|
186139
187330
|
|
|
186140
187331
|
// ../../packages/diagrams/src/importers/bicep/slots.ts
|
|
186141
|
-
function
|
|
187332
|
+
function keyOf3(item, index2) {
|
|
186142
187333
|
if (typeof item === "string") return item;
|
|
186143
187334
|
if (typeof item === "object" && item !== null && !Array.isArray(item) && !(item instanceof Unknown)) {
|
|
186144
187335
|
const name2 = item["name"];
|
|
@@ -186228,9 +187419,9 @@ var init_items3 = __esm({
|
|
|
186228
187419
|
if (slot.transparent) return [];
|
|
186229
187420
|
const body6 = bodyObject(slot.declaration.value);
|
|
186230
187421
|
const attributes2 = [];
|
|
186231
|
-
const add2 = (name2, refs, value = null,
|
|
186232
|
-
if (refs.length === 0 && value === null &&
|
|
186233
|
-
attributes2.push({ name: name2, refs, value, readable:
|
|
187422
|
+
const add2 = (name2, refs, value = null, readable3 = null, vars = []) => {
|
|
187423
|
+
if (refs.length === 0 && value === null && readable3 === null && vars.length === 0) return;
|
|
187424
|
+
attributes2.push({ name: name2, refs, value, readable: readable3, vars });
|
|
186234
187425
|
};
|
|
186235
187426
|
for (const entry2 of body6?.entries ?? []) {
|
|
186236
187427
|
if (entry2.key === "name") {
|
|
@@ -186605,7 +187796,7 @@ var init_model = __esm({
|
|
|
186605
187796
|
let inner = env.bind(value.item, element === void 0 ? { value: item } : { expr: element, env });
|
|
186606
187797
|
if (value.index !== null) inner = inner.bind(value.index, { value: index2 });
|
|
186607
187798
|
if (value.body.kind === "if" && this.evaluator.truth(value.body.test, inner) === false) continue;
|
|
186608
|
-
out.push({ key:
|
|
187799
|
+
out.push({ key: keyOf3(item, index2), env: inner, copies: { kind: "instance" } });
|
|
186609
187800
|
}
|
|
186610
187801
|
return out;
|
|
186611
187802
|
}
|
|
@@ -186667,7 +187858,7 @@ var init_model = __esm({
|
|
|
186667
187858
|
if (Array.isArray(over)) for (const [index2, item] of over.slice(0, MAX_INSTANCES).entries()) {
|
|
186668
187859
|
let inner = env.bind(list.item, { value: item });
|
|
186669
187860
|
if (list.index !== null) inner = inner.bind(list.index, { value: index2 });
|
|
186670
|
-
add2(list.body, inner,
|
|
187861
|
+
add2(list.body, inner, keyOf3(item, index2));
|
|
186671
187862
|
}
|
|
186672
187863
|
}
|
|
186673
187864
|
return out;
|
|
@@ -186773,7 +187964,7 @@ function piecesOf2(text3, start2, end) {
|
|
|
186773
187964
|
for (let index2 = start2 + 1; index2 < end - 1; index2 += 1) {
|
|
186774
187965
|
const char = text3.charAt(index2);
|
|
186775
187966
|
if (char === "\\") {
|
|
186776
|
-
current +=
|
|
187967
|
+
current += ESCAPES2[text3.charAt(index2 + 1)] ?? text3.charAt(index2 + 1);
|
|
186777
187968
|
index2 += 1;
|
|
186778
187969
|
} else if (char === "$" && text3.charAt(index2 + 1) === "{") {
|
|
186779
187970
|
const close2 = interpolationEnd2(text3, index2 + 1);
|
|
@@ -186834,12 +188025,12 @@ function tokenize3(text3) {
|
|
|
186834
188025
|
}
|
|
186835
188026
|
return { tokens, problem: null };
|
|
186836
188027
|
}
|
|
186837
|
-
var TWO_CHAR_SIGNS2,
|
|
188028
|
+
var TWO_CHAR_SIGNS2, ESCAPES2, isWordStart2, isWordChar2;
|
|
186838
188029
|
var init_tokens2 = __esm({
|
|
186839
188030
|
"../../packages/diagrams/src/importers/bicep/tokens.ts"() {
|
|
186840
188031
|
"use strict";
|
|
186841
188032
|
TWO_CHAR_SIGNS2 = /* @__PURE__ */ new Set(["==", "!=", "<=", ">=", "&&", "||", "??", "::", "=>", ".?", "=~", "!~"]);
|
|
186842
|
-
|
|
188033
|
+
ESCAPES2 = { n: "\n", r: "\r", t: " ", "\\": "\\", "'": "'", $: "$" };
|
|
186843
188034
|
isWordStart2 = (char) => /[A-Za-z_]/.test(char);
|
|
186844
188035
|
isWordChar2 = (char) => /[A-Za-z0-9_]/.test(char);
|
|
186845
188036
|
}
|
|
@@ -186868,12 +188059,12 @@ function parseExpression(text3) {
|
|
|
186868
188059
|
throw error62;
|
|
186869
188060
|
}
|
|
186870
188061
|
}
|
|
186871
|
-
var
|
|
186872
|
-
var
|
|
188062
|
+
var MAX_DEPTH11, SKIPPED, PRECEDENCE, ReadError, BicepReader;
|
|
188063
|
+
var init_parse23 = __esm({
|
|
186873
188064
|
"../../packages/diagrams/src/importers/bicep/parse.ts"() {
|
|
186874
188065
|
"use strict";
|
|
186875
188066
|
init_tokens2();
|
|
186876
|
-
|
|
188067
|
+
MAX_DEPTH11 = 64;
|
|
186877
188068
|
SKIPPED = /* @__PURE__ */ new Set(["import", "type", "func", "metadata", "extension", "provider", "assert"]);
|
|
186878
188069
|
PRECEDENCE = { "??": 1, "||": 2, "&&": 3, "==": 4, "!=": 4, "=~": 4, "!~": 4, "<": 5, ">": 5, "<=": 5, ">=": 5, "+": 6, "-": 6, "*": 7, "/": 7, "%": 7 };
|
|
186879
188070
|
ReadError = class extends Error {
|
|
@@ -187058,7 +188249,7 @@ var init_parse22 = __esm({
|
|
|
187058
188249
|
}
|
|
187059
188250
|
/** An expression: a conditional over binary operators over unary ones over postfix chains. */
|
|
187060
188251
|
expression(depth) {
|
|
187061
|
-
if (depth >
|
|
188252
|
+
if (depth > MAX_DEPTH11) this.fail("The expression is nested too deep.", `Keep nesting under ${MAX_DEPTH11} levels.`);
|
|
187062
188253
|
const test = this.binary(0, depth + 1);
|
|
187063
188254
|
if (this.isSign("=>")) {
|
|
187064
188255
|
this.index += 1;
|
|
@@ -187182,7 +188373,7 @@ var init_parse22 = __esm({
|
|
|
187182
188373
|
return value;
|
|
187183
188374
|
}
|
|
187184
188375
|
object(depth) {
|
|
187185
|
-
if (depth >
|
|
188376
|
+
if (depth > MAX_DEPTH11) this.fail("The objects are nested too deep.", `Keep nesting under ${MAX_DEPTH11} levels.`);
|
|
187186
188377
|
const open2 = this.expectSign("{", "An object is written { key: value }.");
|
|
187187
188378
|
const entries2 = [];
|
|
187188
188379
|
const nested2 = [];
|
|
@@ -187220,7 +188411,7 @@ var init_parse22 = __esm({
|
|
|
187220
188411
|
}
|
|
187221
188412
|
}
|
|
187222
188413
|
array(depth) {
|
|
187223
|
-
if (depth >
|
|
188414
|
+
if (depth > MAX_DEPTH11) this.fail("The lists are nested too deep.", `Keep nesting under ${MAX_DEPTH11} levels.`);
|
|
187224
188415
|
const open2 = this.expectSign("[", "A list is written [ a, b ].");
|
|
187225
188416
|
this.skipNewlines();
|
|
187226
188417
|
if (this.isWord("for")) return this.loop(open2, depth);
|
|
@@ -187279,7 +188470,7 @@ function unitOf(file2) {
|
|
|
187279
188470
|
else if (declaration.kind === "output") outputs.set(declaration.name, declaration.value);
|
|
187280
188471
|
else if (declaration.kind === "targetScope" && declaration.value.kind === "string") targetScope = declaration.value.parts.filter((part) => typeof part === "string").join("");
|
|
187281
188472
|
}
|
|
187282
|
-
return { path: file2.path, folder:
|
|
188473
|
+
return { path: file2.path, folder: folderOf3(file2.path), offset: file2.start, params, vars, resources, modules, outputs, declarations: file2.declarations, targetScope };
|
|
187283
188474
|
}
|
|
187284
188475
|
function assignedBy(file2) {
|
|
187285
188476
|
const own2 = { ...unitOf(file2), params: /* @__PURE__ */ new Map() };
|
|
@@ -187291,7 +188482,7 @@ function assignedBy(file2) {
|
|
|
187291
188482
|
return out;
|
|
187292
188483
|
}
|
|
187293
188484
|
function parametersFor(root, parameterFiles, context, index2) {
|
|
187294
|
-
const mine = parameterFiles.filter((file2) => file2.declarations.some((declaration) => declaration.kind === "using" && joinFolder(
|
|
188485
|
+
const mine = parameterFiles.filter((file2) => file2.declarations.some((declaration) => declaration.kind === "using" && joinFolder(folderOf3(file2.path), declaration.path) === root.path));
|
|
187295
188486
|
if (mine.length === 0) return /* @__PURE__ */ new Map();
|
|
187296
188487
|
const chosen = context.options.varFiles ?? [];
|
|
187297
188488
|
const picked = chosen.length > 0 ? mine.filter((file2) => chosen.some((name2) => file2.path === name2 || file2.path.endsWith(`/${name2.replace(/^\.?\//, "")}`))) : mine.length === 1 ? mine : [];
|
|
@@ -187398,7 +188589,7 @@ var init_bicep = __esm({
|
|
|
187398
188589
|
init_modules2();
|
|
187399
188590
|
init_evaluate();
|
|
187400
188591
|
init_model();
|
|
187401
|
-
|
|
188592
|
+
init_parse23();
|
|
187402
188593
|
LISTED6 = 5;
|
|
187403
188594
|
bicepImporter = { format: "bicep", kinds: ["flow"], joins: "\n", extensions: [".bicep", ".bicepparam"], read: readBicep };
|
|
187404
188595
|
}
|
|
@@ -187446,7 +188637,7 @@ function bicepQuotes(text3) {
|
|
|
187446
188637
|
return out;
|
|
187447
188638
|
}
|
|
187448
188639
|
function exprOf(value, start2, depth = 0) {
|
|
187449
|
-
if (depth >
|
|
188640
|
+
if (depth > MAX_DEPTH12) return { kind: "literal", value: null, start: start2 };
|
|
187450
188641
|
if (typeof value === "string") {
|
|
187451
188642
|
if (value.startsWith("[[")) return { kind: "string", parts: [value.slice(1)], start: start2 };
|
|
187452
188643
|
if (value.startsWith("[") && value.endsWith("]")) {
|
|
@@ -187540,13 +188731,13 @@ function templateDeclarations(template, offsetOf) {
|
|
|
187540
188731
|
for (const [name2, output2] of Object.entries(outputs)) if (isRecord2(output2)) declarations.push({ kind: "output", name: name2, value: exprOf(output2["value"], offsetOf(name2)), start: offsetOf(name2) });
|
|
187541
188732
|
return declarations;
|
|
187542
188733
|
}
|
|
187543
|
-
var COPY_INDEX,
|
|
188734
|
+
var COPY_INDEX, MAX_DEPTH12, isRecord2;
|
|
187544
188735
|
var init_convert2 = __esm({
|
|
187545
188736
|
"../../packages/diagrams/src/importers/arm/convert.ts"() {
|
|
187546
188737
|
"use strict";
|
|
187547
|
-
|
|
188738
|
+
init_parse23();
|
|
187548
188739
|
COPY_INDEX = "copyIndex";
|
|
187549
|
-
|
|
188740
|
+
MAX_DEPTH12 = 48;
|
|
187550
188741
|
isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
187551
188742
|
}
|
|
187552
188743
|
});
|
|
@@ -187624,514 +188815,207 @@ var init_arm = __esm({
|
|
|
187624
188815
|
}
|
|
187625
188816
|
});
|
|
187626
188817
|
|
|
187627
|
-
// ../../packages/diagrams/src/importers/
|
|
187628
|
-
function
|
|
187629
|
-
|
|
187630
|
-
|
|
188818
|
+
// ../../packages/diagrams/src/importers/backstage/entities.ts
|
|
188819
|
+
function refOf(written3, fallbackKind, namespace) {
|
|
188820
|
+
const colon = written3.indexOf(":");
|
|
188821
|
+
const kind = colon === -1 ? fallbackKind : written3.slice(0, colon).toLowerCase();
|
|
188822
|
+
const rest = colon === -1 ? written3 : written3.slice(colon + 1);
|
|
188823
|
+
const slash = rest.indexOf("/");
|
|
188824
|
+
return slash === -1 ? `${kind}:${namespace}/${rest}` : `${kind}:${rest.slice(0, slash)}/${rest.slice(slash + 1)}`;
|
|
187631
188825
|
}
|
|
187632
|
-
function
|
|
187633
|
-
|
|
187634
|
-
|
|
187635
|
-
|
|
187636
|
-
|
|
187637
|
-
if (
|
|
187638
|
-
|
|
187639
|
-
|
|
187640
|
-
|
|
187641
|
-
|
|
187642
|
-
|
|
187643
|
-
|
|
187644
|
-
|
|
187645
|
-
|
|
187646
|
-
|
|
187647
|
-
}
|
|
187648
|
-
|
|
187649
|
-
|
|
187650
|
-
|
|
187651
|
-
|
|
187652
|
-
|
|
187653
|
-
|
|
187654
|
-
|
|
187655
|
-
|
|
187656
|
-
|
|
187657
|
-
|
|
187658
|
-
|
|
187659
|
-
|
|
187660
|
-
|
|
187661
|
-
|
|
187662
|
-
|
|
187663
|
-
|
|
187664
|
-
if (quote3 === '"') {
|
|
187665
|
-
if (char === "\\") index2 += 1;
|
|
187666
|
-
else if (char === '"') quote3 = null;
|
|
187667
|
-
} else if (quote3 === "'") {
|
|
187668
|
-
if (char === "'" && text3.charAt(index2 + 1) === "'") index2 += 1;
|
|
187669
|
-
else if (char === "'") quote3 = null;
|
|
187670
|
-
} else if ((char === '"' || char === "'") && opensQuote(text3, index2)) {
|
|
187671
|
-
quote3 = char;
|
|
187672
|
-
} else if (char === "#" && (index2 === 0 || text3.charAt(index2 - 1) === " " || text3.charAt(index2 - 1) === " ")) {
|
|
187673
|
-
return text3.slice(0, index2);
|
|
187674
|
-
}
|
|
187675
|
-
}
|
|
187676
|
-
return text3;
|
|
187677
|
-
}
|
|
187678
|
-
function blockIndicator(text3) {
|
|
187679
|
-
const lastSpace = text3.lastIndexOf(" ");
|
|
187680
|
-
const tail = text3.slice(lastSpace + 1);
|
|
187681
|
-
if (!/^[|>][-+0-9]{0,2}$/.test(tail)) return null;
|
|
187682
|
-
const words2 = text3.slice(0, lastSpace + 1).trim().split(" ").filter((part) => part !== "");
|
|
187683
|
-
while (words2.length > 0 && /^[&!]/.test(words2[words2.length - 1] ?? "")) words2.pop();
|
|
187684
|
-
const head = words2.join(" ");
|
|
187685
|
-
if (head !== "" && !head.endsWith(":") && head !== "-") return null;
|
|
187686
|
-
return { folded: tail.startsWith(">"), keep: tail.includes("+"), strip: tail.includes("-") };
|
|
187687
|
-
}
|
|
187688
|
-
function fold4(lines) {
|
|
187689
|
-
let out = "";
|
|
187690
|
-
for (const line3 of lines) {
|
|
187691
|
-
if (line3 === "") out += "\n";
|
|
187692
|
-
else out += out === "" || out.endsWith("\n") ? line3 : ` ${line3}`;
|
|
187693
|
-
}
|
|
187694
|
-
return out;
|
|
187695
|
-
}
|
|
187696
|
-
function splitDocuments(text3) {
|
|
187697
|
-
const raw = text3.split("\n");
|
|
187698
|
-
const documents = [];
|
|
187699
|
-
let current = { lines: [], line: 1 };
|
|
187700
|
-
let started = false;
|
|
187701
|
-
for (let index2 = 0; index2 < raw.length; index2 += 1) {
|
|
187702
|
-
const full = (raw[index2] ?? "").replace(/\r$/, "");
|
|
187703
|
-
const lineNumber = index2 + 1;
|
|
187704
|
-
if (/^---(\s|$)/.test(full) || /^\.\.\.\s*$/.test(full)) {
|
|
187705
|
-
if (started || current.lines.length > 0) documents.push(current);
|
|
187706
|
-
current = { lines: [], line: lineNumber };
|
|
187707
|
-
started = full.startsWith("---");
|
|
187708
|
-
const rest = cutComment(full.slice(3)).trim();
|
|
187709
|
-
if (full.startsWith("---") && rest !== "" && !/^![^\s]*$/.test(rest)) current.lines.push({ indent: 0, text: rest.replace(/^![^\s]*\s+/, ""), line: lineNumber, block: null });
|
|
187710
|
-
continue;
|
|
187711
|
-
}
|
|
187712
|
-
if (full.startsWith("%") && current.lines.length === 0) continue;
|
|
187713
|
-
const indent = full.length - full.replace(/^ +/, "").length;
|
|
187714
|
-
if (full.charAt(indent) === " " && full.trim() !== "") {
|
|
187715
|
-
return { documents, problem: { line: lineNumber, column: indent + 1, message: "A tab is used to indent this line.", hint: "YAML indents with spaces only. Replace the tab with spaces." } };
|
|
187716
|
-
}
|
|
187717
|
-
const textPart = cutComment(full.slice(indent)).trimEnd();
|
|
187718
|
-
if (textPart === "") continue;
|
|
187719
|
-
const indicator = blockIndicator(textPart);
|
|
187720
|
-
let block = null;
|
|
187721
|
-
if (indicator !== null) {
|
|
187722
|
-
const body6 = [];
|
|
187723
|
-
let bodyIndent = -1;
|
|
187724
|
-
while (index2 + 1 < raw.length) {
|
|
187725
|
-
const next = (raw[index2 + 1] ?? "").replace(/\r$/, "");
|
|
187726
|
-
const nextIndent = next.length - next.replace(/^ +/, "").length;
|
|
187727
|
-
if (next.trim() !== "" && nextIndent <= indent) break;
|
|
187728
|
-
if (next.trim() !== "" && bodyIndent === -1) bodyIndent = nextIndent;
|
|
187729
|
-
body6.push(next.trim() === "" ? "" : next.slice(Math.max(0, bodyIndent)));
|
|
187730
|
-
index2 += 1;
|
|
187731
|
-
}
|
|
187732
|
-
while (!indicator.keep && body6.length > 0 && body6[body6.length - 1] === "") body6.pop();
|
|
187733
|
-
const joined2 = indicator.folded ? fold4(body6) : body6.join("\n");
|
|
187734
|
-
block = indicator.strip || joined2 === "" ? joined2 : `${joined2}
|
|
187735
|
-
`;
|
|
187736
|
-
}
|
|
187737
|
-
current.lines.push({ indent, text: indicator === null ? textPart : textPart.replace(/[|>][-+0-9]*$/, "").trimEnd(), line: lineNumber, block });
|
|
187738
|
-
}
|
|
187739
|
-
if (started || current.lines.length > 0) documents.push(current);
|
|
187740
|
-
return { documents, problem: null };
|
|
188826
|
+
function readEntity2(root) {
|
|
188827
|
+
const kindText = text(get(root, "kind"));
|
|
188828
|
+
const name2 = text(get(get(root, "metadata"), "name"));
|
|
188829
|
+
if (kindText === null || name2 === null) return null;
|
|
188830
|
+
const kind = DRAWN_KINDS2.find((entry2) => entry2.toLowerCase() === kindText.toLowerCase());
|
|
188831
|
+
if (kind === void 0) return QUIET_KINDS2.has(kindText) ? null : { skipped: kindText, line: root.line, column: root.column };
|
|
188832
|
+
const namespace = text(get(get(root, "metadata"), "namespace")) ?? "default";
|
|
188833
|
+
const spec = get(root, "spec");
|
|
188834
|
+
const one = (key, fallback) => {
|
|
188835
|
+
const value = text(get(spec, key));
|
|
188836
|
+
return value === null || value === "" ? null : refOf(value, fallback, namespace);
|
|
188837
|
+
};
|
|
188838
|
+
const many = (key, fallback) => names5(get(spec, key)).map((value) => refOf(value, fallback, namespace));
|
|
188839
|
+
return {
|
|
188840
|
+
kind,
|
|
188841
|
+
ref: `${kind.toLowerCase()}:${namespace}/${name2}`,
|
|
188842
|
+
name: name2,
|
|
188843
|
+
title: text(get(get(root, "metadata"), "title")) ?? text(get(get(spec, "profile"), "displayName")),
|
|
188844
|
+
type: text(get(spec, "type")),
|
|
188845
|
+
lifecycle: text(get(spec, "lifecycle")),
|
|
188846
|
+
owner: one("owner", "group"),
|
|
188847
|
+
system: one("system", "system"),
|
|
188848
|
+
domain: kind === "System" ? one("domain", "domain") : null,
|
|
188849
|
+
parent: kind === "Group" ? one("parent", "group") : one("subcomponentOf", "component"),
|
|
188850
|
+
providesApis: many("providesApis", "api"),
|
|
188851
|
+
consumesApis: many("consumesApis", "api"),
|
|
188852
|
+
dependsOn: many("dependsOn", "component"),
|
|
188853
|
+
dependencyOf: many("dependencyOf", "component"),
|
|
188854
|
+
memberOf: many("memberOf", "group"),
|
|
188855
|
+
line: root.line,
|
|
188856
|
+
column: root.column
|
|
188857
|
+
};
|
|
187741
188858
|
}
|
|
187742
|
-
var
|
|
187743
|
-
|
|
188859
|
+
var DRAWN_KINDS2, QUIET_KINDS2, nameOfRef;
|
|
188860
|
+
var init_entities = __esm({
|
|
188861
|
+
"../../packages/diagrams/src/importers/backstage/entities.ts"() {
|
|
187744
188862
|
"use strict";
|
|
188863
|
+
init_yaml();
|
|
188864
|
+
DRAWN_KINDS2 = ["Domain", "System", "Component", "API", "Resource", "Group", "User"];
|
|
188865
|
+
QUIET_KINDS2 = /* @__PURE__ */ new Set(["Location"]);
|
|
188866
|
+
nameOfRef = (ref) => ref.slice(ref.lastIndexOf("/") + 1);
|
|
187745
188867
|
}
|
|
187746
188868
|
});
|
|
187747
188869
|
|
|
187748
|
-
// ../../packages/diagrams/src/importers/
|
|
187749
|
-
function
|
|
187750
|
-
const
|
|
187751
|
-
|
|
187752
|
-
|
|
187753
|
-
function readQuoted(text3, start2) {
|
|
187754
|
-
const quote3 = text3.charAt(start2);
|
|
187755
|
-
let value = "";
|
|
187756
|
-
for (let index2 = start2 + 1; index2 < text3.length; index2 += 1) {
|
|
187757
|
-
const char = text3.charAt(index2);
|
|
187758
|
-
if (quote3 === "'") {
|
|
187759
|
-
if (char !== "'") value += char;
|
|
187760
|
-
else if (text3.charAt(index2 + 1) === "'") {
|
|
187761
|
-
value += "'";
|
|
187762
|
-
index2 += 1;
|
|
187763
|
-
} else return { value, end: index2 + 1 };
|
|
187764
|
-
} else if (char === '"') {
|
|
187765
|
-
return { value, end: index2 + 1 };
|
|
187766
|
-
} else if (char === "\\") {
|
|
187767
|
-
const next = text3.charAt(index2 + 1);
|
|
187768
|
-
const width = next === "u" ? 4 : next === "x" ? 2 : next === "U" ? 8 : 0;
|
|
187769
|
-
if (width > 0) {
|
|
187770
|
-
const code = Number.parseInt(text3.slice(index2 + 2, index2 + 2 + width), 16);
|
|
187771
|
-
value += Number.isFinite(code) && code <= 1114111 ? String.fromCodePoint(code) : "";
|
|
187772
|
-
index2 += 1 + width;
|
|
187773
|
-
} else {
|
|
187774
|
-
value += ESCAPES2[next] ?? next;
|
|
187775
|
-
index2 += 1;
|
|
187776
|
-
}
|
|
187777
|
-
} else {
|
|
187778
|
-
value += char;
|
|
187779
|
-
}
|
|
188870
|
+
// ../../packages/diagrams/src/importers/backstage/index.ts
|
|
188871
|
+
function brandOf(...texts) {
|
|
188872
|
+
for (const word2 of texts.flatMap((entry2) => (entry2 ?? "").split(/[^A-Za-z0-9]+/))) {
|
|
188873
|
+
const icon = word2.length < 3 ? null : iconForName(word2, "service");
|
|
188874
|
+
if (icon?.startsWith("simple:") === true) return icon;
|
|
187780
188875
|
}
|
|
187781
188876
|
return null;
|
|
187782
188877
|
}
|
|
187783
|
-
function
|
|
187784
|
-
|
|
187785
|
-
|
|
187786
|
-
|
|
187787
|
-
|
|
187788
|
-
|
|
187789
|
-
const
|
|
187790
|
-
|
|
187791
|
-
|
|
187792
|
-
|
|
187793
|
-
|
|
187794
|
-
|
|
187795
|
-
}
|
|
187796
|
-
|
|
187797
|
-
|
|
187798
|
-
|
|
187799
|
-
|
|
187800
|
-
|
|
187801
|
-
|
|
187802
|
-
const reader = new FlowReader(text3, line3, column, resolveAlias);
|
|
187803
|
-
const node3 = reader.value(0);
|
|
187804
|
-
if (!reader.done()) throw new FlowError("Text follows the end of the flow collection.");
|
|
187805
|
-
return node3;
|
|
187806
|
-
}
|
|
187807
|
-
function flowClosed(text3) {
|
|
187808
|
-
let depth = 0;
|
|
187809
|
-
let quote3 = null;
|
|
187810
|
-
for (let index2 = 0; index2 < text3.length; index2 += 1) {
|
|
187811
|
-
const char = text3.charAt(index2);
|
|
187812
|
-
if (quote3 !== null) {
|
|
187813
|
-
if (quote3 === '"' && char === "\\") index2 += 1;
|
|
187814
|
-
else if (char === quote3) quote3 = null;
|
|
187815
|
-
} else if (char === '"' || char === "'") quote3 = char;
|
|
187816
|
-
else if (char === "[" || char === "{") depth += 1;
|
|
187817
|
-
else if (char === "]" || char === "}") depth -= 1;
|
|
188878
|
+
function boxOf3(entity, byOwner) {
|
|
188879
|
+
const type = (entity.type ?? "").toLowerCase();
|
|
188880
|
+
const said = (words3) => cleanText([words3, entity.lifecycle === null || entity.lifecycle === "production" ? null : entity.lifecycle, byOwner || entity.owner === null ? null : `owned by ${nameOfRef(entity.owner)}`].filter((part) => part !== null).join(", "));
|
|
188881
|
+
const label = entity.title ?? entity.name;
|
|
188882
|
+
if (entity.kind === "API") return { type: "gateway", label, sub: said(`${API_NAMES[type] ?? entity.type ?? ""} API`.trim()), icon: API_ICONS[type] ?? "lucide:plug", idHint: entity.name };
|
|
188883
|
+
if (entity.kind === "Resource") {
|
|
188884
|
+
const nodeType = RESOURCE_TYPES.find(([pattern3]) => pattern3.test(type))?.[1] ?? "storage";
|
|
188885
|
+
return { type: nodeType, label, sub: said(entity.type === null ? "Resource" : `Resource, ${entity.type}`), icon: brandOf(entity.title, entity.name, entity.type), idHint: entity.name };
|
|
188886
|
+
}
|
|
188887
|
+
if (entity.kind === "User") return { type: "person", label, sub: "User", icon: null, idHint: entity.name };
|
|
188888
|
+
const kindOf3 = type === "website" ? "client" : "service";
|
|
188889
|
+
const words2 = type === "" ? "Component" : `${type.charAt(0).toUpperCase()}${type.slice(1)}`;
|
|
188890
|
+
return { type: kindOf3, label, sub: said(words2), icon: type === "library" ? "lucide:package" : type === "website" ? "lucide:monitor-smartphone" : brandOf(entity.title, entity.name), idHint: entity.name };
|
|
188891
|
+
}
|
|
188892
|
+
function readBackstage(textIn, context) {
|
|
188893
|
+
const read = parseYaml(textIn);
|
|
188894
|
+
if (read.error !== null) {
|
|
188895
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
188896
|
+
return null;
|
|
187818
188897
|
}
|
|
187819
|
-
|
|
187820
|
-
|
|
187821
|
-
|
|
187822
|
-
|
|
187823
|
-
|
|
187824
|
-
"
|
|
187825
|
-
|
|
187826
|
-
|
|
187827
|
-
|
|
187828
|
-
|
|
187829
|
-
|
|
187830
|
-
|
|
187831
|
-
|
|
187832
|
-
|
|
187833
|
-
|
|
187834
|
-
|
|
187835
|
-
|
|
187836
|
-
|
|
187837
|
-
resolveAlias;
|
|
187838
|
-
index = 0;
|
|
187839
|
-
skipSpace() {
|
|
187840
|
-
while (this.index < this.text.length && /\s/.test(this.text.charAt(this.index))) this.index += 1;
|
|
187841
|
-
}
|
|
187842
|
-
/** The column in the file of the reader's position, for a node it reads. */
|
|
187843
|
-
at() {
|
|
187844
|
-
return this.column + this.index;
|
|
187845
|
-
}
|
|
187846
|
-
/** One value: a collection, a quoted scalar, an alias, or a plain scalar up to `,`, `]`, `}`, or `: `. */
|
|
187847
|
-
value(depth) {
|
|
187848
|
-
if (depth > MAX_FLOW_DEPTH) throw new FlowError("The flow collection is nested too deep.");
|
|
187849
|
-
this.skipSpace();
|
|
187850
|
-
const char = this.text.charAt(this.index);
|
|
187851
|
-
const column = this.at();
|
|
187852
|
-
if (char === "[") return this.sequence(depth);
|
|
187853
|
-
if (char === "{") return this.mapping(depth);
|
|
187854
|
-
if (char === '"' || char === "'") {
|
|
187855
|
-
const read = readQuoted(this.text, this.index);
|
|
187856
|
-
if (read === null) throw new FlowError("A quoted string is never closed.");
|
|
187857
|
-
this.index = read.end;
|
|
187858
|
-
return scalar(read.value, true, this.line, column);
|
|
187859
|
-
}
|
|
187860
|
-
const start2 = this.index;
|
|
187861
|
-
while (this.index < this.text.length) {
|
|
187862
|
-
const next = this.text.charAt(this.index);
|
|
187863
|
-
if (next === "," || next === "]" || next === "}") break;
|
|
187864
|
-
if (next === ":" && /[\s,\]}]/.test(this.text.charAt(this.index + 1) || " ")) break;
|
|
187865
|
-
this.index += 1;
|
|
187866
|
-
}
|
|
187867
|
-
const word2 = this.text.slice(start2, this.index).trim();
|
|
187868
|
-
if (word2.startsWith("*")) return this.resolveAlias(word2.slice(1)) ?? scalar("", false, this.line, column);
|
|
187869
|
-
const props = stripProperties(word2);
|
|
187870
|
-
return tagged(scalar(props.text, false, this.line, column), props.tag);
|
|
187871
|
-
}
|
|
187872
|
-
sequence(depth) {
|
|
187873
|
-
const column = this.at();
|
|
187874
|
-
this.index += 1;
|
|
187875
|
-
const items2 = [];
|
|
187876
|
-
for (; ; ) {
|
|
187877
|
-
this.skipSpace();
|
|
187878
|
-
if (this.index >= this.text.length) throw new FlowError("A [ list is never closed with ].");
|
|
187879
|
-
if (this.text.charAt(this.index) === "]") {
|
|
187880
|
-
this.index += 1;
|
|
187881
|
-
return { kind: "seq", items: items2, line: this.line, column };
|
|
187882
|
-
}
|
|
187883
|
-
items2.push(this.value(depth + 1));
|
|
187884
|
-
this.skipSpace();
|
|
187885
|
-
if (this.text.charAt(this.index) === ",") this.index += 1;
|
|
187886
|
-
else if (this.text.charAt(this.index) !== "]") throw new FlowError("Items of a [ list are separated by commas.");
|
|
187887
|
-
}
|
|
187888
|
-
}
|
|
187889
|
-
mapping(depth) {
|
|
187890
|
-
const column = this.at();
|
|
187891
|
-
this.index += 1;
|
|
187892
|
-
const entries2 = [];
|
|
187893
|
-
for (; ; ) {
|
|
187894
|
-
this.skipSpace();
|
|
187895
|
-
if (this.index >= this.text.length) throw new FlowError("A { mapping is never closed with }.");
|
|
187896
|
-
if (this.text.charAt(this.index) === "}") {
|
|
187897
|
-
this.index += 1;
|
|
187898
|
-
return { kind: "map", entries: entries2, line: this.line, column };
|
|
187899
|
-
}
|
|
187900
|
-
const keyColumn = this.at();
|
|
187901
|
-
const key = this.value(depth + 1);
|
|
187902
|
-
this.skipSpace();
|
|
187903
|
-
let value = scalar("", false, this.line, this.at());
|
|
187904
|
-
if (this.text.charAt(this.index) === ":") {
|
|
187905
|
-
this.index += 1;
|
|
187906
|
-
value = this.value(depth + 1);
|
|
187907
|
-
}
|
|
187908
|
-
entries2.push({ key: key.kind === "scalar" ? key.value : "", value, line: this.line, column: keyColumn });
|
|
187909
|
-
this.skipSpace();
|
|
187910
|
-
if (this.text.charAt(this.index) === ",") this.index += 1;
|
|
187911
|
-
else if (this.text.charAt(this.index) !== "}") throw new FlowError("Entries of a { mapping are separated by commas.");
|
|
187912
|
-
}
|
|
187913
|
-
}
|
|
187914
|
-
/** True when only spaces are left. */
|
|
187915
|
-
done() {
|
|
187916
|
-
this.skipSpace();
|
|
187917
|
-
return this.index >= this.text.length;
|
|
187918
|
-
}
|
|
187919
|
-
};
|
|
187920
|
-
FlowError = class extends Error {
|
|
187921
|
-
};
|
|
188898
|
+
const entities = [];
|
|
188899
|
+
const skipped = [];
|
|
188900
|
+
for (const root of read.documents.map((document2) => document2.root).filter((node3) => node3 !== null)) {
|
|
188901
|
+
const entity = readEntity2(root);
|
|
188902
|
+
if (entity === null) continue;
|
|
188903
|
+
if ("skipped" in entity) skipped.push({ kind: entity.skipped, line: entity.line, column: entity.column });
|
|
188904
|
+
else if (!entities.some((other) => other.ref === entity.ref)) entities.push(entity);
|
|
188905
|
+
}
|
|
188906
|
+
const firstSkipped = skipped[0];
|
|
188907
|
+
if (firstSkipped !== void 0) {
|
|
188908
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, spanAt3(firstSkipped.line, firstSkipped.column), `${countOf2(skipped.length, "entity", "entities")} of a kind this reader does not draw ${skipped.length === 1 ? "was" : "were"} left out: ${[...new Set(skipped.map((entry2) => entry2.kind))].slice(0, 4).join(", ")}.`, "The reader draws Components, APIs, Resources, Systems, Domains, Groups, and Users.");
|
|
188909
|
+
}
|
|
188910
|
+
const byRef = new Map(entities.map((entity) => [entity.ref, entity]));
|
|
188911
|
+
const byOwner = context.options.groupBy === "owner";
|
|
188912
|
+
const boxes2 = entities.filter((entity) => entity.kind === "Component" || entity.kind === "API" || entity.kind === "Resource");
|
|
188913
|
+
if (boxes2.length === 0) {
|
|
188914
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "No Component, API, or Resource was found.", "Send catalog-info.yaml files with apiVersion backstage.io/v1alpha1, a kind, and metadata.name.");
|
|
188915
|
+
return null;
|
|
187922
188916
|
}
|
|
187923
|
-
|
|
187924
|
-
|
|
187925
|
-
|
|
187926
|
-
|
|
187927
|
-
|
|
187928
|
-
|
|
187929
|
-
|
|
187930
|
-
|
|
187931
|
-
if (
|
|
187932
|
-
|
|
187933
|
-
|
|
188917
|
+
const groups = [];
|
|
188918
|
+
const frameOf3 = /* @__PURE__ */ new Map();
|
|
188919
|
+
if (byOwner) {
|
|
188920
|
+
for (const group2 of entities.filter((entity) => entity.kind === "Group")) {
|
|
188921
|
+
const members2 = entities.filter((entity) => entity.kind === "User" && entity.memberOf.includes(group2.ref)).map((user) => user.title ?? user.name);
|
|
188922
|
+
const said = members2.length === 0 ? null : members2.length <= 2 ? members2.join(", ") : countOf2(members2.length, "member");
|
|
188923
|
+
groups.push({ key: group2.ref, label: group2.title ?? group2.name, sub: cleanText(["Group", group2.type, said].filter((part) => part !== null).join(", ")), icon: "lucide:users", parent: group2.parent !== null && byRef.has(group2.parent) ? group2.parent : null, idHint: group2.name });
|
|
188924
|
+
}
|
|
188925
|
+
for (const entity of boxes2) if (entity.owner !== null && byRef.get(entity.owner)?.kind === "Group") frameOf3.set(entity.ref, entity.owner);
|
|
188926
|
+
} else {
|
|
188927
|
+
for (const domain2 of entities.filter((entity) => entity.kind === "Domain")) groups.push({ key: domain2.ref, label: domain2.title ?? domain2.name, sub: cleanText(`Domain${domain2.owner === null ? "" : `, owned by ${nameOfRef(domain2.owner)}`}`), icon: "lucide:map", idHint: domain2.name });
|
|
188928
|
+
for (const system of entities.filter((entity) => entity.kind === "System")) groups.push({ key: system.ref, label: system.title ?? system.name, sub: cleanText(`System${system.owner === null ? "" : `, owned by ${nameOfRef(system.owner)}`}`), icon: "lucide:boxes", parent: system.domain !== null && byRef.has(system.domain) ? system.domain : null, idHint: system.name });
|
|
188929
|
+
for (const entity of boxes2) if (entity.system !== null && byRef.get(entity.system)?.kind === "System") frameOf3.set(entity.ref, entity.system);
|
|
188930
|
+
}
|
|
188931
|
+
const order = { Component: 0, API: 1, Resource: 2 };
|
|
188932
|
+
const ordered = [...boxes2].sort((a, b) => order[a.kind] - order[b.kind]);
|
|
188933
|
+
const nodes = ordered.map((entity) => {
|
|
188934
|
+
const box = boxOf3(entity, byOwner);
|
|
188935
|
+
const system = byOwner && entity.system !== null ? `, in ${nameOfRef(entity.system)}` : "";
|
|
188936
|
+
return { key: entity.ref, ...box, sub: box.sub === null || box.sub === void 0 ? null : cleanText(`${box.sub}${system}`), group: frameOf3.get(entity.ref) ?? null };
|
|
188937
|
+
});
|
|
188938
|
+
const drawn = new Set(nodes.map((node3) => node3.key));
|
|
188939
|
+
const edges = [];
|
|
188940
|
+
const unknown2 = /* @__PURE__ */ new Set();
|
|
188941
|
+
const link2 = (from, to, label, arrow) => {
|
|
188942
|
+
if (!drawn.has(to)) {
|
|
188943
|
+
if (!byRef.has(to)) unknown2.add(to);
|
|
188944
|
+
return;
|
|
188945
|
+
}
|
|
188946
|
+
edges.push({ from, to, label, ...arrow === void 0 ? {} : { arrow } });
|
|
188947
|
+
};
|
|
188948
|
+
for (const entity of ordered) {
|
|
188949
|
+
for (const api of entity.providesApis) link2(entity.ref, api, "provides");
|
|
188950
|
+
for (const api of entity.consumesApis) link2(entity.ref, api, "consumes");
|
|
188951
|
+
for (const target of entity.dependsOn) link2(entity.ref, target, "depends on");
|
|
188952
|
+
for (const source of entity.dependencyOf) if (drawn.has(source)) link2(source, entity.ref, "depends on");
|
|
188953
|
+
if (entity.kind === "Component" && entity.parent !== null) link2(entity.ref, entity.parent, "part of", "-->");
|
|
187934
188954
|
}
|
|
187935
|
-
if (
|
|
187936
|
-
|
|
187937
|
-
const next = text3.charAt(index2 + 1);
|
|
187938
|
-
if (next === "" || next === " " || next === " ") return { key: text3.slice(0, index2).trim(), colon: index2 };
|
|
188955
|
+
if (unknown2.size > 0) {
|
|
188956
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, START, `${countOf2(unknown2.size, "relation")} name${unknown2.size === 1 ? "s an entity" : " entities"} the files do not describe, so no arrow is drawn: ${[...unknown2].slice(0, 3).join(", ")}.`, "Send the catalog-info.yaml files that describe them, or check that each reference names its kind, such as resource:orders-db.");
|
|
187939
188957
|
}
|
|
187940
|
-
|
|
188958
|
+
const shown = /* @__PURE__ */ new Set([...nodes.map((node3) => node3.key), ...groups.map((group2) => group2.key)]);
|
|
188959
|
+
const held = new Set([...frameOf3.values()].flatMap((frame) => [frame, ...ancestorsOf2(frame, groups)]));
|
|
188960
|
+
const keptFrames = entities.filter((entity) => held.has(entity.ref));
|
|
188961
|
+
const named = new Set(
|
|
188962
|
+
byOwner ? [...ordered.flatMap((entity) => entity.system === null ? [] : [entity.system, byRef.get(entity.system)?.domain ?? ""]), ...entities.filter((entity) => entity.kind === "User" && entity.memberOf.some((ref) => held.has(ref))).map((user) => user.ref)] : [...ordered, ...keptFrames].flatMap((entity) => entity.owner === null ? [] : [entity.owner])
|
|
188963
|
+
);
|
|
188964
|
+
const framesKept = groups.filter((group2) => held.has(group2.key)).length;
|
|
188965
|
+
const summarised = entities.filter((entity) => !shown.has(entity.ref) && named.has(entity.ref)).length;
|
|
188966
|
+
const left = entities.filter((entity) => (!shown.has(entity.ref) || groups.some((group2) => group2.key === entity.ref) && !held.has(entity.ref)) && !named.has(entity.ref));
|
|
188967
|
+
const firstLeft = left[0];
|
|
188968
|
+
if (firstLeft !== void 0) {
|
|
188969
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, spanAt3(firstLeft.line, firstLeft.column), `${countOf2(left.length, "entity", "entities")} ${left.length === 1 ? "holds or owns" : "hold or own"} nothing drawn and ${left.length === 1 ? "is" : "are"} left out: ${left.slice(0, 3).map((entity) => entity.ref).join(", ")}.`, byOwner ? "A group is drawn when it owns something, with its members named on its tab." : "Set options.groupBy to owner to draw the groups and users that own the entities.");
|
|
188970
|
+
}
|
|
188971
|
+
const systems = entities.filter((entity) => entity.kind === "System").length;
|
|
188972
|
+
return writeFlow(
|
|
188973
|
+
{
|
|
188974
|
+
title: context.title ?? (byOwner ? "Software catalog by owner" : "Software catalog"),
|
|
188975
|
+
desc: `${countOf2(nodes.length, "entity", "entities")} of a Backstage catalog, ${byOwner ? "framed by the group that owns them" : `framed by ${countOf2(systems, "system")} and the domains that hold them`}. An arrow says a component provides or consumes an API, or depends on another entity.`,
|
|
188976
|
+
direction: "down",
|
|
188977
|
+
nodes,
|
|
188978
|
+
groups,
|
|
188979
|
+
edges,
|
|
188980
|
+
noun: "entities",
|
|
188981
|
+
capSpan: (key) => {
|
|
188982
|
+
const entity = byRef.get(key);
|
|
188983
|
+
return spanAt3(entity?.line ?? 1, entity?.column ?? 1);
|
|
188984
|
+
},
|
|
188985
|
+
advice: byOwner ? "Check that every entity names its owner; one with none sits outside the frames." : "Check that every component names its system; one with none sits outside the frames.",
|
|
188986
|
+
coverage: { noun: "entities", total: entities.length, drawn: nodes.length + framesKept, summarised }
|
|
188987
|
+
},
|
|
188988
|
+
context.report
|
|
188989
|
+
);
|
|
187941
188990
|
}
|
|
187942
|
-
function
|
|
187943
|
-
const
|
|
187944
|
-
|
|
187945
|
-
|
|
187946
|
-
|
|
187947
|
-
|
|
187948
|
-
documents.push({ root: new BlockReader(document2.lines).document(), line: document2.line });
|
|
187949
|
-
} catch (error62) {
|
|
187950
|
-
if (!(error62 instanceof YamlProblem)) throw error62;
|
|
187951
|
-
const problem = { line: error62.line, column: error62.column, message: error62.message, hint: error62.hint };
|
|
187952
|
-
return { documents, error: problem };
|
|
187953
|
-
}
|
|
188991
|
+
function ancestorsOf2(key, groups) {
|
|
188992
|
+
const out = [];
|
|
188993
|
+
let parent = groups.find((group2) => group2.key === key)?.parent ?? null;
|
|
188994
|
+
for (let depth = 0; parent !== null && depth < groups.length && !out.includes(parent); depth += 1) {
|
|
188995
|
+
out.push(parent);
|
|
188996
|
+
parent = groups.find((group2) => group2.key === parent)?.parent ?? null;
|
|
187954
188997
|
}
|
|
187955
|
-
return
|
|
188998
|
+
return out;
|
|
187956
188999
|
}
|
|
187957
|
-
var
|
|
187958
|
-
var
|
|
187959
|
-
"../../packages/diagrams/src/importers/
|
|
189000
|
+
var API_ICONS, RESOURCE_TYPES, API_NAMES, backstageImporter;
|
|
189001
|
+
var init_backstage = __esm({
|
|
189002
|
+
"../../packages/diagrams/src/importers/backstage/index.ts"() {
|
|
187960
189003
|
"use strict";
|
|
187961
|
-
|
|
187962
|
-
|
|
187963
|
-
|
|
187964
|
-
|
|
187965
|
-
|
|
187966
|
-
|
|
187967
|
-
|
|
187968
|
-
|
|
187969
|
-
|
|
187970
|
-
|
|
187971
|
-
|
|
187972
|
-
|
|
187973
|
-
|
|
187974
|
-
|
|
187975
|
-
};
|
|
187976
|
-
isItem3 = (text3) => text3 === "-" || text3.startsWith("- ");
|
|
187977
|
-
BlockReader = class {
|
|
187978
|
-
constructor(lines) {
|
|
187979
|
-
this.lines = lines;
|
|
187980
|
-
}
|
|
187981
|
-
lines;
|
|
187982
|
-
index = 0;
|
|
187983
|
-
anchors = /* @__PURE__ */ new Map();
|
|
187984
|
-
problem(line3, message2, hint2) {
|
|
187985
|
-
return new YamlProblem(line3.line, line3.indent + 1, message2, hint2);
|
|
187986
|
-
}
|
|
187987
|
-
/** The whole document: one block, and nothing left over. */
|
|
187988
|
-
document() {
|
|
187989
|
-
const first = this.lines[0];
|
|
187990
|
-
if (first === void 0) return null;
|
|
187991
|
-
const root = this.block(first.indent, 0);
|
|
187992
|
-
const extra = this.lines[this.index];
|
|
187993
|
-
if (extra !== void 0) throw this.problem(extra, "This line is indented less than the block it follows, or not like the lines before it.", "Line it up with the other keys at its level.");
|
|
187994
|
-
return root;
|
|
187995
|
-
}
|
|
187996
|
-
/** A block that starts at the current line, indented `indent` spaces: a sequence, a mapping, or a scalar. */
|
|
187997
|
-
block(indent, depth) {
|
|
187998
|
-
const line3 = this.lines[this.index];
|
|
187999
|
-
if (depth > MAX_DEPTH12) throw this.problem(line3, "The YAML is nested too deep.", `Keep nesting under ${MAX_DEPTH12} levels.`);
|
|
188000
|
-
if (isItem3(line3.text)) return this.sequence(indent, depth);
|
|
188001
|
-
if (splitKey(line3.text) !== null) return this.mapping(indent, depth);
|
|
188002
|
-
this.index += 1;
|
|
188003
|
-
return this.value(line3.text, line3, indent, depth, line3.indent + 1);
|
|
188004
|
-
}
|
|
188005
|
-
mapping(indent, depth) {
|
|
188006
|
-
const first = this.lines[this.index];
|
|
188007
|
-
const entries2 = [];
|
|
188008
|
-
const merges = [];
|
|
188009
|
-
while (this.index < this.lines.length) {
|
|
188010
|
-
const line3 = this.lines[this.index];
|
|
188011
|
-
if (line3.indent < indent) break;
|
|
188012
|
-
if (line3.indent > indent) throw this.problem(line3, "This line is indented more than the keys around it.", "Indent it like the other keys of the same mapping.");
|
|
188013
|
-
if (isItem3(line3.text)) break;
|
|
188014
|
-
const split = splitKey(line3.text);
|
|
188015
|
-
if (split === null) throw this.problem(line3, "Expected a key followed by a colon.", "Write it as key: value, with a space after the colon.");
|
|
188016
|
-
this.index += 1;
|
|
188017
|
-
const rest = line3.text.slice(split.colon + 1).trim();
|
|
188018
|
-
const value = this.entryValue(rest, line3, indent, depth, line3.indent + split.colon + 2);
|
|
188019
|
-
if (split.key === "<<") merges.push(value);
|
|
188020
|
-
else entries2.push({ key: split.key, value, line: line3.line, column: line3.indent + 1 });
|
|
188021
|
-
}
|
|
188022
|
-
for (const merge3 of merges) {
|
|
188023
|
-
const sources = merge3.kind === "seq" ? merge3.items : [merge3];
|
|
188024
|
-
for (const source of sources) {
|
|
188025
|
-
if (source.kind !== "map") continue;
|
|
188026
|
-
for (const entry2 of source.entries) if (!entries2.some((own2) => own2.key === entry2.key)) entries2.push(entry2);
|
|
188027
|
-
}
|
|
188028
|
-
}
|
|
188029
|
-
return { kind: "map", entries: entries2, line: first.line, column: first.indent + 1 };
|
|
188030
|
-
}
|
|
188031
|
-
/** The value of a mapping entry: on its own line, in a block below it, or a sequence at the same indent. */
|
|
188032
|
-
entryValue(rest, line3, indent, depth, column) {
|
|
188033
|
-
const next = this.lines[this.index];
|
|
188034
|
-
const props = stripProperties(rest);
|
|
188035
|
-
if (props.text === "" && line3.block === null && next !== void 0 && (next.indent > indent || next.indent === indent && isItem3(next.text))) {
|
|
188036
|
-
const node3 = tagged(this.block(next.indent, depth + 1), props.tag);
|
|
188037
|
-
if (props.anchor !== null) this.anchors.set(props.anchor, node3);
|
|
188038
|
-
return node3;
|
|
188039
|
-
}
|
|
188040
|
-
return this.value(rest, line3, indent, depth, column, true);
|
|
188041
|
-
}
|
|
188042
|
-
sequence(indent, depth) {
|
|
188043
|
-
const first = this.lines[this.index];
|
|
188044
|
-
const items2 = [];
|
|
188045
|
-
while (this.index < this.lines.length) {
|
|
188046
|
-
const line3 = this.lines[this.index];
|
|
188047
|
-
if (line3.indent !== indent || !isItem3(line3.text)) {
|
|
188048
|
-
if (line3.indent > indent) throw this.problem(line3, "This line is indented more than the items around it.", "Indent it like the other items, or under the item it belongs to.");
|
|
188049
|
-
break;
|
|
188050
|
-
}
|
|
188051
|
-
const rest = line3.text.slice(1).trimStart();
|
|
188052
|
-
const restColumn = line3.indent + (line3.text.length - rest.length);
|
|
188053
|
-
if (rest === "" && line3.block === null) {
|
|
188054
|
-
this.index += 1;
|
|
188055
|
-
const next = this.lines[this.index];
|
|
188056
|
-
items2.push(next !== void 0 && next.indent > indent ? this.block(next.indent, depth + 1) : scalar("", false, line3.line, restColumn + 1));
|
|
188057
|
-
} else if (line3.block === null && /^![A-Za-z:]+$/.test(rest) && this.lines[this.index + 1] !== void 0 && this.lines[this.index + 1].indent > indent) {
|
|
188058
|
-
const tag = rest;
|
|
188059
|
-
this.index += 1;
|
|
188060
|
-
items2.push(tagged(this.block(this.lines[this.index].indent, depth + 1), tag));
|
|
188061
|
-
} else if (line3.block === null && (isItem3(rest) || splitKey(stripProperties(rest).text) !== null)) {
|
|
188062
|
-
const props = stripProperties(rest);
|
|
188063
|
-
line3.indent = restColumn + props.offset;
|
|
188064
|
-
line3.text = props.text;
|
|
188065
|
-
const node3 = this.block(line3.indent, depth + 1);
|
|
188066
|
-
if (props.anchor !== null) this.anchors.set(props.anchor, node3);
|
|
188067
|
-
items2.push(node3);
|
|
188068
|
-
} else {
|
|
188069
|
-
this.index += 1;
|
|
188070
|
-
items2.push(this.value(rest, line3, indent, depth, restColumn + 1));
|
|
188071
|
-
}
|
|
188072
|
-
}
|
|
188073
|
-
return { kind: "seq", items: items2, line: first.line, column: first.indent + 1 };
|
|
188074
|
-
}
|
|
188075
|
-
/** A value written on a line: a block scalar, an alias, a flow collection, a quoted scalar, or a plain scalar that may run on. */
|
|
188076
|
-
value(text3, line3, indent, depth, column, ofKey = false) {
|
|
188077
|
-
const props = stripProperties(text3);
|
|
188078
|
-
const body6 = props.text;
|
|
188079
|
-
let node3;
|
|
188080
|
-
if (line3.block !== null) {
|
|
188081
|
-
node3 = scalar(line3.block, true, line3.line, column);
|
|
188082
|
-
} else if (body6.startsWith("*")) {
|
|
188083
|
-
const target = this.anchors.get(body6.slice(1).trim());
|
|
188084
|
-
if (target === void 0) throw this.problem(line3, `The alias ${body6} names no anchor written before it.`, "Write the anchor (&name) before the alias that uses it.");
|
|
188085
|
-
node3 = target;
|
|
188086
|
-
} else if (body6.startsWith("[") || body6.startsWith("{")) {
|
|
188087
|
-
node3 = this.flow(this.joined(body6, flowClosed), line3, column + props.offset);
|
|
188088
|
-
} else if (body6.startsWith('"') || body6.startsWith("'")) {
|
|
188089
|
-
const whole2 = this.joined(body6, (joined2) => readQuoted(joined2, 0) !== null);
|
|
188090
|
-
const read = readQuoted(whole2, 0);
|
|
188091
|
-
if (read === null) throw this.problem(line3, "A quoted string is never closed.", "Close it with the same quote it opened with.");
|
|
188092
|
-
node3 = scalar(read.value, true, line3.line, column + props.offset);
|
|
188093
|
-
} else {
|
|
188094
|
-
let plain3 = body6;
|
|
188095
|
-
while (this.index < this.lines.length) {
|
|
188096
|
-
const more = this.lines[this.index];
|
|
188097
|
-
if (more.indent < indent || more.indent === indent && !ofKey) break;
|
|
188098
|
-
if (splitKey(more.text) !== null || isItem3(more.text)) break;
|
|
188099
|
-
plain3 = `${plain3} ${more.text}`;
|
|
188100
|
-
this.index += 1;
|
|
188101
|
-
}
|
|
188102
|
-
node3 = scalar(plain3.trim(), false, line3.line, column + props.offset);
|
|
188103
|
-
}
|
|
188104
|
-
node3 = tagged(node3, props.tag);
|
|
188105
|
-
if (props.anchor !== null) this.anchors.set(props.anchor, node3);
|
|
188106
|
-
return node3;
|
|
188107
|
-
}
|
|
188108
|
-
/** The text of a value that runs over several lines until `complete` says it is whole, consuming those lines. */
|
|
188109
|
-
joined(start2, complete) {
|
|
188110
|
-
let text3 = start2;
|
|
188111
|
-
for (let count3 = 0; !complete(text3) && count3 < MAX_JOINED_LINES && this.index < this.lines.length; count3 += 1) {
|
|
188112
|
-
text3 = `${text3} ${this.lines[this.index].text}`;
|
|
188113
|
-
this.index += 1;
|
|
188114
|
-
}
|
|
188115
|
-
return text3;
|
|
188116
|
-
}
|
|
188117
|
-
flow(text3, line3, column) {
|
|
188118
|
-
try {
|
|
188119
|
-
return readFlow2(text3, line3.line, column, (name2) => this.anchors.get(name2) ?? null);
|
|
188120
|
-
} catch (error62) {
|
|
188121
|
-
if (error62 instanceof FlowError) throw this.problem(line3, error62.message, "Close every [ and { on the line it opens, and separate items with commas.");
|
|
188122
|
-
throw error62;
|
|
188123
|
-
}
|
|
188124
|
-
}
|
|
188125
|
-
};
|
|
188126
|
-
}
|
|
188127
|
-
});
|
|
188128
|
-
|
|
188129
|
-
// ../../packages/diagrams/src/importers/shared/yaml/index.ts
|
|
188130
|
-
var init_yaml = __esm({
|
|
188131
|
-
"../../packages/diagrams/src/importers/shared/yaml/index.ts"() {
|
|
188132
|
-
"use strict";
|
|
188133
|
-
init_access();
|
|
188134
|
-
init_parse23();
|
|
189004
|
+
init_core();
|
|
189005
|
+
init_shared2();
|
|
189006
|
+
init_yaml();
|
|
189007
|
+
init_entities();
|
|
189008
|
+
API_ICONS = { openapi: "simple:swagger", graphql: "simple:graphql", trpc: "simple:trpc", grpc: "lucide:plug-zap", asyncapi: "lucide:radio" };
|
|
189009
|
+
RESOURCE_TYPES = [
|
|
189010
|
+
[/database|db|postgres|mysql|sql|mongo|dynamo|table/, "database"],
|
|
189011
|
+
[/cache|redis|memcache/, "cache"],
|
|
189012
|
+
[/queue|topic|stream|kafka|bus|sqs|sns|pubsub/, "queue"],
|
|
189013
|
+
[/secret|vault|key/, "secret"],
|
|
189014
|
+
[/bucket|storage|s3|blob|file/, "storage"],
|
|
189015
|
+
[/cluster|kubernetes|k8s/, "service"]
|
|
189016
|
+
];
|
|
189017
|
+
API_NAMES = { openapi: "OpenAPI", graphql: "GraphQL", trpc: "tRPC", grpc: "gRPC", asyncapi: "AsyncAPI" };
|
|
189018
|
+
backstageImporter = { format: "backstage", kinds: ["flow"], joins: "\n---\n", extensions: [".yaml", ".yml"], read: readBackstage };
|
|
188135
189019
|
}
|
|
188136
189020
|
});
|
|
188137
189021
|
|
|
@@ -188364,18 +189248,20 @@ var init_template = __esm({
|
|
|
188364
189248
|
itemsOf = (node3) => node3.kind === "seq" ? node3.items : [node3];
|
|
188365
189249
|
subNames = (template) => [...template.matchAll(/\$\{([A-Za-z0-9_:.]+)\}/g)].map((match) => match[1] ?? "");
|
|
188366
189250
|
Template = class {
|
|
188367
|
-
|
|
188368
|
-
|
|
188369
|
-
mappings;
|
|
188370
|
-
resources;
|
|
188371
|
-
conditionMemo = /* @__PURE__ */ new Map();
|
|
188372
|
-
constructor(root) {
|
|
189251
|
+
constructor(root, external = null) {
|
|
189252
|
+
this.external = external;
|
|
188373
189253
|
const section = (key) => entryOf(root, key)?.kind === "map" ? entryOf(root, key).entries : [];
|
|
188374
189254
|
this.parameters = new Map(section("Parameters").map((entry2) => [entry2.key, entry2.value]));
|
|
188375
189255
|
this.conditions = new Map(section("Conditions").map((entry2) => [entry2.key, entry2.value]));
|
|
188376
189256
|
this.mappings = entryOf(root, "Mappings");
|
|
188377
189257
|
this.resources = new Map(section("Resources").filter((entry2) => entry2.value.kind === "map").map((entry2) => [entry2.key, entry2.value]));
|
|
188378
189258
|
}
|
|
189259
|
+
external;
|
|
189260
|
+
parameters;
|
|
189261
|
+
conditions;
|
|
189262
|
+
mappings;
|
|
189263
|
+
resources;
|
|
189264
|
+
conditionMemo = /* @__PURE__ */ new Map();
|
|
188379
189265
|
/** The value of a node as far as the template's defaults give it. */
|
|
188380
189266
|
evaluate(node3, depth = 0) {
|
|
188381
189267
|
if (node3 === void 0 || depth > MAX_DEPTH13) return new Unknown("value");
|
|
@@ -188492,11 +189378,18 @@ var init_template = __esm({
|
|
|
188492
189378
|
const argument = intrinsic.argument;
|
|
188493
189379
|
if (intrinsic.name === "Ref") {
|
|
188494
189380
|
const name2 = scalarOf(argument) ?? "";
|
|
188495
|
-
return this.resources.has(name2) ? [name2] : [];
|
|
189381
|
+
return this.resources.has(name2) ? [name2] : [...this.external?.parameter(name2) ?? []];
|
|
188496
189382
|
}
|
|
188497
189383
|
if (intrinsic.name === "GetAtt") {
|
|
188498
|
-
const target = getAttOf(argument)
|
|
188499
|
-
|
|
189384
|
+
const target = getAttOf(argument);
|
|
189385
|
+
const outside = target === null ? null : this.external?.attribute(target.resource, target.attribute) ?? null;
|
|
189386
|
+
if (outside !== null) return [...outside];
|
|
189387
|
+
return this.resources.has(target?.resource ?? "") ? [target?.resource ?? ""] : [];
|
|
189388
|
+
}
|
|
189389
|
+
if (intrinsic.name === "ImportValue" && this.external !== null) {
|
|
189390
|
+
const name2 = textOf5(this.evaluate(argument, depth + 1));
|
|
189391
|
+
const outside = name2 === null ? null : this.external.imported(name2);
|
|
189392
|
+
if (outside !== null) return [...outside];
|
|
188500
189393
|
}
|
|
188501
189394
|
if (intrinsic.name === "Sub") {
|
|
188502
189395
|
const template = argument.kind === "seq" ? scalarOf(argument.items[0]) : scalarOf(argument);
|
|
@@ -188533,17 +189426,17 @@ var init_template = __esm({
|
|
|
188533
189426
|
});
|
|
188534
189427
|
|
|
188535
189428
|
// ../../packages/diagrams/src/importers/cloudformation/index.ts
|
|
188536
|
-
function
|
|
189429
|
+
function nodeOf2(value, depth = 0) {
|
|
188537
189430
|
const at3 = { line: 1, column: 1 };
|
|
188538
189431
|
if (depth > 64 || value === null || value === void 0) return { kind: "scalar", value: "", quoted: false, isNull: true, ...at3 };
|
|
188539
|
-
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) =>
|
|
188540
|
-
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value:
|
|
189432
|
+
if (Array.isArray(value)) return { kind: "seq", items: value.map((item) => nodeOf2(item, depth + 1)), ...at3 };
|
|
189433
|
+
if (typeof value === "object") return { kind: "map", entries: Object.entries(value).map(([key, entry2]) => ({ key, value: nodeOf2(entry2, depth + 1), ...at3 })), ...at3 };
|
|
188541
189434
|
return { kind: "scalar", value: String(value), quoted: typeof value === "string", isNull: false, ...at3 };
|
|
188542
189435
|
}
|
|
188543
189436
|
function readFile(text3) {
|
|
188544
189437
|
if (/^\s*\{/.test(text3)) {
|
|
188545
189438
|
try {
|
|
188546
|
-
return { root:
|
|
189439
|
+
return { root: nodeOf2(JSON.parse(text3)), problem: null };
|
|
188547
189440
|
} catch (error62) {
|
|
188548
189441
|
return { root: null, problem: { line: 1, column: 1, message: `The template is not JSON: ${error62 instanceof Error ? error62.message : "it cannot be read"}.`, hint: "Send the template as CloudFormation writes it, in JSON or YAML." } };
|
|
188549
189442
|
}
|
|
@@ -188633,6 +189526,451 @@ var init_cloudformation = __esm({
|
|
|
188633
189526
|
}
|
|
188634
189527
|
});
|
|
188635
189528
|
|
|
189529
|
+
// ../../packages/diagrams/src/importers/cdk/assembly.ts
|
|
189530
|
+
function jsonOf(file2) {
|
|
189531
|
+
if (!/^\s*\{/.test(file2.text)) return void 0;
|
|
189532
|
+
try {
|
|
189533
|
+
return JSON.parse(file2.text);
|
|
189534
|
+
} catch {
|
|
189535
|
+
return void 0;
|
|
189536
|
+
}
|
|
189537
|
+
}
|
|
189538
|
+
function manifestStacks(json2, file2) {
|
|
189539
|
+
const out = [];
|
|
189540
|
+
const artifacts = isRecord4(json2["artifacts"]) ? json2["artifacts"] : {};
|
|
189541
|
+
for (const [id, artifact] of Object.entries(artifacts)) {
|
|
189542
|
+
if (!isRecord4(artifact) || artifact["type"] !== "aws:cloudformation:stack") continue;
|
|
189543
|
+
const properties = isRecord4(artifact["properties"]) ? artifact["properties"] : {};
|
|
189544
|
+
const template = typeof properties["templateFile"] === "string" ? properties["templateFile"] : `${id}.template.json`;
|
|
189545
|
+
const logicalPaths = /* @__PURE__ */ new Map();
|
|
189546
|
+
if (isRecord4(artifact["metadata"])) {
|
|
189547
|
+
for (const [path, entries2] of Object.entries(artifact["metadata"])) {
|
|
189548
|
+
if (!Array.isArray(entries2)) continue;
|
|
189549
|
+
for (const entry2 of entries2) if (isRecord4(entry2) && entry2["type"] === "aws:cdk:logicalId" && typeof entry2["data"] === "string") logicalPaths.set(entry2["data"], path.replace(/^\//, ""));
|
|
189550
|
+
}
|
|
189551
|
+
}
|
|
189552
|
+
const at3 = file2.text.indexOf(JSON.stringify(id));
|
|
189553
|
+
out.push({ path: typeof artifact["displayName"] === "string" ? artifact["displayName"] : id, template: `${folderOf4(file2.path)}${template}`, logicalPaths, start: file2.start + Math.max(0, at3) });
|
|
189554
|
+
}
|
|
189555
|
+
return out;
|
|
189556
|
+
}
|
|
189557
|
+
function treeClasses(json2) {
|
|
189558
|
+
const out = /* @__PURE__ */ new Map();
|
|
189559
|
+
const walk = (node3, depth) => {
|
|
189560
|
+
if (!isRecord4(node3) || depth > 64 || out.size > 5e4) return;
|
|
189561
|
+
const info = isRecord4(node3["constructInfo"]) ? node3["constructInfo"] : {};
|
|
189562
|
+
if (typeof node3["path"] === "string" && typeof info["fqn"] === "string") out.set(node3["path"], info["fqn"]);
|
|
189563
|
+
if (isRecord4(node3["children"])) for (const child of Object.values(node3["children"])) walk(child, depth + 1);
|
|
189564
|
+
};
|
|
189565
|
+
walk(json2["tree"], 0);
|
|
189566
|
+
return out;
|
|
189567
|
+
}
|
|
189568
|
+
function cdkPaths(root) {
|
|
189569
|
+
const out = /* @__PURE__ */ new Map();
|
|
189570
|
+
const resources = get(root, "Resources");
|
|
189571
|
+
for (const entry2 of resources?.kind === "map" ? resources.entries : []) {
|
|
189572
|
+
const path = text(get(get(entry2.value, "Metadata"), "aws:cdk:path"));
|
|
189573
|
+
if (path !== null) out.set(entry2.key, path);
|
|
189574
|
+
}
|
|
189575
|
+
return out;
|
|
189576
|
+
}
|
|
189577
|
+
function ownStackPath(root, file2) {
|
|
189578
|
+
const paths = [...cdkPaths(root).values()];
|
|
189579
|
+
const metadata = paths.find((path) => path.endsWith("/CDKMetadata/Default"));
|
|
189580
|
+
if (metadata !== void 0) return metadata.slice(0, -"/CDKMetadata/Default".length);
|
|
189581
|
+
const named = /^(.+?)\.template\.(?:json|ya?ml)$/i.exec(baseName4(file2.path))?.[1];
|
|
189582
|
+
if (named !== void 0) return named;
|
|
189583
|
+
return paths[0]?.split("/")[0] ?? "Stack";
|
|
189584
|
+
}
|
|
189585
|
+
function readAssembly(files) {
|
|
189586
|
+
const stacks = [];
|
|
189587
|
+
const classes = /* @__PURE__ */ new Map();
|
|
189588
|
+
const unknown2 = [];
|
|
189589
|
+
const problems = [];
|
|
189590
|
+
const read = [];
|
|
189591
|
+
for (const file2 of files) {
|
|
189592
|
+
const name2 = baseName4(file2.path);
|
|
189593
|
+
if (name2 === "cdk.out" || name2.endsWith(".assets.json")) continue;
|
|
189594
|
+
const json2 = jsonOf(file2);
|
|
189595
|
+
if (isRecord4(json2) && isRecord4(json2["artifacts"])) {
|
|
189596
|
+
stacks.push(...manifestStacks(json2, file2));
|
|
189597
|
+
continue;
|
|
189598
|
+
}
|
|
189599
|
+
if (isRecord4(json2) && isRecord4(json2["tree"])) {
|
|
189600
|
+
for (const [path, fqn] of treeClasses(json2)) classes.set(path, fqn);
|
|
189601
|
+
continue;
|
|
189602
|
+
}
|
|
189603
|
+
if (isRecord4(json2) && json2["Resources"] === void 0 && (isRecord4(json2["files"]) || isRecord4(json2["dockerImages"]))) continue;
|
|
189604
|
+
const template = readFile(file2.text);
|
|
189605
|
+
if (template.problem !== null || template.root === null) {
|
|
189606
|
+
problems.push({ file: file2, ...template.problem ?? { line: 1, column: 1, message: "The file is empty.", hint: "Send the templates of cdk.out, with manifest.json." } });
|
|
189607
|
+
continue;
|
|
189608
|
+
}
|
|
189609
|
+
if (get(template.root, "Resources") === void 0) unknown2.push(file2);
|
|
189610
|
+
else read.push({ file: file2, root: template.root });
|
|
189611
|
+
}
|
|
189612
|
+
const templates = [];
|
|
189613
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
189614
|
+
const byStack = (stack) => read.find((entry2) => entry2.file.path === stack.template) ?? read.find((entry2) => baseName4(entry2.file.path) === baseName4(stack.template) && !claimed.has(entry2.file));
|
|
189615
|
+
const missing = [];
|
|
189616
|
+
for (const stack of stacks) {
|
|
189617
|
+
const found = byStack(stack);
|
|
189618
|
+
if (found === void 0 || claimed.has(found.file)) {
|
|
189619
|
+
if (found === void 0) missing.push({ stack: stack.path, file: stack.template, start: stack.start });
|
|
189620
|
+
continue;
|
|
189621
|
+
}
|
|
189622
|
+
claimed.add(found.file);
|
|
189623
|
+
templates.push({ file: found.file, root: found.root, stackPath: stack.path, topPath: stack.path, parent: null, manifestPaths: stack.logicalPaths });
|
|
189624
|
+
}
|
|
189625
|
+
const nestedOf = /* @__PURE__ */ new Map();
|
|
189626
|
+
for (const entry2 of read) if (!claimed.has(entry2.file) && /\.nested\.template\.json$/i.test(entry2.file.path)) nestedOf.set(baseName4(entry2.file.path), entry2);
|
|
189627
|
+
for (const entry2 of read) {
|
|
189628
|
+
if (claimed.has(entry2.file) || nestedOf.get(baseName4(entry2.file.path)) === entry2) continue;
|
|
189629
|
+
claimed.add(entry2.file);
|
|
189630
|
+
const path = ownStackPath(entry2.root, entry2.file);
|
|
189631
|
+
templates.push({ file: entry2.file, root: entry2.root, stackPath: path, topPath: path, parent: null, manifestPaths: /* @__PURE__ */ new Map() });
|
|
189632
|
+
}
|
|
189633
|
+
for (let index2 = 0; index2 < templates.length; index2 += 1) {
|
|
189634
|
+
const template = templates[index2];
|
|
189635
|
+
const resources = get(template.root, "Resources");
|
|
189636
|
+
for (const entry2 of resources?.kind === "map" ? resources.entries : []) {
|
|
189637
|
+
if (text(get(entry2.value, "Type")) !== "AWS::CloudFormation::Stack") continue;
|
|
189638
|
+
const asset = text(get(get(entry2.value, "Metadata"), "aws:asset:path"));
|
|
189639
|
+
const nested2 = asset === null ? void 0 : nestedOf.get(baseName4(asset));
|
|
189640
|
+
if (nested2 === void 0 || claimed.has(nested2.file)) continue;
|
|
189641
|
+
claimed.add(nested2.file);
|
|
189642
|
+
const path = text(get(get(entry2.value, "Metadata"), "aws:cdk:path")) ?? template.manifestPaths.get(entry2.key) ?? `${template.stackPath}/${entry2.key}`;
|
|
189643
|
+
templates.push({ file: nested2.file, root: nested2.root, stackPath: nestedStackPath(path), topPath: template.topPath, parent: { template, logical: entry2.key }, manifestPaths: /* @__PURE__ */ new Map() });
|
|
189644
|
+
}
|
|
189645
|
+
}
|
|
189646
|
+
for (const entry2 of nestedOf.values()) {
|
|
189647
|
+
if (claimed.has(entry2.file)) continue;
|
|
189648
|
+
const path = ownStackPath(entry2.root, entry2.file);
|
|
189649
|
+
templates.push({ file: entry2.file, root: entry2.root, stackPath: path, topPath: path, parent: null, manifestPaths: /* @__PURE__ */ new Map() });
|
|
189650
|
+
}
|
|
189651
|
+
return { templates, classes, missing, unknown: unknown2, problems };
|
|
189652
|
+
}
|
|
189653
|
+
var isRecord4, baseName4, folderOf4, nestedStackPath;
|
|
189654
|
+
var init_assembly = __esm({
|
|
189655
|
+
"../../packages/diagrams/src/importers/cdk/assembly.ts"() {
|
|
189656
|
+
"use strict";
|
|
189657
|
+
init_cloudformation();
|
|
189658
|
+
init_yaml();
|
|
189659
|
+
isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
189660
|
+
baseName4 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
189661
|
+
folderOf4 = (path) => path.includes("/") ? path.slice(0, path.lastIndexOf("/") + 1) : "";
|
|
189662
|
+
nestedStackPath = (path) => path.replace(/\.NestedStack\/[^/]*\.NestedStackResource$/, "");
|
|
189663
|
+
}
|
|
189664
|
+
});
|
|
189665
|
+
|
|
189666
|
+
// ../../packages/diagrams/src/importers/cdk/constructs.ts
|
|
189667
|
+
function readable(segment, stack) {
|
|
189668
|
+
const own2 = (segment.split(/[.:]/)[0] || segment).replace(/[0-9A-F]{8}$/, "");
|
|
189669
|
+
const at3 = stack.length >= 3 ? own2.indexOf(stack) : -1;
|
|
189670
|
+
return (at3 > 0 ? own2.slice(0, at3) : own2) || segment;
|
|
189671
|
+
}
|
|
189672
|
+
function frameModules2(tree, classes, startOf3) {
|
|
189673
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
189674
|
+
const used = /* @__PURE__ */ new Set();
|
|
189675
|
+
const modules = [];
|
|
189676
|
+
for (const path of [...tree.frames.keys()].sort((a, b) => a.split("/").length - b.split("/").length || (a < b ? -1 : 1))) {
|
|
189677
|
+
const parent = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : "";
|
|
189678
|
+
const id = path.slice(path.lastIndexOf("/") + 1);
|
|
189679
|
+
const base = `${scopes.get(parent) ?? ""}module.${safe2(id)}`;
|
|
189680
|
+
let scope = `${base}.`;
|
|
189681
|
+
for (let count3 = 2; used.has(scope); count3 += 1) scope = `${base}_${count3}.`;
|
|
189682
|
+
used.add(scope);
|
|
189683
|
+
scopes.set(path, scope);
|
|
189684
|
+
const kind = tree.frames.get(path) ?? "Construct";
|
|
189685
|
+
const fqn = classes.get(path) ?? "";
|
|
189686
|
+
const own2 = /^(?:aws-cdk-lib|@aws-cdk\/[^.]+)\./.test(fqn) && !/\.(?:Stack|NestedStack|Stage)$/.test(fqn) ? fqn.split(".").pop() ?? "" : "";
|
|
189687
|
+
modules.push({ scope, name: path, label: id, instance: null, source: own2, start: startOf3(path), noun: kind });
|
|
189688
|
+
}
|
|
189689
|
+
return { modules, scopes };
|
|
189690
|
+
}
|
|
189691
|
+
var OWN_RESOURCE, constructOf, ConstructTree, safe2;
|
|
189692
|
+
var init_constructs = __esm({
|
|
189693
|
+
"../../packages/diagrams/src/importers/cdk/constructs.ts"() {
|
|
189694
|
+
"use strict";
|
|
189695
|
+
OWN_RESOURCE = /\/(?:Resource|Default)$/;
|
|
189696
|
+
constructOf = (path) => path.replace(OWN_RESOURCE, "");
|
|
189697
|
+
ConstructTree = class {
|
|
189698
|
+
constructor(paths, roots) {
|
|
189699
|
+
this.roots = roots;
|
|
189700
|
+
for (const path of paths) if (OWN_RESOURCE.test(path)) this.wrapping.add(constructOf(path));
|
|
189701
|
+
}
|
|
189702
|
+
roots;
|
|
189703
|
+
/** Construct paths that wrap a resource of their own. */
|
|
189704
|
+
wrapping = /* @__PURE__ */ new Set();
|
|
189705
|
+
/** Frames by path, with what each is. */
|
|
189706
|
+
frames = /* @__PURE__ */ new Map();
|
|
189707
|
+
/** The top stack or nested stack a path belongs to: the longest root it starts with. */
|
|
189708
|
+
rootOf(path) {
|
|
189709
|
+
let best = "";
|
|
189710
|
+
for (const root of this.roots.keys()) if ((path === root || path.startsWith(`${root}/`)) && root.length > best.length) best = root;
|
|
189711
|
+
return best;
|
|
189712
|
+
}
|
|
189713
|
+
/** The frames a resource's construct sits in, and its label: its own id, or, made by a level 2 construct, that construct's id and its own. */
|
|
189714
|
+
place(path, framedStacks) {
|
|
189715
|
+
const construct = constructOf(path);
|
|
189716
|
+
const frames = [];
|
|
189717
|
+
const root = this.rootOf(construct);
|
|
189718
|
+
const top = [...this.roots].filter(([candidate2, kind]) => kind !== "Nested stack" && (root === candidate2 || root.startsWith(`${candidate2}/`))).sort((a, b) => a[0].length - b[0].length)[0]?.[0] ?? "";
|
|
189719
|
+
const segments = construct.split("/");
|
|
189720
|
+
let wrapper = null;
|
|
189721
|
+
for (let depth = 1; depth < segments.length; depth += 1) {
|
|
189722
|
+
const ancestor = segments.slice(0, depth).join("/");
|
|
189723
|
+
const kind = this.roots.get(ancestor);
|
|
189724
|
+
if (ancestor.length <= top.length) {
|
|
189725
|
+
if (framedStacks && top !== "") this.addFrame(frames, ancestor, ancestor === top ? "Stack" : "Stage");
|
|
189726
|
+
continue;
|
|
189727
|
+
}
|
|
189728
|
+
if (kind === "Nested stack") {
|
|
189729
|
+
this.addFrame(frames, ancestor, kind);
|
|
189730
|
+
wrapper = null;
|
|
189731
|
+
continue;
|
|
189732
|
+
}
|
|
189733
|
+
if (wrapper !== null) continue;
|
|
189734
|
+
if (this.wrapping.has(ancestor)) wrapper = depth - 1;
|
|
189735
|
+
else this.addFrame(frames, ancestor, "Construct");
|
|
189736
|
+
}
|
|
189737
|
+
const stack = top.slice(top.lastIndexOf("/") + 1);
|
|
189738
|
+
const own2 = segments.map((segment) => readable(segment, stack));
|
|
189739
|
+
const last = own2[own2.length - 1] ?? construct;
|
|
189740
|
+
if (wrapper === null) return { frames, label: last, maker: null };
|
|
189741
|
+
const rest = own2.slice(wrapper + 1).filter((segment) => segment !== "Default");
|
|
189742
|
+
const maker = own2[wrapper] ?? "";
|
|
189743
|
+
return { frames, label: rest.length >= 2 ? [rest[0], rest[rest.length - 1]].join("_") : [maker, ...rest].join("_"), maker };
|
|
189744
|
+
}
|
|
189745
|
+
addFrame(frames, path, kind) {
|
|
189746
|
+
frames.push(path);
|
|
189747
|
+
if (!this.frames.has(path)) this.frames.set(path, kind);
|
|
189748
|
+
}
|
|
189749
|
+
};
|
|
189750
|
+
safe2 = (name2) => name2.replace(/[^A-Za-z0-9_-]+/g, "_") || "construct";
|
|
189751
|
+
}
|
|
189752
|
+
});
|
|
189753
|
+
|
|
189754
|
+
// ../../packages/diagrams/src/importers/cdk/index.ts
|
|
189755
|
+
function attributeOf2(attribute2, logical, names8) {
|
|
189756
|
+
const name2 = names8.get(logical) ?? logical;
|
|
189757
|
+
const refs = attribute2.refs.map((ref) => names8.get(ref) ?? ref).filter((ref) => ref !== name2);
|
|
189758
|
+
if (attribute2.name !== "name" || attribute2.value === null) return [{ ...attribute2, refs }];
|
|
189759
|
+
if (attribute2.value === logical) return [];
|
|
189760
|
+
if (!/^[A-Za-z][A-Za-z0-9-]*(?:\/[A-Za-z0-9.:_-]+)+$/.test(attribute2.value)) return [{ ...attribute2, refs }];
|
|
189761
|
+
const last = attribute2.value.slice(attribute2.value.lastIndexOf("/") + 1);
|
|
189762
|
+
return [{ ...attribute2, refs, value: last, readable: last }];
|
|
189763
|
+
}
|
|
189764
|
+
function chosenStacks(templates, context) {
|
|
189765
|
+
const wanted2 = context.options.root?.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
189766
|
+
if (wanted2 === void 0 || wanted2 === "") return templates;
|
|
189767
|
+
const tops = [...new Set(templates.map((template) => template.topPath))];
|
|
189768
|
+
const top = tops.find((path) => path === wanted2) ?? tops.find((path) => path.endsWith(`/${wanted2}`)) ?? templates.find((template) => template.file.path === wanted2 || template.file.path.endsWith(`/${wanted2}`))?.topPath;
|
|
189769
|
+
if (top === void 0) {
|
|
189770
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, START, `options.root names ${cleanText(wanted2)}, which is not a stack of the app; every stack is drawn.`, `The stacks sent are: ${tops.join(", ")}.`);
|
|
189771
|
+
return templates;
|
|
189772
|
+
}
|
|
189773
|
+
return templates.filter((template) => template.topPath === top);
|
|
189774
|
+
}
|
|
189775
|
+
function readCdk(joined2, context) {
|
|
189776
|
+
const index2 = new LineIndex(joined2);
|
|
189777
|
+
const files = context.files.map((file2, position) => ({ path: file2.path, start: file2.start, text: joined2.slice(file2.start, context.files[position + 1]?.start ?? joined2.length) }));
|
|
189778
|
+
const assembly = readAssembly(files);
|
|
189779
|
+
for (const problem of assembly.problems) {
|
|
189780
|
+
const lineStart = problem.file.text.split("\n").slice(0, problem.line - 1).join("\n").length + (problem.line > 1 ? 1 : 0);
|
|
189781
|
+
const span = index2.span(problem.file.start + lineStart + problem.column - 1);
|
|
189782
|
+
if (files.length === 1) {
|
|
189783
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, span, problem.message, problem.hint);
|
|
189784
|
+
return null;
|
|
189785
|
+
}
|
|
189786
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, span, `${cleanText(problem.file.path)} is not drawn: ${problem.message}`, problem.hint);
|
|
189787
|
+
}
|
|
189788
|
+
if (assembly.unknown.length > 0) {
|
|
189789
|
+
const first = assembly.unknown[0];
|
|
189790
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(first.start), `${countOf2(assembly.unknown.length, "file")} of the folder ${assembly.unknown.length === 1 ? "is" : "are"} not part of a cloud assembly and ${assembly.unknown.length === 1 ? "is" : "are"} not drawn: ${assembly.unknown.slice(0, LISTED9).map((file2) => cleanText(file2.path, "(no name)")).join(", ")}.`, "Send the cdk.out folder that cdk synth writes: manifest.json, tree.json, and the templates.");
|
|
189791
|
+
}
|
|
189792
|
+
for (const missing of assembly.missing.slice(0, 1)) {
|
|
189793
|
+
const names8 = assembly.missing.map((entry2) => entry2.stack);
|
|
189794
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(missing.start), `The manifest names ${countOf2(names8.length, "stack")} whose template was not sent, so ${names8.length === 1 ? "it is" : "they are"} not drawn: ${names8.slice(0, LISTED9).map((name2) => cleanText(name2)).join(", ")}.`, `Send ${cleanText(missing.file)} with the other files of cdk.out.`);
|
|
189795
|
+
}
|
|
189796
|
+
if (assembly.templates.length === 0) {
|
|
189797
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The files hold no CloudFormation template of a CDK app.", "Run cdk synth and send the cdk.out folder it writes, or the template it prints.");
|
|
189798
|
+
return null;
|
|
189799
|
+
}
|
|
189800
|
+
const templates = chosenStacks(assembly.templates, context);
|
|
189801
|
+
const tops = [...new Set(templates.map((template) => template.topPath))];
|
|
189802
|
+
const roots = /* @__PURE__ */ new Map();
|
|
189803
|
+
for (const template of templates) roots.set(template.stackPath, template.parent === null ? "Stack" : "Nested stack");
|
|
189804
|
+
const reads = [];
|
|
189805
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
189806
|
+
const allPaths = [];
|
|
189807
|
+
const nestedTemplates = /* @__PURE__ */ new Map();
|
|
189808
|
+
for (const template of templates) if (template.parent !== null) nestedTemplates.set(`${template.parent.template.file.path}\0${template.parent.logical}`, template);
|
|
189809
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
189810
|
+
const unsent = [];
|
|
189811
|
+
for (const template of templates) {
|
|
189812
|
+
const paths = cdkPaths(template.root);
|
|
189813
|
+
const names8 = /* @__PURE__ */ new Map();
|
|
189814
|
+
const frames = /* @__PURE__ */ new Set();
|
|
189815
|
+
const resources = get(template.root, "Resources");
|
|
189816
|
+
for (const entry2 of resources?.kind === "map" ? resources.entries : []) {
|
|
189817
|
+
const type = text(get(entry2.value, "Type"));
|
|
189818
|
+
if (type === METADATA_TYPE) continue;
|
|
189819
|
+
if (type === "AWS::CloudFormation::Stack" && nestedTemplates.has(`${template.file.path}\0${entry2.key}`)) {
|
|
189820
|
+
frames.add(entry2.key);
|
|
189821
|
+
continue;
|
|
189822
|
+
}
|
|
189823
|
+
const path = paths.get(entry2.key) ?? template.manifestPaths.get(entry2.key) ?? `${template.stackPath}/${withoutHash(entry2.key)}`;
|
|
189824
|
+
const asset = type === "AWS::CloudFormation::Stack" ? text(get(get(entry2.value, "Metadata"), "aws:asset:path")) : null;
|
|
189825
|
+
if (asset !== null && /\.nested\.template\.json$/i.test(asset)) unsent.push({ path: nestedStackPath(path), file: asset, start: template.file.start + Math.max(0, template.file.text.indexOf(asset)) });
|
|
189826
|
+
let name2 = constructOf(path);
|
|
189827
|
+
if (usedNames.has(name2)) name2 = path;
|
|
189828
|
+
for (let count3 = 2; usedNames.has(name2); count3 += 1) name2 = `${path}_${count3}`;
|
|
189829
|
+
usedNames.add(name2);
|
|
189830
|
+
names8.set(entry2.key, name2);
|
|
189831
|
+
allPaths.push(path);
|
|
189832
|
+
}
|
|
189833
|
+
const read = { template, model: new Template(template.root, null), names: names8, frames };
|
|
189834
|
+
reads.push(read);
|
|
189835
|
+
byFile.set(template, read);
|
|
189836
|
+
}
|
|
189837
|
+
const firstUnsent = unsent[0];
|
|
189838
|
+
if (firstUnsent !== void 0) {
|
|
189839
|
+
context.report.add(DIAGNOSTIC_CODES.importUnresolved, index2.span(firstUnsent.start), `${countOf2(unsent.length, "nested stack")} ${unsent.length === 1 ? "is" : "are"} drawn as one box, because ${unsent.length === 1 ? "its template was" : "their templates were"} not sent: ${unsent.slice(0, LISTED9).map((entry2) => cleanText(entry2.path)).join(", ")}.`, `Send ${cleanText(firstUnsent.file)} with the other files of cdk.out to draw what it makes.`);
|
|
189840
|
+
}
|
|
189841
|
+
const exports = /* @__PURE__ */ new Map();
|
|
189842
|
+
for (const read of reads) {
|
|
189843
|
+
const outputs = get(read.template.root, "Outputs");
|
|
189844
|
+
for (const entry2 of outputs?.kind === "map" ? outputs.entries : []) {
|
|
189845
|
+
const name2 = textOf5(read.model.evaluate(get(get(entry2.value, "Export"), "Name")));
|
|
189846
|
+
const value = get(entry2.value, "Value");
|
|
189847
|
+
if (name2 !== null && value !== void 0) exports.set(name2, { read, value });
|
|
189848
|
+
}
|
|
189849
|
+
}
|
|
189850
|
+
let hops = 0;
|
|
189851
|
+
const refsOf = (read, node3) => {
|
|
189852
|
+
if (node3 === void 0 || hops >= MAX_HOPS) return [];
|
|
189853
|
+
hops += 1;
|
|
189854
|
+
try {
|
|
189855
|
+
return read.model.refs(node3).map((ref) => read.names.get(ref) ?? ref);
|
|
189856
|
+
} finally {
|
|
189857
|
+
hops -= 1;
|
|
189858
|
+
}
|
|
189859
|
+
};
|
|
189860
|
+
for (const read of reads) {
|
|
189861
|
+
const parent = read.template.parent === null ? void 0 : byFile.get(read.template.parent.template);
|
|
189862
|
+
const declaration = parent === void 0 || read.template.parent === null ? void 0 : get(get(parent.template.root, "Resources"), read.template.parent.logical);
|
|
189863
|
+
const model = new Template(read.template.root, {
|
|
189864
|
+
parameter: (name2) => {
|
|
189865
|
+
const passed = get(get(declaration, "Properties"), "Parameters");
|
|
189866
|
+
const value = get(passed, name2);
|
|
189867
|
+
return parent === void 0 || value === void 0 ? null : refsOf(parent, value);
|
|
189868
|
+
},
|
|
189869
|
+
attribute: (resource, attribute2) => {
|
|
189870
|
+
if (!read.frames.has(resource) || !attribute2.startsWith("Outputs.")) return null;
|
|
189871
|
+
const nested2 = nestedTemplates.get(`${read.template.file.path}\0${resource}`);
|
|
189872
|
+
const inner = nested2 === void 0 ? void 0 : byFile.get(nested2);
|
|
189873
|
+
return inner === void 0 ? [] : refsOf(inner, get(get(get(inner.template.root, "Outputs"), attribute2.slice("Outputs.".length)), "Value"));
|
|
189874
|
+
},
|
|
189875
|
+
imported: (name2) => {
|
|
189876
|
+
const exported = exports.get(name2);
|
|
189877
|
+
return exported === void 0 ? null : refsOf(exported.read, exported.value);
|
|
189878
|
+
}
|
|
189879
|
+
});
|
|
189880
|
+
read.model = model;
|
|
189881
|
+
}
|
|
189882
|
+
const tree = new ConstructTree(allPaths, roots);
|
|
189883
|
+
const framed = tops.length > 1;
|
|
189884
|
+
const items2 = [];
|
|
189885
|
+
const empty = [];
|
|
189886
|
+
const placements = /* @__PURE__ */ new Map();
|
|
189887
|
+
const makers = /* @__PURE__ */ new Map();
|
|
189888
|
+
for (const read of reads) {
|
|
189889
|
+
const offsetOf = (logical) => {
|
|
189890
|
+
const at3 = read.template.file.text.search(new RegExp(`^\\s*"?${logical.replace(/[^A-Za-z0-9]/g, "")}"?\\s*:`, "m"));
|
|
189891
|
+
return read.template.file.start + Math.max(0, at3);
|
|
189892
|
+
};
|
|
189893
|
+
const listed2 = templateItems(read.model, offsetOf);
|
|
189894
|
+
empty.push(...listed2.empty.map((logical) => read.names.get(logical) ?? logical));
|
|
189895
|
+
for (const item of listed2.items) {
|
|
189896
|
+
const name2 = read.names.get(item.name);
|
|
189897
|
+
if (name2 === void 0) continue;
|
|
189898
|
+
const path = cdkPaths(read.template.root).get(item.name) ?? read.template.manifestPaths.get(item.name) ?? name2;
|
|
189899
|
+
const place2 = tree.place(path, framed);
|
|
189900
|
+
placements.set(name2, place2.frames);
|
|
189901
|
+
makers.set(name2, place2.maker);
|
|
189902
|
+
items2.push({ ...item, name: name2, label: place2.label, attributes: item.attributes.flatMap((attribute2) => attributeOf2(attribute2, item.name, read.names)) });
|
|
189903
|
+
}
|
|
189904
|
+
}
|
|
189905
|
+
if (empty.length > 0) {
|
|
189906
|
+
context.report.add(DIAGNOSTIC_CODES.importSkipped, START, `${countOf2(empty.length, "resource")} ${empty.length === 1 ? "has a Condition" : "have Conditions"} that the parameters' defaults make false, so ${empty.length === 1 ? "it is" : "they are"} not drawn: ${empty.slice(0, LISTED9).join(", ")}.`, "Give the parameter its value as a default, or synthesize with that value, to draw it.");
|
|
189907
|
+
}
|
|
189908
|
+
if (items2.length === 0) {
|
|
189909
|
+
context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The templates declare no resource that is drawn.", "Send the cdk.out of an app whose stacks make something.");
|
|
189910
|
+
return null;
|
|
189911
|
+
}
|
|
189912
|
+
const labelCount = /* @__PURE__ */ new Map();
|
|
189913
|
+
for (const item of items2) labelCount.set(item.label, (labelCount.get(item.label) ?? 0) + 1);
|
|
189914
|
+
for (const [position, item] of items2.entries()) {
|
|
189915
|
+
const maker = makers.get(item.name) ?? null;
|
|
189916
|
+
if ((labelCount.get(item.label) ?? 0) > 1 && maker !== null && !item.label.startsWith(`${maker}_`)) items2[position] = { ...item, label: `${maker}_${item.label}` };
|
|
189917
|
+
}
|
|
189918
|
+
const startOf3 = (path) => {
|
|
189919
|
+
const owner = reads.find((read) => read.template.stackPath === path) ?? reads.find((read) => read.template.topPath === path.split("/")[0]);
|
|
189920
|
+
const at3 = owner === void 0 ? -1 : owner.template.file.text.indexOf(`"${path}/`);
|
|
189921
|
+
return owner === void 0 ? 0 : owner.template.file.start + Math.max(0, at3);
|
|
189922
|
+
};
|
|
189923
|
+
const { modules, scopes } = frameModules2(tree, assembly.classes, startOf3);
|
|
189924
|
+
const scoped = items2.map((item) => {
|
|
189925
|
+
const frames = placements.get(item.name) ?? [];
|
|
189926
|
+
const innermost = frames[frames.length - 1];
|
|
189927
|
+
return innermost === void 0 ? item : { ...item, scope: scopes.get(innermost) ?? "" };
|
|
189928
|
+
});
|
|
189929
|
+
const stack = itemsToStack(scoped, modules);
|
|
189930
|
+
const byName = new Map(scoped.map((item) => [item.name, item]));
|
|
189931
|
+
const stableName = (key) => {
|
|
189932
|
+
const named = stack.stableName(key);
|
|
189933
|
+
return named.startsWith("module:") ? named.slice("module:".length) : named;
|
|
189934
|
+
};
|
|
189935
|
+
const only = tops.length === 1 ? tops[0] : void 0;
|
|
189936
|
+
return drawStack({
|
|
189937
|
+
resources: stack.resources,
|
|
189938
|
+
modules: stack.modules,
|
|
189939
|
+
providers: /* @__PURE__ */ new Map([["aws", null]]),
|
|
189940
|
+
cloud: "aws",
|
|
189941
|
+
variableName: (name2) => name2,
|
|
189942
|
+
variableValue: () => null,
|
|
189943
|
+
context: context.title === null && only !== void 0 ? { ...context, title: `${cleanText(only)} on AWS` } : context,
|
|
189944
|
+
span: (key) => {
|
|
189945
|
+
const item = byName.get(stack.stableName(key));
|
|
189946
|
+
return item === void 0 ? { line: 1, column: 1, length: 1 } : index2.span(item.start);
|
|
189947
|
+
},
|
|
189948
|
+
tool: "the AWS CDK",
|
|
189949
|
+
stableName,
|
|
189950
|
+
framing: "construct"
|
|
189951
|
+
});
|
|
189952
|
+
}
|
|
189953
|
+
var LISTED9, MAX_HOPS, METADATA_TYPE, withoutHash, cdkImporter;
|
|
189954
|
+
var init_cdk = __esm({
|
|
189955
|
+
"../../packages/diagrams/src/importers/cdk/index.ts"() {
|
|
189956
|
+
"use strict";
|
|
189957
|
+
init_core();
|
|
189958
|
+
init_template();
|
|
189959
|
+
init_items2();
|
|
189960
|
+
init_value();
|
|
189961
|
+
init_shared2();
|
|
189962
|
+
init_yaml();
|
|
189963
|
+
init_terraform();
|
|
189964
|
+
init_assembly();
|
|
189965
|
+
init_constructs();
|
|
189966
|
+
LISTED9 = 3;
|
|
189967
|
+
MAX_HOPS = 8;
|
|
189968
|
+
METADATA_TYPE = "AWS::CDK::Metadata";
|
|
189969
|
+
withoutHash = (logical) => logical.replace(/[0-9A-F]{8}$/, "") || logical;
|
|
189970
|
+
cdkImporter = { format: "cdk", kinds: ["flow"], joins: "\n", extensions: [".json", ".yaml", ".yml", ".out"], read: readCdk };
|
|
189971
|
+
}
|
|
189972
|
+
});
|
|
189973
|
+
|
|
188636
189974
|
// ../../packages/diagrams/src/importers/compose/interpolate.ts
|
|
188637
189975
|
function interpolate(value, depth = 0) {
|
|
188638
189976
|
if (!value.includes("$")) return value;
|
|
@@ -188763,7 +190101,7 @@ function readServices(root) {
|
|
|
188763
190101
|
function declared(root, key) {
|
|
188764
190102
|
return names6(get(root, key));
|
|
188765
190103
|
}
|
|
188766
|
-
function
|
|
190104
|
+
function namesHost2(value, host) {
|
|
188767
190105
|
if (host === "") return false;
|
|
188768
190106
|
for (let index2 = value.indexOf(host); index2 !== -1; index2 = value.indexOf(host, index2 + 1)) {
|
|
188769
190107
|
const before = index2 === 0 ? "" : value.charAt(index2 - 1);
|
|
@@ -188788,7 +190126,7 @@ function subOf(service) {
|
|
|
188788
190126
|
const parts = [runs, ports, replicas].filter((part) => part !== null);
|
|
188789
190127
|
return parts.length === 0 ? null : parts.join(", ");
|
|
188790
190128
|
}
|
|
188791
|
-
function
|
|
190129
|
+
function nodeOf3(service, group2) {
|
|
188792
190130
|
const look = (service.image === null ? null : imageLook(service.image)) ?? imageLook(service.name);
|
|
188793
190131
|
const type = look?.type ?? "service";
|
|
188794
190132
|
return { key: `service:${service.name}`, type, label: service.name, sub: subOf(service), icon: look?.icon ?? iconForName(service.name, type), group: group2, idHint: service.name };
|
|
@@ -188813,14 +190151,14 @@ function groupsOf(services, networks) {
|
|
|
188813
190151
|
const used = networks.filter((network) => [...home.values()].includes(`network:${network}`));
|
|
188814
190152
|
return { groups: used.map((network) => ({ key: `network:${network}`, label: network, type: "network", idHint: `${network}_net` })), home };
|
|
188815
190153
|
}
|
|
188816
|
-
function
|
|
190154
|
+
function edgesOf2(services, volumes) {
|
|
188817
190155
|
const known3 = new Set(services.map((service) => service.name));
|
|
188818
190156
|
const edges = [];
|
|
188819
190157
|
for (const service of services) {
|
|
188820
190158
|
if (service.sharesNetworkOf !== null && known3.has(service.sharesNetworkOf)) edges.push({ from: `service:${service.name}`, to: `service:${service.sharesNetworkOf}`, label: "shares network" });
|
|
188821
190159
|
for (const target of service.dependsOn) if (known3.has(target)) edges.push({ from: `service:${service.name}`, to: `service:${target}` });
|
|
188822
190160
|
for (const other of services) {
|
|
188823
|
-
if (other.name !== service.name && service.environment.some((value) =>
|
|
190161
|
+
if (other.name !== service.name && service.environment.some((value) => namesHost2(value, other.name))) edges.push({ from: `service:${service.name}`, to: `service:${other.name}` });
|
|
188824
190162
|
}
|
|
188825
190163
|
for (const volume of service.volumes) if (volumes.has(volume)) edges.push({ from: `service:${service.name}`, to: `volume:${volume}`, label: "mounts" });
|
|
188826
190164
|
}
|
|
@@ -188849,7 +190187,7 @@ function readCompose(source, context) {
|
|
|
188849
190187
|
const mounted = new Set(services.flatMap((service) => service.volumes));
|
|
188850
190188
|
const volumes = declared(root, "volumes").filter((volume) => mounted.has(volume));
|
|
188851
190189
|
const nodes = [
|
|
188852
|
-
...services.map((service) =>
|
|
190190
|
+
...services.map((service) => nodeOf3(service, home.get(service.name) ?? null)),
|
|
188853
190191
|
...volumes.map((volume) => ({ key: `volume:${volume}`, type: "storage", label: volume, sub: "Named volume", idHint: `${volume}_volume` }))
|
|
188854
190192
|
];
|
|
188855
190193
|
const name2 = text(get(root, "name"));
|
|
@@ -188862,7 +190200,7 @@ function readCompose(source, context) {
|
|
|
188862
190200
|
direction: "down",
|
|
188863
190201
|
nodes,
|
|
188864
190202
|
groups,
|
|
188865
|
-
edges:
|
|
190203
|
+
edges: edgesOf2(services, new Set(volumes)),
|
|
188866
190204
|
noun: "services",
|
|
188867
190205
|
capSpan: (key) => {
|
|
188868
190206
|
const service = services.find((candidate2) => `service:${candidate2.name}` === key);
|
|
@@ -190515,6 +191853,79 @@ var init_git_log = __esm({
|
|
|
190515
191853
|
}
|
|
190516
191854
|
});
|
|
190517
191855
|
|
|
191856
|
+
// ../../packages/diagrams/src/importers/helm/index.ts
|
|
191857
|
+
function chartOf(label) {
|
|
191858
|
+
const match = /^(.+?)-(v?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]*)?)$/.exec(label);
|
|
191859
|
+
return match === null ? { name: label, version: null } : { name: match[1] ?? label, version: match[2] ?? null };
|
|
191860
|
+
}
|
|
191861
|
+
function chartLabel(manifest) {
|
|
191862
|
+
const written3 = manifest.meta.get("helm.sh/chart") ?? manifest.meta.get("chart");
|
|
191863
|
+
if (written3 !== void 0 && written3 !== "") return chartOf(written3);
|
|
191864
|
+
const name2 = manifest.meta.get("app.kubernetes.io/name");
|
|
191865
|
+
return name2 === void 0 || name2 === "" ? null : { name: name2, version: null };
|
|
191866
|
+
}
|
|
191867
|
+
function helmFrames(manifests) {
|
|
191868
|
+
const charts = /* @__PURE__ */ new Map();
|
|
191869
|
+
for (const manifest of manifests) {
|
|
191870
|
+
const release = releaseOf(manifest);
|
|
191871
|
+
const chart = chartLabel(manifest);
|
|
191872
|
+
if (release !== null && chart !== null) charts.set(release, /* @__PURE__ */ new Set([...charts.get(release) ?? [], chart.name]));
|
|
191873
|
+
}
|
|
191874
|
+
return (manifest) => {
|
|
191875
|
+
const frames = [];
|
|
191876
|
+
const release = releaseOf(manifest);
|
|
191877
|
+
const chart = chartLabel(manifest);
|
|
191878
|
+
const partOf2 = manifest.meta.get("app.kubernetes.io/part-of");
|
|
191879
|
+
if (partOf2 !== void 0 && partOf2 !== "" && partOf2 !== release) frames.push({ key: `part-of:${partOf2}`, label: partOf2, sub: "Application", icon: "lucide:boxes", idHint: partOf2 });
|
|
191880
|
+
if (release === null) return frames;
|
|
191881
|
+
const several = (charts.get(release)?.size ?? 0) > 1;
|
|
191882
|
+
const only = several || chart === null ? null : chart;
|
|
191883
|
+
frames.push({ key: `release:${release}`, label: release, sub: cleanText(only === null ? "Release" : `Release of ${only.name}${only.version === null ? "" : ` ${only.version}`}`), icon: "simple:helm", idHint: release });
|
|
191884
|
+
if (several && chart !== null) frames.push({ key: `chart:${release}/${chart.name}`, label: chart.name, sub: cleanText(`Chart${chart.version === null ? "" : ` ${chart.version}`}`), icon: "lucide:package", idHint: chart.name });
|
|
191885
|
+
return frames;
|
|
191886
|
+
};
|
|
191887
|
+
}
|
|
191888
|
+
function readHelm(joined2, context) {
|
|
191889
|
+
const index2 = new LineIndex(joined2);
|
|
191890
|
+
const files = context.files.map((file2, position) => ({ path: file2.path, start: file2.start, text: joined2.slice(file2.start, context.files[position + 1]?.start ?? joined2.length) }));
|
|
191891
|
+
if (files.some((file2) => /(?:^|\/)Chart\.yaml$/.test(file2.path) || file2.path === "" && isChartFile(file2.text))) return drawCharts(files, context, index2);
|
|
191892
|
+
const read = parseYaml(joined2);
|
|
191893
|
+
if (read.error !== null) {
|
|
191894
|
+
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, `${read.error.hint} Send the output of helm template, which renders the chart's templates first.`);
|
|
191895
|
+
return null;
|
|
191896
|
+
}
|
|
191897
|
+
const documents = read.documents.map((document2) => document2.root).filter((root) => root !== null);
|
|
191898
|
+
const releases = /* @__PURE__ */ new Set();
|
|
191899
|
+
const labelled2 = [];
|
|
191900
|
+
for (const root of manifestRoots(documents)) {
|
|
191901
|
+
const manifest = readManifest(root);
|
|
191902
|
+
if (manifest === null) continue;
|
|
191903
|
+
labelled2.push(manifest);
|
|
191904
|
+
const release = releaseOf(manifest);
|
|
191905
|
+
if (release !== null) releases.add(release);
|
|
191906
|
+
}
|
|
191907
|
+
const [only] = releases;
|
|
191908
|
+
return drawManifests(documents, context, {
|
|
191909
|
+
framesOf: helmFrames(labelled2),
|
|
191910
|
+
title: releases.size === 1 && only !== void 0 ? `Helm release ${cleanText(only)}` : "Helm releases",
|
|
191911
|
+
source: "a Helm chart rendered with helm template"
|
|
191912
|
+
});
|
|
191913
|
+
}
|
|
191914
|
+
var releaseOf, helmImporter;
|
|
191915
|
+
var init_helm = __esm({
|
|
191916
|
+
"../../packages/diagrams/src/importers/helm/index.ts"() {
|
|
191917
|
+
"use strict";
|
|
191918
|
+
init_core();
|
|
191919
|
+
init_kubernetes();
|
|
191920
|
+
init_manifests();
|
|
191921
|
+
init_shared2();
|
|
191922
|
+
init_yaml();
|
|
191923
|
+
init_chart();
|
|
191924
|
+
releaseOf = (manifest) => manifest.meta.get("app.kubernetes.io/instance") ?? manifest.meta.get("release") ?? null;
|
|
191925
|
+
helmImporter = { format: "helm", kinds: ["flow"], joins: "\n---\n", extensions: [".yaml", ".yml", ".tpl", ".txt", ".lock"], read: readHelm };
|
|
191926
|
+
}
|
|
191927
|
+
});
|
|
191928
|
+
|
|
190518
191929
|
// ../../packages/diagrams/src/importers/github-actions/workflow.ts
|
|
190519
191930
|
function humanize2(id) {
|
|
190520
191931
|
const words2 = id.replace(/[_-]+/g, " ").trim();
|
|
@@ -190536,7 +191947,7 @@ function commandLabel(run3) {
|
|
|
190536
191947
|
const space = cut.lastIndexOf(" ");
|
|
190537
191948
|
return space > 12 ? cut.slice(0, space) : cut;
|
|
190538
191949
|
}
|
|
190539
|
-
function
|
|
191950
|
+
function readable2(name2) {
|
|
190540
191951
|
let out = "";
|
|
190541
191952
|
let at3 = 0;
|
|
190542
191953
|
for (let open2 = name2.indexOf("${{", at3); open2 !== -1; open2 = name2.indexOf("${{", at3)) {
|
|
@@ -190556,7 +191967,7 @@ function readStep2(step) {
|
|
|
190556
191967
|
const command = run3 === null ? null : commandLabel(run3).split(" ")[0] ?? "";
|
|
190557
191968
|
const icon = (action === null ? null : ACTION_ICONS[action] ?? (action.startsWith("docker/") ? "simple:docker" : null)) ?? (command === null ? null : COMMAND_ICONS[command] ?? null);
|
|
190558
191969
|
const label = name2 ?? (uses !== null ? actionLabel(uses) : run3 !== null ? commandLabel(run3) : "Step");
|
|
190559
|
-
return { label: cleanText(
|
|
191970
|
+
return { label: cleanText(readable2(label), "Step"), icon, line: step.line, column: step.column };
|
|
190560
191971
|
}
|
|
190561
191972
|
function jobDetail(job) {
|
|
190562
191973
|
const workflow = text(get(job, "uses"));
|
|
@@ -190572,7 +191983,7 @@ function jobDetail(job) {
|
|
|
190572
191983
|
function readJobs(root) {
|
|
190573
191984
|
return entries(get(root, "jobs")).map((entry2) => ({
|
|
190574
191985
|
id: entry2.key,
|
|
190575
|
-
label: cleanText(
|
|
191986
|
+
label: cleanText(readable2(text(get(entry2.value, "name")) ?? humanize2(entry2.key)), entry2.key),
|
|
190576
191987
|
needs: names5(get(entry2.value, "needs")),
|
|
190577
191988
|
detail: jobDetail(entry2.value),
|
|
190578
191989
|
steps: items(get(entry2.value, "steps")).filter((step) => step.kind === "map").map(readStep2),
|
|
@@ -190961,298 +192372,46 @@ var init_json = __esm({
|
|
|
190961
192372
|
}
|
|
190962
192373
|
});
|
|
190963
192374
|
|
|
190964
|
-
// ../../packages/diagrams/src/importers/
|
|
190965
|
-
function
|
|
190966
|
-
const
|
|
190967
|
-
|
|
190968
|
-
|
|
190969
|
-
|
|
190970
|
-
|
|
190971
|
-
if (
|
|
190972
|
-
|
|
190973
|
-
|
|
190974
|
-
|
|
190975
|
-
|
|
190976
|
-
|
|
190977
|
-
|
|
190978
|
-
|
|
190979
|
-
|
|
190980
|
-
|
|
190981
|
-
|
|
190982
|
-
|
|
190983
|
-
|
|
190984
|
-
|
|
190985
|
-
add2("ConfigMap", text(at2(variable, ["valueFrom", "configMapKeyRef", "name"])));
|
|
190986
|
-
add2("Secret", text(at2(variable, ["valueFrom", "secretKeyRef", "name"])));
|
|
190987
|
-
}
|
|
190988
|
-
}
|
|
190989
|
-
for (const volume of items(get(spec, "volumes"))) {
|
|
190990
|
-
add2("ConfigMap", text(at2(volume, ["configMap", "name"])));
|
|
190991
|
-
add2("Secret", text(at2(volume, ["secret", "secretName"])));
|
|
190992
|
-
add2("PersistentVolumeClaim", text(at2(volume, ["persistentVolumeClaim", "claimName"])));
|
|
190993
|
-
}
|
|
190994
|
-
return uses;
|
|
190995
|
-
}
|
|
190996
|
-
function ingressRoutes(spec) {
|
|
190997
|
-
const routes = [];
|
|
190998
|
-
const backend = (node3) => text(at2(node3, ["service", "name"])) ?? text(get(node3, "serviceName"));
|
|
190999
|
-
const add2 = (service, label) => {
|
|
191000
|
-
if (service !== null && !routes.some((route) => route.service === service)) routes.push({ service, label });
|
|
191001
|
-
};
|
|
191002
|
-
add2(backend(get(spec, "defaultBackend") ?? get(spec, "backend")), null);
|
|
191003
|
-
for (const rule of items(get(spec, "rules"))) {
|
|
191004
|
-
for (const path of items(at2(rule, ["http", "paths"]))) {
|
|
191005
|
-
const route = text(get(path, "path"));
|
|
191006
|
-
add2(backend(get(path, "backend")), route === null || route === "/" ? text(get(rule, "host")) : route);
|
|
191007
|
-
}
|
|
191008
|
-
}
|
|
191009
|
-
return routes;
|
|
191010
|
-
}
|
|
191011
|
-
function detailOf(kind, spec) {
|
|
191012
|
-
if (kind === "Service") {
|
|
191013
|
-
const ports = items(get(spec, "ports")).map((port) => text(get(port, "port"))).filter((port) => port !== null);
|
|
191014
|
-
return [text(get(spec, "type")) ?? "ClusterIP", ports.length === 0 ? "" : `port ${ports.slice(0, 3).join(", ")}`].filter((part) => part !== "").join(", ");
|
|
191015
|
-
}
|
|
191016
|
-
if (kind === "Ingress") return text(get(items(get(spec, "rules"))[0], "host")) ?? names5(get(items(get(spec, "tls"))[0], "hosts"))[0] ?? null;
|
|
191017
|
-
if (kind === "PersistentVolumeClaim") return text(at2(spec, ["resources", "requests", "storage"]));
|
|
191018
|
-
return null;
|
|
191019
|
-
}
|
|
191020
|
-
function readManifest(root) {
|
|
191021
|
-
const kind = text(get(root, "kind"));
|
|
191022
|
-
const name2 = text(at2(root, ["metadata", "name"]));
|
|
191023
|
-
if (kind === null || name2 === null) return null;
|
|
191024
|
-
const spec = get(root, "spec");
|
|
191025
|
-
const templatePath = WORKLOAD_TEMPLATES[kind];
|
|
191026
|
-
const template = templatePath === void 0 ? kind === "Pod" ? root : void 0 : at2(root, templatePath);
|
|
191027
|
-
const podSpec = get(template, "spec");
|
|
191028
|
-
const firstContainer = items(get(podSpec, "containers"))[0];
|
|
191029
|
-
return {
|
|
191030
|
-
kind,
|
|
191031
|
-
name: name2,
|
|
191032
|
-
namespace: text(at2(root, ["metadata", "namespace"])) ?? "default",
|
|
191033
|
-
line: root.line,
|
|
191034
|
-
column: root.column,
|
|
191035
|
-
labels: template !== void 0 ? stringMap(at2(template, ["metadata", "labels"])) : kind === "Service" ? stringMap(get(spec, "selector")) : /* @__PURE__ */ new Map(),
|
|
191036
|
-
image: text(get(firstContainer, "image")),
|
|
191037
|
-
replicas: text(get(spec, "replicas")),
|
|
191038
|
-
uses: podSpec === void 0 ? [] : podUses(podSpec),
|
|
191039
|
-
routes: kind === "Ingress" ? ingressRoutes(spec) : [],
|
|
191040
|
-
detail: detailOf(kind, spec),
|
|
191041
|
-
values: valuesOf(kind, root, podSpec)
|
|
191042
|
-
};
|
|
191043
|
-
}
|
|
191044
|
-
function manifestRoots(roots) {
|
|
191045
|
-
const out = [];
|
|
191046
|
-
for (const root of roots) {
|
|
191047
|
-
if (text(get(root, "kind")) === "List") out.push(...items(get(root, "items")));
|
|
191048
|
-
else out.push(root);
|
|
191049
|
-
}
|
|
191050
|
-
return out;
|
|
191051
|
-
}
|
|
191052
|
-
var WORKLOAD_TEMPLATES, DRAWN_KINDS, QUIET_KINDS, MAX_VALUE_LENGTH2, at2;
|
|
191053
|
-
var init_manifests = __esm({
|
|
191054
|
-
"../../packages/diagrams/src/importers/kubernetes/manifests.ts"() {
|
|
191055
|
-
"use strict";
|
|
191056
|
-
init_yaml();
|
|
191057
|
-
WORKLOAD_TEMPLATES = {
|
|
191058
|
-
Deployment: ["spec", "template"],
|
|
191059
|
-
StatefulSet: ["spec", "template"],
|
|
191060
|
-
DaemonSet: ["spec", "template"],
|
|
191061
|
-
ReplicaSet: ["spec", "template"],
|
|
191062
|
-
Job: ["spec", "template"],
|
|
191063
|
-
CronJob: ["spec", "jobTemplate", "spec", "template"]
|
|
191064
|
-
};
|
|
191065
|
-
DRAWN_KINDS = /* @__PURE__ */ new Set([...Object.keys(WORKLOAD_TEMPLATES), "Pod", "Service", "Ingress", "ConfigMap", "Secret", "PersistentVolumeClaim"]);
|
|
191066
|
-
QUIET_KINDS = /* @__PURE__ */ new Set([
|
|
191067
|
-
"Namespace",
|
|
191068
|
-
"ServiceAccount",
|
|
191069
|
-
"Role",
|
|
191070
|
-
"ClusterRole",
|
|
191071
|
-
"RoleBinding",
|
|
191072
|
-
"ClusterRoleBinding",
|
|
191073
|
-
"HorizontalPodAutoscaler",
|
|
191074
|
-
"PodDisruptionBudget",
|
|
191075
|
-
"NetworkPolicy",
|
|
191076
|
-
"LimitRange",
|
|
191077
|
-
"ResourceQuota",
|
|
191078
|
-
"PriorityClass",
|
|
191079
|
-
"ServiceMonitor",
|
|
191080
|
-
"PodMonitor",
|
|
191081
|
-
"VerticalPodAutoscaler",
|
|
191082
|
-
"Certificate",
|
|
191083
|
-
"IngressClass",
|
|
191084
|
-
"StorageClass"
|
|
191085
|
-
]);
|
|
191086
|
-
MAX_VALUE_LENGTH2 = 500;
|
|
191087
|
-
at2 = (node3, path) => path.reduce((current, key) => get(current, key), node3);
|
|
191088
|
-
}
|
|
191089
|
-
});
|
|
191090
|
-
|
|
191091
|
-
// ../../packages/diagrams/src/importers/kubernetes/index.ts
|
|
191092
|
-
function namespaceType(name2) {
|
|
191093
|
-
const phrase2 = name2.toLowerCase().replace(/[-_]+/g, " ").trim();
|
|
191094
|
-
const matches3 = GROUP_TYPES.filter((type) => GROUP_TYPE_SPECS[type].phrases.includes(phrase2));
|
|
191095
|
-
return matches3.length === 1 ? matches3[0] : null;
|
|
191096
|
-
}
|
|
191097
|
-
function nodeOf3(manifest, grouped, serviceDetail) {
|
|
191098
|
-
const look = LOOKS[manifest.kind] ?? { type: "service", icon: null, rank: 2 };
|
|
191099
|
-
const image = manifest.image === null ? null : imageLook(manifest.image);
|
|
191100
|
-
const replicas = manifest.replicas !== null && manifest.replicas !== "1" ? `, ${manifest.replicas} replicas` : "";
|
|
191101
|
-
const detail = (serviceDetail ?? manifest.detail) === null ? "" : `, ${serviceDetail ?? manifest.detail}`;
|
|
191102
|
-
return {
|
|
191103
|
-
key: keyOf3(manifest.kind, manifest.namespace, manifest.name),
|
|
191104
|
-
type: image?.type ?? look.type,
|
|
191105
|
-
label: manifest.name,
|
|
191106
|
-
sub: `${manifest.kind}${replicas}${detail}`,
|
|
191107
|
-
// A workload whose image this reader does not know may still be named after a product, such as kafka; lint's own rule finds it.
|
|
191108
|
-
icon: image?.icon ?? look.icon ?? iconForName(manifest.name, image?.type ?? look.type),
|
|
191109
|
-
group: grouped ? `ns:${manifest.namespace}` : null,
|
|
191110
|
-
idHint: manifest.name
|
|
191111
|
-
};
|
|
191112
|
-
}
|
|
191113
|
-
function namesHost2(value, host) {
|
|
191114
|
-
if (host === "") return false;
|
|
191115
|
-
for (let index2 = value.indexOf(host); index2 !== -1; index2 = value.indexOf(host, index2 + 1)) {
|
|
191116
|
-
const before = index2 === 0 ? "" : value.charAt(index2 - 1);
|
|
191117
|
-
const after = value.charAt(index2 + host.length);
|
|
191118
|
-
if (!/[A-Za-z0-9.-]/.test(before) && !/[A-Za-z0-9_-]/.test(after)) return true;
|
|
191119
|
-
}
|
|
191120
|
-
return false;
|
|
191121
|
-
}
|
|
191122
|
-
function foldedServices(drawn) {
|
|
191123
|
-
const folded = /* @__PURE__ */ new Map();
|
|
191124
|
-
for (const service of drawn) {
|
|
191125
|
-
if (service.kind !== "Service") continue;
|
|
191126
|
-
const workloads = selected(service, drawn);
|
|
191127
|
-
const only = workloads[0];
|
|
191128
|
-
if (workloads.length === 1 && only !== void 0) folded.set(keyOf3("Service", service.namespace, service.name), keyOf3(only.kind, only.namespace, only.name));
|
|
191129
|
-
}
|
|
191130
|
-
return folded;
|
|
191131
|
-
}
|
|
191132
|
-
function edgesOf2(drawn, folded, context) {
|
|
191133
|
-
const edges = [];
|
|
191134
|
-
const has = (kind, namespace, name2) => drawn.some((other) => other.kind === kind && other.namespace === namespace && other.name === name2);
|
|
191135
|
-
const unresolved = (manifest, what) => {
|
|
191136
|
-
context.report.add(DIAGNOSTIC_CODES.importUnresolved, spanAt3(manifest.line, manifest.column), `${manifest.kind} ${manifest.name} names the ${what}, which is not in the text.`, "Include its manifest, or leave it out if it is created elsewhere; the arrow was not drawn.");
|
|
191137
|
-
};
|
|
191138
|
-
for (const manifest of drawn) {
|
|
191139
|
-
const from = keyOf3(manifest.kind, manifest.namespace, manifest.name);
|
|
191140
|
-
for (const route of manifest.routes) {
|
|
191141
|
-
const service = keyOf3("Service", manifest.namespace, route.service);
|
|
191142
|
-
if (has("Service", manifest.namespace, route.service)) edges.push({ from, to: folded.get(service) ?? service, label: route.label });
|
|
191143
|
-
else unresolved(manifest, `Service ${route.service}`);
|
|
191144
|
-
}
|
|
191145
|
-
if (manifest.kind === "Service" && !folded.has(from)) {
|
|
191146
|
-
for (const workload of selected(manifest, drawn)) edges.push({ from, to: keyOf3(workload.kind, workload.namespace, workload.name) });
|
|
191147
|
-
}
|
|
191148
|
-
if (manifest.image !== null) {
|
|
191149
|
-
const read = drawn.filter((other) => other.kind === "ConfigMap" && other.namespace === manifest.namespace && manifest.uses.some((use) => use.kind === "ConfigMap" && use.name === other.name));
|
|
191150
|
-
const values = [...manifest.values, ...read.flatMap((config2) => config2.values)];
|
|
191151
|
-
for (const service of drawn) {
|
|
191152
|
-
const host = service.namespace === manifest.namespace ? service.name : `${service.name}.${service.namespace}`;
|
|
191153
|
-
if (service.kind !== "Service" || !values.some((value) => namesHost2(value, host))) continue;
|
|
191154
|
-
const key = keyOf3("Service", service.namespace, service.name);
|
|
191155
|
-
const to = folded.get(key) ?? key;
|
|
191156
|
-
if (to !== from) edges.push({ from, to });
|
|
191157
|
-
}
|
|
191158
|
-
}
|
|
191159
|
-
for (const use of manifest.uses) {
|
|
191160
|
-
if (has(use.kind, manifest.namespace, use.name)) edges.push({ from, to: keyOf3(use.kind, manifest.namespace, use.name), arrow: use.kind === "PersistentVolumeClaim" ? "->" : "-->", label: use.kind === "PersistentVolumeClaim" ? "mounts" : "reads" });
|
|
191161
|
-
else unresolved(manifest, `${use.kind} ${use.name}`);
|
|
191162
|
-
}
|
|
191163
|
-
}
|
|
191164
|
-
return edges;
|
|
191165
|
-
}
|
|
191166
|
-
function readKubernetes(textIn, context) {
|
|
191167
|
-
const read = parseYaml(textIn);
|
|
192375
|
+
// ../../packages/diagrams/src/importers/kustomize/index.ts
|
|
192376
|
+
function withoutHashes(documents) {
|
|
192377
|
+
const hashed = /* @__PURE__ */ new Map();
|
|
192378
|
+
for (const root of documents) {
|
|
192379
|
+
const manifest = readManifest(root);
|
|
192380
|
+
if (manifest !== null && (manifest.kind === "ConfigMap" || manifest.kind === "Secret") && GENERATED_HASH.test(manifest.name)) hashed.set(manifest.name, manifest.name.replace(GENERATED_HASH, ""));
|
|
192381
|
+
}
|
|
192382
|
+
if (hashed.size === 0) return [...documents];
|
|
192383
|
+
const strip = (node3, depth) => {
|
|
192384
|
+
if (depth > 64) return node3;
|
|
192385
|
+
if (node3.kind === "scalar") return hashed.has(node3.value) ? { ...node3, value: hashed.get(node3.value) ?? node3.value } : node3;
|
|
192386
|
+
if (node3.kind === "seq") return { ...node3, items: node3.items.map((item) => strip(item, depth + 1)) };
|
|
192387
|
+
return { ...node3, entries: node3.entries.map((entry2) => ({ ...entry2, value: strip(entry2.value, depth + 1) })) };
|
|
192388
|
+
};
|
|
192389
|
+
return documents.map((root) => strip(root, 0));
|
|
192390
|
+
}
|
|
192391
|
+
function readKustomize(joined2, context) {
|
|
192392
|
+
const index2 = new LineIndex(joined2);
|
|
192393
|
+
const files = context.files.map((file2, position) => ({ path: file2.path, start: file2.start, text: joined2.slice(file2.start, context.files[position + 1]?.start ?? joined2.length) }));
|
|
192394
|
+
if (files.some((file2) => KUSTOMIZATION_NAMES.has(file2.path.slice(file2.path.lastIndexOf("/") + 1)) || file2.path === "" && isKustomization(file2.text))) return drawFolder(files, context, index2);
|
|
192395
|
+
const read = parseYaml(joined2);
|
|
191168
192396
|
if (read.error !== null) {
|
|
191169
192397
|
context.report.add(DIAGNOSTIC_CODES.importUnreadable, spanAt3(read.error.line, read.error.column), read.error.message, read.error.hint);
|
|
191170
192398
|
return null;
|
|
191171
192399
|
}
|
|
191172
|
-
const
|
|
191173
|
-
|
|
191174
|
-
const unknown2 = [];
|
|
191175
|
-
for (const root of roots) {
|
|
191176
|
-
const manifest = readManifest(root);
|
|
191177
|
-
if (manifest === null || QUIET_KINDS.has(manifest.kind)) continue;
|
|
191178
|
-
if (DRAWN_KINDS.has(manifest.kind)) {
|
|
191179
|
-
if (!drawn.some((other) => other.kind === manifest.kind && other.namespace === manifest.namespace && other.name === manifest.name)) drawn.push(manifest);
|
|
191180
|
-
} else unknown2.push(manifest);
|
|
191181
|
-
}
|
|
191182
|
-
const firstUnknown = unknown2[0];
|
|
191183
|
-
if (firstUnknown !== void 0) {
|
|
191184
|
-
const kinds2 = [...new Set(unknown2.map((manifest) => manifest.kind))];
|
|
191185
|
-
context.report.add(
|
|
191186
|
-
DIAGNOSTIC_CODES.importSkipped,
|
|
191187
|
-
spanAt3(firstUnknown.line, firstUnknown.column),
|
|
191188
|
-
`${countOf2(unknown2.length, "object")} of a kind this reader does not draw ${unknown2.length === 1 ? "was" : "were"} left out: ${kinds2.slice(0, 6).join(", ")}.`,
|
|
191189
|
-
"The reader draws workloads, Services, Ingresses, ConfigMaps, Secrets, and PersistentVolumeClaims. Add the others by hand if they matter."
|
|
191190
|
-
);
|
|
191191
|
-
}
|
|
191192
|
-
if (drawn.length === 0) {
|
|
191193
|
-
context.report.add(DIAGNOSTIC_CODES.importNoShape, spanAt3(1, 1), "No workload, Service, Ingress, ConfigMap, Secret, or claim was found.", "Send manifests with apiVersion, kind, and metadata.name, separated by ---.");
|
|
191194
|
-
return null;
|
|
191195
|
-
}
|
|
191196
|
-
const ordered = [...drawn].sort((a, b) => (LOOKS[a.kind]?.rank ?? 2) - (LOOKS[b.kind]?.rank ?? 2));
|
|
191197
|
-
const namespaces = [...new Set(ordered.map((manifest) => manifest.namespace))];
|
|
191198
|
-
const grouped = namespaces.length > 1;
|
|
191199
|
-
const groups = grouped ? namespaces.map((namespace) => ({ key: `ns:${namespace}`, label: namespace, type: namespaceType(namespace), sub: "Namespace", idHint: `ns_${namespace}` })) : [];
|
|
191200
|
-
const only = namespaces[0] ?? "default";
|
|
191201
|
-
const folded = foldedServices(ordered);
|
|
191202
|
-
const servicePorts = /* @__PURE__ */ new Map();
|
|
191203
|
-
for (const manifest of ordered) {
|
|
191204
|
-
const workload = folded.get(keyOf3(manifest.kind, manifest.namespace, manifest.name));
|
|
191205
|
-
const ports = manifest.detail?.replace(/^ClusterIP(, )?/, "") ?? "";
|
|
191206
|
-
if (workload !== void 0 && ports !== "" && !servicePorts.has(workload)) servicePorts.set(workload, ports);
|
|
191207
|
-
}
|
|
191208
|
-
const boxes2 = ordered.filter((manifest) => !folded.has(keyOf3(manifest.kind, manifest.namespace, manifest.name)));
|
|
191209
|
-
const workloads = boxes2.filter((manifest) => manifest.image !== null).length;
|
|
191210
|
-
const others = boxes2.length - workloads;
|
|
191211
|
-
return writeFlow(
|
|
191212
|
-
{
|
|
191213
|
-
title: context.title ?? (grouped || only === "default" ? "Kubernetes workloads" : `Kubernetes namespace ${only}`),
|
|
191214
|
-
desc: `${countOf2(workloads, "workload")}${others > 0 ? ` and ${countOf2(others, "object")} around ${workloads === 1 ? "it" : "them"}` : ""}${grouped ? ` in ${countOf2(namespaces.length, "namespace")}` : ""}, imported from Kubernetes manifests. ${boxes2.some((manifest) => manifest.kind === "Ingress") ? "Traffic flows from each Ingress to the pods behind its Services" : "Solid arrows are calls to a Service"}, and dashed arrows are configuration the pods read.`,
|
|
191215
|
-
direction: "down",
|
|
191216
|
-
nodes: boxes2.map((manifest) => nodeOf3(manifest, grouped, servicePorts.get(keyOf3(manifest.kind, manifest.namespace, manifest.name)) ?? null)),
|
|
191217
|
-
groups,
|
|
191218
|
-
edges: edgesOf2(ordered, folded, context),
|
|
191219
|
-
noun: "objects",
|
|
191220
|
-
capSpan: (key) => {
|
|
191221
|
-
const manifest = ordered.find((candidate2) => keyOf3(candidate2.kind, candidate2.namespace, candidate2.name) === key);
|
|
191222
|
-
return spanAt3(manifest?.line ?? 1, manifest?.column ?? 1);
|
|
191223
|
-
},
|
|
191224
|
-
advice: "Check the arrows from each Service: they follow its selector, so a selector that matches no pod template draws none. Label the Ingress arrows with their paths if they carry none."
|
|
191225
|
-
},
|
|
191226
|
-
context.report
|
|
191227
|
-
);
|
|
192400
|
+
const documents = manifestRoots(read.documents.map((document2) => document2.root).filter((root) => root !== null));
|
|
192401
|
+
return drawManifests(withoutHashes(documents), context, { framesOf: () => [], title: "Kustomize build", source: "the output of kustomize build" });
|
|
191228
192402
|
}
|
|
191229
|
-
var
|
|
191230
|
-
var
|
|
191231
|
-
"../../packages/diagrams/src/importers/
|
|
192403
|
+
var GENERATED_HASH, kustomizeImporter;
|
|
192404
|
+
var init_kustomize = __esm({
|
|
192405
|
+
"../../packages/diagrams/src/importers/kustomize/index.ts"() {
|
|
191232
192406
|
"use strict";
|
|
191233
|
-
init_constants();
|
|
191234
192407
|
init_core();
|
|
192408
|
+
init_kubernetes();
|
|
192409
|
+
init_manifests();
|
|
191235
192410
|
init_shared2();
|
|
191236
192411
|
init_yaml();
|
|
191237
|
-
|
|
191238
|
-
|
|
191239
|
-
|
|
191240
|
-
Service: { type: "gateway", icon: "lucide:network", rank: 1 },
|
|
191241
|
-
Deployment: { type: "service", icon: null, rank: 2 },
|
|
191242
|
-
StatefulSet: { type: "service", icon: null, rank: 2 },
|
|
191243
|
-
DaemonSet: { type: "service", icon: null, rank: 2 },
|
|
191244
|
-
ReplicaSet: { type: "service", icon: null, rank: 2 },
|
|
191245
|
-
Pod: { type: "service", icon: null, rank: 2 },
|
|
191246
|
-
Job: { type: "function", icon: "lucide:play", rank: 3 },
|
|
191247
|
-
CronJob: { type: "function", icon: "lucide:calendar-clock", rank: 3 },
|
|
191248
|
-
PersistentVolumeClaim: { type: "storage", icon: "lucide:hard-drive", rank: 4 },
|
|
191249
|
-
ConfigMap: { type: "storage", icon: "lucide:settings-2", rank: 5 },
|
|
191250
|
-
Secret: { type: "secret", icon: "lucide:key-round", rank: 5 }
|
|
191251
|
-
};
|
|
191252
|
-
keyOf3 = (kind, namespace, name2) => `${namespace}/${kind}/${name2}`;
|
|
191253
|
-
selects = (selector, labels2) => selector.size > 0 && [...selector].every(([key, value]) => labels2.get(key) === value);
|
|
191254
|
-
selected = (service, drawn) => drawn.filter((workload) => workload.namespace === service.namespace && workload.kind !== "Service" && workload.image !== null && selects(service.labels, workload.labels));
|
|
191255
|
-
kubernetesImporter = { format: "kubernetes", kinds: ["flow"], joins: "\n---\n", extensions: [".yaml", ".yml"], read: readKubernetes };
|
|
192412
|
+
init_folder();
|
|
192413
|
+
GENERATED_HASH = /-(?=[^-]*\d)[b-df-hj-np-tv-z0-9]{10}$/;
|
|
192414
|
+
kustomizeImporter = { format: "kustomize", kinds: ["flow"], joins: "\n---\n", extensions: [".yaml", ".yml", ".json", ".env", ".properties", "Kustomization"], read: readKustomize };
|
|
191256
192415
|
}
|
|
191257
192416
|
});
|
|
191258
192417
|
|
|
@@ -192024,7 +193183,7 @@ var init_prisma = __esm({
|
|
|
192024
193183
|
});
|
|
192025
193184
|
|
|
192026
193185
|
// ../../packages/diagrams/src/importers/pulumi/item.ts
|
|
192027
|
-
function
|
|
193186
|
+
function valueAt2(properties, path) {
|
|
192028
193187
|
let current = properties;
|
|
192029
193188
|
for (const key of path) {
|
|
192030
193189
|
if (!isObject2(current)) return null;
|
|
@@ -192048,7 +193207,7 @@ function nameKeyOf2(token, keys) {
|
|
|
192048
193207
|
function itemOf(resource) {
|
|
192049
193208
|
const tokenType = pulumiToTerraform(resource.token);
|
|
192050
193209
|
if (tokenType === null) return null;
|
|
192051
|
-
const type = refineByKind(tokenType,
|
|
193210
|
+
const type = refineByKind(tokenType, valueAt2(resource.properties, ["kind"]));
|
|
192052
193211
|
const attributes2 = [];
|
|
192053
193212
|
const nameKey3 = nameProperty(resource.token, resource.properties);
|
|
192054
193213
|
if (nameKey3 !== null && isObject2(resource.properties)) {
|
|
@@ -192059,7 +193218,7 @@ function itemOf(resource) {
|
|
|
192059
193218
|
const role = roleOf2(type);
|
|
192060
193219
|
for (const [path, attribute2] of DETAILS2) {
|
|
192061
193220
|
if (!placed(attribute2)) continue;
|
|
192062
|
-
const value =
|
|
193221
|
+
const value = valueAt2(resource.properties, path);
|
|
192063
193222
|
if (value !== null) attributes2.push({ name: attribute2 === "sku" ? skuAttribute(role.role === "node" ? role.detail ?? [] : []) : attribute2, refs: [], value });
|
|
192064
193223
|
}
|
|
192065
193224
|
if (isObject2(resource.properties)) {
|
|
@@ -192072,7 +193231,7 @@ function itemOf(resource) {
|
|
|
192072
193231
|
if (resource.dependsOn.length > 0) attributes2.push({ name: "depends_on", refs: resource.dependsOn, value: null });
|
|
192073
193232
|
if (resource.parent !== null) attributes2.push({ name: "parent_id", refs: [resource.parent], value: null });
|
|
192074
193233
|
if (type === "azurerm_role_assignment") {
|
|
192075
|
-
const role2 = roleName(
|
|
193234
|
+
const role2 = roleName(valueAt2(resource.properties, ["roleDefinitionId"]) ?? JSON.stringify(resource.properties));
|
|
192076
193235
|
if (role2 !== null) attributes2.push({ name: "role_definition_name", refs: [], value: role2 });
|
|
192077
193236
|
}
|
|
192078
193237
|
const group2 = attributes2.find((attribute2) => attribute2.name === "resource_group_name");
|
|
@@ -192332,7 +193491,7 @@ function valueOf2(value, depth = 0) {
|
|
|
192332
193491
|
if (depth > 32) return null;
|
|
192333
193492
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null) return value;
|
|
192334
193493
|
if (Array.isArray(value)) return value.map((item) => valueOf2(item, depth + 1));
|
|
192335
|
-
if (
|
|
193494
|
+
if (isRecord5(value)) {
|
|
192336
193495
|
if (value["4dabf18193072939515e22adb298388d"] === "1b47061264138c4ac30d75fd1eb44270") return null;
|
|
192337
193496
|
const out = {};
|
|
192338
193497
|
for (const [key, entry2] of Object.entries(value)) out[key] = valueOf2(entry2, depth + 1);
|
|
@@ -192341,9 +193500,9 @@ function valueOf2(value, depth = 0) {
|
|
|
192341
193500
|
return null;
|
|
192342
193501
|
}
|
|
192343
193502
|
function resourceOf2(raw) {
|
|
192344
|
-
if (!
|
|
193503
|
+
if (!isRecord5(raw) || typeof raw["urn"] !== "string" || typeof raw["type"] !== "string") return null;
|
|
192345
193504
|
const dependencies = {};
|
|
192346
|
-
if (
|
|
193505
|
+
if (isRecord5(raw["propertyDependencies"])) for (const [key, value] of Object.entries(raw["propertyDependencies"])) dependencies[key] = strings(value);
|
|
192347
193506
|
return {
|
|
192348
193507
|
urn: raw["urn"],
|
|
192349
193508
|
type: raw["type"],
|
|
@@ -192375,8 +193534,8 @@ function pathTo(value, wanted2, path, depth = 0) {
|
|
|
192375
193534
|
return null;
|
|
192376
193535
|
}
|
|
192377
193536
|
function readState(json2) {
|
|
192378
|
-
if (!
|
|
192379
|
-
const deployment =
|
|
193537
|
+
if (!isRecord5(json2)) return null;
|
|
193538
|
+
const deployment = isRecord5(json2["deployment"]) ? json2["deployment"] : isRecord5(json2["checkpoint"]) && isRecord5(json2["checkpoint"]["latest"]) ? json2["checkpoint"]["latest"] : null;
|
|
192380
193539
|
if (deployment !== null && Array.isArray(deployment["resources"])) {
|
|
192381
193540
|
return { resources: deployment["resources"].map(resourceOf2).filter((resource) => resource !== null), deleted: 0, kind: "export" };
|
|
192382
193541
|
}
|
|
@@ -192384,7 +193543,7 @@ function readState(json2) {
|
|
|
192384
193543
|
const resources = [];
|
|
192385
193544
|
let deleted = 0;
|
|
192386
193545
|
for (const step of json2["steps"]) {
|
|
192387
|
-
if (!
|
|
193546
|
+
if (!isRecord5(step)) continue;
|
|
192388
193547
|
const op = typeof step["op"] === "string" ? step["op"] : "";
|
|
192389
193548
|
if (op === "delete" || op === "discard" || op === "delete-replaced" || op === "read-discard" || op === "remove-pending-replace") {
|
|
192390
193549
|
deleted += 1;
|
|
@@ -192403,18 +193562,18 @@ function stateResources(state, offsetOf) {
|
|
|
192403
193562
|
const counts = /* @__PURE__ */ new Map();
|
|
192404
193563
|
for (const resource of all) counts.set(logicalName(resource.urn), (counts.get(logicalName(resource.urn)) ?? 0) + 1);
|
|
192405
193564
|
const nameOf10 = (urn) => (counts.get(logicalName(urn)) ?? 0) > 1 ? urn : logicalName(urn);
|
|
192406
|
-
const
|
|
193565
|
+
const safe3 = (name2) => name2.replace(/[^A-Za-z0-9_-]+/g, "_");
|
|
192407
193566
|
const scopeOf2 = (resource) => {
|
|
192408
193567
|
const chain2 = [];
|
|
192409
193568
|
let parent = resource.parent === null ? void 0 : byUrn.get(resource.parent);
|
|
192410
193569
|
for (let depth = 0; parent !== void 0 && depth < 16; depth += 1) {
|
|
192411
|
-
if (!parent.custom) chain2.unshift(`module.${
|
|
193570
|
+
if (!parent.custom) chain2.unshift(`module.${safe3(logicalName(parent.urn))}.`);
|
|
192412
193571
|
parent = parent.parent === null ? void 0 : byUrn.get(parent.parent);
|
|
192413
193572
|
}
|
|
192414
193573
|
return chain2.join("");
|
|
192415
193574
|
};
|
|
192416
193575
|
const modules = all.filter((resource) => !resource.custom).map((resource) => {
|
|
192417
|
-
const scope = `${scopeOf2(resource)}module.${
|
|
193576
|
+
const scope = `${scopeOf2(resource)}module.${safe3(logicalName(resource.urn))}.`;
|
|
192418
193577
|
return { scope, name: scope.slice(0, -1), label: logicalName(resource.urn), instance: null, source: resource.type, start: offsetOf(resource.urn), noun: "Component" };
|
|
192419
193578
|
});
|
|
192420
193579
|
const resources = all.filter((resource) => resource.custom).map((resource) => {
|
|
@@ -192450,15 +193609,15 @@ function stateResources(state, offsetOf) {
|
|
|
192450
193609
|
return { resources, modules };
|
|
192451
193610
|
}
|
|
192452
193611
|
function mergeValues2(outputs, inputs) {
|
|
192453
|
-
if (!
|
|
192454
|
-
if (!
|
|
193612
|
+
if (!isRecord5(outputs)) return inputs;
|
|
193613
|
+
if (!isRecord5(inputs)) return outputs;
|
|
192455
193614
|
return { ...outputs, ...inputs };
|
|
192456
193615
|
}
|
|
192457
|
-
var
|
|
193616
|
+
var isRecord5, strings, logicalName, isPlumbing;
|
|
192458
193617
|
var init_state10 = __esm({
|
|
192459
193618
|
"../../packages/diagrams/src/importers/pulumi/state.ts"() {
|
|
192460
193619
|
"use strict";
|
|
192461
|
-
|
|
193620
|
+
isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
192462
193621
|
strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
192463
193622
|
logicalName = (urn) => urn.slice(urn.lastIndexOf("::") + 2);
|
|
192464
193623
|
isPlumbing = (resource) => resource.type === "pulumi:pulumi:Stack" || resource.type.startsWith("pulumi:providers:");
|
|
@@ -192524,7 +193683,7 @@ function readPulumi(joinedText, context) {
|
|
|
192524
193683
|
const chosenNames = context.options.varFiles ?? [];
|
|
192525
193684
|
const picked = chosenNames.length > 0 ? stacks.filter((stack) => chosenNames.some((name2) => stack.path === name2 || stack.path.endsWith(`/${name2.replace(/^\.?\//, "")}`))) : stacks.length === 1 ? stacks : [];
|
|
192526
193685
|
if (chosenNames.length === 0 && stacks.length === 1) context.report.add(DIAGNOSTIC_CODES.importChanged, index2.span(stacks[0]?.start ?? 0), `The values of ${cleanText(stacks[0]?.path ?? "")} are drawn: it is the only stack configuration sent.`, "Set options.varFiles to draw with another stack.");
|
|
192527
|
-
if (chosenNames.length === 0 && stacks.length > 1) context.report.add(DIAGNOSTIC_CODES.importSkipped, START, `${countOf2(stacks.length, "stack configuration")} are not applied, because each sets the same values: ${stacks.slice(0,
|
|
193686
|
+
if (chosenNames.length === 0 && stacks.length > 1) context.report.add(DIAGNOSTIC_CODES.importSkipped, START, `${countOf2(stacks.length, "stack configuration")} are not applied, because each sets the same values: ${stacks.slice(0, LISTED10).map((stack) => cleanText(stack.path)).join(", ")}.`, `Set options.varFiles to the stack to draw, such as ["${stacks[0]?.path ?? ""}"]; until then, values show their defaults or their names.`);
|
|
192528
193687
|
const config2 = /* @__PURE__ */ new Map();
|
|
192529
193688
|
for (const stack of picked) for (const [key, value] of configOf(stack.root)) config2.set(key, value);
|
|
192530
193689
|
const stackName = picked.length === 1 ? stackOf(picked[0]?.path ?? "") : null;
|
|
@@ -192544,7 +193703,7 @@ function readPulumi(joinedText, context) {
|
|
|
192544
193703
|
else chosen = [match];
|
|
192545
193704
|
}
|
|
192546
193705
|
if (chosen.length === 1) return drawSource(chosen[0], context, index2);
|
|
192547
|
-
context.report.add(DIAGNOSTIC_CODES.importChanged, START, `The files hold ${chosen.length} programs and states (${chosen.slice(0,
|
|
193706
|
+
context.report.add(DIAGNOSTIC_CODES.importChanged, START, `The files hold ${chosen.length} programs and states (${chosen.slice(0, LISTED10).map((source) => source.path).join(", ")}), so each is drawn as a diagram of its own.`, `Set options.root to draw one of them, such as "${chosen[0]?.path ?? ""}".`);
|
|
192548
193707
|
const drafts2 = [];
|
|
192549
193708
|
for (const source of chosen) {
|
|
192550
193709
|
const draft = drawSource(source, { ...context, title: `${context.title ?? "Cloud infrastructure"}: ${source.path}` }, index2);
|
|
@@ -192581,7 +193740,7 @@ function drawSource(source, context, index2) {
|
|
|
192581
193740
|
layered: true
|
|
192582
193741
|
});
|
|
192583
193742
|
}
|
|
192584
|
-
var
|
|
193743
|
+
var LISTED10, stackOf, pulumiImporter;
|
|
192585
193744
|
var init_pulumi = __esm({
|
|
192586
193745
|
"../../packages/diagrams/src/importers/pulumi/index.ts"() {
|
|
192587
193746
|
"use strict";
|
|
@@ -192594,7 +193753,7 @@ var init_pulumi = __esm({
|
|
|
192594
193753
|
init_item();
|
|
192595
193754
|
init_program();
|
|
192596
193755
|
init_state10();
|
|
192597
|
-
|
|
193756
|
+
LISTED10 = 5;
|
|
192598
193757
|
stackOf = (path) => /(?:^|[\\/])Pulumi\.([^.\\/]+)\.ya?ml$/i.exec(path)?.[1] ?? null;
|
|
192599
193758
|
pulumiImporter = { format: "pulumi", kinds: ["flow"], joins: "\n", extensions: [".yaml", ".yml", ".json"], read: readPulumi };
|
|
192600
193759
|
}
|
|
@@ -194003,15 +195162,19 @@ var init_registry4 = __esm({
|
|
|
194003
195162
|
"../../packages/diagrams/src/importers/registry.ts"() {
|
|
194004
195163
|
"use strict";
|
|
194005
195164
|
init_arm();
|
|
195165
|
+
init_backstage();
|
|
194006
195166
|
init_bicep();
|
|
195167
|
+
init_cdk();
|
|
194007
195168
|
init_cloudformation();
|
|
194008
195169
|
init_compose();
|
|
194009
195170
|
init_csv();
|
|
194010
195171
|
init_drizzle();
|
|
194011
195172
|
init_git_log();
|
|
195173
|
+
init_helm();
|
|
194012
195174
|
init_github_actions();
|
|
194013
195175
|
init_json();
|
|
194014
195176
|
init_kubernetes();
|
|
195177
|
+
init_kustomize();
|
|
194015
195178
|
init_openapi();
|
|
194016
195179
|
init_prisma();
|
|
194017
195180
|
init_pulumi();
|
|
@@ -194030,8 +195193,12 @@ var init_registry4 = __esm({
|
|
|
194030
195193
|
arm: armImporter,
|
|
194031
195194
|
pulumi: pulumiImporter,
|
|
194032
195195
|
cloudformation: cloudformationImporter,
|
|
195196
|
+
cdk: cdkImporter,
|
|
194033
195197
|
compose: composeImporter,
|
|
194034
195198
|
kubernetes: kubernetesImporter,
|
|
195199
|
+
helm: helmImporter,
|
|
195200
|
+
kustomize: kustomizeImporter,
|
|
195201
|
+
backstage: backstageImporter,
|
|
194035
195202
|
"github-actions": githubActionsImporter,
|
|
194036
195203
|
csv: csvImporter,
|
|
194037
195204
|
json: jsonImporter,
|
|
@@ -194402,10 +195569,10 @@ var init_definitions = __esm({
|
|
|
194402
195569
|
getDiagramSyntaxTool = defineTool({
|
|
194403
195570
|
name: "get_diagram_syntax",
|
|
194404
195571
|
title: "Get diagram syntax",
|
|
194405
|
-
description: "Read the diagram language as data. Call it once with no kind before your first diagram: the overview, the tables every kind shares (node types, arrows including dotted ..> for asynchronous calls, animated and numbered lines, icon sets, size limits, how to edit an existing SVG), and one line about each kind. For one kind in full, call it again with kind set to it: its statements, limits, and a tested example. kind flow adds the group types (type=), overlays, stack= marks, and a complete cloud architecture example; build the group tree top-down with type=, one node per service, and icons from map_icons or search_icons. For a common architecture, find_pattern gives a checked diagram to adapt.",
|
|
195572
|
+
description: "Read the diagram language as data. Call it once with no kind before your first diagram: the overview, the tables every kind shares (node types, arrows including dotted ..> for asynchronous calls, animated and numbered lines, icon sets, size limits, how to edit an existing SVG), and one line about each kind. For one kind in full, call it again with kind set to it: its statements, limits, and a tested example. kind flow adds the group types (type=), overlays, stack= marks, and a complete cloud architecture example; build the group tree top-down with type=, one node per service, and icons from map_icons or search_icons. For a common architecture, find_pattern gives a checked diagram to adapt. topic import-formats lists what import_source reads.",
|
|
194406
195573
|
input: SyntaxInputSchema,
|
|
194407
195574
|
output: SyntaxResponseSchema,
|
|
194408
|
-
execute: async (input2) => ok(buildSyntax(input2.kind))
|
|
195575
|
+
execute: async (input2) => ok(buildSyntax(input2.kind, input2.topic))
|
|
194409
195576
|
});
|
|
194410
195577
|
readDiagramTool = defineTool({
|
|
194411
195578
|
name: "read_diagram",
|
|
@@ -195503,7 +196670,7 @@ var init_import_source3 = __esm({
|
|
|
195503
196670
|
importSourceWorkflow = defineWorkflow({
|
|
195504
196671
|
name: "import_source",
|
|
195505
196672
|
title: "Import source",
|
|
195506
|
-
description: "Workflow. Turns a file into a finished diagram in one call:
|
|
196673
|
+
description: "Workflow. Turns a file into a finished diagram in one call: a database schema, an API spec, infrastructure as code, manifests, a software catalog, a CI workflow, CSV or JSON data, a folder listing, or a git log. get_diagram_syntax with topic import-formats says what each format reads, draws, and takes. Prefer it to drawing by hand whenever the person has such a file: send its text, never a path, or every file of a folder in files. Returns the source, diagnostics pointing into the file for anything left out, coverage, parts (every diagram of a split file), the validation, an outline, viewUrl, and saveCommand. It runs no code and reads no file or URL. Replaces validate_diagram and outline_diagram.",
|
|
195507
196674
|
input: ImportSourceInputSchema,
|
|
195508
196675
|
output: ImportSourceResponseSchema,
|
|
195509
196676
|
steps: [{ call: "importSource" }, { call: "validate", optional: true }, { call: "outline", optional: true }],
|
|
@@ -197733,7 +198900,7 @@ var init_view = __esm({
|
|
|
197733
198900
|
});
|
|
197734
198901
|
|
|
197735
198902
|
// ../../packages/diagrams/src/tools/view-link.ts
|
|
197736
|
-
function
|
|
198903
|
+
function isRecord6(value) {
|
|
197737
198904
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
197738
198905
|
}
|
|
197739
198906
|
function pictureFileName(source) {
|
|
@@ -197757,7 +198924,7 @@ function savingSentence(hasCommand, release = CLI_RELEASE) {
|
|
|
197757
198924
|
async function attachViewUrl(tool, args, value, base, release = CLI_RELEASE) {
|
|
197758
198925
|
if (tool === "sync_markdown") return rebaseFileLinks(value, base);
|
|
197759
198926
|
const pick3 = SOURCE_OF[tool];
|
|
197760
|
-
if (pick3 === void 0 || !
|
|
198927
|
+
if (pick3 === void 0 || !isRecord6(value) || !isRecord6(args)) return value;
|
|
197761
198928
|
const picked = pick3(args, value);
|
|
197762
198929
|
if (typeof picked !== "string" || picked.length === 0) return value;
|
|
197763
198930
|
const settings = SettingsSchema.safeParse(args["settings"]);
|
|
@@ -197780,20 +198947,20 @@ async function attachViewUrl(tool, args, value, base, release = CLI_RELEASE) {
|
|
|
197780
198947
|
return { ...value, next: `${next}There is no viewUrl: the link would be ${link2.length} characters, over the ${VIEW_LINKS.maxLength} a link may have. ${savingSentence(false, release)}` };
|
|
197781
198948
|
}
|
|
197782
198949
|
function rebaseFileLinks(value, base) {
|
|
197783
|
-
const files =
|
|
198950
|
+
const files = isRecord6(value) ? value["files"] : void 0;
|
|
197784
198951
|
const engine2 = viewBaseFor();
|
|
197785
|
-
if (!
|
|
197786
|
-
const moved3 = files.map((file2) =>
|
|
198952
|
+
if (!isRecord6(value) || !Array.isArray(files) || base === engine2) return value;
|
|
198953
|
+
const moved3 = files.map((file2) => isRecord6(file2) && typeof file2["viewUrl"] === "string" && file2["viewUrl"].startsWith(`${engine2}#`) ? { ...file2, viewUrl: `${base}${file2["viewUrl"].slice(engine2.length)}` } : file2);
|
|
197787
198954
|
return { ...value, files: moved3 };
|
|
197788
198955
|
}
|
|
197789
198956
|
function stripViewLinks(value) {
|
|
197790
|
-
if (!
|
|
198957
|
+
if (!isRecord6(value)) return value;
|
|
197791
198958
|
const kept2 = { ...value };
|
|
197792
198959
|
for (const field of VIEW_LINK_FIELDS) delete kept2[field];
|
|
197793
198960
|
const files = kept2["files"];
|
|
197794
198961
|
if (Array.isArray(files)) {
|
|
197795
198962
|
kept2["files"] = files.map((file2) => {
|
|
197796
|
-
if (!
|
|
198963
|
+
if (!isRecord6(file2) || !("viewUrl" in file2)) return file2;
|
|
197797
198964
|
const { viewUrl: _viewUrl, ...rest } = file2;
|
|
197798
198965
|
return rest;
|
|
197799
198966
|
});
|
|
@@ -198212,7 +199379,7 @@ var init_server_info = __esm({
|
|
|
198212
199379
|
`Draws ${joinWords(kindNouns(), "and")} diagrams from a small line-oriented text language.`,
|
|
198213
199380
|
"Prefer the workflow tools: each does the work of several single tools in one call.",
|
|
198214
199381
|
"When you are unsure which kind of diagram fits, call suggest_diagram with the request in plain words and any data: it ranks the kinds and gives a starter that parses; for a whole document, plan_document_diagrams returns the sections a picture would help, each with a starter.",
|
|
198215
|
-
"When the diagram should come from a file the person has (SQL, Prisma, or Drizzle models, an OpenAPI document, Terraform, Bicep, ARM, Pulumi, or
|
|
199382
|
+
"When the diagram should come from a file the person has (SQL, Prisma, or Drizzle models, an OpenAPI document, Terraform, Bicep, ARM, Pulumi, CloudFormation, or the CDK, docker-compose, Kubernetes manifests, Helm, Kustomize, a Backstage catalog, a GitHub Actions workflow, CSV or JSON data, a folder listing, or a git log), call import_source with its text and format: it builds the whole diagram from the file in one call, and its diagnostics say what was left out get_diagram_syntax with topic import-formats says what each format reads.",
|
|
198216
199383
|
"For a request to draw a common architecture, such as a three-tier network, a serverless API, a container platform, or a queue with workers, call find_pattern first with the request in plain words; when a pattern fits, call draw_from_pattern with its id, a provider flavour (neutral, aws, azure, or gcp), and slot values that rename its parts, or get_pattern to read and edit its source, and when nothing fits, write the diagram from scratch with draw_diagram.",
|
|
198217
199384
|
"Call get_diagram_syntax once with no kind to read the shared language, and again with kind set to the kind you draw for its statements, limits, and example.",
|
|
198218
199385
|
'Write the source and call draw_diagram: it returns every error with line, column, and hint and draws nothing until the source is valid, so fix every error and call again; once valid it returns the warnings, an outline to check the meaning, and the SVG for light and dark. The pictures are most of the answer and you cannot look at them, so pass svg "never" to check a diagram, and draw only when you will save, show, or publish the pictures; when a drawing is too big to read in one answer the SVG is left out, picturesOmitted says so, and svg "always" forces it.',
|