Add support for "<<" anchor references in application.yml

This commit is contained in:
Kris De Volder
2020-03-31 16:12:13 -07:00
parent 4e29c9d4c3
commit 17af13e448
5 changed files with 57 additions and 24 deletions

View File

@@ -148,4 +148,22 @@ public class NodeUtil {
return new DocumentRegion(doc, tup.getKeyNode().getStartMark().getIndex(), tup.getValueNode().getEndMark().getIndex());
}
/**
* Detects whether a given map key-value pair is anchored. I.e. corresponds to
* a bit of yaml like this example:
*
* <pre>
* some-key: &some-anchor
* blah: blah
* more: blah
* </pre>
*/
public static boolean isAnchored(NodeTuple entry) {
if (entry!=null) {
Node v = entry.getValueNode();
return v!=null && v.getAnchor()!=null;
}
return false;
}
}

View File

@@ -28,7 +28,6 @@ import org.springframework.ide.vscode.commons.yaml.ast.NodeRef.TupleKeyRef;
import org.springframework.ide.vscode.commons.yaml.ast.NodeRef.TupleValueRef;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.SequenceNode;
/**
@@ -157,22 +156,4 @@ public class YamlFileAST {
public IDocument getDocument() {
return doc;
}
/**
* Detects whether a given map key-value pair is anchored. I.e. corresponds to
* a bit of yaml like this example:
*
* <pre>
* some-key: &some-anchor
* blah: blah
* more: blah
* </pre>
*/
public boolean isAnchored(NodeTuple entry) {
if (entry!=null) {
Node v = entry.getValueNode();
return v!=null && v.getAnchor()!=null;
}
return false;
}
}

View File

@@ -171,7 +171,7 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
} else {
YTypedProperty prop = beanProperties.get(key);
if (prop==null) {
if (!ast.isAnchored(entry)) {
if (!NodeUtil.isAnchored(entry)) {
unknownBeanProperty(keyNode, type, key);
}
} else {

View File

@@ -49,6 +49,7 @@ import org.springframework.ide.vscode.commons.util.ValueParseException;
import org.springframework.ide.vscode.commons.util.ValueParser;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.ast.NodeMergeSupport;
import org.springframework.ide.vscode.commons.yaml.ast.NodeRef;
import org.springframework.ide.vscode.commons.yaml.ast.NodeRef.Kind;
import org.springframework.ide.vscode.commons.yaml.ast.NodeRef.TupleValueRef;
@@ -72,6 +73,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
private final IProblemCollector problems;
private final TypeUtil typeUtil;
private final IndexNavigator nav;
private final NodeMergeSupport nodeMerger;
private AppYamlQuickfixes quickFixes;
public ApplicationYamlASTReconciler(IProblemCollector problems, IndexNavigator nav, TypeUtil typeUtil, AppYamlQuickfixes quickFixes) {
@@ -79,6 +81,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
this.typeUtil = typeUtil;
this.nav = nav;
this.quickFixes = quickFixes;
this.nodeMerger = new NodeMergeSupport(problems);
}
@Override
@@ -98,8 +101,10 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
protected void reconcile(YamlFileAST root, Node node, IndexNavigator nav) {
switch (node.getNodeId()) {
case mapping:
checkForDuplicateKeys((MappingNode)node);
for (NodeTuple entry : ((MappingNode)node).getValue()) {
MappingNode map = (MappingNode) node;
nodeMerger.flattenMapping(map);
checkForDuplicateKeys(map);
for (NodeTuple entry : map.getValue()) {
reconcile(root, entry, nav);
}
break;
@@ -183,7 +188,9 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
} else {
//both are null, this means there's no valid property with the current prefix
//whether exact or extending it with further navigation
unkownProperty(root.getDocument().getUri(), keyNode, subNav.getPrefix(), entry, quickFixes.MISSING_PROPERTY);
if (!NodeUtil.isAnchored(entry)) { //See https://github.com/spring-projects/sts4/issues/420
unkownProperty(root.getDocument().getUri(), keyNode, subNav.getPrefix(), entry, quickFixes.MISSING_PROPERTY);
}
}
}
}
@@ -221,6 +228,7 @@ public class ApplicationYamlASTReconciler implements YamlASTReconciler {
}
private void reconcile(YamlFileAST root, MappingNode mapping, Type type) {
nodeMerger.flattenMapping(mapping);
checkForDuplicateKeys(mapping);
if (typeUtil.isAtomic(type)) {
expectTypeFoundMapping(type, mapping);

View File

@@ -89,7 +89,33 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
////////////////////////////////////////////////////////////////////////////////////////
@Test public void GH_404_ConsutructorBinding_support() throws Exception {
@Test public void GH_420_anchorReference() throws Exception {
Editor editor;
data("config.bob", "java.lang.String", null, null);
data("config.dude", "java.lang.String", null, null);
editor = newEditor(
"configref: &config\n" +
" bob: bob\n" +
" asdf: dude\n" +
"config:\n" +
" <<: *config"
);
editor.assertProblems("asdf|Unknown");
editor = newEditor(
"configref: &config\n" +
" bob: bob\n" +
" asdf: dude\n" +
"config: *config"
);
editor.assertProblems(
"asdf|Unknown"
);
}
@Test public void GH_404_ConstructorBinding_support() throws Exception {
useProject(createPredefinedMavenProject("gh_404"));
Editor editor;