Skip to content

Commit

Permalink
folding for cron triggers spec
Browse files Browse the repository at this point in the history
  • Loading branch information
brig committed Jan 17, 2025
1 parent e65074f commit 2444528
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 3 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# concord-intellij-plugin Changelog

## [Unreleased]
- folding for cron triggers spec

## [0.10.0]
- logYaml step
- extraDependencies in Profile definition
- logYaml step
- extraDependencies in Profile definition
- Intellij version up

## [0.6.2]
Expand Down Expand Up @@ -75,4 +76,4 @@

## [0.0.1 - 2022-11-07]
### Added
- Initial version
- Initial version
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ dependencies {
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("junit:junit:4.13.2")

implementation("com.cronutils:cron-utils:9.2.0")
}

kotlin {
Expand Down
83 changes: 83 additions & 0 deletions src/main/java/brig/concord/folding/CronExpressionFolding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package brig.concord.folding;

import brig.concord.psi.ProcessDefinitionProvider;
import com.cronutils.descriptor.CronDescriptor;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
import com.intellij.lang.folding.CustomFoldingBuilder;
import com.intellij.openapi.util.TextRange;
import brig.concord.psi.ConcordFile;
import com.intellij.lang.ASTNode;
import com.intellij.lang.folding.FoldingDescriptor;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.yaml.psi.YAMLKeyValue;
import org.jetbrains.yaml.psi.YAMLMapping;

import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.regex.Pattern;

public class CronExpressionFolding extends CustomFoldingBuilder {

private static final Pattern INVALID_CHARS_REGEX = Pattern.compile("[^\\d|A-Z? \\-,/*#]");
private static final CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
private static final CronDescriptor descriptor = CronDescriptor.instance(Locale.getDefault());

@Override
protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) {
return true;
}

@Override
protected void buildLanguageFoldRegions(@NotNull List<FoldingDescriptor> descriptors, @NotNull PsiElement root, @NotNull Document document, boolean quick) {
if (!(root.getContainingFile() instanceof ConcordFile)) {
return;
}

ProcessDefinitionProvider.getInstance().get(root).triggers().stream()
.flatMap(seqItem -> seqItem.getKeysValues().stream())
.filter(kv -> kv.getKey() != null && "cron".equals(kv.getKey().getText()))
.map(YAMLKeyValue::getValue)
.filter(v -> v instanceof YAMLMapping)
.map(YAMLMapping.class::cast)
.map(mapping -> mapping.getKeyValueByKey("spec"))
.filter(Objects::nonNull)
.map(YAMLKeyValue::getValue)
.filter(Objects::nonNull)
.forEach(v -> descriptors.add(new FoldingDescriptor(v, v.getTextRange())));
}

@Override
protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) {
var text = node.getText().trim().replaceAll("'", "").replaceAll("\"", "");
if (!isCronExpression(text)) {
return null;
}

try {
return descriptor.describe(parser.parse(text));
} catch (Exception e) {
// ignore
}

return "invalid cron expression";
}

private static boolean isCronExpression(String expression) {
if (expression == null || expression.isBlank()) {
return false;
}

int expressionParts = expression.split(" ", 8).length;

if (expressionParts < 5 || expressionParts > 7) {
return false;
}

return !INVALID_CHARS_REGEX.matcher(expression).find();
}
}
9 changes: 9 additions & 0 deletions src/main/java/brig/concord/psi/ProcessDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.CommonProcessors;
import com.intellij.util.indexing.FileBasedIndex;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.yaml.psi.*;

Expand All @@ -39,6 +40,14 @@ private YAMLSequence resources(String name) {
return YamlPsiUtils.get(rootDoc, YAMLSequence.class, "resources", name);
}

public @NotNull List<YAMLSequenceItem> triggers() {
var seq = YamlPsiUtils.get(rootDoc, YAMLSequence.class, "triggers");
if (seq == null) {
return List.of();
}
return seq.getItems();
}

@Nullable
public PsiElement flow(String name) {
Project project = rootDoc.getProject();
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<!-- <lang.findUsagesProvider language="Concord" order="before yamlFindUsagesProvider"-->
<!-- implementationClass="brig.concord.FindUsageProvider"/>-->

<!-- <annotator language="yaml" implementationClass="brig.concord.annotator.CronExpressionAnnotator"/>-->
<lang.foldingBuilder language="yaml" implementationClass="brig.concord.folding.CronExpressionFolding"/>

<lang.findUsagesProvider language="yaml" order="before yamlFindUsagesProvider" implementationClass="brig.concord.FindUsageProvider"/>
<usageTypeProvider implementation="brig.concord.FlowUsageTypeProvider"/>

Expand Down

0 comments on commit 2444528

Please sign in to comment.