-
-
Notifications
You must be signed in to change notification settings - Fork 463
Add optional rule UID to DSL Rule file syntax #5449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5056413
d1e460b
fbad5aa
2ea8dd0
203f0bb
90e09ee
7375e71
627afec
fee97bf
22b710e
0b69863
577f57b
36da40e
dd628e0
15a853f
0e3b9e3
fcca257
e6ace1c
62bda5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,8 @@ | |||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| package org.openhab.core.model.rule.runtime.internal; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import static org.openhab.core.model.core.ModelCoreConstants.isIsolatedModel; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import java.util.ArrayList; | ||||||||||||||||||||||||||
| import java.util.Collection; | ||||||||||||||||||||||||||
| import java.util.Iterator; | ||||||||||||||||||||||||||
|
|
@@ -105,6 +107,7 @@ | |||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @author Kai Kreuzer - Initial contribution | ||||||||||||||||||||||||||
| * @author Laurent Garnier - Add support for conditions | ||||||||||||||||||||||||||
| * @author Laurent Garnier - Add optional rule UID + registry notification refactoring | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| @NonNullByDefault | ||||||||||||||||||||||||||
| @Component(immediate = true, service = { DSLRuleProvider.class, RuleProvider.class, DSLScriptContextProvider.class }) | ||||||||||||||||||||||||||
|
|
@@ -115,7 +118,7 @@ public class DSLRuleProvider | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private final Logger logger = LoggerFactory.getLogger(DSLRuleProvider.class); | ||||||||||||||||||||||||||
| private final Collection<ProviderChangeListener<Rule>> listeners = new ArrayList<>(); | ||||||||||||||||||||||||||
| private final Map<String, Rule> rules = new ConcurrentHashMap<>(); | ||||||||||||||||||||||||||
| private final Map<String, List<Rule>> rulesMap = new ConcurrentHashMap<>(); | ||||||||||||||||||||||||||
| private final Map<String, IEvaluationContext> contexts = new ConcurrentHashMap<>(); | ||||||||||||||||||||||||||
| private final Map<String, XExpression> xExpressions = new ConcurrentHashMap<>(); | ||||||||||||||||||||||||||
| private final ReadyMarker marker = new ReadyMarker("rules", "dslprovider"); | ||||||||||||||||||||||||||
|
|
@@ -139,7 +142,7 @@ protected void activate() { | |||||||||||||||||||||||||
| @Deactivate | ||||||||||||||||||||||||||
| protected void deactivate() { | ||||||||||||||||||||||||||
| modelRepository.removeModelRepositoryChangeListener(this); | ||||||||||||||||||||||||||
| rules.clear(); | ||||||||||||||||||||||||||
| rulesMap.clear(); | ||||||||||||||||||||||||||
| contexts.clear(); | ||||||||||||||||||||||||||
| xExpressions.clear(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
@@ -150,82 +153,106 @@ public void addProviderChangeListener(ProviderChangeListener<Rule> listener) { | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||
| public Collection<Rule> getAll() { | ||||||||||||||||||||||||||
| return rules.values(); | ||||||||||||||||||||||||||
| public void removeProviderChangeListener(ProviderChangeListener<Rule> listener) { | ||||||||||||||||||||||||||
| listeners.remove(listener); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||
| public void removeProviderChangeListener(ProviderChangeListener<Rule> listener) { | ||||||||||||||||||||||||||
| listeners.remove(listener); | ||||||||||||||||||||||||||
| public Collection<Rule> getAll() { | ||||||||||||||||||||||||||
| // Ignore isolated models | ||||||||||||||||||||||||||
| return rulesMap.entrySet().stream().filter(e -> !isIsolatedModel(e.getKey())) | ||||||||||||||||||||||||||
| .flatMap(e -> e.getValue().stream()).toList(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Returns all rules originating from the given model name. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @param modelFileName the full model file name, including ".rules" or ".script" extension | ||||||||||||||||||||||||||
| * @return the rules associated with the given model name, or an empty collection if none exist | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| public Collection<Rule> getAllFromModel(String modelFileName) { | ||||||||||||||||||||||||||
| return List.copyOf(rulesMap.getOrDefault(modelFileName, List.of())); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||
| public void modelChanged(String modelFileName, EventType type) { | ||||||||||||||||||||||||||
| String ruleModelType = modelFileName.substring(modelFileName.lastIndexOf(".") + 1); | ||||||||||||||||||||||||||
| List<Rule> oldRules; | ||||||||||||||||||||||||||
| List<Rule> newRules = new ArrayList<>(); | ||||||||||||||||||||||||||
| if ("rules".equalsIgnoreCase(ruleModelType)) { | ||||||||||||||||||||||||||
| boolean isolated = isIsolatedModel(modelFileName); | ||||||||||||||||||||||||||
| String ruleModelName = modelFileName.substring(0, modelFileName.lastIndexOf(".")); | ||||||||||||||||||||||||||
| List<ModelRulePair> modelRules = new ArrayList<>(); | ||||||||||||||||||||||||||
| switch (type) { | ||||||||||||||||||||||||||
| case ADDED: | ||||||||||||||||||||||||||
| case MODIFIED: | ||||||||||||||||||||||||||
| EObject model = modelRepository.getModel(modelFileName); | ||||||||||||||||||||||||||
| int index = 1; | ||||||||||||||||||||||||||
| if (model instanceof RuleModel ruleModel) { | ||||||||||||||||||||||||||
| int index = 1; | ||||||||||||||||||||||||||
| for (org.openhab.core.model.rule.rules.Rule rule : ruleModel.getRules()) { | ||||||||||||||||||||||||||
| Rule newRule = toRule(ruleModelName, rule, index); | ||||||||||||||||||||||||||
| rules.put(newRule.getUID(), newRule); | ||||||||||||||||||||||||||
| xExpressions.put(ruleModelName + "-" + index, rule.getScript()); | ||||||||||||||||||||||||||
| modelRules.add(new ModelRulePair(newRule, null)); | ||||||||||||||||||||||||||
| newRules.add(toRule(ruleModelName, rule, index)); | ||||||||||||||||||||||||||
| if (!isolated) { | ||||||||||||||||||||||||||
| xExpressions.put(ruleModelName + "-" + index, rule.getScript()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| index++; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| handleVarDeclarations(ruleModelName, ruleModel); | ||||||||||||||||||||||||||
| if (!isolated) { | ||||||||||||||||||||||||||
| handleVarDeclarations(ruleModelName, ruleModel); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| case MODIFIED: | ||||||||||||||||||||||||||
| removeRuleModel(ruleModelName); | ||||||||||||||||||||||||||
| EObject modifiedModel = modelRepository.getModel(modelFileName); | ||||||||||||||||||||||||||
| if (modifiedModel instanceof RuleModel ruleModel) { | ||||||||||||||||||||||||||
| int index = 1; | ||||||||||||||||||||||||||
| for (org.openhab.core.model.rule.rules.Rule rule : ruleModel.getRules()) { | ||||||||||||||||||||||||||
| Rule newRule = toRule(ruleModelName, rule, index); | ||||||||||||||||||||||||||
| Rule oldRule = rules.remove(ruleModelName); | ||||||||||||||||||||||||||
| rules.put(newRule.getUID(), newRule); | ||||||||||||||||||||||||||
| xExpressions.put(ruleModelName + "-" + index, rule.getScript()); | ||||||||||||||||||||||||||
| modelRules.add(new ModelRulePair(newRule, oldRule)); | ||||||||||||||||||||||||||
| oldRules = rulesMap.put(modelFileName, newRules); | ||||||||||||||||||||||||||
| if (!isolated) { | ||||||||||||||||||||||||||
| // Cleanup xExpressions for old rules | ||||||||||||||||||||||||||
| int nbOldRules = oldRules == null ? 0 : oldRules.size(); | ||||||||||||||||||||||||||
| while (index <= nbOldRules) { | ||||||||||||||||||||||||||
| xExpressions.remove(ruleModelName + "-" + index); | ||||||||||||||||||||||||||
| index++; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
lolodomo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
| handleVarDeclarations(ruleModelName, ruleModel); | ||||||||||||||||||||||||||
| // Cleanup contexts if no new rules | ||||||||||||||||||||||||||
| if (newRules.isEmpty()) { | ||||||||||||||||||||||||||
| contexts.remove(ruleModelName); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| notifyProviderChangeListeners(calcChanges(modelFileName, oldRules, newRules)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| case REMOVED: | ||||||||||||||||||||||||||
| removeRuleModel(ruleModelName); | ||||||||||||||||||||||||||
| oldRules = rulesMap.remove(modelFileName); | ||||||||||||||||||||||||||
| if (!isolated) { | ||||||||||||||||||||||||||
| for (Iterator<Entry<String, XExpression>> it = xExpressions.entrySet().iterator(); it | ||||||||||||||||||||||||||
| .hasNext();) { | ||||||||||||||||||||||||||
| Entry<String, XExpression> entry = it.next(); | ||||||||||||||||||||||||||
| if (belongsToModel(entry.getKey(), ruleModelName)) { | ||||||||||||||||||||||||||
| it.remove(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| contexts.remove(ruleModelName); | ||||||||||||||||||||||||||
| notifyProviderChangeListeners(calcChanges(modelFileName, oldRules, null)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||
| logger.debug("Unknown event type."); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| notifyProviderChangeListeners(modelRules); | ||||||||||||||||||||||||||
| } else if ("script".equals(ruleModelType)) { | ||||||||||||||||||||||||||
| List<ModelRulePair> modelRules = new ArrayList<>(); | ||||||||||||||||||||||||||
| switch (type) { | ||||||||||||||||||||||||||
| case MODIFIED: | ||||||||||||||||||||||||||
| case ADDED: | ||||||||||||||||||||||||||
| case MODIFIED: | ||||||||||||||||||||||||||
| EObject model = modelRepository.getModel(modelFileName); | ||||||||||||||||||||||||||
| if (model instanceof Script script) { | ||||||||||||||||||||||||||
| Rule oldRule = rules.remove(modelFileName); | ||||||||||||||||||||||||||
| Rule newRule = toRule(modelFileName, script); | ||||||||||||||||||||||||||
| rules.put(newRule.getUID(), newRule); | ||||||||||||||||||||||||||
| modelRules.add(new ModelRulePair(newRule, oldRule)); | ||||||||||||||||||||||||||
| newRules.add(toRule(modelFileName, script)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| oldRules = rulesMap.put(modelFileName, newRules); | ||||||||||||||||||||||||||
| if (!isIsolatedModel(modelFileName)) { | ||||||||||||||||||||||||||
| notifyProviderChangeListeners(calcChanges(modelFileName, oldRules, newRules)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| case REMOVED: | ||||||||||||||||||||||||||
| Rule oldRule = rules.remove(modelFileName); | ||||||||||||||||||||||||||
| if (oldRule != null) { | ||||||||||||||||||||||||||
| listeners.forEach(listener -> listener.removed(this, oldRule)); | ||||||||||||||||||||||||||
| oldRules = rulesMap.remove(modelFileName); | ||||||||||||||||||||||||||
| if (!isIsolatedModel(modelFileName)) { | ||||||||||||||||||||||||||
| notifyProviderChangeListeners(calcChanges(modelFileName, oldRules, null)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||
| logger.debug("Unknown event type."); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| notifyProviderChangeListeners(modelRules); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -244,24 +271,42 @@ private void handleVarDeclarations(String modelName, RuleModel ruleModel) { | |||||||||||||||||||||||||
| contexts.put(modelName, context); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private void removeRuleModel(String modelName) { | ||||||||||||||||||||||||||
| Iterator<Entry<String, Rule>> it = rules.entrySet().iterator(); | ||||||||||||||||||||||||||
| while (it.hasNext()) { | ||||||||||||||||||||||||||
| Entry<String, Rule> entry = it.next(); | ||||||||||||||||||||||||||
| if (belongsToModel(entry.getKey(), modelName)) { | ||||||||||||||||||||||||||
| listeners.forEach(listener -> listener.removed(this, entry.getValue())); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| it.remove(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| private Changes calcChanges(String modelFileName, @Nullable List<Rule> oldRules, @Nullable List<Rule> newRules) { | ||||||||||||||||||||||||||
| if (oldRules == null || oldRules.isEmpty()) { | ||||||||||||||||||||||||||
| return new Changes(newRules == null ? List.of() : List.copyOf(newRules), List.of(), List.of()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Iterator<Entry<String, XExpression>> it2 = xExpressions.entrySet().iterator(); | ||||||||||||||||||||||||||
| while (it2.hasNext()) { | ||||||||||||||||||||||||||
| Entry<String, XExpression> entry = it2.next(); | ||||||||||||||||||||||||||
| if (belongsToModel(entry.getKey(), modelName)) { | ||||||||||||||||||||||||||
| it2.remove(); | ||||||||||||||||||||||||||
| List<Rule> oldMutable = new ArrayList<>(oldRules); | ||||||||||||||||||||||||||
| List<Rule> newMutable = newRules == null ? new ArrayList<>() : new ArrayList<>(newRules); | ||||||||||||||||||||||||||
| List<RulePair> modified = new ArrayList<>(); | ||||||||||||||||||||||||||
| Rule oldRule, newRule; | ||||||||||||||||||||||||||
| boolean found; | ||||||||||||||||||||||||||
| for (Iterator<Rule> iterator = oldMutable.iterator(); iterator.hasNext();) { | ||||||||||||||||||||||||||
| oldRule = iterator.next(); | ||||||||||||||||||||||||||
| found = false; | ||||||||||||||||||||||||||
| String uid = oldRule.getUID(); | ||||||||||||||||||||||||||
| for (Iterator<Rule> newIterator = newMutable.iterator(); newIterator.hasNext() && !found;) { | ||||||||||||||||||||||||||
|
Comment on lines
+283
to
+287
|
||||||||||||||||||||||||||
| newRule = newIterator.next(); | ||||||||||||||||||||||||||
| if (uid.equals(newRule.getUID())) { | ||||||||||||||||||||||||||
| modified.add(new RulePair(oldRule, newRule)); | ||||||||||||||||||||||||||
| newIterator.remove(); | ||||||||||||||||||||||||||
| found = true; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (!found) { | ||||||||||||||||||||||||||
| // Check if the old rule exists in another model file with the same UID | ||||||||||||||||||||||||||
| Rule existingRule = rulesMap.entrySet().stream() | ||||||||||||||||||||||||||
| .filter(e -> !e.getKey().equals(modelFileName) && !isIsolatedModel(e.getKey())) | ||||||||||||||||||||||||||
| .flatMap(e -> e.getValue().stream()).filter(r -> uid.equals(r.getUID())).findAny().orElse(null); | ||||||||||||||||||||||||||
lolodomo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
| if (existingRule != null) { | ||||||||||||||||||||||||||
| modified.add(new RulePair(oldRule, existingRule)); | ||||||||||||||||||||||||||
| found = true; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (found) { | ||||||||||||||||||||||||||
| iterator.remove(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| contexts.remove(modelName); | ||||||||||||||||||||||||||
| return new Changes(newMutable, modified, oldMutable); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private boolean belongsToModel(String id, String modelName) { | ||||||||||||||||||||||||||
|
|
@@ -287,7 +332,10 @@ private Rule toRule(String modelName, Script script) { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private Rule toRule(String modelName, org.openhab.core.model.rule.rules.Rule rule, int index) { | ||||||||||||||||||||||||||
| String name = rule.getName(); | ||||||||||||||||||||||||||
| String uid = modelName + "-" + index; | ||||||||||||||||||||||||||
| String uid = rule.getUid(); | ||||||||||||||||||||||||||
| if (uid == null || uid.isBlank()) { | ||||||||||||||||||||||||||
| uid = modelName + "-" + index; | ||||||||||||||||||||||||||
|
Comment on lines
+335
to
+337
|
||||||||||||||||||||||||||
| String uid = rule.getUid(); | |
| if (uid == null || uid.isBlank()) { | |
| uid = modelName + "-" + index; | |
| String autoUid = modelName + "-" + index; | |
| String uid = rule.getUid(); | |
| if (uid == null || uid.isBlank()) { | |
| uid = autoUid; | |
| } else if (uid.indexOf('/') >= 0) { | |
| logger.warn( | |
| "Ignoring invalid UID '{}' for rule '{}' in model '{}': character '/' is not allowed in rule UIDs. Using auto-generated UID '{}'.", | |
| uid, name, modelName, autoUid); | |
| uid = autoUid; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly the kind of thing I was thinking of when I referred to problematic characters that we don't yet know about. I'd say that it "proves" that #5467 is necessary, and that / must be excluded (this is assuming that copilot's claim is true, but I think I've seen code doing things like that).
Copilot
AI
Apr 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User-provided rule UIDs from the DSL are accepted verbatim (only blank/null falls back to auto-generated). Because rule UIDs are embedded directly into event topics (e.g., openhab/rules/{ruleID}/...), a UID containing '/' will produce an invalid topic that RuleEventFactory cannot parse (it expects exactly 4 topic segments). Add validation/sanitization for configured UIDs (at minimum reject '/' and fall back to the auto-generated UID, ideally with a warning log) to prevent runtime event failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a separate PR, #5467, that deals with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User-provided rule UIDs from the DSL are accepted verbatim (only blank/null falls back to auto-generated). Because rule UIDs are embedded directly into event topics (e.g., openhab/rules/{ruleID}/...), a UID containing '/' will produce an invalid topic that RuleEventFactory cannot parse (it expects exactly 4 topic segments). Add validation/sanitization for configured UIDs (at minimum reject '/' and fall back to the auto-generated UID, ideally with a warning log) to prevent runtime event failures.
I think this comment from copilot is the best reason to reject my wild idea. It does correctly point out the UID should be validated more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Nadahar : maybe it is good to exclude the / in that PR, even if there is a more general discussion in parallel in another PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,7 +12,7 @@ VariableDeclaration: | |||||||||||||||||||
| ; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Rule: | ||||||||||||||||||||
| 'rule' name=(STRING|ID) ('[' tags+=(ID|STRING) (',' tags+=(ID|STRING))* ']')? | ||||||||||||||||||||
| 'rule' name=(STRING|ID) ('uid' '='? uid=(STRING|ID))? ('[' tags+=(ID|STRING) (',' tags+=(ID|STRING))* ']')? | ||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why make the = sign optional? I see potential for parser issues when anything is ever changed to the syntax (add a field).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No equal sign - neither mandatory, nor optional - is also a viable approach.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think that would be inconsistent with what has been done in other DSL formats.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was referring to the other formats, e.g. openhab-core/bundles/org.openhab.core.model.item/src/org/openhab/core/model/Items.xtext Lines 32 to 39 in 911e102
openhab-core/bundles/org.openhab.core.model.thing/src/org/openhab/core/model/thing/Thing.xtext Line 68 in 911e102
I also think it's "safer" to have a more explicit syntax, it allows more flexibility for potential future changes to the format.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not far from forgiving and closing that PR...
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My suggestion, make = required to make this explicit and be done with it. I am fine with all else, so when I find the time we can proceed. |
||||||||||||||||||||
| 'when' eventtrigger+=EventTrigger ('or' eventtrigger+=EventTrigger)* | ||||||||||||||||||||
| ('but' 'only' 'if' conditions+=Condition ('and' conditions+=Condition)*)? | ||||||||||||||||||||
| 'then' script=XExpressionInClosure | ||||||||||||||||||||
|
|
||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.