add watch mode to validator

This commit is contained in:
Grahame Grieve 2023-06-19 22:43:54 +10:00
parent 394077c8ec
commit 2b8e61e2cb
7 changed files with 87 additions and 10 deletions

View File

@ -211,6 +211,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
@Getter @Setter private boolean showMessagesFromReferences; @Getter @Setter private boolean showMessagesFromReferences;
@Getter @Setter private boolean doImplicitFHIRPathStringConversion; @Getter @Setter private boolean doImplicitFHIRPathStringConversion;
@Getter @Setter private HtmlInMarkdownCheck htmlInMarkdownCheck; @Getter @Setter private HtmlInMarkdownCheck htmlInMarkdownCheck;
@Getter @Setter private boolean allowDoubleQuotesInFHIRPath;
@Getter @Setter private Locale locale; @Getter @Setter private Locale locale;
@Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>(); @Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>();
@Getter @Setter private List<String> extensionDomains = new ArrayList<>(); @Getter @Setter private List<String> extensionDomains = new ArrayList<>();
@ -262,6 +263,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
showMessagesFromReferences = other.showMessagesFromReferences; showMessagesFromReferences = other.showMessagesFromReferences;
doImplicitFHIRPathStringConversion = other.doImplicitFHIRPathStringConversion; doImplicitFHIRPathStringConversion = other.doImplicitFHIRPathStringConversion;
htmlInMarkdownCheck = other.htmlInMarkdownCheck; htmlInMarkdownCheck = other.htmlInMarkdownCheck;
allowDoubleQuotesInFHIRPath = other.allowDoubleQuotesInFHIRPath;
locale = other.locale; locale = other.locale;
igs.addAll(other.igs); igs.addAll(other.igs);
extensionDomains.addAll(other.extensionDomains); extensionDomains.addAll(other.extensionDomains);
@ -471,6 +473,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
context.loadFromPackage(npmX, null); context.loadFromPackage(npmX, null);
this.fhirPathEngine = new FHIRPathEngine(context); this.fhirPathEngine = new FHIRPathEngine(context);
this.fhirPathEngine.setAllowDoubleQuotes(false);
} }
private String getVersionFromPack(Map<String, byte[]> source) { private String getVersionFromPack(Map<String, byte[]> source) {
@ -839,6 +842,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
validator.setQuestionnaireMode(questionnaireMode); validator.setQuestionnaireMode(questionnaireMode);
validator.setLevel(level); validator.setLevel(level);
validator.setHtmlInMarkdownCheck(htmlInMarkdownCheck); validator.setHtmlInMarkdownCheck(htmlInMarkdownCheck);
validator.setAllowDoubleQuotesInFHIRPath(allowDoubleQuotesInFHIRPath);
validator.setNoUnicodeBiDiControlChars(noUnicodeBiDiControlChars); validator.setNoUnicodeBiDiControlChars(noUnicodeBiDiControlChars);
validator.setDoImplicitFHIRPathStringConversion(doImplicitFHIRPathStringConversion); validator.setDoImplicitFHIRPathStringConversion(doImplicitFHIRPathStringConversion);
if (format == FhirFormat.SHC) { if (format == FhirFormat.SHC) {

View File

@ -12,6 +12,7 @@ import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.settings.FhirSettings;
import org.hl7.fhir.validation.cli.services.ValidatorWatchMode;
import org.hl7.fhir.validation.cli.utils.EngineMode; import org.hl7.fhir.validation.cli.utils.EngineMode;
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.cli.utils.ValidationLevel; import org.hl7.fhir.validation.cli.utils.ValidationLevel;
@ -53,7 +54,8 @@ public class CliContext {
private boolean doImplicitFHIRPathStringConversion = false; private boolean doImplicitFHIRPathStringConversion = false;
@JsonProperty("htmlInMarkdownCheck") @JsonProperty("htmlInMarkdownCheck")
private HtmlInMarkdownCheck htmlInMarkdownCheck = HtmlInMarkdownCheck.WARNING; private HtmlInMarkdownCheck htmlInMarkdownCheck = HtmlInMarkdownCheck.WARNING;
@JsonProperty("allowDoubleQuotesInFHIRPath")
private boolean allowDoubleQuotesInFHIRPath = false;
@JsonProperty("langTransform") @JsonProperty("langTransform")
private String langTransform = null; private String langTransform = null;
@JsonProperty("map") @JsonProperty("map")
@ -139,6 +141,8 @@ public class CliContext {
@JsonProperty("fhirSettingsFile") @JsonProperty("fhirSettingsFile")
private String fhirSettingsFile; private String fhirSettingsFile;
@JsonProperty("watchMode")
private ValidatorWatchMode watchMode = ValidatorWatchMode.NONE;
@JsonProperty("map") @JsonProperty("map")
public String getMap() { public String getMap() {
@ -294,6 +298,16 @@ public class CliContext {
this.htmlInMarkdownCheck = htmlInMarkdownCheck; this.htmlInMarkdownCheck = htmlInMarkdownCheck;
} }
@JsonProperty("allowDoubleQuotesInFHIRPath")
public boolean isAllowDoubleQuotesInFHIRPath() {
return allowDoubleQuotesInFHIRPath;
}
@JsonProperty("allowDoubleQuotesInFHIRPath")
public void setAllowDoubleQuotesInFHIRPath(boolean allowDoubleQuotesInFHIRPath) {
this.allowDoubleQuotesInFHIRPath = allowDoubleQuotesInFHIRPath;
}
@JsonProperty("locale") @JsonProperty("locale")
public String getLanguageCode() { public String getLanguageCode() {
return locale; return locale;
@ -705,8 +719,10 @@ public class CliContext {
noInvariants == that.noInvariants && noInvariants == that.noInvariants &&
displayWarnings == that.displayWarnings && displayWarnings == that.displayWarnings &&
wantInvariantsInMessages == that.wantInvariantsInMessages && wantInvariantsInMessages == that.wantInvariantsInMessages &&
allowDoubleQuotesInFHIRPath == that.allowDoubleQuotesInFHIRPath &&
Objects.equals(extensions, that.extensions) && Objects.equals(extensions, that.extensions) &&
Objects.equals(map, that.map) && Objects.equals(map, that.map) &&
Objects.equals(htmlInMarkdownCheck, that.htmlInMarkdownCheck) &&
Objects.equals(output, that.output) && Objects.equals(output, that.output) &&
Objects.equals(outputSuffix, that.outputSuffix) && Objects.equals(outputSuffix, that.outputSuffix) &&
Objects.equals(htmlOutput, that.htmlOutput) && Objects.equals(htmlOutput, that.htmlOutput) &&
@ -727,21 +743,23 @@ public class CliContext {
Objects.equals(profiles, that.profiles) && Objects.equals(profiles, that.profiles) &&
Objects.equals(sources, that.sources) && Objects.equals(sources, that.sources) &&
Objects.equals(crumbTrails, that.crumbTrails) && Objects.equals(crumbTrails, that.crumbTrails) &&
Objects.equals(forPublication, that.forPublication) && Objects.equals(forPublication, that.forPublication)&&
Objects.equals(allowExampleUrls, that.allowExampleUrls) && Objects.equals(allowExampleUrls, that.allowExampleUrls) &&
Objects.equals(showTimes, that.showTimes) && Objects.equals(showTimes, that.showTimes) &&
mode == that.mode && mode == that.mode &&
Objects.equals(locale, that.locale) && Objects.equals(locale, that.locale) &&
Objects.equals(outputStyle, that.outputStyle) && Objects.equals(outputStyle, that.outputStyle) &&
Objects.equals(jurisdiction, that.jurisdiction) && Objects.equals(jurisdiction, that.jurisdiction) &&
Objects.equals(locations, that.locations); Objects.equals(locations, that.locations) &&
Objects.equals(watchMode, that.watchMode) ;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, return Objects.hash(doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT, noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars); targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, watchMode,
htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath);
} }
@Override @Override
@ -792,6 +810,9 @@ public class CliContext {
", locale='" + locale + '\'' + ", locale='" + locale + '\'' +
", locations=" + locations + ", locations=" + locations +
", bundleValidationRules=" + bundleValidationRules + ", bundleValidationRules=" + bundleValidationRules +
", htmlInMarkdownCheck=" + htmlInMarkdownCheck +
", allowDoubleQuotesInFHIRPath=" + allowDoubleQuotesInFHIRPath +
", watchMode=" + watchMode +
'}'; '}';
} }
@ -805,4 +826,17 @@ public class CliContext {
public String getFhirSettingsFile() { public String getFhirSettingsFile() {
return fhirSettingsFile; return fhirSettingsFile;
} }
@JsonProperty("watchMode")
public ValidatorWatchMode getWatchMode() {
return watchMode;
}
@JsonProperty("watchMode")
public CliContext setWatchMode(ValidatorWatchMode watchMode) {
this.watchMode = watchMode;
return this;
}
} }

View File

@ -143,11 +143,10 @@ public class ValidationService {
return versions; return versions;
} }
public void validateSources(CliContext cliContext, ValidationEngine validator) throws Exception { public void validateSources(CliContext cliContext, ValidationEngine validator, ValidatorWatchMode watch) throws Exception {
if (cliContext.getProfiles().size() > 0) { if (cliContext.getProfiles().size() > 0) {
System.out.println(" Profiles: " + cliContext.getProfiles()); System.out.println(" Profiles: " + cliContext.getProfiles());
} }
ValidatorWatchMode watch = ValidatorWatchMode.NONE;
IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion()); IgLoader igLoader = new IgLoader(validator.getPcm(), validator.getContext(), validator.getVersion());
List<ValidationRecord> records = new ArrayList<>(); List<ValidationRecord> records = new ArrayList<>();
@ -467,6 +466,7 @@ public class ValidationService {
validationEngine.setShowMessagesFromReferences(cliContext.isShowMessagesFromReferences()); validationEngine.setShowMessagesFromReferences(cliContext.isShowMessagesFromReferences());
validationEngine.setDoImplicitFHIRPathStringConversion(cliContext.isDoImplicitFHIRPathStringConversion()); validationEngine.setDoImplicitFHIRPathStringConversion(cliContext.isDoImplicitFHIRPathStringConversion());
validationEngine.setHtmlInMarkdownCheck(cliContext.getHtmlInMarkdownCheck()); validationEngine.setHtmlInMarkdownCheck(cliContext.getHtmlInMarkdownCheck());
validationEngine.setAllowDoubleQuotesInFHIRPath(cliContext.isAllowDoubleQuotesInFHIRPath());
validationEngine.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages()); validationEngine.setNoExtensibleBindingMessages(cliContext.isNoExtensibleBindingMessages());
validationEngine.setNoUnicodeBiDiControlChars(cliContext.isNoUnicodeBiDiControlChars()); validationEngine.setNoUnicodeBiDiControlChars(cliContext.isNoUnicodeBiDiControlChars());
validationEngine.setNoInvariantChecks(cliContext.isNoInvariants()); validationEngine.setNoInvariantChecks(cliContext.isNoInvariants());

View File

@ -7,6 +7,7 @@ import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.validation.ValidationEngine; import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ValidationService; import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.services.ValidatorWatchMode;
import org.hl7.fhir.validation.cli.utils.Display; import org.hl7.fhir.validation.cli.utils.Display;
import java.io.PrintStream; import java.io.PrintStream;
@ -54,7 +55,7 @@ public class ValidateTask extends ValidationEngineTask {
} }
System.out.println("Validating"); System.out.println("Validating");
validationService.validateSources(cliContext, validationEngine); validationService.validateSources(cliContext, validationEngine, cliContext.getWatchMode());
} }
} }

View File

@ -10,6 +10,7 @@ import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck; import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
import org.hl7.fhir.validation.cli.services.ValidatorWatchMode;
public class Params { public class Params {
@ -83,6 +84,7 @@ public class Params {
public static final String HTML_IN_MARKDOWN = "-html-in-markdown"; public static final String HTML_IN_MARKDOWN = "-html-in-markdown";
public static final String SRC_LANG = "-src-lang"; public static final String SRC_LANG = "-src-lang";
public static final String TGT_LANG = "-tgt-lang"; public static final String TGT_LANG = "-tgt-lang";
public static final String ALLOW_DOUBLE_QUOTES = "-allow-double-quotes-in-fhirpath";
public static final String RUN_TESTS = "-run-tests"; public static final String RUN_TESTS = "-run-tests";
@ -96,6 +98,7 @@ public class Params {
public static final String INPUT = "-input"; public static final String INPUT = "-input";
public static final String FILTER = "-filter"; public static final String FILTER = "-filter";
private static final String FHIR_SETTINGS_PARAM = "-fhir-settings"; private static final String FHIR_SETTINGS_PARAM = "-fhir-settings";
private static final String WATCH_MODE_PARAM = "-watch-mode";
/** /**
* Checks the list of passed in params to see if it contains the passed in param. * Checks the list of passed in params to see if it contains the passed in param.
@ -240,6 +243,8 @@ public class Params {
cliContext.setNoInternalCaching(true); cliContext.setNoInternalCaching(true);
} else if (args[i].equals(NO_EXTENSIBLE_BINDING_WARNINGS)) { } else if (args[i].equals(NO_EXTENSIBLE_BINDING_WARNINGS)) {
cliContext.setNoExtensibleBindingMessages(true); cliContext.setNoExtensibleBindingMessages(true);
} else if (args[i].equals(ALLOW_DOUBLE_QUOTES)) {
cliContext.setAllowDoubleQuotesInFHIRPath(true);
} else if (args[i].equals(NO_UNICODE_BIDI_CONTROL_CHARS)) { } else if (args[i].equals(NO_UNICODE_BIDI_CONTROL_CHARS)) {
cliContext.setNoUnicodeBiDiControlChars(true); cliContext.setNoUnicodeBiDiControlChars(true);
} else if (args[i].equals(NO_INVARIANTS)) { } else if (args[i].equals(NO_INVARIANTS)) {
@ -381,6 +386,12 @@ public class Params {
} else { } else {
throw new Exception("Can only nominate a single -map parameter"); throw new Exception("Can only nominate a single -map parameter");
} }
} else if (args[i].equals(WATCH_MODE_PARAM)) {
if (i + 1 == args.length) {
throw new Error("Specified -watch-mode without indicating mode value");
} else {
cliContext.setWatchMode(readWatchMode(args[++i]));
}
} else if (args[i].startsWith(X)) { } else if (args[i].startsWith(X)) {
i++; i++;
} else if (args[i].equals(CONVERT)) { } else if (args[i].equals(CONVERT)) {
@ -402,6 +413,21 @@ public class Params {
return cliContext; return cliContext;
} }
private static ValidatorWatchMode readWatchMode(String s) {
if (s == null) {
return ValidatorWatchMode.NONE;
}
switch (s.toLowerCase()) {
case "all" : return ValidatorWatchMode.ALL;
case "none" : return ValidatorWatchMode.NONE;
case "single" : return ValidatorWatchMode.SINGLE;
case "a" : return ValidatorWatchMode.ALL;
case "n" : return ValidatorWatchMode.NONE;
case "s" : return ValidatorWatchMode.SINGLE;
}
throw new Error("The watch mode ''"+s+"'' is not valid");
}
private static String processJurisdiction(String s) { private static String processJurisdiction(String s) {
if (s.startsWith("urn:iso:std:iso:3166#") || s.startsWith("urn:iso:std:iso:3166:-2#") || s.startsWith("http://unstats.un.org/unsd/methods/m49/m49.htm#")) { if (s.startsWith("urn:iso:std:iso:3166#") || s.startsWith("urn:iso:std:iso:3166:-2#") || s.startsWith("http://unstats.un.org/unsd/methods/m49/m49.htm#")) {
return s; return s;

View File

@ -5,8 +5,8 @@ The validation tool compares a resource against the base definitions and any
profiles declared in the resource (Resource.meta.profile) or specified on the profiles declared in the resource (Resource.meta.profile) or specified on the
command line command line
The FHIR validation tool validates a FHIR resource or bundle. Schema and The FHIR validation tool validates a FHIR resource or bundle. Syntax and content is checked
schematron checking is performed, then some additional checks are performed. against the specification and other profiles as specified.
* XML & Json (FHIR versions {{XML_AND_JSON_FHIR_VERSIONS}}) * XML & Json (FHIR versions {{XML_AND_JSON_FHIR_VERSIONS}})
* Turtle (FHIR versions {{TURTLE_FHIR_VERSIONS}}) * Turtle (FHIR versions {{TURTLE_FHIR_VERSIONS}})
@ -72,6 +72,16 @@ The following parameters are supported:
Default: results are sent to the std out. Default: results are sent to the std out.
-outputSuffix [string]: used in -convert and -snapshot to deal with -outputSuffix [string]: used in -convert and -snapshot to deal with
one or more result files (where -output can only have one) one or more result files (where -output can only have one)
-watch-mode [mode]:
Specify that the validator remain running and re-validate when any
of the validated files changes. The validator has to be terminated with
ctrl-c etc in this mode.
This parameter can have one of the following values:
* none: the default - don't wait, just stop when finished
* single: when any of the validated files changes, re-validate it
* all: when any of the validated files changes, re-validate all of them
All is useful when the content includes internal dependencies e.g.
a profile and it's value sets.
-debug -debug
Produce additional information about the loading/validation process Produce additional information about the loading/validation process
-recurse -recurse

View File

@ -3,6 +3,7 @@ package org.hl7.fhir.validation;
import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ValidationService; import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.services.ValidatorWatchMode;
import org.hl7.fhir.validation.cli.tasks.*; import org.hl7.fhir.validation.cli.tasks.*;
import org.hl7.fhir.validation.cli.utils.Params; import org.hl7.fhir.validation.cli.utils.Params;
@ -245,9 +246,10 @@ public class ValidatorCliTests {
final String[] args = new String[]{"dummyFile.json"}; final String[] args = new String[]{"dummyFile.json"};
CliContext cliContext = Params.loadCliContext(args); CliContext cliContext = Params.loadCliContext(args);
ValidatorCli cli = mockValidatorCliWithService(cliContext); ValidatorCli cli = mockValidatorCliWithService(cliContext);
ValidatorWatchMode watchMode = ValidatorWatchMode.NONE;
cli.readParamsAndExecuteTask(cliContext, args); cli.readParamsAndExecuteTask(cliContext, args);
Mockito.verify(validationService).determineVersion(same(cliContext)); Mockito.verify(validationService).determineVersion(same(cliContext));
Mockito.verify(validationService).validateSources(same(cliContext), same(validationEngine)); Mockito.verify(validationService).validateSources(same(cliContext), same(validationEngine), same(watchMode));
} }
@Test @Test