mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
RUBY-20082 Apply JSON Schema to YAML
review: IDEA-CR-33311
This commit is contained in:
@@ -3,6 +3,7 @@ package com.jetbrains.jsonSchema.extension;
|
||||
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
import com.jetbrains.jsonSchema.impl.JsonOriginalPsiWalker;
|
||||
@@ -21,15 +22,22 @@ import java.util.Set;
|
||||
public interface JsonLikePsiWalker {
|
||||
JsonOriginalPsiWalker JSON_ORIGINAL_PSI_WALKER = new JsonOriginalPsiWalker();
|
||||
|
||||
boolean isName(PsiElement element);
|
||||
/**
|
||||
* Returns YES in place where a property name is expected,
|
||||
* NO in place where a property value is expected,
|
||||
* UNSURE where both property name and property value can be present
|
||||
*/
|
||||
ThreeState isName(PsiElement element);
|
||||
|
||||
boolean isPropertyWithValue(@NotNull PsiElement element);
|
||||
PsiElement goUpToCheckable(@NotNull final PsiElement element);
|
||||
@Nullable
|
||||
List<JsonSchemaVariantsTreeBuilder.Step> findPosition(@NotNull final PsiElement element, boolean forceLastTransition);
|
||||
boolean isNameQuoted();
|
||||
boolean onlyDoubleQuotesForStringLiterals();
|
||||
default boolean quotesForStringLiterals() { return true; }
|
||||
boolean hasPropertiesBehindAndNoComma(@NotNull PsiElement element);
|
||||
Set<String> getPropertyNamesOfParentObject(@NotNull PsiElement element);
|
||||
Set<String> getPropertyNamesOfParentObject(@NotNull PsiElement originalPosition, PsiElement computedPosition);
|
||||
@Nullable
|
||||
JsonPropertyAdapter getParentPropertyAdapter(@NotNull PsiElement element);
|
||||
boolean isTopJsonElement(@NotNull PsiElement element);
|
||||
@@ -46,4 +54,13 @@ public interface JsonLikePsiWalker {
|
||||
.map(extension -> extension.create(schemaObject))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
default String getDefaultObjectValue(boolean includeWhitespaces) { return "{}"; }
|
||||
@Nullable default String defaultObjectValueDescription() { return null; }
|
||||
default String getDefaultArrayValue(boolean includeWhitespaces) { return "[]"; }
|
||||
@Nullable default String defaultArrayValueDescription() { return null; }
|
||||
|
||||
default boolean invokeEnterBeforeObjectAndArray() { return false; }
|
||||
|
||||
default String getNodeTextForValidation(PsiElement element) { return element.getText(); }
|
||||
}
|
||||
|
||||
@@ -28,5 +28,4 @@ public interface JsonPropertyAdapter {
|
||||
@Nullable JsonValueAdapter getValue();
|
||||
@NotNull PsiElement getDelegate();
|
||||
@Nullable JsonObjectValueAdapter getParentObject();
|
||||
@Nullable JsonArrayValueAdapter getParentArray();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
@@ -36,14 +37,14 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isName(PsiElement element) {
|
||||
public ThreeState isName(PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof JsonObject) {
|
||||
return true;
|
||||
return ThreeState.YES;
|
||||
} else if (parent instanceof JsonProperty) {
|
||||
return PsiTreeUtil.isAncestor(((JsonProperty)parent).getNameElement(), element, false);
|
||||
return PsiTreeUtil.isAncestor(((JsonProperty)parent).getNameElement(), element, false) ? ThreeState.YES : ThreeState.NO;
|
||||
}
|
||||
return false;
|
||||
return ThreeState.NO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,8 +139,8 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPropertyNamesOfParentObject(@NotNull PsiElement element) {
|
||||
final JsonObject object = PsiTreeUtil.getParentOfType(element, JsonObject.class);
|
||||
public Set<String> getPropertyNamesOfParentObject(@NotNull PsiElement originalPosition, PsiElement computedPosition) {
|
||||
final JsonObject object = PsiTreeUtil.getParentOfType(originalPosition, JsonObject.class);
|
||||
if (object != null) {
|
||||
return object.getPropertyList().stream()
|
||||
.filter(p -> !isNameQuoted() || p.getNameElement() instanceof JsonStringLiteral)
|
||||
|
||||
@@ -147,6 +147,11 @@ class JsonSchemaAnnotatorChecker {
|
||||
if (JsonSchemaType._boolean.equals(type)) {
|
||||
checkForEnum(value.getDelegate(), schema);
|
||||
}
|
||||
else if (JsonSchemaType._string_number.equals(type)) {
|
||||
checkNumber(value.getDelegate(), schema, type);
|
||||
checkString(value.getDelegate(), schema);
|
||||
checkForEnum(value.getDelegate(), schema);
|
||||
}
|
||||
else if (JsonSchemaType._number.equals(type) || JsonSchemaType._integer.equals(type)) {
|
||||
checkNumber(value.getDelegate(), schema, type);
|
||||
checkForEnum(value.getDelegate(), schema);
|
||||
@@ -444,25 +449,25 @@ class JsonSchemaAnnotatorChecker {
|
||||
if (schema.getEnum() == null || schema.getPattern() != null) return;
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(value, schema);
|
||||
if (walker == null) return;
|
||||
final String text = StringUtil.notNullize(value.getText());
|
||||
final String text = StringUtil.notNullize(walker.getNodeTextForValidation(value));
|
||||
final List<Object> objects = schema.getEnum();
|
||||
for (Object object : objects) {
|
||||
if (walker.onlyDoubleQuotesForStringLiterals()) {
|
||||
if (object.toString().equalsIgnoreCase(text)) return;
|
||||
}
|
||||
else {
|
||||
if (equalsIgnoreQuotesAndCase(object.toString(), text)) return;
|
||||
if (equalsIgnoreQuotesAndCase(object.toString(), text, walker.quotesForStringLiterals())) return;
|
||||
}
|
||||
}
|
||||
error("Value should be one of: [" + StringUtil.join(objects, o -> o.toString(), ", ") + "]", value,
|
||||
JsonValidationError.FixableIssueKind.NonEnumValue, null);
|
||||
}
|
||||
|
||||
private static boolean equalsIgnoreQuotesAndCase(@NotNull final String s1, @NotNull final String s2) {
|
||||
private static boolean equalsIgnoreQuotesAndCase(@NotNull final String s1, @NotNull final String s2, boolean requireQuotedValues) {
|
||||
final boolean quoted1 = StringUtil.isQuotedString(s1);
|
||||
final boolean quoted2 = StringUtil.isQuotedString(s2);
|
||||
if (quoted1 != quoted2) return false;
|
||||
if (!quoted1) return s1.equalsIgnoreCase(s2);
|
||||
if (requireQuotedValues && quoted1 != quoted2) return false;
|
||||
if (requireQuotedValues && !quoted1) return s1.equalsIgnoreCase(s2);
|
||||
return StringUtil.unquoteString(s1).equalsIgnoreCase(StringUtil.unquoteString(s2));
|
||||
}
|
||||
|
||||
@@ -545,6 +550,11 @@ class JsonSchemaAnnotatorChecker {
|
||||
if (JsonSchemaType._integer.equals(input) && JsonSchemaType._number.equals(matchType)) {
|
||||
return input;
|
||||
}
|
||||
if (JsonSchemaType._string_number.equals(input) && (JsonSchemaType._number.equals(matchType)
|
||||
|| JsonSchemaType._integer.equals(matchType)
|
||||
|| JsonSchemaType._string.equals(matchType))) {
|
||||
return input;
|
||||
}
|
||||
return matchType;
|
||||
}
|
||||
}
|
||||
@@ -575,8 +585,10 @@ class JsonSchemaAnnotatorChecker {
|
||||
private void checkArrayItems(@NotNull JsonValueAdapter array, @NotNull final List<JsonValueAdapter> list, final JsonSchemaObject schema) {
|
||||
if (schema.isUniqueItems()) {
|
||||
final MultiMap<String, JsonValueAdapter> valueTexts = new MultiMap<>();
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(array.getDelegate(), schema);
|
||||
assert walker != null;
|
||||
for (JsonValueAdapter adapter : list) {
|
||||
valueTexts.putValue(adapter.getDelegate().getText(), adapter);
|
||||
valueTexts.putValue(walker.getNodeTextForValidation(adapter.getDelegate()), adapter);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Collection<JsonValueAdapter>> entry: valueTexts.entrySet()) {
|
||||
@@ -638,7 +650,9 @@ class JsonSchemaAnnotatorChecker {
|
||||
}
|
||||
|
||||
private void checkString(PsiElement propValue, JsonSchemaObject schema) {
|
||||
final String value = StringUtil.unquoteString(propValue.getText());
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(propValue, schema);
|
||||
assert walker != null;
|
||||
final String value = StringUtil.unquoteString(walker.getNodeTextForValidation(propValue));
|
||||
if (schema.getMinLength() != null) {
|
||||
if (value.length() < schema.getMinLength()) {
|
||||
error("String is shorter than " + schema.getMinLength(), propValue);
|
||||
@@ -677,9 +691,12 @@ class JsonSchemaAnnotatorChecker {
|
||||
|
||||
private void checkNumber(PsiElement propValue, JsonSchemaObject schema, JsonSchemaType schemaType) {
|
||||
Number value;
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(propValue, schema);
|
||||
assert walker != null;
|
||||
String valueText = walker.getNodeTextForValidation(propValue);
|
||||
if (JsonSchemaType._integer.equals(schemaType)) {
|
||||
try {
|
||||
value = Integer.valueOf(propValue.getText());
|
||||
value = Integer.valueOf(valueText);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
error("Integer value expected", propValue,
|
||||
@@ -690,12 +707,14 @@ class JsonSchemaAnnotatorChecker {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
value = Double.valueOf(propValue.getText());
|
||||
value = Double.valueOf(valueText);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
error("Double value expected", propValue,
|
||||
JsonValidationError.FixableIssueKind.TypeMismatch,
|
||||
new JsonValidationError.TypeMismatchIssueData(new JsonSchemaType[]{schemaType}));
|
||||
if (!JsonSchemaType._string_number.equals(schemaType)) {
|
||||
error("Double value expected", propValue,
|
||||
JsonValidationError.FixableIssueKind.TypeMismatch,
|
||||
new JsonValidationError.TypeMismatchIssueData(new JsonSchemaType[]{schemaType}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -840,7 +859,7 @@ class JsonSchemaAnnotatorChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (correct.size() == 1) return current;
|
||||
if (correct.size() == 1) return correct.get(0);
|
||||
if (correct.size() > 0) {
|
||||
final JsonSchemaType type = JsonSchemaType.getType(value);
|
||||
if (type != null) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.actions.EditorActionUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -29,6 +30,7 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider;
|
||||
@@ -131,26 +133,27 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
if (myWalker == null) return;
|
||||
final PsiElement checkable = myWalker.goUpToCheckable(myPosition);
|
||||
if (checkable == null) return;
|
||||
final boolean isName = myWalker.isName(checkable);
|
||||
final List<JsonSchemaVariantsTreeBuilder.Step> position = myWalker.findPosition(checkable, !isName);
|
||||
if (position == null || position.isEmpty() && !isName) return;
|
||||
final ThreeState isName = myWalker.isName(checkable);
|
||||
final List<JsonSchemaVariantsTreeBuilder.Step> position = myWalker.findPosition(checkable, isName == ThreeState.NO);
|
||||
if (position == null || position.isEmpty() && isName == ThreeState.NO) return;
|
||||
|
||||
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(myRootSchema, false, position).resolve();
|
||||
// too long here, refactor further
|
||||
schemas.forEach(schema -> {
|
||||
if (isName) {
|
||||
if (isName != ThreeState.NO) {
|
||||
final boolean insertComma = myWalker.hasPropertiesBehindAndNoComma(myPosition);
|
||||
final boolean hasValue = myWalker.isPropertyWithValue(myPosition.getParent().getParent());
|
||||
|
||||
final Collection<String> properties = myWalker.getPropertyNamesOfParentObject(myOriginalPosition);
|
||||
final Collection<String> properties = myWalker.getPropertyNamesOfParentObject(myOriginalPosition, myPosition);
|
||||
final JsonPropertyAdapter adapter = myWalker.getParentPropertyAdapter(myOriginalPosition);
|
||||
|
||||
final Map<String, JsonSchemaObject> schemaProperties = schema.getProperties();
|
||||
addAllPropertyVariants(insertComma, hasValue, properties, adapter, schemaProperties);
|
||||
addIfThenElsePropertyNameVariants(schema, insertComma, hasValue, properties, adapter);
|
||||
}
|
||||
else {
|
||||
suggestValues(schema);
|
||||
|
||||
if (isName != ThreeState.YES) {
|
||||
suggestValues(schema, isName == ThreeState.NO);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -199,17 +202,17 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
.forEach(name -> addPropertyVariant(name, schemaProperties.get(name), hasValue, insertComma));
|
||||
}
|
||||
|
||||
private void suggestValues(JsonSchemaObject schema) {
|
||||
suggestValuesForSchemaVariants(schema.getAnyOf());
|
||||
suggestValuesForSchemaVariants(schema.getOneOf());
|
||||
suggestValuesForSchemaVariants(schema.getAllOf());
|
||||
private void suggestValues(JsonSchemaObject schema, boolean isSurelyValue) {
|
||||
suggestValuesForSchemaVariants(schema.getAnyOf(), isSurelyValue);
|
||||
suggestValuesForSchemaVariants(schema.getOneOf(), isSurelyValue);
|
||||
suggestValuesForSchemaVariants(schema.getAllOf(), isSurelyValue);
|
||||
|
||||
if (schema.getEnum() != null) {
|
||||
for (Object o : schema.getEnum()) {
|
||||
addValueVariant(o.toString(), null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (isSurelyValue) {
|
||||
final JsonSchemaType type = schema.getType();
|
||||
if (type != null) {
|
||||
suggestByType(schema, type);
|
||||
@@ -233,9 +236,11 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
} else if (JsonSchemaType._null.equals(type)) {
|
||||
addValueVariant("null", null);
|
||||
} else if (JsonSchemaType._array.equals(type)) {
|
||||
addValueVariant("[]", null, createArrayOrObjectLiteralInsertHandler());
|
||||
addValueVariant(myWalker.getDefaultArrayValue(true), null,
|
||||
myWalker.defaultArrayValueDescription(), createArrayOrObjectLiteralInsertHandler(myWalker.invokeEnterBeforeObjectAndArray()));
|
||||
} else if (JsonSchemaType._object.equals(type)) {
|
||||
addValueVariant("{}", null, createArrayOrObjectLiteralInsertHandler());
|
||||
addValueVariant(myWalker.getDefaultObjectValue(true), null,
|
||||
myWalker.defaultObjectValueDescription(), createArrayOrObjectLiteralInsertHandler(myWalker.invokeEnterBeforeObjectAndArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,18 +248,23 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
Object defaultValue = schema.getDefault();
|
||||
String defaultValueString = defaultValue == null ? null : defaultValue.toString();
|
||||
if (!StringUtil.isEmpty(defaultValueString)) {
|
||||
String quotedValue = defaultValueString;
|
||||
if (!StringUtil.isQuotedString(quotedValue)) {
|
||||
quotedValue = StringUtil.wrapWithDoubleQuote(quotedValue);
|
||||
String normalizedValue = defaultValueString;
|
||||
boolean shouldQuote = myWalker.quotesForStringLiterals();
|
||||
boolean isQuoted = StringUtil.isQuotedString(normalizedValue);
|
||||
if (shouldQuote && !isQuoted) {
|
||||
normalizedValue = StringUtil.wrapWithDoubleQuote(normalizedValue);
|
||||
}
|
||||
addValueVariant(quotedValue, null);
|
||||
else if (!shouldQuote && isQuoted) {
|
||||
normalizedValue = StringUtil.unquoteString(normalizedValue);
|
||||
}
|
||||
addValueVariant(normalizedValue, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void suggestValuesForSchemaVariants(List<JsonSchemaObject> list) {
|
||||
private void suggestValuesForSchemaVariants(List<JsonSchemaObject> list, boolean isSurelyValue) {
|
||||
if (list != null && list.size() > 0) {
|
||||
for (JsonSchemaObject schemaObject : list) {
|
||||
suggestValues(schemaObject);
|
||||
suggestValues(schemaObject, isSurelyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,12 +278,17 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
|
||||
|
||||
private void addValueVariant(@NotNull String key, @SuppressWarnings("SameParameterValue") @Nullable final String description) {
|
||||
addValueVariant(key, description, null);
|
||||
addValueVariant(key, description, null, null);
|
||||
}
|
||||
|
||||
private void addValueVariant(@NotNull String key, @SuppressWarnings("SameParameterValue") @Nullable final String description,
|
||||
private void addValueVariant(@NotNull String key,
|
||||
@SuppressWarnings("SameParameterValue") @Nullable final String description,
|
||||
@Nullable final String altText,
|
||||
@Nullable InsertHandler<LookupElement> handler) {
|
||||
LookupElementBuilder builder = LookupElementBuilder.create(!myWrapInQuotes ? StringUtil.unquoteString(key) : key);
|
||||
if (altText != null) {
|
||||
builder = builder.withPresentableText(altText);
|
||||
}
|
||||
if (description != null) {
|
||||
builder = builder.withTypeText(description);
|
||||
}
|
||||
@@ -326,12 +341,19 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
return variants.stream().map(JsonSchemaObject::getType).filter(Objects::nonNull).distinct().count() <= 1;
|
||||
}
|
||||
|
||||
private static InsertHandler<LookupElement> createArrayOrObjectLiteralInsertHandler() {
|
||||
private static InsertHandler<LookupElement> createArrayOrObjectLiteralInsertHandler(boolean newline) {
|
||||
return new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
EditorModificationUtil.moveCaretRelatively(context.getEditor(), -1);
|
||||
AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null);
|
||||
Editor editor = context.getEditor();
|
||||
|
||||
if (!newline) {
|
||||
EditorModificationUtil.moveCaretRelatively(editor, -1);
|
||||
}
|
||||
else {
|
||||
EditorActionUtil.moveCaretToLineEnd(editor, false, false);
|
||||
}
|
||||
AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(editor, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -383,48 +405,82 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
if (handleInsideQuotesInsertion(context, editor, hasValue)) return;
|
||||
|
||||
if (finalType != null) {
|
||||
boolean hadEnter;
|
||||
switch (finalType) {
|
||||
case _object:
|
||||
stringToInsert = ":{}" + comma;
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 2);
|
||||
EditorModificationUtil.insertStringAtCaret(editor, ": ",
|
||||
false, true, 2);
|
||||
hadEnter = false;
|
||||
boolean invokeEnter = myWalker.invokeEnterBeforeObjectAndArray();
|
||||
if (invokeEnter) {
|
||||
invokeEnterHandler(editor);
|
||||
hadEnter = true;
|
||||
}
|
||||
stringToInsert = myWalker.getDefaultObjectValue(false) + comma;
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert,
|
||||
false, true,
|
||||
hadEnter ? 0 : 1);
|
||||
|
||||
if (hadEnter) {
|
||||
EditorActionUtil.moveCaretToLineEnd(editor, false, false);
|
||||
}
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
formatInsertedString(context, stringToInsert.length());
|
||||
EditorActionHandler handler = EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ENTER);
|
||||
handler.execute(editor, editor.getCaretModel().getCurrentCaret(),
|
||||
DataManager.getInstance().getDataContext(editor.getContentComponent()));
|
||||
if (!invokeEnter) {
|
||||
invokeEnterHandler(editor);
|
||||
}
|
||||
break;
|
||||
case _boolean:
|
||||
String value = String.valueOf(Boolean.TRUE.toString().equals(defaultValueAsString));
|
||||
stringToInsert = ":" + value + comma;
|
||||
stringToInsert = ": " + value + comma;
|
||||
SelectionModel model = editor.getSelectionModel();
|
||||
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, stringToInsert.length() - comma.length());
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert,
|
||||
false, true, stringToInsert.length() - comma.length());
|
||||
formatInsertedString(context, stringToInsert.length());
|
||||
int start = editor.getSelectionModel().getSelectionStart();
|
||||
model.setSelection(start - value.length(), start);
|
||||
AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null);
|
||||
break;
|
||||
case _array:
|
||||
stringToInsert = ":[]" + comma;
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 2);
|
||||
EditorModificationUtil.insertStringAtCaret(editor, ": ",
|
||||
false, true, 2);
|
||||
hadEnter = false;
|
||||
if (myWalker.invokeEnterBeforeObjectAndArray()) {
|
||||
invokeEnterHandler(editor);
|
||||
hadEnter = true;
|
||||
}
|
||||
stringToInsert = myWalker.getDefaultArrayValue(false) + comma;
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert,
|
||||
false, true,
|
||||
hadEnter ? 0 : 1);
|
||||
if (hadEnter) {
|
||||
EditorActionUtil.moveCaretToLineEnd(editor, false, false);
|
||||
}
|
||||
|
||||
formatInsertedString(context, stringToInsert.length());
|
||||
break;
|
||||
case _string:
|
||||
case _integer:
|
||||
insertPropertyWithEnum(context, editor, defaultValueAsString, values, finalType, comma);
|
||||
insertPropertyWithEnum(context, editor, defaultValueAsString, values, finalType, comma, myWalker);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
else {
|
||||
insertPropertyWithEnum(context, editor, defaultValueAsString, values, null, comma);
|
||||
insertPropertyWithEnum(context, editor, defaultValueAsString, values, null, comma, myWalker);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void invokeEnterHandler(Editor editor) {
|
||||
EditorActionHandler handler = EditorActionManager.getInstance().getActionHandler(IdeActions.ACTION_EDITOR_ENTER);
|
||||
handler.execute(editor, editor.getCaretModel().getCurrentCaret(),
|
||||
DataManager.getInstance().getDataContext(editor.getContentComponent()));
|
||||
}
|
||||
|
||||
private boolean handleInsideQuotesInsertion(@NotNull InsertionContext context, @NotNull Editor editor, boolean hasValue) {
|
||||
if (myInsideStringLiteral) {
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
@@ -474,24 +530,30 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
public static void insertPropertyWithEnum(InsertionContext context,
|
||||
private static void insertPropertyWithEnum(InsertionContext context,
|
||||
Editor editor,
|
||||
String defaultValue,
|
||||
List<Object> values,
|
||||
JsonSchemaType type, String comma) {
|
||||
JsonSchemaType type,
|
||||
String comma,
|
||||
JsonLikePsiWalker walker) {
|
||||
if (!walker.quotesForStringLiterals() && defaultValue != null) {
|
||||
defaultValue = StringUtil.unquoteString(defaultValue);
|
||||
}
|
||||
final boolean isNumber = type != null && (JsonSchemaType._integer.equals(type) || JsonSchemaType._number.equals(type)) ||
|
||||
type == null && (defaultValue != null &&
|
||||
!StringUtil.isQuotedString(defaultValue) || values != null && ContainerUtil.and(values, v -> !(v instanceof String)));
|
||||
boolean hasValues = !ContainerUtil.isEmpty(values);
|
||||
boolean hasDefaultValue = !StringUtil.isEmpty(defaultValue);
|
||||
String stringToInsert = ":" + (hasDefaultValue ? defaultValue : (isNumber ? "" : "\"\"")) + comma;
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 1);
|
||||
if (!isNumber || hasDefaultValue) {
|
||||
boolean hasQuotes = isNumber || !walker.quotesForStringLiterals();
|
||||
String stringToInsert = ": " + (hasDefaultValue ? defaultValue : (hasQuotes ? "" : "\"\"")) + comma;
|
||||
EditorModificationUtil.insertStringAtCaret(editor, stringToInsert, false, true, 2);
|
||||
if (!hasQuotes || hasDefaultValue) {
|
||||
SelectionModel model = editor.getSelectionModel();
|
||||
int caretStart = model.getSelectionStart();
|
||||
int newOffset = caretStart + (hasDefaultValue ? defaultValue.length() : 1);
|
||||
if (hasDefaultValue && !isNumber) newOffset--;
|
||||
model.setSelection(isNumber ? caretStart : (caretStart + 1), newOffset);
|
||||
if (hasDefaultValue && !hasQuotes) newOffset--;
|
||||
model.setSelection(hasQuotes ? caretStart : (caretStart + 1), newOffset);
|
||||
editor.getCaretModel().moveToOffset(newOffset);
|
||||
}
|
||||
|
||||
@@ -502,7 +564,8 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
public static void formatInsertedString(@NotNull InsertionContext context, int offset) {
|
||||
public static void formatInsertedString(@NotNull InsertionContext context,
|
||||
int offset) {
|
||||
Project project = context.getProject();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(context.getDocument());
|
||||
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.jetbrains.jsonSchema.impl;
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.json.psi.JsonFile;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -64,7 +65,6 @@ public class JsonSchemaComplianceChecker {
|
||||
rootToCheck = findTopLevelElement(myWalker, element);
|
||||
} else {
|
||||
rootToCheck = firstProp.getParentObject();
|
||||
if (rootToCheck == null) rootToCheck = firstProp.getParentArray();
|
||||
if (rootToCheck == null || !myWalker.isTopJsonElement(rootToCheck.getDelegate().getParent())) {
|
||||
return;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class JsonSchemaComplianceChecker {
|
||||
if (checkIfAlreadyProcessed(entry.getKey())) continue;
|
||||
String value = entry.getValue().getMessage();
|
||||
if (myMessagePrefix != null) value = myMessagePrefix + value;
|
||||
LocalQuickFix fix = entry.getValue().createFix();
|
||||
LocalQuickFix fix = entry.getKey().getContainingFile() instanceof JsonFile ? entry.getValue().createFix() : null;
|
||||
if (fix == null) {
|
||||
myHolder.registerProblem(entry.getKey(), value);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.json.JsonLanguage;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.AtomicClearableLazyValue;
|
||||
import com.intellij.openapi.util.Factory;
|
||||
@@ -281,9 +278,7 @@ public class JsonSchemaServiceImpl implements JsonSchemaService {
|
||||
}
|
||||
|
||||
private static boolean isProviderAvailable(@NotNull final VirtualFile file, @NotNull JsonSchemaFileProvider provider) {
|
||||
final FileType type = file.getFileType();
|
||||
final boolean isJson = type instanceof LanguageFileType && ((LanguageFileType)type).getLanguage().isKindOf(JsonLanguage.INSTANCE);
|
||||
return (isJson || !SchemaType.userSchema.equals(provider.getSchemaType())) && provider.isAvailable(file);
|
||||
return provider.isAvailable(file);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @author Irina.Chernushina on 7/15/2015.
|
||||
*/
|
||||
public enum JsonSchemaType {
|
||||
_string, _number, _integer, _object, _array, _boolean, _null, _any;
|
||||
_string, _number, _integer, _object, _array, _boolean, _null, _any, _string_number;
|
||||
|
||||
public String getName() {
|
||||
return name().substring(1);
|
||||
@@ -20,6 +20,7 @@ public enum JsonSchemaType {
|
||||
return "\"\"";
|
||||
case _number:
|
||||
case _integer:
|
||||
case _string_number:
|
||||
return "0";
|
||||
case _object:
|
||||
return "{}";
|
||||
@@ -35,11 +36,29 @@ public enum JsonSchemaType {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSimple() {
|
||||
switch (this) {
|
||||
case _string:
|
||||
case _number:
|
||||
case _integer:
|
||||
case _boolean:
|
||||
case _null:
|
||||
return true;
|
||||
case _object:
|
||||
case _array:
|
||||
case _any:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static JsonSchemaType getType(@NotNull final JsonValueAdapter value) {
|
||||
if (value.isNull()) return _null;
|
||||
if (value.isBooleanLiteral()) return _boolean;
|
||||
if (value.isStringLiteral()) return _string;
|
||||
if (value.isStringLiteral()) {
|
||||
return value.isNumberLiteral() ? _string_number : _string;
|
||||
}
|
||||
if (value.isArray()) return _array;
|
||||
if (value.isObject()) return _object;
|
||||
if (value.isNumberLiteral()) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.json.psi.JsonObject;
|
||||
import com.intellij.json.psi.JsonProperty;
|
||||
import com.intellij.json.psi.JsonValue;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
@@ -67,12 +66,6 @@ public class JsonJsonPropertyAdapter implements JsonPropertyAdapter {
|
||||
return myProperty.getParent() instanceof JsonObject ? new JsonJsonObjectAdapter((JsonObject)myProperty.getParent()) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonArrayValueAdapter getParentArray() {
|
||||
return myProperty.getParent() instanceof JsonArray ? new JsonJsonArrayAdapter((JsonArray)myProperty.getParent()) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsonValueAdapter createAdapterByType(@NotNull JsonValue value) {
|
||||
if (value instanceof JsonObject) return new JsonJsonObjectAdapter((JsonObject)value);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.jetbrains.jsonSchema.widget;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.json.JsonLanguage;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
@@ -34,7 +35,9 @@ import java.util.stream.Collectors;
|
||||
|
||||
class JsonSchemaStatusWidget extends EditorBasedStatusBarPopup {
|
||||
private static final String JSON_SCHEMA_BAR = "JSON: ";
|
||||
private static final String JSON_SCHEMA_BAR_OTHER_FILES = "Schema: ";
|
||||
private static final String JSON_SCHEMA_TOOLTIP = "JSON Schema: ";
|
||||
private static final String JSON_SCHEMA_TOOLTIP_OTHER_FILES = "Validated by JSON Schema: ";
|
||||
private final JsonSchemaService myService;
|
||||
private static final String ID = "JSONSchemaSelector";
|
||||
|
||||
@@ -146,16 +149,23 @@ class JsonSchemaStatusWidget extends EditorBasedStatusBarPopup {
|
||||
return state;
|
||||
}
|
||||
|
||||
FileType fileType = file.getFileType();
|
||||
Language language = fileType instanceof LanguageFileType ? ((LanguageFileType)fileType).getLanguage() : null;
|
||||
boolean isJsonFile = language instanceof JsonLanguage;
|
||||
|
||||
String tooltip = isJsonFile ? JSON_SCHEMA_TOOLTIP : JSON_SCHEMA_TOOLTIP_OTHER_FILES;
|
||||
String bar = isJsonFile ? JSON_SCHEMA_BAR : JSON_SCHEMA_BAR_OTHER_FILES;
|
||||
|
||||
JsonSchemaFileProvider provider = myService.getSchemaProvider(schemaFile);
|
||||
if (provider != null) {
|
||||
String providerName = provider.getPresentableName();
|
||||
String shortName = StringUtil.trimEnd(StringUtil.trimEnd(providerName, ".json"), "-schema");
|
||||
String name = shortName.startsWith("JSON schema") ? shortName : (JSON_SCHEMA_BAR + shortName);
|
||||
String name = shortName.startsWith("JSON schema") ? shortName : (bar + shortName);
|
||||
String kind = provider.getSchemaType() == SchemaType.embeddedSchema || provider.getSchemaType() == SchemaType.schema ? " (bundled)" : "";
|
||||
return new MyWidgetState(JSON_SCHEMA_TOOLTIP + providerName + kind, name, true);
|
||||
return new MyWidgetState(tooltip + providerName + kind, name, true);
|
||||
}
|
||||
|
||||
return new MyWidgetState(JSON_SCHEMA_TOOLTIP + getSchemaFileDesc(schemaFile), JSON_SCHEMA_BAR + getPresentableNameForFile(schemaFile),
|
||||
return new MyWidgetState(tooltip + getSchemaFileDesc(schemaFile), bar + getPresentableNameForFile(schemaFile),
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,46 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.extensions.AreaPicoContainer;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.json.JsonLanguage;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.intellij.util.containers.Predicate;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaComplianceInspection;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 9/21/2015.
|
||||
*/
|
||||
public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
public class JsonSchemaHighlightingTest extends JsonSchemaHighlightingTestBase {
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PlatformTestUtil.getCommunityPath() + "/json/tests/testData/jsonSchema/highlighting";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestFileName() {
|
||||
return "config.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspectionProfile() {
|
||||
return new JsonSchemaComplianceInspection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<VirtualFile> getAvailabilityPredicate() {
|
||||
return file -> file.getFileType() instanceof LanguageFileType && ((LanguageFileType)file.getFileType()).getLanguage().isKindOf(
|
||||
JsonLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
public void testNumberMultipleWrong() throws Exception {
|
||||
doTest("{ \"properties\": { \"prop\": {\"type\": \"number\", \"multipleOf\": 2}}}",
|
||||
"{ \"prop\": <warning descr=\"Is not multiple of 2\">3</warning>}");
|
||||
@@ -644,36 +654,6 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
return "{\"type\": \"object\", \"properties\": {\"prop\": " + s + "}}";
|
||||
}
|
||||
|
||||
private void doTest(@Language("JSON") @NotNull final String schema, @NotNull final String text) throws Exception {
|
||||
enableInspectionTool(new JsonSchemaComplianceInspection());
|
||||
|
||||
final PsiFile file = createFile(myModule, "config.json", text);
|
||||
|
||||
registerProvider(getProject(), schema);
|
||||
Disposer.register(getTestRootDisposable(), new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
JsonSchemaTestServiceImpl.setProvider(null);
|
||||
}
|
||||
});
|
||||
configureByFile(file.getVirtualFile());
|
||||
doTest(file.getVirtualFile(), true, false);
|
||||
}
|
||||
|
||||
public void registerProvider(Project project, @NotNull String schema) throws IOException {
|
||||
File dir = createTempDir("json_schema_test", true);
|
||||
File child = new File(dir, "schema.json");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
child.createNewFile();
|
||||
FileUtil.writeToFile(child, schema);
|
||||
VirtualFile schemaFile = getVirtualFile(child);
|
||||
JsonSchemaTestServiceImpl.setProvider(new JsonSchemaTestProvider(schemaFile));
|
||||
AreaPicoContainer container = Extensions.getArea(project).getPicoContainer();
|
||||
String key = JsonSchemaService.class.getName();
|
||||
container.unregisterComponent(key);
|
||||
container.registerComponentImplementation(key, JsonSchemaTestServiceImpl.class);
|
||||
}
|
||||
|
||||
public void testExclusiveMinMaxV6() throws Exception {
|
||||
@Language("JSON") String exclusiveMinSchema = "{\"properties\": {\"prop\": {\"exclusiveMinimum\": 3}}}";
|
||||
doTest(exclusiveMinSchema, "{\"prop\": <warning>2</warning>}");
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.extensions.AreaPicoContainer;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.containers.Predicate;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class JsonSchemaHighlightingTestBase extends DaemonAnalyzerTestCase {
|
||||
|
||||
protected abstract String getTestFileName();
|
||||
protected abstract InspectionProfileEntry getInspectionProfile();
|
||||
protected abstract Predicate<VirtualFile> getAvailabilityPredicate();
|
||||
|
||||
protected void doTest(@Language("JSON") @NotNull final String schema, @NotNull final String text) throws Exception {
|
||||
enableInspectionTool(getInspectionProfile());
|
||||
|
||||
final PsiFile file = createFile(myModule, getTestFileName(), text);
|
||||
|
||||
registerProvider(getProject(), schema);
|
||||
Disposer.register(getTestRootDisposable(), new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
JsonSchemaTestServiceImpl.setProvider(null);
|
||||
}
|
||||
});
|
||||
configureByFile(file.getVirtualFile());
|
||||
doTest(file.getVirtualFile(), true, false);
|
||||
}
|
||||
|
||||
private void registerProvider(Project project, @NotNull String schema) throws IOException {
|
||||
File dir = createTempDir("json_schema_test", true);
|
||||
File child = new File(dir, "schema.json");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
child.createNewFile();
|
||||
FileUtil.writeToFile(child, schema);
|
||||
VirtualFile schemaFile = getVirtualFile(child);
|
||||
JsonSchemaTestServiceImpl.setProvider(new JsonSchemaTestProvider(schemaFile, getAvailabilityPredicate()));
|
||||
AreaPicoContainer container = Extensions.getArea(project).getPicoContainer();
|
||||
String key = JsonSchemaService.class.getName();
|
||||
container.unregisterComponent(key);
|
||||
container.registerComponentImplementation(key, JsonSchemaTestServiceImpl.class);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
|
||||
import com.intellij.json.JsonLanguage;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.Predicate;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider;
|
||||
import com.jetbrains.jsonSchema.extension.SchemaType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -11,14 +10,16 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class JsonSchemaTestProvider implements JsonSchemaFileProvider {
|
||||
private final VirtualFile mySchemaFile;
|
||||
private final Predicate<? super VirtualFile> myAvailabilityPredicate;
|
||||
|
||||
public JsonSchemaTestProvider(VirtualFile schemaFile) {
|
||||
public JsonSchemaTestProvider(VirtualFile schemaFile, Predicate<? super VirtualFile> availabilityPredicate) {
|
||||
mySchemaFile = schemaFile;
|
||||
myAvailabilityPredicate = availabilityPredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull VirtualFile file) {
|
||||
return file.getFileType() instanceof LanguageFileType && ((LanguageFileType)file.getFileType()).getLanguage().isKindOf(JsonLanguage.INSTANCE);
|
||||
return myAvailabilityPredicate.apply(file);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.EditorTestUtil;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
@@ -31,7 +32,7 @@ import java.util.List;
|
||||
* @author Irina.Chernushina on 2/20/2017.
|
||||
*/
|
||||
public abstract class JsonBySchemaCompletionBaseTest extends CompletionTestCase {
|
||||
protected void testBySchema(@NotNull final String schema, final @NotNull String text, final @NotNull String extension,
|
||||
protected void testBySchema(@Language("JSON") @NotNull final String schema, final @NotNull String text, final @NotNull String extension,
|
||||
final @NotNull String... variants) throws Exception {
|
||||
final int position = EditorTestUtil.getCaretPosition(text);
|
||||
Assert.assertTrue(position > 0);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.json.JsonFileType;
|
||||
import com.intellij.json.psi.JsonFile;
|
||||
import com.intellij.json.psi.JsonObject;
|
||||
@@ -13,17 +11,17 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaHeavyAbstractTest;
|
||||
import com.jetbrains.jsonSchema.UserDefinedJsonSchemaConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 3/4/2017.
|
||||
*/
|
||||
public class JsonBySchemaHeavyCompletionTest extends JsonSchemaHeavyAbstractTest {
|
||||
public class JsonBySchemaHeavyCompletionTest extends JsonBySchemaHeavyCompletionTestBase {
|
||||
@Override
|
||||
protected String getExtensionWithoutDot() {
|
||||
return "json";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/tests/testData/jsonSchema/completion";
|
||||
@@ -61,6 +59,10 @@ public class JsonBySchemaHeavyCompletionTest extends JsonSchemaHeavyAbstractTest
|
||||
baseInsertTest("insertPropertyName", "testObjectType");
|
||||
}
|
||||
|
||||
public void testInsertArrayType() throws Exception {
|
||||
baseInsertTest("insertPropertyName", "testArrayType");
|
||||
}
|
||||
|
||||
public void testInsertBooleanType() throws Exception {
|
||||
baseInsertTest("insertPropertyName", "testBooleanType");
|
||||
}
|
||||
@@ -133,52 +135,5 @@ public class JsonBySchemaHeavyCompletionTest extends JsonSchemaHeavyAbstractTest
|
||||
});
|
||||
}
|
||||
|
||||
private void baseCompletionTest(@SuppressWarnings("SameParameterValue") final String folder,
|
||||
@SuppressWarnings("SameParameterValue") final String testFile, @NotNull String... items) throws Exception {
|
||||
baseTest(folder, testFile, () -> {
|
||||
complete();
|
||||
assertStringItems(items);
|
||||
});
|
||||
}
|
||||
|
||||
private void baseInsertTest(@SuppressWarnings("SameParameterValue") final String folder, final String testFile) throws Exception {
|
||||
baseTest(folder, testFile, () -> {
|
||||
final CodeCompletionHandlerBase handlerBase = new CodeCompletionHandlerBase(CompletionType.BASIC);
|
||||
handlerBase.invokeCompletion(getProject(), getEditor());
|
||||
if (myItems != null) {
|
||||
selectItem(myItems[0]);
|
||||
}
|
||||
try {
|
||||
checkResultByFile("/" + folder + "/" + testFile + "_after.json");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void baseTest(@NotNull final String folder, @NotNull final String testFile, @NotNull final Runnable checker) throws Exception {
|
||||
skeleton(new Callback() {
|
||||
@Override
|
||||
public void registerSchemes() {
|
||||
final String moduleDir = getModuleDir(getProject());
|
||||
|
||||
final UserDefinedJsonSchemaConfiguration base =
|
||||
new UserDefinedJsonSchemaConfiguration("base", JsonSchemaVersion.SCHEMA_4, moduleDir + "/Schema.json", false,
|
||||
Collections.singletonList(new UserDefinedJsonSchemaConfiguration.Item(testFile + ".json", true, false))
|
||||
);
|
||||
addSchema(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureFiles() {
|
||||
configureByFiles(null, "/" + folder + "/" + testFile + ".json", "/" + folder + "/Schema.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCheck() {
|
||||
checker.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaHeavyAbstractTest;
|
||||
import com.jetbrains.jsonSchema.UserDefinedJsonSchemaConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public abstract class JsonBySchemaHeavyCompletionTestBase extends JsonSchemaHeavyAbstractTest {
|
||||
protected void baseCompletionTest(@SuppressWarnings("SameParameterValue") final String folder,
|
||||
@SuppressWarnings("SameParameterValue") final String testFile, @NotNull String... items) throws Exception {
|
||||
baseTest(folder, testFile, () -> {
|
||||
complete();
|
||||
assertStringItems(items);
|
||||
});
|
||||
}
|
||||
|
||||
protected void baseInsertTest(@SuppressWarnings("SameParameterValue") final String folder, final String testFile) throws Exception {
|
||||
baseTest(folder, testFile, () -> {
|
||||
final CodeCompletionHandlerBase handlerBase = new CodeCompletionHandlerBase(CompletionType.BASIC);
|
||||
handlerBase.invokeCompletion(getProject(), getEditor());
|
||||
if (myItems != null) {
|
||||
selectItem(myItems[0]);
|
||||
}
|
||||
try {
|
||||
checkResultByFile("/" + folder + "/" + testFile + "_after." + getExtensionWithoutDot());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract String getExtensionWithoutDot();
|
||||
|
||||
protected void baseTest(@NotNull final String folder, @NotNull final String testFile, @NotNull final Runnable checker) throws Exception {
|
||||
skeleton(new JsonSchemaHeavyAbstractTest.Callback() {
|
||||
@Override
|
||||
public void registerSchemes() {
|
||||
final String moduleDir = getModuleDir(getProject());
|
||||
|
||||
final UserDefinedJsonSchemaConfiguration base =
|
||||
new UserDefinedJsonSchemaConfiguration("base", JsonSchemaVersion.SCHEMA_4, moduleDir + "/Schema.json", false,
|
||||
Collections
|
||||
.singletonList(new UserDefinedJsonSchemaConfiguration.Item(testFile + "." + getExtensionWithoutDot(), true, false))
|
||||
);
|
||||
addSchema(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureFiles() {
|
||||
configureByFiles(null, "/" + folder + "/" + testFile + "." + getExtensionWithoutDot(), "/" + folder + "/Schema.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCheck() {
|
||||
checker.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,9 @@
|
||||
},
|
||||
"booleanType": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"arrayType": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"arrayTy<caret>"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"arrayType": [<caret>]
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"integerType":<caret>
|
||||
"integerType": <caret>
|
||||
}
|
||||
@@ -16,5 +16,8 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.spellchecker" />
|
||||
<orderEntry type="module" module-name="intellij.xml" />
|
||||
<orderEntry type="module" module-name="intellij.json" />
|
||||
<orderEntry type="module" module-name="intellij.json.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.java.testFramework" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -26,6 +26,10 @@
|
||||
|
||||
<projectService serviceImplementation="org.jetbrains.yaml.YAMLElementGenerator"/>
|
||||
|
||||
<completion.contributor order="first" language="yaml"
|
||||
implementationClass="org.jetbrains.yaml.schema.YamlJsonSchemaCompletionContributor"/>
|
||||
<lang.documentationProvider language="yaml" implementationClass="org.jetbrains.yaml.schema.YamlJsonSchemaDocumentationProvider" order="first"/>
|
||||
|
||||
<lang.elementManipulator forClass="org.jetbrains.yaml.psi.impl.YAMLScalarImpl"
|
||||
implementationClass="org.jetbrains.yaml.psi.impl.YAMLScalarElementManipulator"/>
|
||||
<breadcrumbsInfoProvider implementation="org.jetbrains.yaml.breadcrumbs.YAMLBreadcrumbsInfoProvider"/>
|
||||
@@ -55,8 +59,20 @@
|
||||
groupKey="inspections.group.name" enabledByDefault="true"
|
||||
implementationClass="org.jetbrains.yaml.inspections.YAMLUnusedAnchorInspection"/>
|
||||
|
||||
<localInspection language="yaml" bundle="messages.YAMLBundle"
|
||||
shortName="YAMLSchemaValidation"
|
||||
key="inspections.schema.validation.name"
|
||||
groupKey="inspections.group.name"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
implementationClass="org.jetbrains.yaml.schema.YamlJsonSchemaHighlightingInspection"/>
|
||||
</extensions>
|
||||
|
||||
|
||||
<extensions defaultExtensionNs="Json">
|
||||
<Like.Psi.Walker.Factory implementation="org.jetbrains.yaml.schema.YamlJsonLikePsiWalkerFactory"/>
|
||||
<Schema.Enabler implementation="org.jetbrains.yaml.schema.YamlJsonEnabler" />
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij.spellchecker">
|
||||
<support language="yaml" implementationClass="org.jetbrains.yaml.YAMLSpellcheckerStrategy"/>
|
||||
</extensions>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Validates YAML file against a JSON Schema, if the schema is specified
|
||||
<!-- tooltip end -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -69,6 +69,7 @@ inspections.unresolved.alias.name=Unresolved alias
|
||||
inspections.unresolved.alias.message=Can''t resolve alias {0}
|
||||
inspections.recursive.alias.name=Recursive alias
|
||||
inspections.recursive.alias.message=Alias can't be recursive
|
||||
inspections.schema.validation.name=Validation by JSON Schema
|
||||
inspections.duplicated.keys.name=Duplicated YAML keys
|
||||
inspections.unused.anchor.name=Unused anchor
|
||||
inspections.unused.anchor.message=Anchor {0} is never used
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLSequence;
|
||||
import org.jetbrains.yaml.psi.YAMLSequenceItem;
|
||||
import org.jetbrains.yaml.psi.YAMLValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class YamlArrayAdapter implements JsonArrayValueAdapter {
|
||||
|
||||
@NotNull private final YAMLSequence myArray;
|
||||
@NotNull private final NotNullLazyValue<List<JsonValueAdapter>> myChildAdapters = new NotNullLazyValue<List<JsonValueAdapter>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<JsonValueAdapter> compute() {
|
||||
return computeChildAdapters();
|
||||
}
|
||||
};
|
||||
|
||||
public YamlArrayAdapter(@NotNull YAMLSequence array) {myArray = array;}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JsonValueAdapter> getElements() {
|
||||
return myChildAdapters.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStringLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumberLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBooleanLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getDelegate() {
|
||||
return myArray;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonObjectValueAdapter getAsObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonArrayValueAdapter getAsArray() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCheckIntegralRequirements() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsonValueAdapter> computeChildAdapters() {
|
||||
List<YAMLSequenceItem> items = myArray.getItems();
|
||||
List<JsonValueAdapter> adapters = ContainerUtil.newArrayListWithCapacity(items.size());
|
||||
for (YAMLSequenceItem item: items) {
|
||||
YAMLValue value = item.getValue();
|
||||
if (value == null) continue;
|
||||
adapters.add(YamlPropertyAdapter.createValueAdapterByType(value));
|
||||
}
|
||||
return adapters;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLValue;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class YamlGenericValueAdapter implements JsonValueAdapter {
|
||||
@NotNull private final YAMLValue myValue;
|
||||
|
||||
public YamlGenericValueAdapter(@NotNull YAMLValue value) {myValue = value;}
|
||||
|
||||
@Override
|
||||
public boolean isShouldBeIgnored() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStringLiteral() {
|
||||
String text = myValue.getText();
|
||||
return !hasNonStringTags(text); /*values should always validate as string*/
|
||||
}
|
||||
|
||||
private static boolean hasNonStringTags(@NotNull String text) {
|
||||
return hasTag(text, "bool")
|
||||
|| hasTag(text, "null")
|
||||
|| hasTag(text, "int")
|
||||
|| hasTag(text, "float");
|
||||
}
|
||||
|
||||
private static boolean hasTag(@NotNull String text, @NotNull String tagName) {
|
||||
return StringUtil.startsWith(text, "!!" + tagName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumberLiteral() {
|
||||
String text = myValue.getText();
|
||||
return isNumber(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBooleanLiteral() {
|
||||
String text = myValue.getText();
|
||||
return "true".equals(text) || "false".equals(text) || hasTag(text, "bool");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull() {
|
||||
String text = myValue.getText();
|
||||
return "null".equals(text) || hasTag(text, "null");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getDelegate() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonObjectValueAdapter getAsObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonArrayValueAdapter getAsArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCheckIntegralRequirements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isNumber(@Nullable String s) {
|
||||
if (s == null) return false;
|
||||
return isInteger(s) || isFloat(s);
|
||||
}
|
||||
|
||||
// http://yaml.org/spec/1.2/spec.html#id2803828
|
||||
private static boolean isInteger(@NotNull String s) {
|
||||
if (s.length() == 0) return false;
|
||||
if ("0".equals(s)) return true;
|
||||
if (hasTag(s, "int")) return true;
|
||||
int startIndex = s.charAt(0) == '-' ? 1 : 0;
|
||||
for (int i = startIndex; i < s.length(); ++i) {
|
||||
if (i == startIndex && s.charAt(i) == '0') return false;
|
||||
if (!Character.isDigit(s.charAt(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// http://yaml.org/spec/1.2/spec.html#id2804092
|
||||
private static boolean isFloat(@NotNull String s) {
|
||||
if (".inf".equals(s) || "-.inf".equals(s) || ".nan".equals(s)) return true;
|
||||
if (hasTag(s, "float")) return true;
|
||||
return Pattern.matches("-?[1-9](\\.[0-9]*[1-9])?(e[-+][1-9][0-9]*)?", s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaEnabler;
|
||||
import org.jetbrains.yaml.YAMLLanguage;
|
||||
|
||||
public class YamlJsonEnabler implements JsonSchemaEnabler {
|
||||
@Override
|
||||
public boolean isEnabledForFile(VirtualFile file) {
|
||||
FileType type = file.getFileType();
|
||||
return type instanceof LanguageFileType && ((LanguageFileType)type).getLanguage() instanceof YAMLLanguage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalkerFactory;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.yaml.psi.YAMLFile;
|
||||
|
||||
public class YamlJsonLikePsiWalkerFactory implements JsonLikePsiWalkerFactory {
|
||||
@Override
|
||||
public boolean handles(@NotNull PsiElement element) {
|
||||
return element.getContainingFile() instanceof YAMLFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsonLikePsiWalker create(@NotNull JsonSchemaObject schemaObject) {
|
||||
return new YamlJsonPsiWalker();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaVariantsTreeBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.YAMLTokenTypes;
|
||||
import org.jetbrains.yaml.psi.*;
|
||||
import org.jetbrains.yaml.psi.impl.YAMLBlockMappingImpl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class YamlJsonPsiWalker implements JsonLikePsiWalker {
|
||||
|
||||
public YamlJsonPsiWalker() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreeState isName(PsiElement element) {
|
||||
PsiElement parent = element.getParent();
|
||||
if (parent instanceof YAMLDocument || parent instanceof YAMLMapping) {
|
||||
return ThreeState.YES;
|
||||
}
|
||||
|
||||
if (parent instanceof YAMLKeyValue && isFirstChild(element, parent)) {
|
||||
ASTNode prev = element.getNode().getTreePrev();
|
||||
return prev.getElementType() == YAMLTokenTypes.INDENT ? ThreeState.YES : ThreeState.NO;
|
||||
}
|
||||
|
||||
if (parent instanceof YAMLSequenceItem && isFirstChild(element, parent)) {
|
||||
return ThreeState.UNSURE;
|
||||
}
|
||||
return ThreeState.NO;
|
||||
}
|
||||
|
||||
private static boolean isFirstChild(PsiElement element, PsiElement parent) {
|
||||
PsiElement[] children = parent.getChildren();
|
||||
return children.length != 0 && children[0] == element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPropertyWithValue(@NotNull PsiElement element) {
|
||||
return element instanceof YAMLKeyValue && ((YAMLKeyValue)element).getValue() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTopJsonElement(@NotNull PsiElement element) {
|
||||
return element instanceof YAMLFile || element instanceof YAMLDocument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement goUpToCheckable(@NotNull PsiElement element) {
|
||||
PsiElement current = element;
|
||||
while (current != null && !(current instanceof PsiFile)) {
|
||||
if (current instanceof YAMLValue || current instanceof YAMLKeyValue) {
|
||||
return current;
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNameQuoted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonValueAdapter createValueAdapter(@NotNull PsiElement element) {
|
||||
return element instanceof YAMLValue ? YamlPropertyAdapter.createValueAdapterByType((YAMLValue)element) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onlyDoubleQuotesForStringLiterals() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPropertiesBehindAndNoComma(@NotNull PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonPropertyAdapter getParentPropertyAdapter(@NotNull PsiElement element) {
|
||||
final YAMLKeyValue property = PsiTreeUtil.getParentOfType(element, YAMLKeyValue.class, false);
|
||||
if (property == null) return null;
|
||||
// it is a parent property only if its value contains the current property
|
||||
YAMLValue value = property.getValue();
|
||||
if (value == null || !PsiTreeUtil.isAncestor(value, element, true)) return null;
|
||||
return new YamlPropertyAdapter(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPropertyNamesOfParentObject(@NotNull PsiElement originalPosition, PsiElement computedPosition) {
|
||||
YAMLMapping object = PsiTreeUtil.getParentOfType(originalPosition, YAMLMapping.class);
|
||||
if (object == null) object = PsiTreeUtil.getParentOfType(computedPosition, YAMLMapping.class);
|
||||
if (object == null) return Collections.emptySet();
|
||||
return object.getKeyValues().stream().filter(p -> p != null && p.getName() != null)
|
||||
.map(p -> p.getName()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<JsonSchemaVariantsTreeBuilder.Step> findPosition(@NotNull PsiElement element, boolean forceLastTransition) {
|
||||
final List<JsonSchemaVariantsTreeBuilder.Step> steps = new ArrayList<>();
|
||||
PsiElement current = element;
|
||||
while (!breakCondition(current)) {
|
||||
final PsiElement position = current;
|
||||
current = current.getParent();
|
||||
if (current instanceof YAMLSequence) {
|
||||
YAMLSequence array = (YAMLSequence)current;
|
||||
final List<YAMLSequenceItem> expressions = array.getItems();
|
||||
int idx = -1;
|
||||
for (int i = 0; i < expressions.size(); i++) {
|
||||
final YAMLSequenceItem value = expressions.get(i);
|
||||
if (position.equals(value)) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx != -1) {
|
||||
steps.add(JsonSchemaVariantsTreeBuilder.Step.createArrayElementStep(idx));
|
||||
}
|
||||
} else if (current instanceof YAMLSequenceItem) {
|
||||
// do nothing - handled by the upper condition
|
||||
} else if (current instanceof YAMLKeyValue) {
|
||||
final String propertyName = StringUtil.notNullize(((YAMLKeyValue)current).getName());
|
||||
current = current.getParent();
|
||||
if (!(current instanceof YAMLMapping)) return null;//incorrect syntax?
|
||||
steps.add(JsonSchemaVariantsTreeBuilder.Step.createPropertyStep(propertyName));
|
||||
} else if (current instanceof YAMLMapping && position instanceof YAMLKeyValue) {
|
||||
// if either value or not first in the chain - needed for completion variant
|
||||
final String propertyName = StringUtil.notNullize(((YAMLKeyValue)position).getName());
|
||||
steps.add(JsonSchemaVariantsTreeBuilder.Step.createPropertyStep(propertyName));
|
||||
} else if (breakCondition(current)) {
|
||||
break;
|
||||
} else {
|
||||
if (current instanceof YAMLMapping) {
|
||||
List<YAMLPsiElement> elements = ((YAMLMapping)current).getYAMLElements();
|
||||
if (elements.size() == 0) return null;
|
||||
YAMLPsiElement last = elements.get(elements.size() - 1);
|
||||
if (last == position) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;//something went wrong
|
||||
}
|
||||
}
|
||||
Collections.reverse(steps);
|
||||
return steps;
|
||||
}
|
||||
|
||||
private static boolean breakCondition(PsiElement current) {
|
||||
return current instanceof PsiFile || current instanceof YAMLDocument ||
|
||||
current instanceof YAMLBlockMappingImpl && current.getParent() instanceof YAMLDocument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean quotesForStringLiterals() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultObjectValue(boolean includeWhitespaces) {
|
||||
return includeWhitespaces ? "\n " : "";
|
||||
}
|
||||
|
||||
@Nullable public String defaultObjectValueDescription() { return "start object"; }
|
||||
|
||||
@Override
|
||||
public String getDefaultArrayValue(boolean includeWhitespaces) {
|
||||
return includeWhitespaces ? "\n - " : "- ";
|
||||
}
|
||||
|
||||
@Nullable public String defaultArrayValueDescription() { return "start array"; }
|
||||
|
||||
@Override
|
||||
public boolean invokeEnterBeforeObjectAndArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNodeTextForValidation(PsiElement element) {
|
||||
String text = element.getText();
|
||||
if (!StringUtil.startsWith(text, "!!")) return text;
|
||||
// remove tags
|
||||
int spaceIndex = text.indexOf(' ');
|
||||
return spaceIndex > 0 ? text.substring(spaceIndex + 1) : text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionContributor;
|
||||
import com.intellij.codeInsight.completion.CompletionParameters;
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaCompletionContributor;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class YamlJsonSchemaCompletionContributor extends CompletionContributor {
|
||||
@Override
|
||||
public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
|
||||
final PsiElement position = parameters.getPosition();
|
||||
final JsonSchemaService jsonSchemaService = JsonSchemaService.Impl.get(position.getProject());
|
||||
JsonSchemaObject object = jsonSchemaService.getSchemaObject(parameters.getOriginalFile().getVirtualFile());
|
||||
if (object != null) {
|
||||
JsonSchemaCompletionContributor.doCompletion(parameters, result, object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.lang.documentation.DocumentationProviderEx;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaDocumentationProvider;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class YamlJsonSchemaDocumentationProvider extends DocumentationProviderEx {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
||||
return findSchemaAndGenerateDoc(element, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
|
||||
return findSchemaAndGenerateDoc(element, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String findSchemaAndGenerateDoc(PsiElement element, final boolean preferShort) {
|
||||
final JsonSchemaService jsonSchemaService = JsonSchemaService.Impl.get(element.getProject());
|
||||
PsiFile containingFile = element.getContainingFile();
|
||||
if (containingFile == null) return null;
|
||||
VirtualFile virtualFile = containingFile.getVirtualFile();
|
||||
if (virtualFile == null) return null;
|
||||
JsonSchemaObject schemaObject = jsonSchemaService.getSchemaObject(virtualFile);
|
||||
if (schemaObject == null) return null;
|
||||
return JsonSchemaDocumentationProvider.generateDoc(element, schemaObject, preferShort);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement getCustomDocumentationElement(@NotNull Editor editor,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable PsiElement contextElement) {
|
||||
return contextElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaComplianceChecker;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.yaml.YAMLBundle;
|
||||
import org.jetbrains.yaml.psi.YAMLDocument;
|
||||
import org.jetbrains.yaml.psi.YAMLFile;
|
||||
import org.jetbrains.yaml.psi.YamlPsiElementVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class YamlJsonSchemaHighlightingInspection extends LocalInspectionTool {
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return YAMLBundle.message("inspections.schema.validation.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
|
||||
boolean isOnTheFly,
|
||||
@NotNull LocalInspectionToolSession session) {
|
||||
PsiFile file = holder.getFile();
|
||||
if (!(file instanceof YAMLFile)) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
List<YAMLDocument> documents = ((YAMLFile)file).getDocuments();
|
||||
if (documents.size() != 1) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
|
||||
PsiElement root = documents.get(0).getTopLevelValue();
|
||||
if (root == null) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
|
||||
JsonSchemaService service = JsonSchemaService.Impl.get(file.getProject());
|
||||
VirtualFile virtualFile = file.getViewProvider().getVirtualFile();
|
||||
if (!service.isApplicableToFile(virtualFile)) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
final JsonSchemaObject rootSchema = service.getSchemaObject(virtualFile);
|
||||
if (rootSchema == null) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
|
||||
JsonSchemaObject object = service.getSchemaObject(virtualFile);
|
||||
if (object == null) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
return new YamlPsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (element != root) return;
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(element, object);
|
||||
if (walker == null) return;
|
||||
|
||||
new JsonSchemaComplianceChecker(object, holder, walker, session, "Schema validation: ").annotate(element);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLKeyValue;
|
||||
import org.jetbrains.yaml.psi.YAMLMapping;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class YamlObjectAdapter implements JsonObjectValueAdapter {
|
||||
|
||||
@NotNull private final YAMLMapping myObject;
|
||||
@NotNull private final NotNullLazyValue<List<JsonPropertyAdapter>> myChildAdapters = new NotNullLazyValue<List<JsonPropertyAdapter>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected List<JsonPropertyAdapter> compute() {
|
||||
return computeChildAdapters();
|
||||
}
|
||||
};
|
||||
|
||||
public YamlObjectAdapter(@NotNull YAMLMapping object) {myObject = object;}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStringLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumberLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBooleanLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getDelegate() {
|
||||
return myObject;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonObjectValueAdapter getAsObject() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonArrayValueAdapter getAsArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCheckIntegralRequirements() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JsonPropertyAdapter> getPropertyList() {
|
||||
return myChildAdapters.getValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsonPropertyAdapter> computeChildAdapters() {
|
||||
Collection<YAMLKeyValue> keyValues = myObject.getKeyValues();
|
||||
List<JsonPropertyAdapter> adapters = ContainerUtil.newArrayListWithCapacity(keyValues.size());
|
||||
for (YAMLKeyValue value : keyValues) {
|
||||
adapters.add(new YamlPropertyAdapter(value));
|
||||
}
|
||||
return adapters;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter;
|
||||
import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.psi.YAMLKeyValue;
|
||||
import org.jetbrains.yaml.psi.YAMLMapping;
|
||||
import org.jetbrains.yaml.psi.YAMLSequence;
|
||||
import org.jetbrains.yaml.psi.YAMLValue;
|
||||
|
||||
public class YamlPropertyAdapter implements JsonPropertyAdapter {
|
||||
|
||||
private final YAMLKeyValue myProperty;
|
||||
|
||||
public YamlPropertyAdapter(@NotNull YAMLKeyValue property) {myProperty = property;}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getName() {
|
||||
return myProperty.getKeyText();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonValueAdapter getNameValueAdapter() {
|
||||
return null; // todo: we need a separate adapter for names; but currently names schema is rarely used, let's just skip validation
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonValueAdapter getValue() {
|
||||
YAMLValue value = myProperty.getValue();
|
||||
return value == null ? null : createValueAdapterByType(value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getDelegate() {
|
||||
return myProperty;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonObjectValueAdapter getParentObject() {
|
||||
return myProperty.getParentMapping() != null ? new YamlObjectAdapter(myProperty.getParentMapping()) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsonValueAdapter createValueAdapterByType(@NotNull YAMLValue value) {
|
||||
if (value instanceof YAMLMapping) return new YamlObjectAdapter((YAMLMapping) value);
|
||||
if (value instanceof YAMLSequence) return new YamlArrayAdapter((YAMLSequence) value);
|
||||
return new YamlGenericValueAdapter(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.jetbrains.jsonSchema.impl.JsonBySchemaCompletionBaseTest;
|
||||
|
||||
public class YamlByJsonSchemaCompletionTest extends JsonBySchemaCompletionBaseTest {
|
||||
public void testTopLevel() throws Exception {
|
||||
testBySchema("{\"properties\": {\"prima\": {}, \"proto\": {}, \"primus\": {}}}", "proto: 5\n<caret>", "yml",
|
||||
"prima", "primus");
|
||||
}
|
||||
|
||||
public void testNested() throws Exception {
|
||||
testBySchema("{\"properties\": {\"prima\": {\"properties\": {\"proto\": {}, \"primus\": {}}}}}",
|
||||
"prima:\n <caret>", "yml",
|
||||
"primus", "proto");
|
||||
}
|
||||
|
||||
public void testNestedInArray() throws Exception {
|
||||
testBySchema("{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"colorMap\": {\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": {\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"hue\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" },\n" +
|
||||
" \"saturation\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" },\n" +
|
||||
" \"value\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}", "colorMap:\n - <caret>", "yml", "hue", "saturation", "value");
|
||||
}
|
||||
|
||||
public void testEnumInArray() throws Exception {
|
||||
testBySchema("{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"colorMap\": {\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": {\n" +
|
||||
" \"enum\": [\"white\", \"blue\", \"red\"]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}", "colorMap:\n - <caret>", "yml", "blue", "red", "white");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.jetbrains.jsonSchema.JsonBySchemaDocumentationBaseTest;
|
||||
|
||||
public class YamlByJsonSchemaDocumentationTest extends JsonBySchemaDocumentationBaseTest {
|
||||
@Override
|
||||
public String getTestDataPath() {
|
||||
return PathManagerEx.getCommunityHomePath() + "/plugins/yaml/testSrc/org/jetbrains/yaml/schema/data";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return ""; // unused
|
||||
}
|
||||
|
||||
public void testDoc() throws Exception {
|
||||
doTest(true, "yml");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.json.JsonFileType;
|
||||
import com.intellij.json.psi.JsonFile;
|
||||
import com.intellij.json.psi.JsonObject;
|
||||
import com.intellij.json.psi.JsonStringLiteral;
|
||||
import com.intellij.json.psi.JsonValue;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.jsonSchema.impl.JsonBySchemaHeavyCompletionTest;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class YamlByJsonSchemaHeavyCompletionTest extends JsonBySchemaHeavyCompletionTest {
|
||||
@Override
|
||||
public String getTestDataPath() {
|
||||
return PathManagerEx.getCommunityHomePath() + "/plugins/yaml/testSrc/org/jetbrains/yaml/schema/data/completion";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return ""; // unused
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExtensionWithoutDot() {
|
||||
return "yml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testEditingSchemaAffectsCompletion() throws Exception {
|
||||
baseTest(getTestName(true), "testEditing", () -> {
|
||||
complete();
|
||||
assertStringItems("preserve", "react", "react-native");
|
||||
|
||||
final PsiFile schema = myFile.getParent().findFile("Schema.json");
|
||||
final int idx = schema.getText().indexOf("react-native");
|
||||
Assert.assertTrue(idx > 0);
|
||||
PsiElement element = schema.findElementAt(idx);
|
||||
element = element instanceof JsonStringLiteral ? element : PsiTreeUtil.getParentOfType(element, JsonStringLiteral.class);
|
||||
Assert.assertTrue(element instanceof JsonStringLiteral);
|
||||
|
||||
final PsiFile dummy = PsiFileFactory.getInstance(myProject).createFileFromText("test.json", JsonFileType.INSTANCE,
|
||||
"{\"a\": \"completelyChanged\"}");
|
||||
Assert.assertTrue(dummy instanceof JsonFile);
|
||||
final JsonValue top = ((JsonFile)dummy).getTopLevelValue();
|
||||
final JsonValue newLiteral = ((JsonObject)top).findProperty("a").getValue();
|
||||
|
||||
PsiElement finalElement = element;
|
||||
WriteAction.run(() -> finalElement.replace(newLiteral));
|
||||
|
||||
complete();
|
||||
assertStringItems("completelyChanged", "preserve", "react");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testOneOfWithNotFilledPropertyValue() throws Exception {
|
||||
baseCompletionTest("oneOfWithEnumValue", "oneOfWithEmptyPropertyValue", "business", "home");
|
||||
}
|
||||
|
||||
public void testObjectLiteral() throws Exception {
|
||||
baseInsertTest("insertArrayOrObjectLiteral", "objectLiteral");
|
||||
complete();
|
||||
assertStringItems("insideTopObject1", "insideTopObject2");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,704 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.Predicate;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaHighlightingTestBase;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.yaml.YAMLLanguage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class YamlByJsonSchemaHighlightingTest extends JsonSchemaHighlightingTestBase {
|
||||
@Override
|
||||
public String getTestDataPath() {
|
||||
return PathManagerEx.getCommunityHomePath() + "/plugins/yaml/testSrc/org/jetbrains/yaml/schema/data";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestFileName() {
|
||||
return "config.yml";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspectionProfile() {
|
||||
return new YamlJsonSchemaHighlightingInspection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<VirtualFile> getAvailabilityPredicate() {
|
||||
return file -> file.getFileType() instanceof LanguageFileType && ((LanguageFileType)file.getFileType()).getLanguage().isKindOf(
|
||||
YAMLLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
public void testEnum1() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\"prop\": {\"enum\": [1,2,3,\"18\"]}}}";
|
||||
doTest(schema, "prop: 1");
|
||||
doTest(schema, "prop: <warning>foo</warning>");
|
||||
}
|
||||
|
||||
public void testMissingProp() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\"prop\": {}, \"flop\": {}}, \"required\": [\"flop\"]}";
|
||||
|
||||
doTest(schema, "<warning>prop: 2</warning>");
|
||||
doTest(schema, "prop: 2\nflop: a");
|
||||
doTest(schema, "flop: a");
|
||||
}
|
||||
|
||||
public void testNumberMultipleWrong() throws Exception {
|
||||
doTest("{ \"properties\": { \"prop\": {\"type\": \"number\", \"multipleOf\": 2}}}",
|
||||
"prop: <warning descr=\"Schema validation: Is not multiple of 2\">3</warning>");
|
||||
}
|
||||
|
||||
public void testNumberMultipleCorrect() throws Exception {
|
||||
doTest("{ \"properties\": { \"prop\": {\"type\": \"number\", \"multipleOf\": 2}}}", "prop: 4");
|
||||
}
|
||||
|
||||
public void testNumberMinMax() throws Exception {
|
||||
doTest("{ \"properties\": { \"prop\": {\n" +
|
||||
" \"type\": \"number\",\n" +
|
||||
" \"minimum\": 0,\n" +
|
||||
" \"maximum\": 100,\n" +
|
||||
" \"exclusiveMaximum\": true\n" +
|
||||
"}}}", "prop: 14");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testEnum() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\"prop\": {\"enum\": [1,2,3,\"18\"]}}}";
|
||||
doTest(schema, "prop: 18");
|
||||
doTest(schema, "prop: 2");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Value should be one of: [1, 2, 3, \\\"18\\\"]\">6</warning>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testSimpleString() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\"prop\": {\"type\": \"string\", \"minLength\": 2, \"maxLength\": 3}}}";
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: String is shorter than 2\">s</warning>");
|
||||
doTest(schema, "prop: sh");
|
||||
doTest(schema, "prop: sho");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: String is longer than 3\">shor</warning>");
|
||||
}
|
||||
|
||||
public void testArray() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": {\n" +
|
||||
" \"type\": \"number\", \"minimum\": 18" +
|
||||
" }\n" +
|
||||
"}");
|
||||
doTest(schema, "prop:\n - 101\n - 102");
|
||||
doTest(schema, "prop:\n - <warning descr=\"Schema validation: Less than a minimum 18.0\">16</warning>");
|
||||
doTest(schema, "prop:\n - <warning descr=\"Schema validation: Type is not allowed. Expected: number.\">test</warning>");
|
||||
}
|
||||
|
||||
public void testTopLevelArray() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": {\n" +
|
||||
" \"type\": \"number\", \"minimum\": 18" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "- 101\n- 102");
|
||||
}
|
||||
|
||||
public void testTopLevelObjectArray() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": {\n" +
|
||||
" \"type\": \"object\", \"properties\": {\"a\": {\"type\": \"number\"}}" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "- a: <warning descr=\"Schema validation: Type is not allowed. Expected: number.\">true</warning>");
|
||||
doTest(schema, "- a: 18");
|
||||
}
|
||||
|
||||
public void testArrayTuples1() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": [{\n" +
|
||||
" \"type\": \"number\", \"minimum\": 18" +
|
||||
" }, {\"type\" : \"string\"}]\n" +
|
||||
"}");
|
||||
doTest(schema, "prop:\n - 101\n - 102");
|
||||
|
||||
@Language("JSON") final String schema2 = schema("{\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": [{\n" +
|
||||
" \"type\": \"number\", \"minimum\": 18" +
|
||||
" }, {\"type\" : \"string\"}],\n" +
|
||||
"\"additionalItems\": false}");
|
||||
doTest(schema2, "prop:\n - 101\n - 102\n - <warning descr=\"Schema validation: Additional items are not allowed\">additional</warning>");
|
||||
}
|
||||
|
||||
public void testArrayLength() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{\"type\": \"array\", \"minItems\": 2, \"maxItems\": 3}");
|
||||
doTest(schema, "prop:\n <warning descr=\"Schema validation: Array is shorter than 2\">- 1</warning>");
|
||||
doTest(schema, "prop:\n - 1\n - 2");
|
||||
doTest(schema, "prop:\n <warning descr=\"Schema validation: Array is longer than 3\">- 1\n - 2\n - 3\n - 4</warning>");
|
||||
}
|
||||
|
||||
public void testArrayUnique() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{\"type\": \"array\", \"uniqueItems\": true}");
|
||||
doTest(schema, "prop:\n - 1\n - 2");
|
||||
doTest(schema, "prop:\n - <warning descr=\"Schema validation: Item is not unique\">1</warning>\n - 2\n - test\n - <warning descr=\"Schema validation: Item is not unique\">1</warning>");
|
||||
}
|
||||
|
||||
public void testMetadataIsOk() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"title\" : \"Match anything\",\n" +
|
||||
" \"description\" : \"This is a schema that matches anything.\",\n" +
|
||||
" \"default\" : \"Default value\"\n" +
|
||||
"}";
|
||||
doTest(schema, "anything: 1");
|
||||
}
|
||||
|
||||
public void testRequiredField() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"type\": \"object\", \"properties\": {\"a\": {}, \"b\": {}}, \"required\": [\"a\"]}";
|
||||
doTest(schema, "a: 11");
|
||||
doTest(schema, "a: 1\nb: true");
|
||||
doTest(schema, "<warning descr=\"Schema validation: Missing required property 'a'\">b: alarm</warning>");
|
||||
}
|
||||
|
||||
public void testInnerRequired() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{\"type\": \"object\", \"properties\": {\"a\": {}, \"b\": {}}, \"required\": [\"a\"]}");
|
||||
doTest(schema, "prop:\n a: 11");
|
||||
doTest(schema, "prop:\n a: 1\n b: true");
|
||||
doTest(schema, "prop:\n <warning descr=\"Schema validation: Missing required property 'a'\">b: alarm</warning>");
|
||||
}
|
||||
|
||||
public void testAdditionalPropertiesAllowed() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{}");
|
||||
doTest(schema, "prop:\n q: true\n someStuff: 20");
|
||||
}
|
||||
|
||||
public void testAdditionalPropertiesDisabled() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"type\": \"object\", \"properties\": {\"prop\": {}}, \"additionalProperties\": false}";
|
||||
// not sure abt inner object
|
||||
doTest(schema, "prop:\n q: true\n<warning descr=\"Schema validation: Property 'someStuff' is not allowed\">someStuff: 20</warning>");
|
||||
}
|
||||
|
||||
public void testAdditionalPropertiesSchema() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"type\": \"object\", \"properties\": {\"a\": {}}," +
|
||||
"\"additionalProperties\": {\"type\": \"number\"}}";
|
||||
doTest(schema, "a: moo\nb: 5\nc: <warning descr=\"Schema validation: Type is not allowed. Expected: number.\">foo</warning>");
|
||||
}
|
||||
|
||||
public void testMinMaxProperties() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"type\": \"object\", \"minProperties\": 2, \"maxProperties\": 3}";
|
||||
doTest(schema, "<warning descr=\"Schema validation: Number of properties is less than 2\">a: 3</warning>");
|
||||
doTest(schema, "a: 1\nb: 5");
|
||||
doTest(schema, "<warning descr=\"Schema validation: Number of properties is greater than 3\">a: 1\nb: 22\nc: 333\nd: 4444</warning>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testOneOf() throws Exception {
|
||||
final List<String> subSchemas = new ArrayList<>();
|
||||
subSchemas.add("{\"type\": \"number\"}");
|
||||
subSchemas.add("{\"type\": \"boolean\"}");
|
||||
@Language("JSON") final String schema = schema("{\"oneOf\": [" + StringUtil.join(subSchemas, ", ") + "]}");
|
||||
doTest(schema, "prop: 5");
|
||||
doTest(schema, "prop: true");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Type is not allowed. Expected one of: boolean, number.\">aaa</warning>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testOneOfForTwoMatches() throws Exception {
|
||||
final List<String> subSchemas = new ArrayList<>();
|
||||
subSchemas.add("{\"type\": \"string\", \"enum\": [\"a\", \"b\"]}");
|
||||
subSchemas.add("{\"type\": \"string\", \"enum\": [\"a\", \"c\"]}");
|
||||
@Language("JSON") final String schema = schema("{\"oneOf\": [" + StringUtil.join(subSchemas, ", ") + "]}");
|
||||
doTest(schema, "prop: b");
|
||||
doTest(schema, "prop: c");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Validates to more than one variant\">a</warning>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testOneOfSelectError() throws Exception {
|
||||
final List<String> subSchemas = new ArrayList<>();
|
||||
subSchemas.add("{\"type\": \"string\",\n" +
|
||||
" \"enum\": [\n" +
|
||||
" \"off\", \"warn\", \"error\"\n" +
|
||||
" ]}");
|
||||
subSchemas.add("{\"type\": \"integer\"}");
|
||||
@Language("JSON") final String schema = schema("{\"oneOf\": [" + StringUtil.join(subSchemas, ", ") + "]}");
|
||||
doTest(schema, "prop: off");
|
||||
doTest(schema, "prop: 12");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Value should be one of: [\\\"off\\\", \\\"warn\\\", \\\"error\\\"]\">wrong</warning>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testAnyOf() throws Exception {
|
||||
final List<String> subSchemas = new ArrayList<>();
|
||||
subSchemas.add("{\"type\": \"string\", \"enum\": [\"a\", \"b\"]}");
|
||||
subSchemas.add("{\"type\": \"string\", \"enum\": [\"a\", \"c\"]}");
|
||||
@Language("JSON") final String schema = schema("{\"anyOf\": [" + StringUtil.join(subSchemas, ", ") + "]}");
|
||||
doTest(schema, "prop: b");
|
||||
doTest(schema, "prop: c");
|
||||
doTest(schema, "prop: a");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Value should be one of: [\\\"a\\\", \\\"b\\\"]\">d</warning>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void testAllOf() throws Exception {
|
||||
final List<String> subSchemas = new ArrayList<>();
|
||||
subSchemas.add("{\"type\": \"integer\", \"multipleOf\": 2}");
|
||||
subSchemas.add("{\"enum\": [1,2,3]}");
|
||||
@Language("JSON") final String schema = schema("{\"allOf\": [" + StringUtil.join(subSchemas, ", ") + "]}");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Is not multiple of 2\">1</warning>");
|
||||
doTest(schema, "prop: <warning descr=\"Schema validation: Value should be one of: [1, 2, 3]\">4</warning>");
|
||||
doTest(schema, "prop: 2");
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
public void testObjectInArray() throws Exception {
|
||||
@Language("JSON") final String schema = schema("{\"type\": \"array\", \"items\": {\"type\": \"object\"," +
|
||||
"\"properties\": {" +
|
||||
"\"innerType\":{}, \"innerValue\":{}" +
|
||||
"}, \"additionalProperties\": false" +
|
||||
"}}");
|
||||
doTest(schema, "prop:\n- innerType: aaa\n <warning descr=\"Schema validation: Property 'alien' is not allowed\">alien: bee</warning>");
|
||||
}
|
||||
|
||||
public void testObjectDeeperInArray() throws Exception {
|
||||
final String innerTypeSchema = "{\"properties\": {\"only\": {}}, \"additionalProperties\": false}";
|
||||
@Language("JSON") final String schema = schema("{\"type\": \"array\", \"items\": {\"type\": \"object\"," +
|
||||
"\"properties\": {" +
|
||||
"\"innerType\":" + innerTypeSchema +
|
||||
"}, \"additionalProperties\": false" +
|
||||
"}}");
|
||||
doTest(schema,
|
||||
"prop:\n- innerType:\n only: true\n <warning descr=\"Schema validation: Property 'hidden' is not allowed\">hidden: false</warning>");
|
||||
}
|
||||
|
||||
public void testInnerObjectPropValueInArray() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\"prop\": {\"type\": \"array\", \"items\": {\"enum\": [1,2,3]}}}}";
|
||||
doTest(schema, "prop:\n - 1\n - 3");
|
||||
doTest(schema, "prop:\n - <warning descr=\"Schema validation: Value should be one of: [1, 2, 3]\">out</warning>");
|
||||
}
|
||||
|
||||
public void testAllOfProperties() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"allOf\": [{\"type\": \"object\", \"properties\": {\"first\": {}}}," +
|
||||
" {\"properties\": {\"second\": {\"enum\": [33,44]}}}], \"additionalProperties\": false}";
|
||||
// doTest(schema, "first: true\nsecond: <warning descr=\"Schema validation: Value should be one of: [33, 44]\">null</warning>");
|
||||
doTest(schema, "first: true\nsecond: 44\n<warning descr=\"Schema validation: Property 'other' is not allowed\">other: 15</warning>");
|
||||
doTest(schema, "first: true\nsecond: <warning descr=\"Schema validation: Value should be one of: [33, 44]\">12</warning>");
|
||||
}
|
||||
|
||||
public void testWithWaySelection() throws Exception {
|
||||
final String subSchema1 = "{\"enum\": [1,2,3,4,5]}";
|
||||
final String subSchema2 = "{\"type\": \"array\", \"items\": {\"properties\": {\"kilo\": {}}, \"additionalProperties\": false}}";
|
||||
@Language("JSON") final String schema = "{\"properties\": {\"prop\": {\"oneOf\": [" + subSchema1 + ", " + subSchema2 + "]}}}";
|
||||
doTest(schema, "prop:\n - <warning descr=\"Schema validation: Property 'foxtrot' is not allowed\">foxtrot: 15</warning>\n kilo: 20");
|
||||
}
|
||||
|
||||
public void testPatternPropertiesHighlighting() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"patternProperties\": {\n" +
|
||||
" \"^A\" : {\n" +
|
||||
" \"type\": \"number\"\n" +
|
||||
" },\n" +
|
||||
" \"B\": {\n" +
|
||||
" \"type\": \"boolean\"\n" +
|
||||
" },\n" +
|
||||
" \"C\": {\n" +
|
||||
" \"enum\": [\"test\", \"em\"]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "Abezjana: 2\n" +
|
||||
"Auto: <warning descr=\"Schema validation: Type is not allowed. Expected: number.\">no</warning>\n" +
|
||||
"BAe: <warning descr=\"Schema validation: Type is not allowed. Expected: boolean.\">22</warning>\n" +
|
||||
"Boloto: <warning descr=\"Schema validation: Type is not allowed. Expected: boolean.\">2</warning>\n" +
|
||||
"Cyan: <warning descr=\"Schema validation: Value should be one of: [\\\"test\\\", \\\"em\\\"]\">me</warning>\n");
|
||||
}
|
||||
|
||||
public void testPatternPropertiesFromIssue() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"type\": \"object\",\n" +
|
||||
" \"additionalProperties\": false,\n" +
|
||||
" \"patternProperties\": {\n" +
|
||||
" \"p[0-9]\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" },\n" +
|
||||
" \"a[0-9]\": {\n" +
|
||||
" \"enum\": [\"auto!\"]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema,
|
||||
"p1: 1\n" +
|
||||
"p2: 3\n" +
|
||||
"a2: auto!\n" +
|
||||
"a1: <warning descr=\"Schema validation: Value should be one of: [\\\"auto!\\\"]\">moto!</warning>\n"
|
||||
);
|
||||
}
|
||||
|
||||
public void testPatternForPropertyValue() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"withPattern\": {\n" +
|
||||
" \"pattern\": \"p[0-9]\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
final String correctText = "withPattern: p1";
|
||||
final String wrongText = "withPattern: <warning descr=\"Schema validation: String is violating the pattern: 'p[0-9]'\">wrong</warning>";
|
||||
doTest(schema, correctText);
|
||||
doTest(schema, wrongText);
|
||||
}
|
||||
|
||||
public void testPatternWithSpecialEscapedSymbols() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"withPattern\": {\n" +
|
||||
" \"pattern\": \"^\\\\d{4}\\\\-(0?[1-9]|1[012])\\\\-(0?[1-9]|[12][0-9]|3[01])$\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
@Language("yaml") final String correctText = "withPattern: 1234-11-11";
|
||||
final String wrongText = "withPattern: <warning descr=\"Schema validation: String is violating the pattern: '^\\d{4}\\-(0?[1-9]|1[012])\\-(0?[1-9]|[12][0-9]|3[01])$'\">wrong</warning>\n";
|
||||
doTest(schema, correctText);
|
||||
doTest(schema, wrongText);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
|
||||
public void testRootObjectRedefinedAdditionalPropertiesForbidden() throws Exception {
|
||||
doTest(rootObjectRedefinedSchema(), "<warning descr=\"Schema validation: Property 'a' is not allowed\">a: true</warning>\n" +
|
||||
"r1: allowed!");
|
||||
}
|
||||
|
||||
public void testNumberOfSameNamedPropertiesCorrectlyChecked() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"size\": {\n" +
|
||||
" \"type\": \"object\",\n" +
|
||||
" \"minProperties\": 2,\n" +
|
||||
" \"maxProperties\": 3,\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"a\": {\n" +
|
||||
" \"type\": \"boolean\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema,
|
||||
"size: \n" +
|
||||
" <warning descr=\"Schema validation: Number of properties is greater than 3\">a: <warning descr=\"Schema validation: Type is not allowed. Expected: boolean.\">1</warning>\n" +
|
||||
" b: 3\n" +
|
||||
" c: 4\n" +
|
||||
" a: <warning descr=\"Schema validation: Type is not allowed. Expected: boolean.\">5</warning>" +
|
||||
"</warning>\n");
|
||||
}
|
||||
|
||||
public void testManyDuplicatesInArray() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"array\":{\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"uniqueItems\": true\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "array: \n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">1</warning>\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">1</warning>\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">1</warning>\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">2</warning>\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">2</warning>\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">2</warning>\n" +
|
||||
" - 5\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">3</warning>\n" +
|
||||
" - <warning descr=\"Schema validation: Item is not unique\">3</warning>\n");
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
public void testPropertyValueAlsoHighlightedIfPatternIsInvalid() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"withPattern\": {\n" +
|
||||
" \"pattern\": \"^[]$\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
final String text = "withPattern:" +
|
||||
" <warning descr=\"Schema validation: Can not check string by pattern because of error: Unclosed character class near index 3\n^[]$\n ^\">(124)555-4216</warning>";
|
||||
doTest(schema, text);
|
||||
}
|
||||
|
||||
public void testNotSchema() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\n" +
|
||||
" \"not_type\": { \"not\": { \"type\": \"string\" } }\n" +
|
||||
" }}";
|
||||
doTest(schema, "not_type: <warning descr=\"Schema validation: Validates against 'not' schema\">wrong</warning>");
|
||||
}
|
||||
|
||||
public void testNotSchemaCombinedWithNormal() throws Exception {
|
||||
@Language("JSON") final String schema = "{\"properties\": {\n" +
|
||||
" \"not_type\": {\n" +
|
||||
" \"pattern\": \"^[a-z]*[0-5]*$\",\n" +
|
||||
" \"not\": { \"pattern\": \"^[a-z]{1}[0-5]$\" }\n" +
|
||||
" }\n" +
|
||||
" }}";
|
||||
doTest(schema, "not_type: va4");
|
||||
doTest(schema, "not_type: <warning descr=\"Schema validation: Validates against 'not' schema\">a4</warning>");
|
||||
doTest(schema, "not_type: <warning descr=\"Schema validation: String is violating the pattern: '^[a-z]*[0-5]*$'\">4a4</warning>");
|
||||
}
|
||||
|
||||
public void testDoNotMarkOneOfThatDiffersWithFormat() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
"\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"withFormat\": {\n" +
|
||||
" \"type\": \"string\"," +
|
||||
" \"oneOf\": [\n" +
|
||||
" {\n" +
|
||||
" \"format\":\"hostname\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"format\": \"ip4\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "withFormat: localhost");
|
||||
}
|
||||
|
||||
public void testAcceptSchemaWithoutType() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
"\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"withFormat\": {\n" +
|
||||
" \"oneOf\": [\n" +
|
||||
" {\n" +
|
||||
" \"format\":\"hostname\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"format\": \"ip4\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "withFormat: localhost");
|
||||
}
|
||||
|
||||
public void testArrayItemReference() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"items\": [\n" +
|
||||
" {\n" +
|
||||
" \"type\": \"integer\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"$ref\": \"#/items/0\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
doTest(schema, "- 1\n- 2");
|
||||
doTest(schema, "- 1\n- <warning>foo</warning>");
|
||||
}
|
||||
|
||||
public void testValidateAdditionalItems() throws Exception {
|
||||
@Language("JSON") final String schema = "{\n" +
|
||||
" \"definitions\": {\n" +
|
||||
" \"options\": {\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": {\n" +
|
||||
" \"type\": \"number\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"items\": [\n" +
|
||||
" {\n" +
|
||||
" \"type\": \"boolean\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"type\": \"boolean\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"additionalItems\": {\n" +
|
||||
" \"$ref\": \"#/definitions/options/items\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "- true\n- true");
|
||||
doTest(schema, "- true\n- true\n- 1\n- 2\n- 3");
|
||||
doTest(schema, "- true\n- true\n- 1\n- <warning>qq</warning>");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testExclusiveMinMaxV6() throws Exception {
|
||||
@Language("JSON") String exclusiveMinSchema = "{\"properties\": {\"prop\": {\"exclusiveMinimum\": 3}}}";
|
||||
doTest(exclusiveMinSchema, "prop: <warning>2</warning>");
|
||||
doTest(exclusiveMinSchema, "prop: <warning>3</warning>");
|
||||
doTest(exclusiveMinSchema, "prop: 4");
|
||||
|
||||
@Language("JSON") String exclusiveMaxSchema = "{\"properties\": {\"prop\": {\"exclusiveMaximum\": 3}}}";
|
||||
doTest(exclusiveMaxSchema, "prop: 2");
|
||||
doTest(exclusiveMaxSchema, "prop: <warning>3</warning>");
|
||||
doTest(exclusiveMaxSchema, "prop: <warning>4</warning>");
|
||||
}
|
||||
|
||||
/*todo later
|
||||
public void testPropertyNamesV6() throws Exception {
|
||||
doTest("{\"propertyNames\": {\"minLength\": 7}}", "{<warning>\"prop\"</warning>: 2}");
|
||||
doTest("{\"properties\": {\"prop\": {\"propertyNames\": {\"minLength\": 7}}}}", "{\"prop\": {<warning>\"qq\"</warning>: 7}}");
|
||||
}*/
|
||||
|
||||
public void testContainsV6() throws Exception {
|
||||
@Language("JSON") String schema = "{\"properties\": {\"prop\": {\"type\": \"array\", \"contains\": {\"type\": \"number\"}}}}";
|
||||
doTest(schema, "prop:\n <warning>- a\n - true</warning>");
|
||||
doTest(schema, "prop:\n - a\n - true\n - 1");
|
||||
}
|
||||
|
||||
public void testConstV6() throws Exception {
|
||||
@Language("JSON") String schema = "{\"properties\": {\"prop\": {\"type\": \"string\", \"const\": \"foo\"}}}";
|
||||
doTest(schema, "prop: <warning>a</warning>");
|
||||
doTest(schema, "prop: <warning>5</warning>");
|
||||
doTest(schema, "prop: foo");
|
||||
}
|
||||
|
||||
public void testIfThenElseV7() throws Exception {
|
||||
@Language("JSON") String schema = "{\n" +
|
||||
" \"if\": {\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"a\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"required\": [\"a\"]\n" +
|
||||
" },\n" +
|
||||
" \"then\": {\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"b\": {\n" +
|
||||
" \"type\": \"number\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"required\": [\"b\"]\n" +
|
||||
" },\n" +
|
||||
" \"else\": {\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"c\": {\n" +
|
||||
" \"type\": \"boolean\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"required\": [\"c\"]\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "c: <warning>5</warning>");
|
||||
doTest(schema, "c: true");
|
||||
doTest(schema, "<warning>a: a\nc: true</warning>");
|
||||
doTest(schema, "a: a\nb: <warning>true</warning>");
|
||||
doTest(schema, "a: a\nb: 5");
|
||||
}
|
||||
|
||||
public void testNestedOneOf() throws Exception {
|
||||
@Language("JSON") String schema = "{\"type\":\"object\",\n" +
|
||||
" \"oneOf\": [\n" +
|
||||
" {\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"type\": \"string\",\n" +
|
||||
" \"oneOf\": [\n" +
|
||||
" {\n" +
|
||||
" \"pattern\": \"(good)\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"pattern\": \"(ok)\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"type\": \"string\",\n" +
|
||||
" \"pattern\": \"^(fine)\"\n" +
|
||||
" },\n" +
|
||||
" \"extra\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"required\": [\"type\", \"extra\"]\n" +
|
||||
" }\n" +
|
||||
" ]}";
|
||||
|
||||
doTest(schema, "type: good");
|
||||
doTest(schema, "type: ok");
|
||||
doTest(schema, "type: <warning>doog</warning>");
|
||||
doTest(schema, "type: <warning>ko</warning>");
|
||||
}
|
||||
|
||||
public void testArrayRefs() throws Exception {
|
||||
@Language("JSON") String schema = "{\n" +
|
||||
" \"myDefs\": {\n" +
|
||||
" \"myArray\": [\n" +
|
||||
" {\n" +
|
||||
" \"type\": \"number\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"type\": \"boolean\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"type\": \"array\",\n" +
|
||||
" \"items\": [\n" +
|
||||
" {\n" +
|
||||
" \"$ref\": \"#/myDefs/myArray/0\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"$ref\": \"#/myDefs/myArray/1\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
doTest(schema, "- 1\n- <warning>2</warning>");
|
||||
doTest(schema, "- <warning>a</warning>\n- <warning>2</warning>");
|
||||
doTest(schema, "- <warning>a</warning>\n- true");
|
||||
doTest(schema, "- 1\n- false");
|
||||
}
|
||||
|
||||
public void testWithTags() throws Exception {
|
||||
@Language("JSON") String schema = "{\"properties\": { \"platform\": { \"enum\": [\"x86\", \"x64\"] } }}";
|
||||
doTest(schema, "platform:\n !!str x64");
|
||||
doTest(schema, "platform:\n <warning>a x64</warning>");
|
||||
}
|
||||
|
||||
static String schema(final String s) {
|
||||
return "{\"type\": \"object\", \"properties\": {\"prop\": " + s + "}}";
|
||||
}
|
||||
|
||||
public static String rootObjectRedefinedSchema() {
|
||||
return "{\n" +
|
||||
" \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n" +
|
||||
" \"type\": \"object\",\n" +
|
||||
" \"$ref\" : \"#/definitions/root\",\n" +
|
||||
" \"definitions\": {\n" +
|
||||
" \"root\" : {\n" +
|
||||
" \"type\": \"object\",\n" +
|
||||
" \"additionalProperties\": false,\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"r1\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" },\n" +
|
||||
" \"r2\": {\n" +
|
||||
" \"type\": \"string\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.yaml.schema;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
@SuppressWarnings({"JUnitTestCaseWithNoTests", "JUnitTestClassNamingConvention"})
|
||||
public class YamlJsonSchemaTestSuite extends TestCase {
|
||||
public static Test suite() {
|
||||
final TestSuite suite = new TestSuite(YamlJsonSchemaTestSuite.class.getSimpleName());
|
||||
suite.addTestSuite(YamlByJsonSchemaDocumentationTest.class);
|
||||
suite.addTestSuite(YamlByJsonSchemaCompletionTest.class);
|
||||
suite.addTestSuite(YamlByJsonSchemaHeavyCompletionTest.class);
|
||||
suite.addTestSuite(YamlByJsonSchemaHighlightingTest.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"properties": {
|
||||
"jsx": {
|
||||
"oneOf": [
|
||||
{"enum": [ "preserve", "react" ]},
|
||||
{"enum": [ "react-native" ]}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
jsx: <caret>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"properties": {
|
||||
"top": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"enum": [1,2,3]
|
||||
}
|
||||
},
|
||||
"topObject": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"insideTopObject1": {},
|
||||
"insideTopObject2": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
top: <caret>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
top:
|
||||
- <caret>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
topObject: <caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
topObject:
|
||||
<caret>
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"properties": {
|
||||
"jsx": {
|
||||
"enum": [ "preserve", "react", "react-native" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
jsx: <caret>
|
||||
@@ -0,0 +1 @@
|
||||
jsx: preserve
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"properties": {
|
||||
"jsx": {
|
||||
"enum": [ "preserve", "react", "react-native" ]
|
||||
},
|
||||
"withStringDefaultValue": {
|
||||
"default": "stringDefault"
|
||||
},
|
||||
"withIntegerDefaultValue": {
|
||||
"default": 118
|
||||
},
|
||||
"integerType": {
|
||||
"type": "integer"
|
||||
},
|
||||
"stringType": {
|
||||
"type": "string"
|
||||
},
|
||||
"objectType": {
|
||||
"type": "object"
|
||||
},
|
||||
"booleanType": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"arrayType": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
arrayTy<caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
arrayType:
|
||||
- <caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
booleanTy<caret>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
booleanTy<caret>
|
||||
someOtherProperty: false
|
||||
@@ -0,0 +1,2 @@
|
||||
booleanType: <selection>false<caret></selection>
|
||||
someOtherProperty: false
|
||||
@@ -0,0 +1,2 @@
|
||||
booleanType: <selection>false<caret></selection>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
withStringDefault<caret>
|
||||
@@ -0,0 +1 @@
|
||||
withStringDefaultValue: <selection>stringDefault<caret></selection>
|
||||
@@ -0,0 +1 @@
|
||||
integerTy<caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
integerTy<caret>
|
||||
someOtherProperty: 1
|
||||
@@ -0,0 +1,2 @@
|
||||
integerType:<caret>
|
||||
someOtherProperty: 1
|
||||
@@ -0,0 +1 @@
|
||||
integerType: <caret>
|
||||
@@ -0,0 +1 @@
|
||||
js<caret>
|
||||
@@ -0,0 +1 @@
|
||||
withIntegerDefault<caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
withIntegerDefault<caret>
|
||||
someOtherProperty: 112
|
||||
@@ -0,0 +1,2 @@
|
||||
withIntegerDefaultValue: <selection>118<caret></selection>
|
||||
someOtherProperty: 112
|
||||
@@ -0,0 +1 @@
|
||||
withIntegerDefaultValue: <selection>118<caret></selection>
|
||||
@@ -0,0 +1 @@
|
||||
withStringDefault<caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
withStringDefault<caret>
|
||||
some: 2
|
||||
@@ -0,0 +1,2 @@
|
||||
withStringDefaultValue: <selection>stringDefault<caret></selection>
|
||||
some: 2
|
||||
@@ -0,0 +1 @@
|
||||
withStringDefault<caret>
|
||||
@@ -0,0 +1 @@
|
||||
withStringDefaultValue: <selection>stringDefault<caret></selection>
|
||||
@@ -0,0 +1 @@
|
||||
withStringDefaultValue: <selection>stringDefault<caret></selection>
|
||||
@@ -0,0 +1 @@
|
||||
jsx: <caret>
|
||||
@@ -0,0 +1 @@
|
||||
objectTy<caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
objectType:
|
||||
<caret>
|
||||
@@ -0,0 +1 @@
|
||||
stringTy<caret>
|
||||
@@ -0,0 +1,2 @@
|
||||
stringTy<caret>
|
||||
someOtherProperty: 123
|
||||
@@ -0,0 +1,2 @@
|
||||
stringType:<caret>
|
||||
someOtherProperty: 123
|
||||
@@ -0,0 +1 @@
|
||||
stringType: <caret>
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
|
||||
"definitions": {
|
||||
"address": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"street_address": { "type": "string" },
|
||||
"city": { "type": "string" },
|
||||
"state": { "type": "string" }
|
||||
},
|
||||
"required": ["street_address", "city", "state"]
|
||||
},
|
||||
"office_address": {
|
||||
"properties": {
|
||||
"type": { "enum": [ "business" ] },
|
||||
"building": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "building"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"home_address": {
|
||||
"properties": {
|
||||
"type": { "enum": [ "home" ] },
|
||||
"street_address": { "type": "string" },
|
||||
"city": { "type": "string" },
|
||||
"state": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "street_address", "city", "state"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"partOne": {
|
||||
"properties": {"one": {"type": "string"}}
|
||||
},
|
||||
"partTwo": {
|
||||
"properties": {"two": {"type": "integer"}}
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client_address": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/office_address" },
|
||||
{ "$ref": "#/definitions/home_address" }
|
||||
]
|
||||
},
|
||||
"parts": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/partOne" },
|
||||
{ "$ref": "#/definitions/partTwo" }
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
client_address:
|
||||
building: 1
|
||||
type: <caret>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<b>subscriptions</b>: object<br/><br/>All server-side subscriptions
|
||||
@@ -0,0 +1,2 @@
|
||||
su<caret>bscriptions:
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-06/schema#",
|
||||
"title": "JSON schema for Prisma prisma.yml files",
|
||||
"definitions": {
|
||||
"subscription": {
|
||||
"description": "A piece of code that you should run."
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"subscriptions": {
|
||||
"description": "All server-side subscriptions",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/subscription"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<b>subscriptions</b>: object<br/><br/>All server-side subscriptions
|
||||
Reference in New Issue
Block a user