UNPKG

structurizr-parser

Version:
1,672 lines (1,651 loc) 57.9 kB
// src/Lexer.ts import { createToken, Lexer } from "chevrotain"; var BlockComment = createToken({ name: "blockComment", pattern: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//, group: Lexer.SKIPPED }); var LineComment = createToken({ name: "lineComment", pattern: /\/\/(.*?)\r?\n/, group: Lexer.SKIPPED }); var HashComment = createToken({ name: "hashComment", pattern: /\#(.*?)\r?\n/, group: Lexer.SKIPPED }); var Url = createToken({ name: "url", pattern: /(https?:\/\/[^ ]*)/i }); var FilePath = createToken({ name: "filePath", pattern: /\.\.?\/[^\n"?:*<>|]+\.[A-z0-9]+/i }); var StringLiteral = createToken({ name: "StringLiteral", pattern: /"(?:[^\\"]|\\(?:[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/ }); var Identifier = createToken({ name: "identifier", pattern: /[a-zA-z][a-zA-z.]*\_?[0-9]*/ }); var BangInclude = createToken({ name: "bangInclude", pattern: /!include/i }); var BangConstant = createToken({ name: "bangConstant", pattern: /!constant/i }); var BangDocs = createToken({ name: "bangDocs", pattern: /!docs/i }); var BangAdrs = createToken({ name: "bangAdrs", pattern: /!adrs/i }); var BangIndentifiers = createToken({ name: "bangIdentifiers", pattern: /!identifiers/i }); var BangImpliedRelationships = createToken({ name: "bangImpliedRelationships", pattern: /!impliedrelationships/i }); var Workspace = createToken({ name: "workspace", pattern: /workspace/i, longer_alt: Identifier }); var Extends = createToken({ name: "extends", pattern: /extends/i, longer_alt: Identifier }); var Model = createToken({ name: "model", pattern: /model/i, longer_alt: Identifier }); var Name = createToken({ name: "name", pattern: /name/i, longer_alt: Identifier }); var Enterprise = createToken({ name: "enterprise", pattern: /enterprise/i, longer_alt: Identifier }); var Group = createToken({ name: "group", pattern: /group/i, longer_alt: Identifier }); var Person = createToken({ name: "person", pattern: /person/i, longer_alt: Identifier }); var SoftwareSystem = createToken({ name: "softwareSystem", pattern: /softwaresystem/i, longer_alt: Identifier }); var Container = createToken({ name: "container", pattern: /container/i, longer_alt: Identifier }); var Component = createToken({ name: "component", pattern: /component/i, longer_alt: Identifier }); var DeploymentEnvironment = createToken({ name: "deploymentEnvironment", pattern: /deploymentenvironment/i }); var DeploymentGroup = createToken({ name: "deploymentGroup", pattern: /deploymentgroup/i }); var DeploymentNode = createToken({ name: "deploymentNode", pattern: /deploymentnode/i }); var InfrastructureNode = createToken({ name: "infrastructureNodel", pattern: /infrastructurenode/i }); var SoftwareSystemInstance = createToken({ name: "softwareSystemInstance", pattern: /softwaresysteminstance/i }); var ContainerInstance = createToken({ name: "containerInstance", pattern: /containerinstance/i }); var Element = createToken({ name: "element", pattern: /element/i, longer_alt: Identifier }); var Views = createToken({ name: "views", pattern: /views/i, longer_alt: Identifier }); var SystemLandscape = createToken({ name: "systemLandscape", pattern: /systemlandscape/i }); var SystemContext = createToken({ name: "systemContext", pattern: /systemcontext/i }); var Filtered = createToken({ name: "filtered", pattern: /filtered/i, longer_alt: Identifier }); var Dynamic = createToken({ name: "dynamic", pattern: /dynamic/i, longer_alt: Identifier }); var Deployment = createToken({ name: "deployment", pattern: /deployment/i, longer_alt: Identifier }); var Custom = createToken({ name: "custom", pattern: /custom/i, longer_alt: Identifier }); var Image = createToken({ name: "image", pattern: /image/i, longer_alt: Identifier }); var Title = createToken({ name: "title", pattern: /title/i, longer_alt: Identifier }); var Animation = createToken({ name: "animation", pattern: /animation/i, longer_alt: Identifier }); var Styles = createToken({ name: "styles", pattern: /styles/i, longer_alt: Identifier }); var Relationship = createToken({ name: "relationship", pattern: /relationship/i, longer_alt: Identifier }); var Themes = createToken({ name: "themes", pattern: /themes/i, longer_alt: Identifier }); var Theme = createToken({ name: "theme", pattern: /theme/i, longer_alt: Themes }); var Branding = createToken({ name: "branding", pattern: /branding/i, longer_alt: Identifier }); var Terminology = createToken({ name: "terminology", pattern: /terminology/i, longer_alt: Identifier }); var Configuration = createToken({ name: "configuration", pattern: /configuration/i, longer_alt: Identifier }); var Users = createToken({ name: "users", pattern: /users/i, longer_alt: Identifier }); var Include = createToken({ name: "include", pattern: /include/i, longer_alt: Identifier }); var AutoLayout = createToken({ name: "autoLayout", pattern: /autoLayout/i, longer_alt: Identifier }); var Description = createToken({ name: "description", pattern: /description/i, longer_alt: Identifier }); var Properties = createToken({ name: "properties", pattern: /properties/i, longer_alt: Identifier }); var Shape = createToken({ name: "shape", pattern: /shape/i, longer_alt: Identifier }); var Background = createToken({ name: "background", pattern: /background/i, longer_alt: Identifier }); var Color = createToken({ name: "color", pattern: /color/i, longer_alt: Identifier }); var Colour = createToken({ name: "colour", pattern: /colour/i, longer_alt: Identifier }); var ShapeEnum = createToken({ name: "shapeEnum", pattern: /Box|RoundedBox|Circle|Ellipse|Hexagon|Cylinder|Pipe|Person|Robot|Folder|WebBrowser|MobileDevicePortrait|MobileDeviceLandscape|Component/i, longer_alt: Identifier }); var FontSize = createToken({ name: "fontSize", pattern: /fontsize/i, longer_alt: Identifier }); var Opacity = createToken({ name: "opacity", pattern: /opacity/i, longer_alt: Identifier }); var Equals = createToken({ name: "equals", pattern: /=/ }); var RelatedTo = createToken({ name: "relatedTo", pattern: /->/ }); var Value = createToken({ name: "value", pattern: Lexer.NA }); var Bool = createToken({ name: "bool", pattern: /(true|false)/i, categories: Value, longer_alt: Identifier }); var HexColor = createToken({ name: "hexColor", pattern: /#[0-9A-Fa-f]{6}/, categories: Value }); var Word = createToken({ name: "word", pattern: /[a-zA-Z][a-zA-Z0-9_]*/, categories: Value, longer_alt: Identifier }); var Float = createToken({ name: "float", pattern: /-?[0-9]+\.[0-9]+/, categories: Value }); var Int = createToken({ name: "int", pattern: /-?(?:0|[1-9][0-9]*)/, categories: Value }); var Wildcard = createToken({ name: "wildcard", pattern: /(\*)/ }); var LBrace = createToken({ name: "lBrace", pattern: /\{/, label: "{" }); var RBrace = createToken({ name: "rBrace", pattern: /\}/, label: "}" }); var WhiteSpace = createToken({ name: "whiteSpace", pattern: /[\s\t\n\r]+/, group: Lexer.SKIPPED }); var allTokens = [ WhiteSpace, BlockComment, LineComment, Url, FilePath, HexColor, HashComment, StringLiteral, BangInclude, BangConstant, BangDocs, BangAdrs, BangIndentifiers, BangImpliedRelationships, Workspace, Extends, Name, Model, Enterprise, Group, Person, SoftwareSystemInstance, SoftwareSystem, ContainerInstance, Container, Component, DeploymentEnvironment, DeploymentGroup, DeploymentNode, InfrastructureNode, Element, Views, SystemLandscape, SystemContext, Filtered, Dynamic, Deployment, Custom, Image, Title, Animation, Styles, Relationship, Themes, Theme, Branding, Terminology, Configuration, Users, Include, AutoLayout, Description, Properties, Shape, Background, Color, Colour, ShapeEnum, FontSize, Opacity, Equals, RelatedTo, Bool, Identifier, Value, Word, Float, Int, Wildcard, LBrace, RBrace ]; var StructurizrLexer = new Lexer(allTokens); // src/Parser.ts import { CstParser } from "chevrotain"; var structurizrParser = class extends CstParser { constructor() { super(allTokens); this.performSelfAnalysis(); } // Rules go here workspaceWrapper = this.RULE("workspaceWrapper", () => { this.CONSUME(Workspace); this.OR([ { ALT: () => { this.CONSUME(Extends); this.CONSUME(FilePath); } }, { ALT: () => { this.OPTION1(() => { this.CONSUME1(StringLiteral); }); this.OPTION2(() => { this.CONSUME2(StringLiteral); }); } } ]); this.SUBRULE(this.workspaceSection); }); workspaceSection = this.RULE("workspaceSection", () => { this.CONSUME(LBrace); this.OPTION1(() => { this.CONSUME(Name); this.CONSUME1(StringLiteral); }); this.OPTION2(() => { this.CONSUME(Description); this.CONSUME2(StringLiteral); }); this.SUBRULE(this.modelSection); this.OPTION(() => { this.SUBRULE(this.viewsSection); }); this.CONSUME(RBrace); }); modelSection = this.RULE("modelSection", () => { this.CONSUME(Model); this.SUBRULE(this.modelChildSection); }); modelChildSection = this.RULE("modelChildSection", () => { this.CONSUME1(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.systemGroupSection); } }, { ALT: () => { this.SUBRULE(this.personSection); } }, { ALT: () => { this.SUBRULE(this.softwareSystemSection); } }, { ALT: () => { this.SUBRULE(this.explicitRelationship); } }, { ALT: () => { this.SUBRULE(this.deploymentEnvironmentSection); } } ]); }); this.CONSUME1(RBrace); }); systemGroupSection = this.RULE("systemGroupSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(Group); this.CONSUME(StringLiteral); this.SUBRULE(this.systemGroupChildSection); }); systemGroupChildSection = this.RULE("systemGroupChildSection", () => { this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.personSection); } }, { ALT: () => { this.SUBRULE(this.softwareSystemSection); } } ]); }); this.CONSUME(RBrace); }); personSection = this.RULE("personSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(Person); this.CONSUME(StringLiteral); this.OPTION1(() => { this.CONSUME1(StringLiteral); }); this.OPTION2(() => { this.CONSUME2(StringLiteral); }); }); softwareSystemSection = this.RULE("softwareSystemSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(SoftwareSystem); this.CONSUME(StringLiteral); this.MANY(() => { this.CONSUME1(StringLiteral); }); this.OPTION1(() => { this.SUBRULE(this.softwareSystemChildSection); }); }); softwareSystemChildSection = this.RULE("softwareSystemChildSection", () => { this.CONSUME1(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.containerSection); } }, { ALT: () => { this.SUBRULE(this.implicitRelationship); } } ]); ; }); this.CONSUME1(RBrace); }); containerSection = this.RULE("containerSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(Container); this.CONSUME(StringLiteral); this.MANY(() => { this.CONSUME1(StringLiteral); }); this.OPTION1(() => this.SUBRULE(this.containerChildSection)); }); containerChildSection = this.RULE("containerChildSection", () => { this.CONSUME1(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.componentSection); } }, { ALT: () => { this.SUBRULE(this.implicitRelationship); } } ]); }); this.CONSUME1(RBrace); }); componentSection = this.RULE("componentSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(Component); this.CONSUME(StringLiteral); this.MANY(() => { this.CONSUME1(StringLiteral); }); }); explicitRelationship = this.RULE("explicitRelationship", () => { this.CONSUME(Identifier); this.CONSUME(RelatedTo); this.CONSUME1(Identifier); this.MANY(() => { this.CONSUME(StringLiteral); }); }); implicitRelationship = this.RULE("implicitRelationship", () => { this.CONSUME(RelatedTo); this.CONSUME1(Identifier); this.MANY(() => { this.CONSUME(StringLiteral); }); }); deploymentEnvironmentSection = this.RULE("deploymentEnvironmentSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(DeploymentEnvironment); this.CONSUME(StringLiteral); this.SUBRULE(this.deploymentEnvironmentChildSection); }); deploymentEnvironmentChildSection = this.RULE("deploymentEnvironmentChildSection", () => { this.CONSUME(LBrace); this.MANY(() => this.OR([ { ALT: () => { this.SUBRULE(this.deploymentNodeSection); } }, { ALT: () => { this.SUBRULE(this.containerInstanceSection); } }, { ALT: () => { this.SUBRULE(this.explicitRelationship); } } ])); this.CONSUME(RBrace); }); deploymentNodeSection = this.RULE("deploymentNodeSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(DeploymentNode); this.CONSUME(StringLiteral); this.OPTION1(() => this.CONSUME1(StringLiteral)); this.OPTION2(() => this.CONSUME2(StringLiteral)); this.OPTION3(() => this.CONSUME3(StringLiteral)); this.OPTION4(() => this.CONSUME4(Int)); this.OPTION5(() => this.SUBRULE(this.deploymentNodeChildSection)); }); deploymentNodeChildSection = this.RULE("deploymentNodeChildSection", () => { this.CONSUME(LBrace); this.MANY(() => this.OR([ { ALT: () => { this.SUBRULE(this.deploymentNodeSection); } }, { ALT: () => { this.SUBRULE(this.containerInstanceSection); } }, { ALT: () => { this.SUBRULE(this.softwareSystemInstanceSection); } } ])); this.CONSUME(RBrace); }); containerInstanceSection = this.RULE("containerInstanceSection", () => { this.OPTION(() => { this.CONSUME(Identifier); this.CONSUME(Equals); }); this.CONSUME(ContainerInstance); this.CONSUME1(Identifier); this.MANY(() => { this.CONSUME(StringLiteral); }); }); softwareSystemInstanceSection = this.RULE("softwareSystemInstanceSection", () => { this.CONSUME(SoftwareSystemInstance); this.CONSUME(Identifier); this.MANY(() => { this.CONSUME(StringLiteral); }); }); viewsSection = this.RULE("viewsSection", () => { this.CONSUME(Views); this.SUBRULE(this.viewsChildSection); }); viewsChildSection = this.RULE("viewsChildSection", () => { this.CONSUME1(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.systemLandscapeView); } }, { ALT: () => { this.SUBRULE(this.systemContextView); } }, { ALT: () => { this.SUBRULE(this.containerView); } }, { ALT: () => { this.SUBRULE(this.componentView); } }, { ALT: () => { this.SUBRULE(this.imageSection); } }, { ALT: () => { this.SUBRULE(this.stylesSection); } }, { ALT: () => { this.SUBRULE(this.dynamicSection); } }, { ALT: () => { this.SUBRULE(this.deploymentSection); } } ]); }); this.CONSUME1(RBrace); }); systemLandscapeView = this.RULE("systemLandscapeView", () => { this.CONSUME(SystemLandscape); this.MANY(() => { this.CONSUME(StringLiteral); }); this.SUBRULE(this.viewOptions); }); viewOptions = this.RULE("viewOptions", () => { this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.includeOptions); } }, { ALT: () => { this.SUBRULE(this.autoLayoutOptions); } }, { ALT: () => { this.SUBRULE(this.animationOptions); } }, { ALT: () => { this.SUBRULE(this.descriptionOptions); } }, { ALT: () => { this.SUBRULE(this.propertiesOptions); } } ]); }); this.CONSUME(RBrace); }); includeOptions = this.RULE("includeOptions", () => { this.CONSUME(Include); this.OR([ { ALT: () => { this.CONSUME(Wildcard); } }, { ALT: () => { this.CONSUME(Identifier); } } ]); }); autoLayoutOptions = this.RULE("autoLayoutOptions", () => { this.CONSUME(AutoLayout); this.OPTION(() => { this.CONSUME(Identifier); }); this.OPTION1(() => { this.CONSUME(Int); }); this.OPTION2(() => { this.CONSUME1(Int); }); }); animationOptions = this.RULE("animationOptions", () => { this.CONSUME(Animation); this.CONSUME(LBrace); this.MANY(() => { this.CONSUME(Identifier); this.OPTION(() => this.CONSUME(Value)); }); this.CONSUME(RBrace); }); descriptionOptions = this.RULE("descriptionOptions", () => { this.CONSUME(Description); this.CONSUME(StringLiteral); }); propertiesOptions = this.RULE("propertiesOptions", () => { this.CONSUME(Properties); this.CONSUME(LBrace); this.MANY(() => { this.CONSUME(Identifier); this.CONSUME(Value); }); this.CONSUME(RBrace); }); systemContextView = this.RULE("systemContextView", () => { this.CONSUME(SystemContext); this.CONSUME(Identifier); this.MANY(() => { this.CONSUME2(StringLiteral); }); this.SUBRULE(this.viewOptions); }); containerView = this.RULE("containerView", () => { this.CONSUME(Container); this.CONSUME(Identifier); this.MANY(() => { this.CONSUME2(StringLiteral); }); this.SUBRULE(this.viewOptions); }); componentView = this.RULE("componentView", () => { this.CONSUME(Component); this.CONSUME(Identifier); this.MANY(() => { this.CONSUME2(StringLiteral); }); this.SUBRULE(this.viewOptions); }); imageSection = this.RULE("imageSection", () => { this.CONSUME(Image); this.OR([ { ALT: () => { this.CONSUME(Wildcard); } }, { ALT: () => { this.CONSUME(Identifier); } } ]); this.OPTION(() => this.CONSUME(StringLiteral)); this.CONSUME(LBrace); this.OR2([ { ALT: () => { this.CONSUME2(Image); this.CONSUME(Url); } } ]); this.OPTION2(() => { this.CONSUME(Title); this.CONSUME2(StringLiteral); }); this.CONSUME(RBrace); }); dynamicSection = this.RULE("dynamicSection", () => { this.CONSUME(Dynamic); this.CONSUME(Identifier); this.OPTION(() => this.CONSUME(StringLiteral)); this.OPTION1(() => this.CONSUME1(StringLiteral)); this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => this.SUBRULE(this.explicitRelationship) }, { ALT: () => this.SUBRULE(this.autoLayoutOptions) }, { ALT: () => { this.CONSUME(Description); this.CONSUME3(StringLiteral); } } ]); }); this.CONSUME(RBrace); }); deploymentSection = this.RULE("deploymentSection", () => { this.CONSUME(Deployment); this.CONSUME(Identifier); this.CONSUME(StringLiteral); this.OPTION(() => this.CONSUME1(StringLiteral)); this.OPTION1(() => this.CONSUME2(StringLiteral)); this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.includeOptions); } }, { ALT: () => { this.SUBRULE(this.animationOptions); } }, { ALT: () => { this.SUBRULE(this.autoLayoutOptions); } }, { ALT: () => { this.CONSUME(Description); this.CONSUME3(StringLiteral); } } ]); }); this.CONSUME(RBrace); }); stylesSection = this.RULE("stylesSection", () => { this.CONSUME(Styles); this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.elementStyleSection); } }, { ALT: () => { this.SUBRULE(this.relationshipStyleSection); } } ]); }); this.CONSUME(RBrace); }); elementStyleSection = this.RULE("elementStyleSection", () => { this.CONSUME(Element); this.CONSUME(StringLiteral); this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.shapeStyle); } }, { ALT: () => { this.SUBRULE(this.backgroundStyle); } }, { ALT: () => { this.SUBRULE(this.colorStyle); } }, { ALT: () => { this.SUBRULE(this.colourStyle); } }, { ALT: () => { this.SUBRULE(this.fontStyle); } }, { ALT: () => { this.SUBRULE(this.opacityStyle); } } ]); }); this.CONSUME(RBrace); }); relationshipStyleSection = this.RULE("relationshipStyleSection", () => { this.CONSUME(Relationship); this.CONSUME(Identifier); this.CONSUME(LBrace); this.MANY(() => { this.OR([ { ALT: () => { this.SUBRULE(this.backgroundStyle); } }, { ALT: () => { this.SUBRULE(this.colorStyle); } }, { ALT: () => { this.SUBRULE(this.colourStyle); } } ]); }); this.CONSUME(RBrace); }); shapeStyle = this.RULE("shapeStyle", () => { this.CONSUME(Shape); this.OR([ { ALT: () => { this.CONSUME(ShapeEnum); } }, { ALT: () => { this.CONSUME(Person); } } ]); ; }); backgroundStyle = this.RULE("backgroundStyle", () => { this.CONSUME(Background); this.CONSUME(HexColor); }); colorStyle = this.RULE("colorStyle", () => { this.CONSUME(Color); this.CONSUME(HexColor); }); colourStyle = this.RULE("colourStyle", () => { this.CONSUME(Colour); this.CONSUME(HexColor); }); fontStyle = this.RULE("fontStyle", () => { this.CONSUME(FontSize); this.CONSUME(Int); }); opacityStyle = this.RULE("opacityStyle", () => { this.CONSUME(Opacity); this.CONSUME(Int); }); }; var StructurizrParser = new structurizrParser(); var BaseStructurizrVisitor = StructurizrParser.getBaseCstVisitorConstructor(); // src/StructurizrInterpreter.ts import { RankDirection, Workspace as Workspace2 } from "structurizr-typescript"; var structurizrInterpreter = class extends BaseStructurizrVisitor { _debug = false; elementsByIdentifier = /* @__PURE__ */ new Map(); // identifier, id workspace = new Workspace2("", ""); // Dummy object, should be overwritten when new Cst provided constructor() { super(); this.validateVisitor(); } set Debug(flag) { this._debug = flag; } workspaceWrapper(node) { this._debug && console.log("Here we are at workspaceWrapper node:"); this.workspace = new Workspace2("Name", "Description"); if (node.workspaceSection) { this.visit(node.workspaceSection); } return this.workspace; } workspaceSection(node) { this._debug && console.log("`Here we are at workspaceSection node:"); if (node.name) { this.workspace.name = node.StringLiteral[0]?.image; } ; if (node.description) { this.workspace.description = node.StringLiteral[1]?.image; } ; if (node.modelSection) { this.visit(node.modelSection); } if (node.viewsSection) { this.visit(node.viewsSection); } } modelSection(node) { this._debug && console.log("Here we are at modelSection node:"); if (node.modelChildSection) { this.visit(node.modelChildSection); } } modelChildSection(node) { this._debug && console.log("Here we are at modelChildSection node:"); if (node.systemGroupSection) { for (const group of node.systemGroupSection) { this.visit(group); } } if (node.personSection) { for (const person of node.personSection) { this.visit(person); } } if (node.softwareSystemSection) { for (const sSystem of node.softwareSystemSection) { this.visit(sSystem); } } if (node.explicitRelationship) { for (const relationship of node.explicitRelationship) { this.visit(relationship); } } if (node.deploymentEnvironmentSection) { for (const depEnv of node.deploymentEnvironmentSection) { this.visit(depEnv); } } } systemGroupSection(node) { this._debug && console.log(`Here we are at systemGroupSection with node: ${node.name}`); } systemGroupChildSection(node) { this._debug && console.log(`Here we are at systemGroupChildSection with node: ${node.name}`); } personSection(node) { this._debug && console.log("Here we are at personSection node:"); const name = node.StringLiteral[0]?.image ?? ""; const desc = node.StringLiteral[1]?.image ?? ""; const p = this.workspace.model.addPerson(stripQuotes(name), stripQuotes(desc)); if (node.identifier && p) { this.elementsByIdentifier.set(stripQuotes(node.identifier[0].image), p.id); } } softwareSystemSection(node) { this._debug && console.log("Here we are at softwareSystemSection node:"); const name = node.StringLiteral[0]?.image ?? ""; const desc = node.StringLiteral[1]?.image ?? ""; const s = this.workspace.model.addSoftwareSystem(stripQuotes(name), stripQuotes(desc)); if (node.identifier && s) { this.elementsByIdentifier.set(stripQuotes(node.identifier[0].image), s.id); } } softwareSystemChildSection(node) { this._debug && console.log(`Here we are at softwareSystemChildSection with node: ${node.name}`); } containerSection(node) { this._debug && console.log(`Here we are at ContainerSection with node: ${node.name}`); } containerChildSection(node) { this._debug && console.log(`Here we are at ContainerChildSection with node: ${node.name}`); } componentSection(node) { this._debug && console.log(`Here we are at ComponentSection with node: ${node.name}`); } explicitRelationship(node) { this._debug && console.log("Here we are at explicitRelationship node:"); const s_id = this.elementsByIdentifier.get(node.identifier[0].image); const t_id = this.elementsByIdentifier.get(node.identifier[1].image); if (s_id && t_id) { const source = this.workspace.model.getElement(s_id); const target = this.workspace.model.getElement(t_id); const desc = node.StringLiteral[0]?.image ?? ""; const r = this.workspace.model.addRelationship(source, target, desc); } else { throw new Error("Unknown identifiers used in relationship definition"); } } implicitRelationship(node) { this._debug && console.log(`Here we are at implicitRelationship with node: ${node.name}`); } deploymentEnvironmentSection(node) { this._debug && console.log(`Here we are at deploymentEnvironmentSection with node: ${node.name}`); } deploymentEnvironmentChildSection(node) { this._debug && console.log(`Here we are at deploymentEnvironmentChildSection with node: ${node.name}`); } deploymentNodeSection(node) { this._debug && console.log(`Here we are at deploymentNodeSection with node: ${node.name}`); } deploymentNodeChildSection(node) { this._debug && console.log(`Here we are at deploymentNodeChildSection with node: ${node.name}`); } containerInstanceSection(node) { this._debug && console.log(`Here we are at containerInstanceSection with node: ${node.name}`); } softwareSystemInstanceSection(node) { this._debug && console.log(`Here we are at softwareSystemInstanceSection with node: ${node.name}`); } viewsSection(node) { this._debug && console.log("Here we are at viewsSection node:"); if (node.viewsChildSection) { this.visit(node.viewsChildSection); } } viewsChildSection(node) { this._debug && console.log("Here we are at viewsChildSection node:"); if (node.systemLandscapeView) { for (const view of node.systemLandscapeView) { this.visit(view); } } if (node.systemContextView) { for (const view of node.systemContextView) { this.visit(view); } } if (node.containerView) { for (const view of node.containerView) { this.visit(view); } } if (node.componentView) { for (const view of node.componentView) { this.visit(view); } } if (node.imageSection) { for (const image of node.imageSection) { this.visit(image); } } if (node.stylesSection) { for (const style of node.stylesSection) { this.visit(style); } } if (node.dynamicSection) { for (const dyn of node.dynamicSection) { this.visit(dyn); } } if (node.deploymentSection) { for (const deployment of node.deploymentSection) { this.visit(deployment); } } } systemLandscapeView(node) { this._debug && console.log(`Here we are at systemLandscapeView with node: ${node.name}`); } viewOptions(node, view) { this._debug && console.log("Here we are at viewOptions node:"); if (node.includeOptions) { for (const inc of node.includeOptions) { this.visit(inc, view); } } if (node.autoLayoutOptions) { this.visit(node.autoLayoutOptions, view); } if (node.animationOptions) { } if (node.descriptionOptions) { } if (node.propertiesOptions) { } } includeOptions(node, view) { this._debug && console.log("Here we are at includeOptions node:"); if (node.wildcard) { view.addAllElements(); } if (node.identifier) { const e_id = this.elementsByIdentifier.get(node.identifier[0].image) ?? ""; const ele = this.workspace.model.getElement(e_id); if (ele) { view.addElement(ele, true); } } } autoLayoutOptions(node, view) { this._debug && console.log("Here we are at autoLayoutOptions node:"); const rankDir = node.identifier?.[0].image; const rankSep = node.int?.[0].image; const nodeSep = node.int?.[1].image; let rankDirEnum = RankDirection.TopBottom; if (rankDir) { switch (rankDir) { case "tb": rankDirEnum = RankDirection.TopBottom; break; case "bt": rankDirEnum = RankDirection.BottomTop; break; case "lr": rankDirEnum = RankDirection.LeftRight; break; case "rl": rankDirEnum = RankDirection.RightLeft; break; } view.setAutomaticLayout(rankDirEnum, rankSep, nodeSep); } else { view.setAutomaticLayout(true); } } animationOptions(node) { this._debug && console.log(`Here we are at animationOptions with node: ${node.name}`); } descriptionOptions(node) { this._debug && console.log(`Here we are at descriptionOptions with node: ${node.name}`); } propertiesOptions(node) { this._debug && console.log(`Here we are at propertiesOptions with node: ${node.name}`); } systemContextView(node) { this._debug && console.log("Here we are at systemContextView node:"); const sws_id = this.elementsByIdentifier.get(node.identifier[0].image) ?? ""; const sws = this.workspace.model.getElement(sws_id); const key = node.StringLiteral[0]?.image ?? ""; const desc = node.StringLiteral[1]?.image ?? ""; const view = this.workspace.views.createSystemContextView(sws, stripQuotes(key), stripQuotes(desc)); if (node.viewOptions) { this.visit(node.viewOptions, view); } } containerView(node) { this._debug && console.log(`Here we are at containerView with node: ${node.name}`); } componentView(node) { this._debug && console.log(`Here we are at componentView with node: ${node.name}`); } imageSection(node) { this._debug && console.log(`Here we are at imageSection with node: ${node.name}`); } dynamicSection(node) { this._debug && console.log(`Here we are at dynamicSection with node: ${node.name}`); } deploymentSection(node) { this._debug && console.log(`Here we are at deploymentSection with node: ${node.name}`); } stylesSection(node) { this._debug && console.log(`Here we are at stylesSection with node: ${node.name}`); } elementStyleSection(node) { this._debug && console.log(`Here we are at elementStyleSection with node: ${node.name}`); } relationshipStyleSection(node) { this._debug && console.log(`Here we are at relationshipStyleSection with node: ${node.name}`); } shapeStyle(node) { this._debug && console.log(`Here we are at shapeStyle with node: ${node.name}`); } backgroundStyle(node) { this._debug && console.log(`Here we are at backgroundStyle with node: ${node.name}`); } colorStyle(node) { this._debug && console.log(`Here we are at colorStyle with node: ${node.name}`); } colourStyle(node) { this._debug && console.log(`Here we are at colourStyle with node: ${node.name}`); } fontStyle(node) { this._debug && console.log(`Here we are at fontStyle with node: ${node.name}`); } opacityStyle(node) { this._debug && console.log(`Here we are at opacityStyle with node: ${node.name}`); } }; function stripQuotes(str) { if (typeof str !== "string") { throw new TypeError("Expected a string"); } return str.replace(/^"(.+)"$/, "$1"); } var StructurizrInterpreter = new structurizrInterpreter(); // src/C4Interpreter.ts import { nanoid } from "nanoid"; // src/c4/c4relationship.ts var C4Relationship = class { targetId; description; technology; constructor(targetId, description, technology) { this.targetId = targetId; this.description = description ?? ""; this.technology = technology ?? ""; } get TargetId() { return this.targetId; } get Description() { return this.description; } get Technology() { return this.technology; } }; // src/c4/c4element.ts var C4Element = class { id; name; description; tags = []; relationships = []; constructor(id, name, description, tags) { this.id = id; this.name = name; this.description = description ?? ""; if (tags) { this.tags.push(...tags); } } get Id() { return this.id; } get Name() { return this.name; } get Description() { return this.description; } get Tags() { return this.tags; } get Relationships() { return this.relationships; } addRelationship(targetId, description, technology) { const rel = new C4Relationship(targetId, description, technology); this.relationships.push(rel); } }; // src/c4/c4component.ts var C4Component = class extends C4Element { constructor(id, name, description) { super(id, name, description); } findElement(e_id) { let reply = []; if (this.Id === e_id) { reply.push(this); return reply; } return reply; } }; // src/c4/c4view.ts var C4View = class { type; key; description; include = []; constructor(type, key, description) { this.type = type; this.key = key; this.description = description; } includeEntity(id) { this.include.push(id); } get Type() { return this.type; } get Key() { return this.key; } get Description() { return this.description; } get Include() { return this.include; } }; // src/c4/c4componentview.ts var C4ComponentView = class extends C4View { componentID; /** * */ constructor(componentId, key, description) { super("Component", key, description); this.componentID = componentId; } get ComponentId() { return this.componentID; } }; // src/c4/c4container.ts var C4Container = class extends C4Element { components = []; constructor(id, name, description) { super(id, name, description); } addComponent(component) { this.components.push(component); } findElement(e_id) { let reply = []; if (this.Id === e_id) { reply.push(this); return reply; } else { for (const con of this.components) { const ele = con.findElement(e_id); if (ele.length > 0) { reply.push(this); reply.push(...ele); return reply; } } } return reply; } get Components() { return this.components; } get NestedRelationships() { let rels = []; rels = rels.concat(this.Relationships); this.components.forEach((c) => { rels = rels.concat(c.Relationships); }); return rels; } }; // src/c4/c4containerview.ts var C4ContainerView = class extends C4View { containerID; /** * */ constructor(containerId, key, description) { super("Container", key, description); this.containerID = containerId; } get ContainerId() { return this.containerID; } }; // src/c4/c4elementstyle.ts var C4ElementStyle = class { tag = ""; shape; background; color; constructor() { } }; // src/c4/c4group.ts var C4Group = class { id; name; people = []; softwaresystems = []; constructor(id, name) { this.id = id; this.name = name; } addPerson(person) { this.people.push(person); } addSoftwareSystem(ssys) { this.softwaresystems.push(ssys); } get Id() { return this.id; } get Name() { return this.name; } get People() { return this.people; } get SoftwareSystems() { return this.softwaresystems; } findElement(e_id) { let tree = []; for (const per of this.people) { let tree2 = per.findElement(e_id); if (tree2.length > 0) { return tree2; } } for (const element of this.softwaresystems) { let tree2 = element.findElement(e_id); if (tree2.length > 0) { return tree2; } } return tree; } }; // src/c4/c4person.ts var C4Person = class extends C4Element { location; constructor(id, name, description, location) { super(id, name, description); this.location = location ?? "Unspecified"; } findElement(e_id) { let reply = []; if (this.Id === e_id) { reply.push(this); return reply; } return reply; } get Location() { return this.location; } }; // src/c4/c4relationshipstyle.ts var C4RelationshipStyle = class { }; // src/c4/c4softwaresystem.ts var C4SoftwareSystem = class extends C4Element { containers = []; constructor(id, name, description) { super(id, name, description); } addContainer(container) { this.containers.push(container); } // This method recursively checks for an element with the ID matching the provided value findElement(e_id) { let reply = []; if (this.Id === e_id) { reply.push(this); return reply; } else { for (const con of this.containers) { const ele = con.findElement(e_id); if (ele.length > 0) { reply.push(this); reply.push(...ele); return reply; } } } return reply; } get Containers() { return this.containers; } get NestedRelationships() { let rels = []; rels = rels.concat(this.Relationships); this.containers.forEach((c) => { rels = rels.concat(c.NestedRelationships); }); return rels; } }; // src/c4/c4systemcontextview.ts var C4SystemContextView = class extends C4View { systemID; /** * */ constructor(systemId, key, description) { super("SystemContext", key, description); this.systemID = systemId; } get SystemId() { return this.systemID; } }; // src/c4/c4systemlandscapeview.ts var C4SystemLandscapeView = class extends C4View { /** * */ constructor(key, description) { super("SystemLandscape", key, description); } }; // src/c4/c4model.ts var C4Model = class { people = []; softwaresystems = []; groups = []; constructor() { } addGroup(group) { this.groups.push(group); } addPerson(person) { this.people.push(person); } addSoftwareSystem(ssys) { this.softwaresystems.push(ssys); } addRelationship(s_id, t_id, desc) { let source_tree = this.findElement(s_id); let target_tree = this.findElement(t_id); if (source_tree.length > 0 && target_tree.length > 0) { let src_ele = source_tree.pop(); let tgt_ele = target_tree.pop(); src_ele?.addRelationship(t_id, desc); } } findElement(e_id) { let tree = []; for (const per of this.people) { let tree2 = per.findElement(e_id); if (tree2.length > 0) { return tree2; } } for (const element of this.softwaresystems) { let tree2 = element.findElement(e_id); if (tree2.length > 0) { return tree2; } } for (const grp of this.groups) { let tree2 = grp.findElement(e_id); if (tree2.length > 0) { return tree2; } } return tree; } get People() { return this.people; } get SoftwareSystems() { return this.softwaresystems; } get Groups() { return this.groups; } }; // src/c4/c4styles.ts var C4Styles = class { elementStyles = []; relationshipStyles = []; constructor() { } addElementStyle(style) { this.elementStyles.push(style); } addRelationshipStyle(style) { this.relationshipStyles.push(style); } get ElementStyles() { return this.elementStyles; } get RelationshipStyles() { return this.relationshipStyles; } }; // src/c4/c4workspace.ts var C4Workspace = class { id; name; description; model = new C4Model(); views = []; styles = new C4Styles(); constructor(id, name, description) { this.id = id; this.name = name; this.description = description; } setName(name) { this.name = name; } setDescription(description) { this.description = description; } addGroup(group) { this.model.addGroup(group); } addPerson(person) { this.model.addPerson(person); } addSoftwareSystem(ssys) { this.model.addSoftwareSystem(ssys); } addRelationship(s_id, t_id, desc) { this.model.addRelationship(s_id, t_id, desc); } addView(view) { this.views.push(view); } addRelationshipStyle(style) { this.styles.addRelationshipStyle(style); } addElementStyle(style) { this.styles.addElementStyle(style); } get Model() { return this.model; } get Views() { return this.views; } get Styles() { return this.styles; } }; // src/C4Interpreter.ts var c4Interpreter = class extends BaseStructurizrVisitor { _debug = false; // This needs to be better workspace = new C4Workspace("", "", ""); constructor() { super(); this.validateVisitor(); } set Debug(flag) { this._debug = flag; } // This is the top level entry point. It will recurse the entire Parser tree and then build MX files // based on the view instructions // At present it returns the workspace object but that will be changed once this works workspaceWrapper(node) { this._debug && console.log("Here we are at workspaceWrapper node:"); this.workspace = new C4Workspace("main", node.name, node.description); if (node.workspaceSection) { this.visit(node.workspaceSection); } return this.workspace; } workspaceSection(node) { this._debug && console.log("Here we are at workspaceSection node:"); if (node.name) { this.workspace.setName(node.StringLiteral[0]?.image); } ; if (node.description) { this.workspace.setDescription(node.StringLiteral[1]?.image); } ; if (node.modelSection) { this.visit(node.modelSection); } if (node.viewsSection) { this.visit(node.viewsSection); } } modelSection(node) { this._debug && console.log("Here we are at modelSection node:"); if (node.modelChildSection) { this.visit(node.modelChildSection); } } modelChildSection(node) { this._debug && console.log("Here we are at modelChildSection node:"); if (node.systemGroupSection) { for (const group of node.systemGroupSection) { this.visit(group); } } if (node.personSection) { for (const person of node.personSection) { this.visit(person); } } if (node.softwareSystemSection) { for (const sSystem of node.softwareSystemSection) { this.visit(sSystem); } } if (node.explicitRelationship) { for (const relationship of node.explicitRelationship) { this.visit(relationship); } } if (node.deploymentEnvironmentSection) { for (const depEnv of node.deploymentEnvironmentSection) { this.visit(depEnv); } } } systemGroupSection(node) { this._debug && console.log("Here we are at systemGroupSection node:"); let id = nanoid(); if (node.identifier) { id = node.identifier[0].image; } const name = stripQuotes2(node.StringLiteral[0]?.image ?? ""); const group = new C4Group(id, name); if (node.systemGroupChildSection) { this.visit(node.systemGroupChildSection, group); } this.workspace.addGroup(group); } systemGroupChildSection(node, group) { this._debug && console.log("Here we are at systemGroupChildSection with node:"); if (node.personSection) { for (const person of node.personSection) { this.visit(person, group); } } if (node.softwareSystemSection) { for (const sSystem of node.softwareSystemSection) { this.visit(sSystem, group); } } } personSection(node, group) { this._debug && console.log("Here we are at personSection node:"); const id = node.identifier[0].image; const name = stripQuotes2(node.StringLiteral[0]?.image ?? ""); const description = stripQuotes2(node.StringLiteral[1]?.image ?? ""); const person = new C4Person(id, name, description); if (group) { group.addPerson(person); } else { this.workspace.addPerson(person); } } softwareSystemSection(node, group) { this._debug && console.log("Here we are at softwareSystemSection node:"); const id = node.identifier[0].image; const name = stripQuotes2(node.StringLiteral[0]?.image ?? ""); const description = stripQuotes2(node.StringLiteral[1]?.image ?? ""); const ssys = new C4SoftwareSystem(id, name, description); if (node.softwareSystemChildSection) { this.visit(node.softwareSystemChildSection, ssys); } if (group) { group.addSoftwareSystem(ssys); } else { this.workspace.addSoftwareSystem(ssys); } } softwareSystemChildSection(node, ssys) { this._debug && console.log("Here we are at softwareSystemChildSection node:"); if (node.containerSection) { for (const ctr of node.containerSection) { this.visit(ctr, ssys); } } } containerSection(node, ssys) { this._debug && console.log("Here we are at ContainerSection node:"); const id = node.identifier[0].image; const name = stripQuotes2(node.StringLiteral[0]?.image ?? ""); const description = stripQuotes2(node.StringLiteral[1]?.image ?? ""); const container = new C4Container(id, name, description); if (node.containerChildSection) { this.visit(node.containerChildSection, container); } ssys.addContainer(container); } containerChildSection(node, ctr) { this._debug && console.log("Here we are at ContainerChildSection node:"); if (node.componentSection) { for (const comp of node.componentSection) { this.visit(comp, ctr); } } } componentSection(node, ctr) { this._debug && console.log("Here we are at ComponentSection node:"); const id = node.identifier[0].image; const name = stripQuotes2(node.StringLiteral[0]?.image ?? ""); const description = stripQuotes2(node.StringLiteral[1]?.image ?? ""); const component = new C4Component(id, name, description); ctr.addComponent(component); } explicitRelationship(node) { this._debug && console.log("Here we are at explicitRelationship node:"); const s_id = node.identifier[0].image; const t_id = node.identifier[1].image; const desc = stripQuotes2(node.StringLiteral[0]?.image ?? ""); this.workspace.addRelationship(s_id, t_id, desc); } implicitRelationship(node) { this._debug && console.log(`Here we are at implicitRelationship with node: ${node.name}`); } deploymentEnvironmentSection(node) { this._debug && console.log(`Here we are at deploymentEnvironmentSection with node: ${node.name}`); } deploymentEnvironmentChildSection(node) { this._debug && console.log(`Here we are at deploymentEnvironmentChildSection with node: ${node.name}`); } deploymentNodeSection(node) { this._debug && console.log(`Here we are at deploymentNodeSection with node: ${node.name}`); } deploymentNodeChildSection(node) { this._debug && console.log(`Here we are at deploymentNodeChildSection with node: ${node.name}`); } containerInstanceSection(node) { this._debug && console.log(`Here we are at containerInstanceSection with node: ${node.name}`); } softwareSystemInstanceSection(node) { this._debug && console.log(`Here we are at softwareSystemInstanceSection with node: ${node.name}`); } viewsSection(node) { this._debug && console.log("Here we are at viewsSection node:"); if (node.viewsChildSection) { this.visit(node.viewsChildSection); } } vi