Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import "http://www.avaloq.com/tools/ddk/xtext/export/Export"

interface {
InterfaceExpression=unordered;
UserData=name;
}

export InterfaceExpression as ref
{
data ex = this.getExpr().toString();
}
export UserData as name
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2026 Avaloq Group AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Avaloq Group AG - initial API and implementation
*******************************************************************************/
package com.avaloq.tools.ddk.xtext.export.generator;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

import com.avaloq.tools.ddk.xtext.export.export.ExportModel;
import com.avaloq.tools.ddk.xtext.test.export.util.ExportTestUtil;
import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTest;


/**
* Regression tests for URI-based package derivation in {@link ExportGeneratorX}.
*/
@SuppressWarnings("nls")
public class ExportGeneratorXTest extends AbstractXtextTest {

private final ExportGeneratorX exportGeneratorX = getXtextTestUtil().get(ExportGeneratorX.class);

@Override
protected ExportTestUtil getXtextTestUtil() {
return ExportTestUtil.getInstance();
}

@Test
public void testShallowProjectUriFallsBackToProjectPackage() {
final ExportModel model = (ExportModel) getTestSource().getModel();

assertEquals("test.naming.ExportGeneratorXTestExportedNamesProvider", exportGeneratorX.getExportedNamesProvider(model));
assertEquals("test.resource.ExportGeneratorXTestResourceDescriptionManager", exportGeneratorX.getResourceDescriptionManager(model));
assertEquals("test.resource.ExportGeneratorXTestResourceDescriptionStrategy", exportGeneratorX.getResourceDescriptionStrategy(model));
assertEquals("test.resource.ExportGeneratorXTestResourceDescriptionConstants", exportGeneratorX.getResourceDescriptionConstants(model));
assertEquals("test.resource.ExportGeneratorXTestFingerprintComputer", exportGeneratorX.getFingerprintComputer(model));
assertEquals("test.resource.ExportGeneratorXTestFragmentProvider", exportGeneratorX.getFragmentProvider(model));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@
*******************************************************************************/
package com.avaloq.tools.ddk.xtext.test.export;

import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;

import com.avaloq.tools.ddk.xtext.export.exporting.ExportExportingTest;
import com.avaloq.tools.ddk.xtext.export.formatting.ExportFormattingTest;
import com.avaloq.tools.ddk.xtext.export.scoping.ExportScopingTest;
import com.avaloq.tools.ddk.xtext.export.validation.ExportValidationTest;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;

import com.avaloq.tools.ddk.xtext.export.generator.ExportGeneratorXTest;
import com.avaloq.tools.ddk.xtext.export.exporting.ExportExportingTest;
import com.avaloq.tools.ddk.xtext.export.formatting.ExportFormattingTest;
import com.avaloq.tools.ddk.xtext.export.scoping.ExportScopingTest;
import com.avaloq.tools.ddk.xtext.export.validation.ExportValidationTest;


/**
* Empty class serving only as holder for JUnit4 annotations.
*/
@Suite
@SelectClasses({ExportFormattingTest.class, ExportValidationTest.class, ExportScopingTest.class, ExportExportingTest.class})
public class ExportTestSuite {
}
@Suite
@SelectClasses({ExportFormattingTest.class, ExportValidationTest.class, ExportScopingTest.class, ExportExportingTest.class, ExportGeneratorXTest.class})
public class ExportTestSuite {
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,25 @@ import com.avaloq.tools.ddk.xtext.expression.generator.EClassComparator
import com.avaloq.tools.ddk.xtext.expression.generator.GenModelUtil2
import com.avaloq.tools.ddk.xtext.expression.generator.GeneratorUtil
import com.avaloq.tools.ddk.xtext.expression.generator.Naming
import com.google.common.collect.ListMultimap
import com.google.inject.Inject
import java.util.Collection
import java.util.List
import java.util.Map
import com.google.common.collect.ListMultimap
import com.google.inject.Inject
import java.util.Collection
import java.util.List
import java.util.Map
import org.eclipse.emf.ecore.EAttribute
import org.eclipse.emf.ecore.EClass
import org.eclipse.emf.ecore.EClassifier
import org.eclipse.emf.ecore.EPackage
import org.eclipse.xtext.Grammar

class ExportGeneratorX {

@Inject
extension Naming
class ExportGeneratorX {

static val URI_PROJECT_SEGMENT_INDEX = 1
static val URI_PACKAGE_START_INDEX = 3
static val DEFAULT_PACKAGE_SEGMENT = "generated"

@Inject
extension Naming

def String getName(ExportModel model) {
val uri = model.eResource().getURI();
Expand All @@ -50,51 +54,92 @@ class ExportGeneratorX {
return grammarResource?.contents.head as Grammar
}

def String getExportedNamesProvider(ExportModel model) {
val uri = model.eResource().getURI();
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".naming." + getName(model) + "ExportedNamesProvider";
}

def String getResourceDescriptionManager(ExportModel model) {
val uri = model.eResource().getURI();
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionManager";
}
def String getExportedNamesProvider(ExportModel model) {
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return model.basePackage + ".naming." + getName(model) + "ExportedNamesProvider";
}

def String getResourceDescriptionManager(ExportModel model) {
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return model.basePackage + ".resource." + getName(model) + "ResourceDescriptionManager";
}

def String getResourceDescriptionManager(Grammar grammar) {
return grammar.name.toJavaPackage + ".resource." + grammar.name.toSimpleName + "ResourceDescriptionManager";
}

def String getResourceDescriptionStrategy(ExportModel model) {
val uri = model.eResource().getURI();
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionStrategy";
}

def String getResourceDescriptionConstants(ExportModel model) {
val uri = model.eResource().getURI();
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "ResourceDescriptionConstants";
}

def String getFingerprintComputer(ExportModel model) {
val uri = model.eResource().getURI();
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FingerprintComputer";
}

def String getFragmentProvider(ExportModel model) {
val uri = model.eResource().getURI();
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + getName(model) + "FragmentProvider";
}

def String getExportFeatureExtension(ExportModel model) {
val uri = model.eResource().getURI();
// TODO we still need to add a package to the models. Extension models already have a name in contrast to cases above
return String.join(".", uri.segmentsList().subList(3, uri.segmentCount() - 1)) + ".resource." + model.name + "ExportFeatureExtension";
}
def String getResourceDescriptionStrategy(ExportModel model) {
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return model.basePackage + ".resource." + getName(model) + "ResourceDescriptionStrategy";
}

def String getResourceDescriptionConstants(ExportModel model) {
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return model.basePackage + ".resource." + getName(model) + "ResourceDescriptionConstants";
}

def String getFingerprintComputer(ExportModel model) {
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return model.basePackage + ".resource." + getName(model) + "FingerprintComputer";
}

def String getFragmentProvider(ExportModel model) {
// TODO this is a hack; to support modularization we should probably add name to export models (as with scope models)
return model.basePackage + ".resource." + getName(model) + "FragmentProvider";
}

def String getExportFeatureExtension(ExportModel model) {
// TODO we still need to add a package to the models. Extension models already have a name in contrast to cases above
return model.basePackage + ".resource." + model.name + "ExportFeatureExtension";
}

private def String getBasePackage(ExportModel model) {
val uri = model.eResource.URI
val packageFromUri = uri.packageFromUri
if (packageFromUri !== null) {
return packageFromUri
}
return uri.fallbackPackage
}

private def String getPackageFromUri(org.eclipse.emf.common.util.URI uri) {
val packageSegments = uri.segmentsList
if (packageSegments.size > URI_PACKAGE_START_INDEX + 1 && "src".equals(packageSegments.get(URI_PROJECT_SEGMENT_INDEX + 1))) {
return String.join(".", packageSegments.subList(URI_PACKAGE_START_INDEX, uri.segmentCount - 1))
}
return null
}

private def String getFallbackPackage(org.eclipse.emf.common.util.URI uri) {
val segments = uri.segmentsList
if (segments.size > URI_PROJECT_SEGMENT_INDEX) {
return segments.get(URI_PROJECT_SEGMENT_INDEX).safePackageSegment
}
return DEFAULT_PACKAGE_SEGMENT
}

private def String getSafePackageSegment(String segment) {
if (segment === null || segment.empty) {
return DEFAULT_PACKAGE_SEGMENT
}
val normalizedSegment = segment.toLowerCase
val builder = new StringBuilder()
for (var i = 0; i < normalizedSegment.length; i++) {
val character = normalizedSegment.charAt(i)
if (builder.length == 0) {
if (Character.isJavaIdentifierStart(character)) {
builder.append(character)
} else if (Character.isJavaIdentifierPart(character)) {
builder.append('_').append(character)
} else {
builder.append('_')
}
} else {
builder.append(if (Character.isJavaIdentifierPart(character)) character else '_')
}
}
return if (builder.length == 0) DEFAULT_PACKAGE_SEGMENT else builder.toString
}

/**
* Return the export specification for a type's supertype, if any, or null otherwise.
Expand Down
Loading