From c1b9e4f948ef2e157f7c85c157686a726e0b9367 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Mon, 19 Oct 2026 22:49:30 +0200 Subject: [PATCH] Add basePackage to BoundedContext (#375) Declares where a Bounded Context lives in the code, e.g. basePackage = com.transit.ticketsales Same syntax as on Modules (dot-separated identifiers), the equal sign is optional like for the other Bounded Context attributes. --- .../dsl/BoundedContextDSLParsingTest.xtend | 50 +++++++++++++++++++ .../contextmapper/dsl/ContextMappingDSL.xtext | 1 + .../ContextMappingDSLFormatter.xtend | 1 + 3 files changed, 52 insertions(+) diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/BoundedContextDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/BoundedContextDSLParsingTest.xtend index 0c00b5e0..afdb3fa5 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/BoundedContextDSLParsingTest.xtend +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/BoundedContextDSLParsingTest.xtend @@ -295,6 +295,56 @@ class BoundedContextDSLParsingTest { assertEquals("Gate validation", result.boundedContexts.get(0).nonResponsibilities.get(0)); } + @Test + def void canDefineBasePackage() { + // given + val String dslSnippet = ''' + BoundedContext TicketSales { + basePackage = com.transit.ticketsales + } + '''; + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals("com.transit.ticketsales", result.boundedContexts.get(0).basePackage); + } + + @Test + def void canDefineBasePackageWithoutEqualSign() { + // given + val String dslSnippet = ''' + BoundedContext TicketSales { + basePackage com.transit.ticketsales + Module refunds { + basePackage = com.transit.ticketsales.refunds + } + } + '''; + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals("com.transit.ticketsales", result.boundedContexts.get(0).basePackage); + assertEquals("com.transit.ticketsales.refunds", result.boundedContexts.get(0).modules.get(0).basePackage); + } + + @Test + def void cannotDefineInvalidBasePackage() { + // given + val String dslSnippet = ''' + BoundedContext TicketSales { + basePackage = com..transit + } + '''; + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + // then + assertFalse(result.eResource.errors.isEmpty); + } + @Test def void canDefineAttributesWithoutEqualSign() { // given diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index e3e2b8c4..15b68f93 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -60,6 +60,7 @@ BoundedContext: (('responsibilities' ('=')? responsibilities+=STRING) ("," responsibilities+=STRING)*)? & (('nonResponsibilities' ('=')? nonResponsibilities+=STRING) ("," nonResponsibilities+=STRING)*)? & ('implementationTechnology' ('=')? implementationTechnology=STRING)? & + ('basePackage' ('=')? basePackage=JavaIdentifier)? & ('knowledgeLevel' ('=')? knowledgeLevel=KnowledgeLevel)?) ('businessModel' ('=')? businessModel=STRING)? & ('evolution' ('=')? evolution=Evolution)? & diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/formatting2/ContextMappingDSLFormatter.xtend b/org.contextmapper.dsl/src/org/contextmapper/dsl/formatting2/ContextMappingDSLFormatter.xtend index 1ce258c7..7dc32092 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/formatting2/ContextMappingDSLFormatter.xtend +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/formatting2/ContextMappingDSLFormatter.xtend @@ -122,6 +122,7 @@ class ContextMappingDSLFormatter extends TacticDDDLanguageFormatter { boundedContext.regionFor.keyword("responsibilities").prepend[newLine] boundedContext.regionFor.keyword("nonResponsibilities").prepend[newLine] boundedContext.regionFor.keyword("implementationTechnology").prepend[newLine] + boundedContext.regionFor.keyword("basePackage").prepend[newLine] boundedContext.regionFor.keyword("knowledgeLevel").prepend[newLine] for (aggregate : boundedContext.aggregates) {