mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
WEB-25281 JSON Schema: support 'pattern' for checking property value
This commit is contained in:
@@ -373,10 +373,13 @@ class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// todo: regular expressions, format
|
||||
/*if (schema.getPattern() != null) {
|
||||
LOG.info("Unsupported property used: 'pattern'");
|
||||
if (schema.getPattern() != null) {
|
||||
if (!schema.checkByPattern(value)) {
|
||||
error("String is violating the pattern: '" + schema.getPattern() + "'", propValue);
|
||||
}
|
||||
}
|
||||
// I think we are not gonna to support format, there are a couple of RFCs there to check upon..
|
||||
/*
|
||||
if (schema.getFormat() != null) {
|
||||
LOG.info("Unsupported property used: 'format'");
|
||||
}*/
|
||||
|
||||
@@ -26,6 +26,7 @@ public class JsonSchemaObject {
|
||||
private Map<String, JsonSchemaObject> myProperties;
|
||||
private Map<String, JsonSchemaObject> myPatternProperties;
|
||||
private final PatternCalculator myPatternCalculator = new PatternCalculator();
|
||||
private final PatternCalculator myValuesPatternCalculator = new PatternCalculator();
|
||||
|
||||
private String myId;
|
||||
private String mySchema;
|
||||
@@ -97,6 +98,7 @@ public class JsonSchemaObject {
|
||||
myDefinitions = other.myDefinitions;
|
||||
myPatternProperties = other.myPatternProperties;
|
||||
myPatternCalculator.clear();
|
||||
myValuesPatternCalculator.clear();
|
||||
|
||||
myType = other.myType;
|
||||
myDefault = other.myDefault;
|
||||
@@ -142,6 +144,7 @@ public class JsonSchemaObject {
|
||||
myDefinitions = copyMap(myDefinitions, other.myDefinitions);
|
||||
myPatternProperties = copyMap(myPatternProperties, other.myPatternProperties);
|
||||
myPatternCalculator.clear();
|
||||
myValuesPatternCalculator.clear();
|
||||
if (!StringUtil.isEmptyOrSpaces(other.myDescription)) {
|
||||
myDescription = other.myDescription;
|
||||
}
|
||||
@@ -305,6 +308,7 @@ public class JsonSchemaObject {
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
myPattern = pattern;
|
||||
myValuesPatternCalculator.clear();
|
||||
}
|
||||
|
||||
public Boolean getAdditionalPropertiesAllowed() {
|
||||
@@ -538,14 +542,14 @@ public class JsonSchemaObject {
|
||||
|
||||
@Nullable
|
||||
public JsonSchemaObject getMatchingPatternPropertySchema(@NotNull String name) {
|
||||
return myPatternCalculator.getMatchingPatternPropertySchema(myPatternProperties, name);
|
||||
if (myPatternProperties == null) return null;
|
||||
final String pattern = myPatternCalculator.selectMatchingPattern(myPatternProperties.keySet(), name);
|
||||
return pattern == null ? null : myPatternProperties.get(pattern);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String adaptSchemaPattern(String pattern) {
|
||||
pattern = pattern.startsWith("^") || pattern.startsWith("*") || pattern.startsWith(".") ? pattern : (".*" + pattern);
|
||||
pattern = pattern.endsWith("+") || pattern.endsWith("*") ? pattern : (pattern + ".*");
|
||||
return pattern;
|
||||
public boolean checkByPattern(@NotNull String value) {
|
||||
if (getPattern() == null) return true;
|
||||
return getPattern().equals(myValuesPatternCalculator.selectMatchingPattern(Collections.singletonList(getPattern()), value));
|
||||
}
|
||||
|
||||
public static void iterateAllInnerSchemas(@NotNull final JsonSchemaObject object, @NotNull final SchemaConsumer schemaConsumer) {
|
||||
@@ -603,22 +607,17 @@ public class JsonSchemaObject {
|
||||
private SLRUMap<String, String> myCachedPatternProperties;
|
||||
|
||||
@Nullable
|
||||
public JsonSchemaObject getMatchingPatternPropertySchema(@Nullable final Map<String, JsonSchemaObject> patternProperties,
|
||||
@NotNull final String name) {
|
||||
if (patternProperties == null || patternProperties.isEmpty()) return null;
|
||||
final Map<String, Pattern> patterns;
|
||||
public String selectMatchingPattern(@Nullable final Collection<String> patterns, @NotNull final String name) {
|
||||
if (patterns == null || patterns.isEmpty()) return null;
|
||||
final Map<String, Pattern> cachedPatterns;
|
||||
synchronized (myLock) {
|
||||
if (myCachedPatterns == null) {
|
||||
initPatternCache(patternProperties);
|
||||
} else {
|
||||
assert myCachedPatternProperties != null;
|
||||
final String s = myCachedPatternProperties.get(name);
|
||||
if (s != null) return patternProperties.get(s);
|
||||
}
|
||||
patterns = new HashMap<>(myCachedPatterns);
|
||||
initPatternCache(patterns);
|
||||
final String s = myCachedPatternProperties.get(name);
|
||||
if (s != null) return s;
|
||||
cachedPatterns = new HashMap<>(myCachedPatterns);
|
||||
}
|
||||
|
||||
return matchPatternsToString(name, patternProperties, patterns);
|
||||
return matchPatternsToString(name, patterns, cachedPatterns);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@@ -628,14 +627,13 @@ public class JsonSchemaObject {
|
||||
}
|
||||
}
|
||||
|
||||
private JsonSchemaObject matchPatternsToString(@NotNull final String name,
|
||||
@NotNull final Map<String, JsonSchemaObject> patternProperties,
|
||||
@NotNull Map<String, Pattern> patterns) {
|
||||
final List<String> strings = new ArrayList<>(patternProperties.keySet());
|
||||
private String matchPatternsToString(@NotNull final String name, @NotNull final Collection<String> patterns,
|
||||
@NotNull Map<String, Pattern> cachedPatterns) {
|
||||
final List<String> strings = new ArrayList<>(patterns);
|
||||
Collections.sort(strings);
|
||||
|
||||
for (final String pattern : strings) {
|
||||
final Pattern compiledPattern = patterns.get(pattern);
|
||||
final Pattern compiledPattern = cachedPatterns.get(pattern);
|
||||
assert compiledPattern != null;
|
||||
try {
|
||||
final boolean matches = compiledPattern.matcher(StringUtil.newBombedCharSequence(name, 300)).matches();
|
||||
@@ -643,24 +641,35 @@ public class JsonSchemaObject {
|
||||
synchronized (myLock) {
|
||||
if (myCachedPatterns.containsKey(pattern)) myCachedPatternProperties.put(name, pattern);
|
||||
}
|
||||
return patternProperties.get(pattern);
|
||||
return pattern;
|
||||
}
|
||||
} catch (ProcessCanceledException e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
synchronized (myLock) {
|
||||
if (myCachedPatterns.equals(patterns)) myCachedPatternProperties.put(name, "");
|
||||
if (myCachedPatterns.equals(cachedPatterns)) myCachedPatternProperties.put(name, "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initPatternCache(@NotNull final Map<String, JsonSchemaObject> patternProperties) {
|
||||
myCachedPatterns = new HashMap<>(patternProperties.size(), 1.0f);
|
||||
myCachedPatternProperties = new SLRUMap<>(100, 100);
|
||||
for (String pattern : patternProperties.keySet()) {
|
||||
myCachedPatterns.put(pattern, Pattern.compile(adaptSchemaPattern(pattern)));
|
||||
private void initPatternCache(@NotNull final Collection<String> patterns) {
|
||||
if (myCachedPatterns == null) {
|
||||
myCachedPatterns = new HashMap<>(patterns.size());
|
||||
myCachedPatternProperties = new SLRUMap<>(100, 100);
|
||||
}
|
||||
for (String pattern : patterns) {
|
||||
if (!myCachedPatterns.containsKey(pattern))
|
||||
myCachedPatterns.put(pattern, Pattern.compile(adaptSchemaPattern(pattern)));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String adaptSchemaPattern(String pattern) {
|
||||
pattern = pattern.startsWith("^") || pattern.startsWith("*") || pattern.startsWith(".") ? pattern : (".*" + pattern);
|
||||
pattern = pattern.endsWith("+") || pattern.endsWith("*") || pattern.endsWith("$") ? pattern : (pattern + ".*");
|
||||
pattern = pattern.replace("\\\\", "\\");
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,14 @@ import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaAnnotator;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 9/21/2015.
|
||||
@@ -360,6 +363,29 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
"}");
|
||||
}
|
||||
|
||||
public void testPatternForPropertyValue() throws Exception {
|
||||
final String schema = "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"withPattern\": {\n" +
|
||||
" \"pattern\": \"p[0-9]\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
final String correctText = "{\n" +
|
||||
" \"withPattern\": \"p1\"\n" +
|
||||
"}";
|
||||
final String wrongText = "{\n" +
|
||||
" \"withPattern\": <warning descr=\"String is violating the pattern: 'p[0-9]'\">\"wrong\"</warning>\n" +
|
||||
"}";
|
||||
testImpl(schema, correctText);
|
||||
testImpl(schema, wrongText);
|
||||
}
|
||||
|
||||
public void testRegexp() throws Exception {
|
||||
final Matcher matcher = Pattern.compile("^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$").matcher("(112)555-1212");
|
||||
Assert.assertTrue(matcher.matches());
|
||||
}
|
||||
|
||||
public void testRootObjectRedefinedAdditionalPropertiesForbidden() throws Exception {
|
||||
testImpl(rootObjectRedefinedSchema(), "{<warning descr=\"Property 'a' is not allowed\">\"a\": true</warning>," +
|
||||
"\"r1\": \"allowed!\"}");
|
||||
|
||||
Reference in New Issue
Block a user