Merge pull request #318 from ahdis/oe_structuremaps

structure maps: line comments and fhir path expression
This commit is contained in:
Grahame Grieve 2020-08-26 12:51:10 +10:00 committed by GitHub
commit f52297ae26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 32 deletions

View File

@ -284,7 +284,10 @@ public class StructureMapUtilities {
b.append("\" = \""); b.append("\" = \"");
b.append(Utilities.escapeJson(map.getName())); b.append(Utilities.escapeJson(map.getName()));
b.append("\"\r\n\r\n"); b.append("\"\r\n\r\n");
if (map.getDescription()!=null) {
renderMultilineDoco(b, map.getDescription(), 0);
b.append("\r\n");
}
renderConceptMaps(b, map); renderConceptMaps(b, map);
renderUses(b, map); renderUses(b, map);
renderImports(b, map); renderImports(b, map);
@ -392,8 +395,8 @@ public class StructureMapUtilities {
} }
b.append("as "); b.append("as ");
b.append(s.getMode().toCode()); b.append(s.getMode().toCode());
b.append("\r\n");
renderDoco(b, s.getDocumentation()); renderDoco(b, s.getDocumentation());
b.append("\r\n");
} }
if (map.hasStructure()) if (map.hasStructure())
b.append("\r\n"); b.append("\r\n");
@ -416,6 +419,9 @@ public class StructureMapUtilities {
} }
private static void renderGroup(StringBuilder b, StructureMapGroupComponent g) { private static void renderGroup(StringBuilder b, StructureMapGroupComponent g) {
if (g.hasDocumentation()) {
renderMultilineDoco(b, g.getDocumentation(), 0);
}
b.append("group "); b.append("group ");
b.append(g.getName()); b.append(g.getName());
b.append("("); b.append("(");
@ -464,6 +470,9 @@ public class StructureMapUtilities {
} }
private static void renderRule(StringBuilder b, StructureMapGroupRuleComponent r, int indent) { private static void renderRule(StringBuilder b, StructureMapGroupRuleComponent r, int indent) {
if (r.getDocumentation()!=null) {
renderMultilineDoco(b, r.getDocumentation(),indent);
}
for (int i = 0; i < indent; i++) for (int i = 0; i < indent; i++)
b.append(' '); b.append(' ');
boolean canBeAbbreviated = checkisSimple(r); boolean canBeAbbreviated = checkisSimple(r);
@ -499,7 +508,6 @@ public class StructureMapUtilities {
} }
if (r.hasRule()) { if (r.hasRule()) {
b.append(" then {\r\n"); b.append(" then {\r\n");
renderDoco(b, r.getDocumentation());
for (StructureMapGroupRuleComponent ir : r.getRule()) { for (StructureMapGroupRuleComponent ir : r.getRule()) {
renderRule(b, ir, indent+2); renderRule(b, ir, indent+2);
} }
@ -539,7 +547,6 @@ public class StructureMapUtilities {
} }
} }
b.append(";"); b.append(";");
renderDoco(b, r.getDocumentation());
b.append("\r\n"); b.append("\r\n");
} }
@ -653,13 +660,13 @@ public class StructureMapUtilities {
renderTransformParam(b, rt.getParameter().get(0)); renderTransformParam(b, rt.getParameter().get(0));
} else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 1) { } else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 1) {
b.append("("); b.append("(");
b.append("\""+((StringType) rt.getParameter().get(0).getValue()).asStringValue()+"\""); b.append(((StringType) rt.getParameter().get(0).getValue()).asStringValue());
b.append(")"); b.append(")");
} else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 2) { } else if (rt.getTransform() == StructureMapTransform.EVALUATE && rt.getParameter().size() == 2) {
b.append(rt.getTransform().toCode()); b.append(rt.getTransform().toCode());
b.append("("); b.append("(");
b.append(((IdType) rt.getParameter().get(0).getValue()).asStringValue()); b.append(((IdType) rt.getParameter().get(0).getValue()).asStringValue());
b.append("\""+((StringType) rt.getParameter().get(1).getValue()).asStringValue()+"\""); b.append(((StringType) rt.getParameter().get(1).getValue()).asStringValue());
b.append(")"); b.append(")");
} else { } else {
b.append(rt.getTransform().toCode()); b.append(rt.getTransform().toCode());
@ -718,10 +725,25 @@ public class StructureMapUtilities {
private static void renderDoco(StringBuilder b, String doco) { private static void renderDoco(StringBuilder b, String doco) {
if (Utilities.noString(doco)) if (Utilities.noString(doco))
return; return;
if (b!=null && b.length()>1 && b.charAt(b.length()-1)!='\n' && b.charAt(b.length()-1)!=' ') {
b.append(" ");
}
b.append("// "); b.append("// ");
b.append(doco.replace("\r\n", " ").replace("\r", " ").replace("\n", " ")); b.append(doco.replace("\r\n", " ").replace("\r", " ").replace("\n", " "));
} }
private static void renderMultilineDoco(StringBuilder b, String doco, int indent) {
if (Utilities.noString(doco))
return;
String[] lines = doco.split("\\r?\\n");
for(String line: lines) {
for (int i = 0; i < indent; i++)
b.append(' ');
renderDoco(b, line);
b.append("\r\n");
}
}
public StructureMap parse(String text, String srcName) throws FHIRException { public StructureMap parse(String text, String srcName) throws FHIRException {
FHIRLexer lexer = new FHIRLexer(text, srcName); FHIRLexer lexer = new FHIRLexer(text, srcName);
if (lexer.done()) if (lexer.done())
@ -732,8 +754,9 @@ public class StructureMapUtilities {
result.setUrl(lexer.readConstant("url")); result.setUrl(lexer.readConstant("url"));
lexer.token("="); lexer.token("=");
result.setName(lexer.readConstant("name")); result.setName(lexer.readConstant("name"));
lexer.skipComments(); if (lexer.hasComment()) {
result.setDescription(getMultiLineComments(lexer));
}
while (lexer.hasToken("conceptmap")) while (lexer.hasToken("conceptmap"))
parseConceptMap(result, lexer); parseConceptMap(result, lexer);
@ -807,6 +830,18 @@ public class StructureMapUtilities {
lexer.token("}"); lexer.token("}");
} }
private String getMultiLineComments(FHIRLexer lexer) {
String comment = null;
while (lexer.hasComment()) {
String newComment = lexer.take().substring(2).trim();
if (comment == null) {
comment = newComment;
} else {
comment += "\r\n"+newComment;
}
}
return comment;
}
private ConceptMapGroupComponent getGroup(ConceptMap map, String srcs, String tgts) { private ConceptMapGroupComponent getGroup(ConceptMap map, String srcs, String tgts) {
for (ConceptMapGroupComponent grp : map.getGroup()) { for (ConceptMapGroupComponent grp : map.getGroup()) {
@ -850,6 +885,7 @@ public class StructureMapUtilities {
private void parseUses(StructureMap result, FHIRLexer lexer) throws FHIRException { private void parseUses(StructureMap result, FHIRLexer lexer) throws FHIRException {
lexer.token("uses"); lexer.token("uses");
int currentLine = lexer.getCurrentLocation().getLine();
StructureMapStructureComponent st = result.addStructure(); StructureMapStructureComponent st = result.addStructure();
st.setUrl(lexer.readConstant("url")); st.setUrl(lexer.readConstant("url"));
if (lexer.hasToken("alias")) { if (lexer.hasToken("alias")) {
@ -859,25 +895,34 @@ public class StructureMapUtilities {
lexer.token("as"); lexer.token("as");
st.setMode(StructureMapModelMode.fromCode(lexer.take())); st.setMode(StructureMapModelMode.fromCode(lexer.take()));
lexer.skipToken(";"); lexer.skipToken(";");
if (lexer.hasComment()) { if (lexer.hasComment() && currentLine == lexer.getCurrentLocation().getLine()) {
st.setDocumentation(lexer.take().substring(2).trim()); st.setDocumentation(lexer.take().substring(2).trim());
} }
lexer.skipComments();
} }
private void parseImports(StructureMap result, FHIRLexer lexer) throws FHIRException { private void parseImports(StructureMap result, FHIRLexer lexer) throws FHIRException {
lexer.token("imports"); lexer.token("imports");
int currentLine = lexer.getCurrentLocation().getLine();
result.addImport(lexer.readConstant("url")); result.addImport(lexer.readConstant("url"));
lexer.skipToken(";"); lexer.skipToken(";");
if (lexer.hasComment()) { if (lexer.hasComment() && currentLine == lexer.getCurrentLocation().getLine()) {
lexer.next(); lexer.next();
} }
lexer.skipComments();
} }
private void parseGroup(StructureMap result, FHIRLexer lexer) throws FHIRException { private void parseGroup(StructureMap result, FHIRLexer lexer) throws FHIRException {
String comment = null;
if (lexer.hasComment()) {
comment = getMultiLineComments(lexer);
if (lexer.done()) {
return ;
}
}
lexer.token("group"); lexer.token("group");
StructureMapGroupComponent group = result.addGroup(); StructureMapGroupComponent group = result.addGroup();
if (comment != null) {
group.setDocumentation(comment);
}
boolean newFmt = false; boolean newFmt = false;
if (lexer.hasToken("for")) { if (lexer.hasToken("for")) {
lexer.token("for"); lexer.token("for");
@ -923,7 +968,6 @@ public class StructureMapUtilities {
} }
lexer.token("{"); lexer.token("{");
} }
lexer.skipComments();
if (newFmt) { if (newFmt) {
while (!lexer.hasToken("}")) { while (!lexer.hasToken("}")) {
if (lexer.done()) if (lexer.done())
@ -931,6 +975,7 @@ public class StructureMapUtilities {
parseRule(result, group.getRule(), lexer, true); parseRule(result, group.getRule(), lexer, true);
} }
} else { } else {
lexer.skipComments();
while (lexer.hasToken("input")) while (lexer.hasToken("input"))
parseInput(group, lexer, false); parseInput(group, lexer, false);
while (!lexer.hasToken("endgroup")) { while (!lexer.hasToken("endgroup")) {
@ -942,7 +987,6 @@ public class StructureMapUtilities {
lexer.next(); lexer.next();
if (newFmt && lexer.hasToken(";")) if (newFmt && lexer.hasToken(";"))
lexer.next(); lexer.next();
lexer.skipComments();
} }
private void parseInput(StructureMapGroupComponent group, FHIRLexer lexer, boolean newFmt) throws FHIRException { private void parseInput(StructureMapGroupComponent group, FHIRLexer lexer, boolean newFmt) throws FHIRException {
@ -969,12 +1013,19 @@ public class StructureMapUtilities {
private void parseRule(StructureMap map, List<StructureMapGroupRuleComponent> list, FHIRLexer lexer, boolean newFmt) throws FHIRException { private void parseRule(StructureMap map, List<StructureMapGroupRuleComponent> list, FHIRLexer lexer, boolean newFmt) throws FHIRException {
StructureMapGroupRuleComponent rule = new StructureMapGroupRuleComponent(); StructureMapGroupRuleComponent rule = new StructureMapGroupRuleComponent();
list.add(rule);
if (!newFmt) { if (!newFmt) {
rule.setName(lexer.takeDottedToken()); rule.setName(lexer.takeDottedToken());
lexer.token(":"); lexer.token(":");
lexer.token("for"); lexer.token("for");
} else {
if (lexer.hasComment()) {
rule.setDocumentation(this.getMultiLineComments(lexer));
if (lexer.hasToken("}")) {
return ; // catched a comment at the end
} }
}
}
list.add(rule);
boolean done = false; boolean done = false;
while (!done) { while (!done) {
parseSource(rule, lexer); parseSource(rule, lexer);
@ -996,10 +1047,6 @@ public class StructureMapUtilities {
lexer.token("then"); lexer.token("then");
if (lexer.hasToken("{")) { if (lexer.hasToken("{")) {
lexer.token("{"); lexer.token("{");
if (lexer.hasComment()) {
rule.setDocumentation(lexer.take().substring(2).trim());
}
lexer.skipComments();
while (!lexer.hasToken("}")) { while (!lexer.hasToken("}")) {
if (lexer.done()) if (lexer.done())
throw lexer.error("premature termination expecting '}' in nested group"); throw lexer.error("premature termination expecting '}' in nested group");
@ -1016,7 +1063,7 @@ public class StructureMapUtilities {
} }
} }
} else if (lexer.hasComment()) { } else if (lexer.hasComment()) {
rule.setDocumentation(lexer.take().substring(2).trim()); rule.setDocumentation(getMultiLineComments(lexer));
} }
if (isSimpleSyntax(rule)) { if (isSimpleSyntax(rule)) {
rule.getSourceFirstRep().setVariable(AUTO_VAR_NAME); rule.getSourceFirstRep().setVariable(AUTO_VAR_NAME);
@ -1041,7 +1088,6 @@ public class StructureMapUtilities {
} }
lexer.token(";"); lexer.token(";");
} }
lexer.skipComments();
} }
private boolean isSimpleSyntax(StructureMapGroupRuleComponent rule) { private boolean isSimpleSyntax(StructureMapGroupRuleComponent rule) {

View File

@ -10,23 +10,23 @@ import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.StructureMap; import org.hl7.fhir.r5.model.StructureMap;
import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupRuleTargetComponent;
import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.StructureMapUtilities; import org.hl7.fhir.r5.utils.StructureMapUtilities;
import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices; import org.hl7.fhir.r5.utils.StructureMapUtilities.ITransformerServices;
import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.cache.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion; import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@Disabled // org.hl7.fhir.exceptions.FHIRException: Unable to resolve package id hl7.fhir.core#4.0.0
public class StructureMapUtilitiesTest implements ITransformerServices { public class StructureMapUtilitiesTest implements ITransformerServices {
static private SimpleWorkerContext context; static private SimpleWorkerContext context;
// @BeforeAll @BeforeAll
static public void setUp() throws Exception { static public void setUp() throws Exception {
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION); FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.core", "4.0.0")); context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1"));
} }
@Test @Test
@ -39,6 +39,42 @@ public class StructureMapUtilitiesTest implements ITransformerServices {
assertEquals("expression", structureMap.getGroup().get(2).getRule().get(1).getName()); assertEquals("expression", structureMap.getGroup().get(2).getRule().get(1).getName());
} }
private void assertSerializeDeserialize(StructureMap structureMap) {
assertEquals("syntax", structureMap.getName());
assertEquals("Title of this map\r\nAuthor", structureMap.getDescription());
assertEquals("http://github.com/FHIR/fhir-test-cases/r5/fml/syntax", structureMap.getUrl());
assertEquals("Patient", structureMap.getStructure().get(0).getAlias());
assertEquals("http://hl7.org/fhir/StructureDefinition/Patient", structureMap.getStructure().get(0).getUrl());
assertEquals("Source Documentation", structureMap.getStructure().get(0).getDocumentation());
assertEquals("http://hl7.org/fhir/StructureDefinition/Patient", structureMap.getStructure().get(0).getUrl());
assertEquals("http://hl7.org/fhir/StructureDefinition/Basic", structureMap.getStructure().get(1).getUrl());
assertEquals("Target Documentation", structureMap.getStructure().get(1).getDocumentation());
assertEquals("Groups\r\nrule for patient group", structureMap.getGroup().get(0).getDocumentation());
assertEquals("Comment to rule", structureMap.getGroup().get(0).getRule().get(0).getDocumentation());
assertEquals("Copy identifier short syntax", structureMap.getGroup().get(0).getRule().get(1).getDocumentation());
StructureMapGroupRuleTargetComponent target = structureMap.getGroup().get(0).getRule().get(2).getTarget().get(1);
assertEquals("'urn:uuid:' + r.lower()", target.getParameter().get(0).toString());
}
@Test
public void testSyntax() throws IOException, FHIRException {
StructureMapUtilities scu = new StructureMapUtilities(context, this);
String fileMap = TestingUtilities.loadTestResource("r5", "fml", "syntax.map");
System.out.println(fileMap);
StructureMap structureMap = scu.parse(fileMap, "Syntax");
assertSerializeDeserialize(structureMap);
String renderedMap = StructureMapUtilities.render(structureMap);
StructureMap map = scu.parse(renderedMap, "Syntax");
System.out.println(map);
assertSerializeDeserialize(map);
}
@Override @Override
public void log(String message) { public void log(String message) {
} }

View File

@ -17,7 +17,7 @@
<properties> <properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version> <hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.33</validator_test_case_version> <validator_test_case_version>1.1.34-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.6.2</junit_jupiter_version> <junit_jupiter_version>5.6.2</junit_jupiter_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version> <maven_surefire_version>3.0.0-M4</maven_surefire_version>
<jacoco_version>0.8.5</jacoco_version> <jacoco_version>0.8.5</jacoco_version>