mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
json schema: fix some external references navigation (both for property names into schema and from $ref)
refactor resolve logic so that it is more clear this fixes WEB-24965 JSON Schema: navigation from property names in package.json to package json schema does not work and WEB-21364 JSON Schema:Unable to create relative references to local files
This commit is contained in:
+1
-3
@@ -19,7 +19,6 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaFileType;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsProjectConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -48,8 +47,7 @@ public class JsonSchemaProjectSelfProviderFactory implements JsonSchemaProviderF
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, @NotNull VirtualFile file) {
|
||||
if (!JsonSchemaFileType.INSTANCE.equals(file.getFileType())) return false;
|
||||
return JsonSchemaMappingsProjectConfiguration.getInstance(project).isRegisteredSchemaFile(file);
|
||||
return JsonSchemaFileType.INSTANCE.equals(file.getFileType());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.jsonSchema.extension.schema;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaResourcesRootsProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 1/10/2017.
|
||||
*/
|
||||
public class JsonSchemaByPropertyIndexResolver {
|
||||
@NotNull private final String myReferenceName;
|
||||
@NotNull private final Project myProject;
|
||||
@Nullable private final VirtualFile mySchemaFile;
|
||||
|
||||
private VirtualFile myFile;
|
||||
private Integer myOffset;
|
||||
|
||||
public JsonSchemaByPropertyIndexResolver(@NotNull String referenceName,
|
||||
@NotNull Project project,
|
||||
@Nullable VirtualFile schemaFile) {
|
||||
myReferenceName = referenceName;
|
||||
myProject = project;
|
||||
mySchemaFile = schemaFile;
|
||||
}
|
||||
|
||||
public PsiElement resolveByName() {
|
||||
final GlobalSearchScope scope;
|
||||
if (mySchemaFile != null) {
|
||||
scope = GlobalSearchScope.fileScope(myProject, mySchemaFile);
|
||||
} else {
|
||||
scope = JsonSchemaResourcesRootsProvider.enlarge(myProject, GlobalSearchScope.allScope(myProject));
|
||||
}
|
||||
|
||||
FileBasedIndex.getInstance().processValues(JsonSchemaFileIndex.PROPERTIES_INDEX, myReferenceName, null, (file, value) -> {
|
||||
if (!scope.contains(file)) return true;
|
||||
myFile = file;
|
||||
myOffset = value;
|
||||
return false;
|
||||
}, scope);
|
||||
|
||||
if (myFile != null) {
|
||||
myOffset = myOffset == null ? 0 : myOffset;
|
||||
final PsiFile file = PsiManager.getInstance(myProject).findFile(myFile);
|
||||
if (file != null) {
|
||||
return file.findElementAt(myOffset);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.jsonSchema.extension.schema;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaReader;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaWalker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.jetbrains.jsonSchema.extension.schema.JsonSchemaInsideSchemaResolver.PROPERTIES;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 1/10/2017.
|
||||
*/
|
||||
public class JsonSchemaBySchemaObjectResolver {
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final VirtualFile mySchemaFile;
|
||||
@NotNull private final String myShortPropertyName;
|
||||
@NotNull private final List<JsonSchemaWalker.Step> myPosition;
|
||||
@NotNull private final PairConsumer<VirtualFile, String> myConsumer;
|
||||
|
||||
public JsonSchemaBySchemaObjectResolver(@NotNull Project project,
|
||||
@NotNull VirtualFile schemaFile,
|
||||
@NotNull String shortPropertyName,
|
||||
@NotNull List<JsonSchemaWalker.Step> position,
|
||||
@NotNull PairConsumer<VirtualFile, String> consumer) {
|
||||
myProject = project;
|
||||
mySchemaFile = schemaFile;
|
||||
myShortPropertyName = shortPropertyName;
|
||||
myPosition = position.subList(0, position.size() - 1);
|
||||
myConsumer = consumer;
|
||||
}
|
||||
|
||||
public void iterateMatchingDefinitions() {
|
||||
final JsonSchemaWalker.CompletionSchemesConsumer consumer = new JsonSchemaWalker.CompletionSchemesConsumer() {
|
||||
@Override
|
||||
public void consume(boolean isName, @NotNull JsonSchemaObject schema) {
|
||||
//myConsumer.consume(mySchemaFile, myShortPropertyName);//todo using short property name here is wrong
|
||||
processDefinitionAddress(schema, myShortPropertyName);
|
||||
|
||||
List<JsonSchemaObject> list = new ArrayList<>();
|
||||
if (schema.getAllOf() != null) list.addAll(schema.getAllOf());
|
||||
if (schema.getAnyOf() != null) list.addAll(schema.getAnyOf());
|
||||
if (schema.getOneOf() != null) list.addAll(schema.getOneOf());
|
||||
for (JsonSchemaObject schemaObject : list) {
|
||||
processDefinitionAddress(schemaObject, myShortPropertyName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JsonSchemaService.Impl.getEx(myProject).visitSchemaObject(
|
||||
mySchemaFile,
|
||||
object -> {
|
||||
if (myPosition.isEmpty()) {
|
||||
consumer.consume(true, object);
|
||||
return true;
|
||||
}
|
||||
JsonSchemaWalker.extractSchemaVariants(consumer, object, true, myPosition);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void processDefinitionAddress(@NotNull JsonSchemaObject parSchema, @NotNull String propertyName) {
|
||||
final String definitionAddress = parSchema.getDefinitionAddress();
|
||||
if (StringUtil.isEmptyOrSpaces(definitionAddress)) return;
|
||||
|
||||
final JsonSchemaReader.SchemaUrlSplitter splitter = new JsonSchemaReader.SchemaUrlSplitter(definitionAddress);
|
||||
|
||||
if (!splitter.isAbsolute()) {
|
||||
VirtualFile schemaFile = mySchemaFile;
|
||||
if (parSchema.getId() != null) {
|
||||
schemaFile = JsonSchemaService.Impl.getEx(myProject).getSchemaFileById(parSchema.getId(), mySchemaFile);
|
||||
if (schemaFile == null) return;
|
||||
}
|
||||
final String newReferenceName = definitionAddress.substring(1) + PROPERTIES + propertyName;
|
||||
myConsumer.consume(schemaFile, newReferenceName);
|
||||
} else {
|
||||
String relative = splitter.getRelativePath();
|
||||
if (StringUtil.isEmptyOrSpaces(relative)) {
|
||||
relative = PROPERTIES + propertyName;
|
||||
} else {
|
||||
relative += ((relative.endsWith("/") ? PROPERTIES.substring(1) : PROPERTIES) + propertyName);
|
||||
}
|
||||
assert splitter.getSchemaId() != null;
|
||||
|
||||
final VirtualFile schemaFile = JsonSchemaService.Impl.getEx(myProject).getSchemaFileById(parSchema.getId(), mySchemaFile);
|
||||
if (schemaFile == null) return;
|
||||
myConsumer.consume(schemaFile, relative);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.jsonSchema.extension.schema;
|
||||
|
||||
import com.intellij.json.psi.JsonObject;
|
||||
import com.intellij.json.psi.JsonProperty;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaFileType;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import com.jetbrains.jsonSchema.impl.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 7/7/2016.
|
||||
*/
|
||||
public class JsonSchemaDefinitionResolver {
|
||||
public static final String PROPERTIES = "/properties/";
|
||||
@Nullable private String myRef;
|
||||
@Nullable JsonSchemaObject mySchemaObject;
|
||||
|
||||
@NotNull private final PsiElement myElement;
|
||||
@Nullable final String mySchemaId;
|
||||
|
||||
public JsonSchemaDefinitionResolver(@NotNull PsiElement element, @Nullable String schemaId) {
|
||||
myElement = element;
|
||||
mySchemaId = schemaId;
|
||||
}
|
||||
|
||||
public JsonSchemaDefinitionResolver setSchemaObject(@NotNull final JsonSchemaObject value) {
|
||||
mySchemaObject = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonSchemaDefinitionResolver setRef(@NotNull final String value) {
|
||||
myRef = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement doResolve() {
|
||||
PsiElement result = tryResolveByName();
|
||||
if (result != null) return result;
|
||||
if (mySchemaId == null) {
|
||||
return tryResolveBySchemaObject();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement doResolveInSchemaFile() {
|
||||
if (!JsonSchemaFileType.INSTANCE.equals(myElement.getContainingFile().getFileType())) return null;
|
||||
if (myRef == null) initializeName();
|
||||
if (myRef == null) return null;
|
||||
final PsiElement element = resolveInSomeSchema(myRef, myElement.getProject(), null, myElement.getContainingFile().getVirtualFile());
|
||||
if (element != null) return element;
|
||||
if (mySchemaId == null) {
|
||||
return tryResolveBySchemaObject();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PsiElement tryResolveBySchemaObject() {
|
||||
if (!(myElement.getParent() instanceof JsonProperty)) return null;
|
||||
final Ref<PsiElement> ref = new Ref<>();
|
||||
|
||||
final String propertyName = ((JsonProperty)myElement.getParent()).getName();
|
||||
|
||||
JsonSchemaService.Impl.getEx(myElement.getProject()).iterateSchemaObjects(
|
||||
myElement.getContainingFile().getVirtualFile(),
|
||||
object -> {
|
||||
final JsonSchemaWalker.CompletionSchemesConsumer consumer = new JsonSchemaWalker.CompletionSchemesConsumer() {
|
||||
@Override
|
||||
public void consume(boolean isName, @NotNull JsonSchemaObject schema) {
|
||||
if (!ref.isNull()) return;
|
||||
|
||||
ref.set(processDefinitionAddress(schema, propertyName));
|
||||
if (!ref.isNull()) return;
|
||||
|
||||
List<JsonSchemaObject> list = new ArrayList<>();
|
||||
if (schema.getAllOf() != null) list.addAll(schema.getAllOf());
|
||||
if (schema.getAnyOf() != null) list.addAll(schema.getAnyOf());
|
||||
if (schema.getOneOf() != null) list.addAll(schema.getOneOf());
|
||||
for (JsonSchemaObject schemaObject : list) {
|
||||
ref.set(processDefinitionAddress(schemaObject, propertyName));
|
||||
if (!ref.isNull()) return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final List<JsonSchemaWalker.Step> position = JsonSchemaWalker.findPosition(((JsonProperty)myElement.getParent()).getNameElement(), true);
|
||||
if (position == null || position.isEmpty()) return true; // to continue iteration
|
||||
JsonSchemaWalker.extractSchemaVariants(consumer, object, true, position);
|
||||
return ref.isNull();
|
||||
});
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement processDefinitionAddress(JsonSchemaObject parSchema, String propertyName) {
|
||||
final String definitionAddress = parSchema.getDefinitionAddress();
|
||||
if (StringUtil.isEmptyOrSpaces(definitionAddress)) return null;
|
||||
|
||||
final JsonSchemaReader.SchemaUrlSplitter splitter = new JsonSchemaReader.SchemaUrlSplitter(definitionAddress);
|
||||
|
||||
if (!splitter.isAbsolute()) {
|
||||
VirtualFile schemaFile = null;
|
||||
if (parSchema.getId() != null) {
|
||||
schemaFile = JsonSchemaService.Impl.getEx(myElement.getProject()).getSchemaFileById(parSchema.getId());
|
||||
}
|
||||
return resolveInSomeSchema(definitionAddress.substring(1) + PROPERTIES + propertyName, myElement.getProject(), parSchema.getId(), schemaFile);
|
||||
} else {
|
||||
String relative = splitter.getRelativePath();
|
||||
if (StringUtil.isEmptyOrSpaces(relative)) {
|
||||
relative = PROPERTIES + propertyName;
|
||||
} else {
|
||||
relative += ((relative.endsWith("/") ? PROPERTIES.substring(1) : PROPERTIES) + propertyName);
|
||||
}
|
||||
|
||||
return resolveInSomeSchema(relative, myElement.getProject(), splitter.getSchemaId(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private PsiElement tryResolveByName() {
|
||||
if (myRef == null) initializeName();
|
||||
if (myRef == null) return null;
|
||||
|
||||
if (mySchemaId == null) {
|
||||
final JsonSchemaServiceEx schemaServiceEx = JsonSchemaService.Impl.getEx(myElement.getProject());
|
||||
final Collection<Pair<VirtualFile, String>> pairs = schemaServiceEx.getSchemaFilesByFile(myElement.getContainingFile().getVirtualFile());
|
||||
if (pairs != null && ! pairs.isEmpty()) {
|
||||
for (Pair<VirtualFile, String> pair : pairs) {
|
||||
final PsiElement element = resolveInSomeSchema(myRef, myElement.getProject(), pair.getSecond(), pair.getFirst());
|
||||
if (element != null) return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return resolveInSomeSchema(myRef, myElement.getProject(), mySchemaId, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement resolveInSomeSchema(@NotNull String referenceName,
|
||||
@NotNull final Project project,
|
||||
@Nullable final String schemaId,
|
||||
final @Nullable VirtualFile filterFile) {
|
||||
final Ref<Pair<VirtualFile, Integer>> reference = new Ref<>();
|
||||
|
||||
final FileBasedIndex index = FileBasedIndex.getInstance();
|
||||
final GlobalSearchScope fileScope = filterFile == null ? null : GlobalSearchScope.fileScope(project, filterFile);
|
||||
final GlobalSearchScope enlarged = fileScope != null && JsonSchemaResourcesRootsProvider.ourFiles.getValue().contains(filterFile) ? fileScope :
|
||||
JsonSchemaResourcesRootsProvider.enlarge(project, fileScope == null ? GlobalSearchScope.allScope(project) : fileScope);
|
||||
index.processValues(JsonSchemaFileIndex.PROPERTIES_INDEX, referenceName, null, new FileBasedIndex.ValueProcessor<Integer>() {
|
||||
@Override
|
||||
public boolean process(@NotNull VirtualFile file, Integer value) {
|
||||
final VirtualFile extractedFile = extractFileFromSchemaId();
|
||||
if (extractedFile != null) {
|
||||
if (!file.equals(extractedFile)) return false;
|
||||
}
|
||||
else if (schemaId != null) {
|
||||
if (!JsonSchemaService.Impl.getEx(project).checkFileForId(schemaId, file)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
reference.set(Pair.create(file, value));
|
||||
return false;
|
||||
}
|
||||
}, enlarged);
|
||||
|
||||
if (!reference.isNull()) {
|
||||
final Pair<VirtualFile, Integer> pair = reference.get();
|
||||
final PsiFile file = PsiManager.getInstance(project).findFile(pair.getFirst());
|
||||
if (file != null) {
|
||||
return file.findElementAt(pair.getSecond());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile extractFileFromSchemaId() {
|
||||
if (mySchemaId == null) return null;
|
||||
VirtualFile dir = myElement.getContainingFile().getVirtualFile();
|
||||
if (!dir.isDirectory()) dir = dir.getParent();
|
||||
if (dir == null || !dir.isValid()) return null;
|
||||
return VfsUtil.findRelativeFile(dir, JsonSchemaExportedDefinitions.normalizeId(mySchemaId).
|
||||
replace("\\", "/").split("/"));
|
||||
}
|
||||
|
||||
private void initializeName() {
|
||||
final List<String> names = new ArrayList<>();
|
||||
final PsiElement parent = myElement.getParent();
|
||||
if (!(parent instanceof JsonProperty)) return;
|
||||
JsonProperty element = (JsonProperty)parent;
|
||||
while (true) {
|
||||
names.add(StringUtil.unquoteString(element.getName()));
|
||||
if (!(element.getParent() instanceof JsonObject)) break;
|
||||
final PsiElement grand = element.getParent().getParent();
|
||||
if (grand instanceof JsonProperty && ((JsonProperty)grand).getValue() != null &&
|
||||
((JsonProperty)grand).getValue().equals(element.getParent())) {
|
||||
element = (JsonProperty) grand;
|
||||
} else break;
|
||||
}
|
||||
final StringBuilder path = new StringBuilder();
|
||||
Collections.reverse(names);
|
||||
for (String name : names) {
|
||||
path.append(PROPERTIES).append(name);
|
||||
}
|
||||
myRef = path.toString();
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.jsonSchema.extension.schema;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaExportedDefinitions;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaWalker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 1/10/2017.
|
||||
*/
|
||||
public class JsonSchemaInsideSchemaResolver {
|
||||
public static final String PROPERTIES = "/properties/";
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final VirtualFile mySchemaFile;
|
||||
@NotNull private final String myReference;
|
||||
@NotNull private final List<JsonSchemaWalker.Step> mySteps;
|
||||
@NotNull private final MultiMap<VirtualFile, String> myVisitedDefinitions = new MultiMap<VirtualFile, String>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Collection<String> createCollection() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
};
|
||||
|
||||
public JsonSchemaInsideSchemaResolver(@NotNull Project project,
|
||||
@NotNull VirtualFile schemaFile,
|
||||
@NotNull String reference, @NotNull List<JsonSchemaWalker.Step> steps) {
|
||||
myProject = project;
|
||||
mySchemaFile = schemaFile;
|
||||
myReference = reference;
|
||||
mySteps = steps;
|
||||
}
|
||||
|
||||
public PsiElement resolveInSchemaRecursively() {
|
||||
final ArrayDeque<Trinity<VirtualFile, List<JsonSchemaWalker.Step>, String>> queue = new ArrayDeque<>();
|
||||
queue.add(Trinity.create(mySchemaFile, mySteps, myReference));
|
||||
myVisitedDefinitions.putValue(mySchemaFile, myReference);
|
||||
while (!queue.isEmpty()) {
|
||||
final Trinity<VirtualFile, List<JsonSchemaWalker.Step>, String> trinity = queue.removeFirst();
|
||||
final VirtualFile schemaFile = trinity.getFirst();
|
||||
final String reference = JsonSchemaExportedDefinitions.normalizeId(trinity.getThird());
|
||||
final PsiElement element = new JsonSchemaByPropertyIndexResolver(reference, myProject, schemaFile).resolveByName();
|
||||
if (element != null) return element;
|
||||
final List<String> parts = ContainerUtil.filter(reference.replace("\\", "/").split("/"), s -> !StringUtil.isEmptyOrSpaces(s));
|
||||
final String shortName = parts.get(parts.size() - 1);
|
||||
final List<JsonSchemaWalker.Step> steps = trinity.getSecond();
|
||||
new JsonSchemaBySchemaObjectResolver(myProject, schemaFile, shortName, steps,
|
||||
(file, relativeReference) -> {
|
||||
final Pair<List<JsonSchemaWalker.Step>, String> innerSteps = JsonSchemaWalker.buildSteps(relativeReference);
|
||||
if (mySchemaFile.equals(file) &&
|
||||
(myReference.equals(relativeReference) || myVisitedDefinitions.get(file).contains(relativeReference)))
|
||||
return;
|
||||
myVisitedDefinitions.putValue(file, relativeReference);
|
||||
queue.add(Trinity.create(file, innerSteps.getFirst(), relativeReference));
|
||||
}).iterateMatchingDefinitions();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+22
-10
@@ -16,15 +16,23 @@
|
||||
package com.jetbrains.jsonSchema.extension.schema;
|
||||
|
||||
import com.intellij.json.psi.JsonValue;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.ElementManipulators;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiReferenceProvider;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaExportedDefinitions;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaReader;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaServiceEx;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaWalker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 3/31/2016.
|
||||
*/
|
||||
@@ -50,18 +58,22 @@ public class JsonSchemaRefReferenceProvider extends PsiReferenceProvider {
|
||||
@Override
|
||||
public PsiElement resolveInner() {
|
||||
final String text = getCanonicalText();
|
||||
String id = null;
|
||||
String ref = text.substring(1);
|
||||
final boolean isGlobal = !text.startsWith("#");
|
||||
if (isGlobal) {
|
||||
final int idx = text.indexOf("#");
|
||||
if (idx <= 0) return null;
|
||||
id = text.substring(0, idx);
|
||||
ref = text.substring(idx + 1);
|
||||
return new JsonSchemaDefinitionResolver(getElement(), id).setRef(ref).doResolve();
|
||||
|
||||
final JsonSchemaReader.SchemaUrlSplitter splitter = new JsonSchemaReader.SchemaUrlSplitter(text);
|
||||
VirtualFile schemaFile = getElement().getContainingFile().getVirtualFile();
|
||||
if (splitter.isAbsolute()) {
|
||||
assert splitter.getSchemaId() != null;
|
||||
schemaFile = JsonSchemaServiceEx.Impl.getEx(getElement().getProject()).getSchemaFileById(splitter.getSchemaId(), schemaFile);
|
||||
if (schemaFile == null) return null;
|
||||
}
|
||||
if (StringUtil.isEmptyOrSpaces(splitter.getRelativePath())) {
|
||||
return myElement.getManager().findFile(schemaFile);
|
||||
}
|
||||
|
||||
return new JsonSchemaDefinitionResolver(getElement(), null).setRef(ref).doResolveInSchemaFile();
|
||||
final String normalized = JsonSchemaExportedDefinitions.normalizeId(splitter.getRelativePath());
|
||||
final Pair<List<JsonSchemaWalker.Step>, String> steps = JsonSchemaWalker.buildSteps(normalized);
|
||||
return new JsonSchemaInsideSchemaResolver(myElement.getProject(), schemaFile, normalized, steps.getFirst())
|
||||
.resolveInSchemaRecursively();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-2
@@ -15,17 +15,30 @@
|
||||
*/
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.json.psi.JsonObject;
|
||||
import com.intellij.json.psi.JsonProperty;
|
||||
import com.intellij.json.psi.JsonStringLiteral;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.ElementManipulators;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiReferenceProvider;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.jsonSchema.extension.schema.JsonSchemaBaseReference;
|
||||
import com.jetbrains.jsonSchema.extension.schema.JsonSchemaDefinitionResolver;
|
||||
import com.jetbrains.jsonSchema.extension.schema.JsonSchemaInsideSchemaResolver;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.jetbrains.jsonSchema.extension.schema.JsonSchemaInsideSchemaResolver.PROPERTIES;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 4/15/2016.
|
||||
*/
|
||||
@@ -44,7 +57,46 @@ public class JsonPropertyName2SchemaDefinitionReferenceProvider extends PsiRefer
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement resolveInner() {
|
||||
return new JsonSchemaDefinitionResolver(getElement(), null).doResolve();
|
||||
final String reference = getReference();
|
||||
if (reference == null) return null;
|
||||
final JsonSchemaServiceEx schemaServiceEx = JsonSchemaService.Impl.getEx(myElement.getProject());
|
||||
final Collection<Pair<VirtualFile, String>> pairs = schemaServiceEx.getSchemaFilesByFile(myElement.getContainingFile().getVirtualFile());
|
||||
if (pairs != null && ! pairs.isEmpty()) {
|
||||
for (Pair<VirtualFile, String> pair : pairs) {
|
||||
final VirtualFile schemaFile = pair.getFirst();
|
||||
final List<JsonSchemaWalker.Step> steps = JsonSchemaWalker.findPosition(getElement(), true, true);
|
||||
if (steps == null) continue;
|
||||
//steps.add(0, new JsonSchemaWalker.Step(JsonSchemaWalker.StateType._unknown, new JsonSchemaWalker.PropertyTransition("properties")));
|
||||
final PsiElement element =
|
||||
new JsonSchemaInsideSchemaResolver(myElement.getProject(), schemaFile, reference, steps).resolveInSchemaRecursively();
|
||||
if (element != null) return element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getReference() {
|
||||
final List<String> names = new ArrayList<>();
|
||||
final PsiElement parent = getElement().getParent();
|
||||
if (!(parent instanceof JsonProperty)) return null;
|
||||
JsonProperty element = (JsonProperty)parent;
|
||||
while (true) {
|
||||
names.add(StringUtil.unquoteString(element.getName()));
|
||||
if (!(element.getParent() instanceof JsonObject)) break;
|
||||
final PsiElement grand = element.getParent().getParent();
|
||||
if (grand instanceof JsonProperty && ((JsonProperty)grand).getValue() != null &&
|
||||
((JsonProperty)grand).getValue().equals(element.getParent())) {
|
||||
element = (JsonProperty)grand;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
final StringBuilder path = new StringBuilder();
|
||||
Collections.reverse(names);
|
||||
for (String name : names) {
|
||||
path.append(PROPERTIES).append(name);
|
||||
}
|
||||
return path.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,8 @@ public class JsonSchemaExportedDefinitions {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String normalizeId(@NotNull final String id) {
|
||||
return id.endsWith("#") ? id.substring(0, id.length() - 1) : id;
|
||||
public static String normalizeId(@NotNull String id) {
|
||||
id = id.endsWith("#") ? id.substring(0, id.length() - 1) : id;
|
||||
return id.startsWith("#") ? id.substring(1) : id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Processor;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -29,10 +30,12 @@ import java.util.Set;
|
||||
*/
|
||||
public interface JsonSchemaServiceEx extends JsonSchemaService {
|
||||
|
||||
void visitSchemaObject(@NotNull VirtualFile schemaFile, @NotNull Processor<JsonSchemaObject> consumer);
|
||||
|
||||
boolean checkFileForId(@NotNull String id, @NotNull VirtualFile file);
|
||||
|
||||
@Nullable
|
||||
VirtualFile getSchemaFileById(@NotNull String id);
|
||||
VirtualFile getSchemaFileById(@NotNull String id, VirtualFile referent);
|
||||
|
||||
@Nullable
|
||||
Collection<Pair<VirtualFile, String>> getSchemaFilesByFile(@NotNull final VirtualFile file);
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.NullableLazyValue;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -35,6 +36,7 @@ import com.jetbrains.jsonSchema.extension.JsonSchemaProviderFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
@@ -163,6 +165,16 @@ public class JsonSchemaServiceImpl implements JsonSchemaServiceEx {
|
||||
wrapper.iterateSchemaObjects(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSchemaObject(@NotNull final VirtualFile schemaFile, @NotNull Processor<JsonSchemaObject> consumer) {
|
||||
final JsonSchemaObjectCodeInsightWrapper wrapper;
|
||||
synchronized (myLock) {
|
||||
wrapper = myWrappers.get(schemaFile);
|
||||
}
|
||||
if (wrapper == null) return;
|
||||
wrapper.iterateSchemaObjects(consumer);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<Pair<Boolean, String>> getMatchingSchemaDescriptors(@Nullable VirtualFile file) {
|
||||
@@ -366,8 +378,16 @@ public class JsonSchemaServiceImpl implements JsonSchemaServiceEx {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFile getSchemaFileById(@NotNull String id) {
|
||||
return myDefinitions.getSchemaFileById(id);
|
||||
public VirtualFile getSchemaFileById(@NotNull String id, @Nullable VirtualFile referent) {
|
||||
final VirtualFile schemaFile = myDefinitions.getSchemaFileById(id);
|
||||
if (schemaFile != null) return schemaFile;
|
||||
final String normalizedId = JsonSchemaExportedDefinitions.normalizeId(id);
|
||||
if (FileUtil.isAbsolute(normalizedId) || referent == null) return VfsUtil.findFileByIoFile(new File(normalizedId), false);
|
||||
VirtualFile dir = referent.isDirectory() ? referent : referent.getParent();
|
||||
if (dir != null && dir.isValid()) {
|
||||
return VfsUtil.findRelativeFile(dir, normalizedId.replace("\\", "/").split("/"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,10 +13,8 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 10/22/2015.
|
||||
@@ -48,7 +46,7 @@ public class JsonSchemaWalker {
|
||||
|
||||
public static void findSchemasForAnnotation(@NotNull final PsiElement element, @NotNull final CompletionSchemesConsumer consumer,
|
||||
@NotNull final JsonSchemaObject rootSchema) {
|
||||
final List<Step> position = findPosition(element, false);
|
||||
final List<Step> position = findPosition(element, false, true);
|
||||
if (position == null || position.isEmpty()) return;
|
||||
|
||||
extractSchemaVariants(consumer, rootSchema, false, position);
|
||||
@@ -59,7 +57,7 @@ public class JsonSchemaWalker {
|
||||
final PsiElement checkable = goUpToCheckable(element);
|
||||
if (checkable == null) return;
|
||||
final boolean isName = isName(checkable);
|
||||
final List<Step> position = findPosition(checkable, isName);
|
||||
final List<Step> position = findPosition(checkable, isName, !isName);
|
||||
if (position == null || position.isEmpty()) {
|
||||
if (isName) consumer.consume(true, rootSchema);
|
||||
return;
|
||||
@@ -68,6 +66,13 @@ public class JsonSchemaWalker {
|
||||
extractSchemaVariants(consumer, rootSchema, isName, position);
|
||||
}
|
||||
|
||||
public static Pair<List<Step>, String> buildSteps(@NotNull String nameInSchema) {
|
||||
final String[] chain = JsonSchemaExportedDefinitions.normalizeId(nameInSchema).replace("\\", "/").split("/");
|
||||
final List<Step> steps = Arrays.stream(chain).map(item -> new Step(StateType._unknown, new PropertyTransition(item)))
|
||||
.collect(Collectors.toList());
|
||||
return Pair.create(steps, chain[chain.length - 1]);
|
||||
}
|
||||
|
||||
public static void extractSchemaVariants(@NotNull CompletionSchemesConsumer consumer,
|
||||
@NotNull JsonSchemaObject rootSchema, boolean isName, List<Step> position) {
|
||||
final ArrayDeque<Pair<JsonSchemaObject, Integer>> queue = new ArrayDeque<>();
|
||||
@@ -82,7 +87,8 @@ public class JsonSchemaWalker {
|
||||
consumer.consume(isName, schema);
|
||||
continue;
|
||||
}
|
||||
if (step.getTransition() != null && !step.getTransition().possibleFromState(step.getType())) continue;
|
||||
if (step.getTransition() != null && !StateType._unknown.equals(step.getType())
|
||||
&& !step.getTransition().possibleFromState(step.getType())) continue;
|
||||
|
||||
final Condition<JsonSchemaObject> byTypeFilter = object -> byStateType(step.getType(), object);
|
||||
// not??
|
||||
@@ -112,7 +118,7 @@ public class JsonSchemaWalker {
|
||||
for (JsonSchemaObject object : list) {
|
||||
final TransitionResultConsumer transitionResultConsumer = new TransitionResultConsumer();
|
||||
step.getTransition().step(object, transitionResultConsumer);
|
||||
// nothing or anything does not contribute to competion
|
||||
// nothing or anything does not contribute to completion
|
||||
if (transitionResultConsumer.getSchema() != null) {
|
||||
if ((pair.getSecond() + 1) >= position.size()) consumer.consume(isName, transitionResultConsumer.getSchema());
|
||||
else queue.add(Pair.create(transitionResultConsumer.getSchema(), pair.getSecond() + 1));
|
||||
@@ -123,6 +129,7 @@ public class JsonSchemaWalker {
|
||||
}
|
||||
|
||||
private static boolean byStateType(@NotNull final StateType type, @NotNull final JsonSchemaObject schema) {
|
||||
if (StateType._unknown.equals(type)) return true;
|
||||
final JsonSchemaType requiredType = type.getCorrespondingJsonType();
|
||||
if (requiredType == null) return true;
|
||||
if (schema.getType() != null) {
|
||||
@@ -159,7 +166,7 @@ public class JsonSchemaWalker {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Step> findPosition(@NotNull final PsiElement element, boolean isName) {
|
||||
public static List<Step> findPosition(@NotNull final PsiElement element, boolean isName, boolean forceLastTransition) {
|
||||
final List<Step> steps = new ArrayList<>();
|
||||
if (!(element.getParent() instanceof JsonObject) && !isName) {
|
||||
steps.add(new Step(StateType._value, null));
|
||||
@@ -186,12 +193,12 @@ public class JsonSchemaWalker {
|
||||
current = current.getParent();
|
||||
if (!(current instanceof JsonObject)) return null;//incorrect syntax?
|
||||
// if either value or not first in the chain - needed for completion variant
|
||||
if (position != element || !isName) {
|
||||
if (position != element || forceLastTransition) {
|
||||
steps.add(new Step(StateType._object, new PropertyTransition(propertyName)));
|
||||
}
|
||||
} else if (current instanceof JsonObject && position instanceof JsonProperty) {
|
||||
// if either value or not first in the chain - needed for completion variant
|
||||
if (position != element || !isName) {
|
||||
if (position != element || forceLastTransition) {
|
||||
final String propertyName = ((JsonProperty)position).getName();
|
||||
steps.add(new Step(StateType._object, new PropertyTransition(propertyName)));
|
||||
}
|
||||
@@ -225,10 +232,10 @@ public class JsonSchemaWalker {
|
||||
}
|
||||
}
|
||||
|
||||
private static class PropertyTransition implements Transition {
|
||||
public static class PropertyTransition implements Transition {
|
||||
@NotNull private final String myName;
|
||||
|
||||
private PropertyTransition(@NotNull String name) {
|
||||
protected PropertyTransition(@NotNull String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@@ -259,6 +266,11 @@ public class JsonSchemaWalker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ArrayTransition implements Transition {
|
||||
@@ -297,8 +309,8 @@ public class JsonSchemaWalker {
|
||||
void step(@NotNull JsonSchemaObject parent, @NotNull TransitionResultConsumer resultConsumer);
|
||||
}
|
||||
|
||||
private enum StateType {
|
||||
_object(JsonSchemaType._object), _array(JsonSchemaType._array), _value(null);
|
||||
public enum StateType {
|
||||
_object(JsonSchemaType._object), _array(JsonSchemaType._array), _value(null), _unknown(null);
|
||||
|
||||
@Nullable
|
||||
private final JsonSchemaType myCorrespondingJsonType;
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 3/28/2016.
|
||||
@@ -290,7 +291,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
|
||||
public void registerSchemes() {
|
||||
final String moduleDir = getModuleDir(getProject());
|
||||
addSchema(new JsonSchemaMappingsConfigurationBase.SchemaInfo("one", moduleDir + "/refToDefinitionInFileSchema.json", false, Collections.emptyList()));
|
||||
addSchema(new JsonSchemaMappingsConfigurationBase.SchemaInfo("one", moduleDir + "/definitionsSchema.json", false, Collections.emptyList()));
|
||||
addSchema(new JsonSchemaMappingsConfigurationBase.SchemaInfo("two", moduleDir + "/definitionsSchema.json", false, Collections.emptyList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -311,6 +312,62 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
|
||||
});
|
||||
}
|
||||
|
||||
public void testFindRefToOtherFile() throws Exception {
|
||||
skeleton(new Callback() {
|
||||
@Override
|
||||
public void registerSchemes() {
|
||||
final String moduleDir = getModuleDir(getProject());
|
||||
addSchema(new JsonSchemaMappingsConfigurationBase.SchemaInfo("one", moduleDir + "/refToOtherFileSchema.json", false, Collections.emptyList()));
|
||||
addSchema(new JsonSchemaMappingsConfigurationBase.SchemaInfo("two", moduleDir + "/definitionsSchema.json", false, Collections.emptyList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureFiles() throws Exception {
|
||||
configureByFiles(null, "/refToOtherFileSchema.json", "/definitionsSchema.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCheck() {
|
||||
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
|
||||
final PsiReference referenceAt = myFile.findReferenceAt(offset);
|
||||
Assert.assertNotNull(referenceAt);
|
||||
final PsiElement resolve = referenceAt.resolve();
|
||||
Assert.assertNotNull(resolve);
|
||||
Assert.assertEquals("definitionsSchema.json", resolve.getContainingFile().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testNavigateToPropertyDefinitionInPackageJsonSchema() throws Exception {
|
||||
skeleton(new Callback() {
|
||||
@Override
|
||||
public void registerSchemes() {
|
||||
final String moduleDir = getModuleDir(getProject());
|
||||
final List<JsonSchemaMappingsConfigurationBase.Item> patterns = Collections.singletonList(
|
||||
new JsonSchemaMappingsConfigurationBase.Item("package.json", true, false));
|
||||
addSchema(new JsonSchemaMappingsConfigurationBase.SchemaInfo("one", moduleDir + "/packageJsonSchema.json", false, patterns));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureFiles() throws Exception {
|
||||
configureByFiles(null, "/package.json", "/packageJsonSchema.json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCheck() {
|
||||
final String text = myFile.getText();
|
||||
final int indexOf = text.indexOf("dependencies");
|
||||
assertTrue(indexOf > 0);
|
||||
final PsiReference referenceAt = myFile.findReferenceAt(indexOf);
|
||||
Assert.assertNotNull(referenceAt);
|
||||
final PsiElement resolve = referenceAt.resolve();
|
||||
Assert.assertNotNull(resolve);
|
||||
Assert.assertEquals("packageJsonSchema.json", resolve.getContainingFile().getName());
|
||||
Assert.assertEquals("\"dependencies\"", resolve.getText());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getModuleDir(@NotNull final Project project) {
|
||||
String moduleDir = null;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "ufr-cards-frontend-stub",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"stylelint": "1.0"
|
||||
},
|
||||
"stylelint": {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "JSON schema for package.json files",
|
||||
"definitions": {
|
||||
"person": {
|
||||
"type": [ "object", "string" ],
|
||||
"required": [ "name" ],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"coreProperties": {
|
||||
"type": "object",
|
||||
|
||||
"patternProperties": {
|
||||
"^_": {
|
||||
"description": "Any property starting with _ is valid.",
|
||||
"additionalProperties": true,
|
||||
"additionalItems": true
|
||||
}
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Name of the package",
|
||||
"type": "string",
|
||||
"maxLength": 214,
|
||||
"minLength": 1
|
||||
},
|
||||
"version": {
|
||||
"title": "Version of the package",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"title": "Description of the package",
|
||||
"type": "string"
|
||||
},
|
||||
"keywords": {
|
||||
"title": "Array of keyword strings",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
"title": "Url to the project homepage",
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"bugs": {
|
||||
"title": "Project's issue tracker and/or email address",
|
||||
"type": [ "object", "string" ],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "The url to the project's issue tracker",
|
||||
"format": "uri"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"title": "The email address to which issues should be reported",
|
||||
"format": "email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"license": {
|
||||
"type": "string",
|
||||
"title": "License of the project"
|
||||
},
|
||||
"licenses": {
|
||||
"title": "Licenses of the project",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"author": {
|
||||
"title": "Author of package",
|
||||
"type": [ "object", "string" ],
|
||||
"required": [ "name" ],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"contributors": {
|
||||
"title": "Contributors of the package",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/person"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"title": "Files to include in the project",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"main": {
|
||||
"title": "Entry module to the package",
|
||||
"type": "string"
|
||||
},
|
||||
"jsnext:main": {
|
||||
"title": "Entry module to the package, ES6 version",
|
||||
"type": "string"
|
||||
},
|
||||
"bin": {
|
||||
"title": "Executable files to install into PATH",
|
||||
"type": [ "string", "object" ],
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"man": {
|
||||
"title": "Documentation files for man",
|
||||
"type": [ "array", "string" ],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"title": "Structure of the package",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bin": {
|
||||
"title": "Folder for binary files",
|
||||
"type": "string"
|
||||
},
|
||||
"doc": {
|
||||
"title": "Folder for markdown files",
|
||||
"type": "string"
|
||||
},
|
||||
"example": {
|
||||
"title": "Folder for example scripts",
|
||||
"type": "string"
|
||||
},
|
||||
"lib": {
|
||||
"title": "Folder where the bulk of your library is",
|
||||
"type": "string"
|
||||
},
|
||||
"man": {
|
||||
"title": "Folder that is full of man pages",
|
||||
"type": "string"
|
||||
},
|
||||
"test": {
|
||||
"title": "Folder for tests",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"title": "Repository of code",
|
||||
"type": ["object", "string"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"title": "Commands to run at various times in the lifecycle of package",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"title": "Configuration parameters",
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"dependencies": {
|
||||
"title": "Dependencies of the package",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"title": "Development dependencies of the package",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"bundleDependencies": {
|
||||
"type": "array",
|
||||
"title": "Dependencies bundled when publishing the package",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"bundledDependencies": {
|
||||
"type": "array",
|
||||
"title": "Dependencies bundled when publishing the package",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"title": "Options dependencies of the package",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"title": "Peer dependencies of the package",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"title": "Compatible node and npm versions",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"engineStrict": {
|
||||
"title": "Require compatible engines only",
|
||||
"type": "boolean"
|
||||
},
|
||||
"os": {
|
||||
"title": "Compatible operating systems",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"cpu": {
|
||||
"title": "Compatible CPU architectures",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"preferGlobal": {
|
||||
"title": "true, if global installation is preferred",
|
||||
"type": "boolean"
|
||||
},
|
||||
"private": {
|
||||
"title": "true, if package shouldn't be published",
|
||||
"type": "boolean"
|
||||
},
|
||||
"publishConfig": {
|
||||
"title": "Set of config values to use at publish-time",
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"eslintConfig" : {
|
||||
"$ref": "https://github.com/SchemaStore/schemastore/tree/master/src/schemas/json/eslintrc.json#"
|
||||
},
|
||||
"stylelint" : {
|
||||
"$ref": "https://jetbrains.com/stylelintrc.json#"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/coreProperties" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"properties": {
|
||||
"searcher": {
|
||||
"$ref": "<caret>definitionsSchema.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user