diff --git a/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java b/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java index 49a353de5043..b031ca5a1912 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java +++ b/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java @@ -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 diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaByPropertyIndexResolver.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaByPropertyIndexResolver.java new file mode 100644 index 000000000000..162a6b17849d --- /dev/null +++ b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaByPropertyIndexResolver.java @@ -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; + } +} diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaBySchemaObjectResolver.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaBySchemaObjectResolver.java new file mode 100644 index 000000000000..387cf6e4843d --- /dev/null +++ b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaBySchemaObjectResolver.java @@ -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 myPosition; + @NotNull private final PairConsumer myConsumer; + + public JsonSchemaBySchemaObjectResolver(@NotNull Project project, + @NotNull VirtualFile schemaFile, + @NotNull String shortPropertyName, + @NotNull List position, + @NotNull PairConsumer 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 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); + } + } +} diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java deleted file mode 100644 index 434f50d3e06e..000000000000 --- a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java +++ /dev/null @@ -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 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 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 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> pairs = schemaServiceEx.getSchemaFilesByFile(myElement.getContainingFile().getVirtualFile()); - if (pairs != null && ! pairs.isEmpty()) { - for (Pair 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> 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() { - @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 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 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(); - } -} diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaInsideSchemaResolver.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaInsideSchemaResolver.java new file mode 100644 index 000000000000..0bd6e1b2c357 --- /dev/null +++ b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaInsideSchemaResolver.java @@ -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 mySteps; + @NotNull private final MultiMap myVisitedDefinitions = new MultiMap() { + @NotNull + @Override + protected Collection createCollection() { + return new HashSet<>(); + } + }; + + public JsonSchemaInsideSchemaResolver(@NotNull Project project, + @NotNull VirtualFile schemaFile, + @NotNull String reference, @NotNull List steps) { + myProject = project; + mySchemaFile = schemaFile; + myReference = reference; + mySteps = steps; + } + + public PsiElement resolveInSchemaRecursively() { + final ArrayDeque, String>> queue = new ArrayDeque<>(); + queue.add(Trinity.create(mySchemaFile, mySteps, myReference)); + myVisitedDefinitions.putValue(mySchemaFile, myReference); + while (!queue.isEmpty()) { + final Trinity, 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 parts = ContainerUtil.filter(reference.replace("\\", "/").split("/"), s -> !StringUtil.isEmptyOrSpaces(s)); + final String shortName = parts.get(parts.size() - 1); + final List steps = trinity.getSecond(); + new JsonSchemaBySchemaObjectResolver(myProject, schemaFile, shortName, steps, + (file, relativeReference) -> { + final Pair, 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; + } +} diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaRefReferenceProvider.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaRefReferenceProvider.java index 38495a5cbb9c..afb9b8d79d26 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaRefReferenceProvider.java +++ b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaRefReferenceProvider.java @@ -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, String> steps = JsonSchemaWalker.buildSteps(normalized); + return new JsonSchemaInsideSchemaResolver(myElement.getProject(), schemaFile, normalized, steps.getFirst()) + .resolveInSchemaRecursively(); } } } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonPropertyName2SchemaDefinitionReferenceProvider.java b/json/src/com/jetbrains/jsonSchema/impl/JsonPropertyName2SchemaDefinitionReferenceProvider.java index c99576fb5d40..f2d7450a00c5 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonPropertyName2SchemaDefinitionReferenceProvider.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonPropertyName2SchemaDefinitionReferenceProvider.java @@ -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> pairs = schemaServiceEx.getSchemaFilesByFile(myElement.getContainingFile().getVirtualFile()); + if (pairs != null && ! pairs.isEmpty()) { + for (Pair pair : pairs) { + final VirtualFile schemaFile = pair.getFirst(); + final List 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 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(); } } } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaExportedDefinitions.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaExportedDefinitions.java index aa772625e5a0..5678d6d10473 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaExportedDefinitions.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaExportedDefinitions.java @@ -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; } } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceEx.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceEx.java index 24ccf0cda8d1..e0e69923e15c 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceEx.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceEx.java @@ -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 consumer); + boolean checkFileForId(@NotNull String id, @NotNull VirtualFile file); @Nullable - VirtualFile getSchemaFileById(@NotNull String id); + VirtualFile getSchemaFileById(@NotNull String id, VirtualFile referent); @Nullable Collection> getSchemaFilesByFile(@NotNull final VirtualFile file); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java index e5b008b3db2b..2c719f7dcd88 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java @@ -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 consumer) { + final JsonSchemaObjectCodeInsightWrapper wrapper; + synchronized (myLock) { + wrapper = myWrappers.get(schemaFile); + } + if (wrapper == null) return; + wrapper.iterateSchemaObjects(consumer); + } + @Nullable @Override public List> 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 diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaWalker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaWalker.java index 9bd036634e7a..0cd4daadb89f 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaWalker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaWalker.java @@ -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 position = findPosition(element, false); + final List 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 position = findPosition(checkable, isName); + final List 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, String> buildSteps(@NotNull String nameInSchema) { + final String[] chain = JsonSchemaExportedDefinitions.normalizeId(nameInSchema).replace("\\", "/").split("/"); + final List 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 position) { final ArrayDeque> 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 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 findPosition(@NotNull final PsiElement element, boolean isName) { + public static List findPosition(@NotNull final PsiElement element, boolean isName, boolean forceLastTransition) { final List 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; diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaCrossReferencesTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaCrossReferencesTest.java index 27c47f963af3..147396c81643 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaCrossReferencesTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaCrossReferencesTest.java @@ -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 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; diff --git a/json/tests/testData/jsonSchema/crossReferences/package.json b/json/tests/testData/jsonSchema/crossReferences/package.json new file mode 100644 index 000000000000..66ffe8d7fe96 --- /dev/null +++ b/json/tests/testData/jsonSchema/crossReferences/package.json @@ -0,0 +1,10 @@ +{ + "name": "ufr-cards-frontend-stub", + "version": "0.0.1", + "description": "", + "dependencies": { + "stylelint": "1.0" + }, + "stylelint": { + } +} \ No newline at end of file diff --git a/json/tests/testData/jsonSchema/crossReferences/packageJsonSchema.json b/json/tests/testData/jsonSchema/crossReferences/packageJsonSchema.json new file mode 100644 index 000000000000..3594210fe67e --- /dev/null +++ b/json/tests/testData/jsonSchema/crossReferences/packageJsonSchema.json @@ -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" } + ] +} diff --git a/json/tests/testData/jsonSchema/crossReferences/refToOtherFileSchema.json b/json/tests/testData/jsonSchema/crossReferences/refToOtherFileSchema.json new file mode 100644 index 000000000000..49a5491a836f --- /dev/null +++ b/json/tests/testData/jsonSchema/crossReferences/refToOtherFileSchema.json @@ -0,0 +1,7 @@ +{ + "properties": { + "searcher": { + "$ref": "definitionsSchema.json" + } + } +} \ No newline at end of file