All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.json.psi.impl.JsonPsiImplUtils Maven / Gradle / Ivy

package com.intellij.json.psi.impl;

import com.intellij.icons.AllIcons;
import com.intellij.json.JsonBundle;
import com.intellij.json.JsonParserDefinition;
import com.intellij.json.codeinsight.JsonStandardComplianceInspection;
import com.intellij.json.psi.*;
import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class JsonPsiImplUtils {
  private static final Key>> STRING_FRAGMENTS = new Key>>("JSON string fragments");

  @NotNull
  public static String getName(@NotNull JsonProperty property) {
    return StringUtil.unescapeStringCharacters(JsonPsiUtil.stripQuotes(property.getNameElement().getText()));
  }

  /**
   * Actually only JSON string literal should be accepted as valid name of property according to standard,
   * but for compatibility with JavaScript integration any JSON literals as well as identifiers (unquoted words)
   * are possible and highlighted as error later.
   *
   * @see JsonStandardComplianceInspection
   */
  @NotNull
  public static JsonValue getNameElement(@NotNull JsonProperty property) {
    final PsiElement firstChild = property.getFirstChild();
    assert firstChild instanceof JsonLiteral || firstChild instanceof JsonReferenceExpression;
    return (JsonValue)firstChild;
  }

  @Nullable
  public static JsonValue getValue(@NotNull JsonProperty property) {
    return PsiTreeUtil.getNextSiblingOfType(getNameElement(property), JsonValue.class);
  }

  public static boolean isQuotedString(@NotNull JsonLiteral literal) {
    return literal.getNode().findChildByType(JsonParserDefinition.STRING_LITERALS) != null;
  }

  @Nullable
  public static ItemPresentation getPresentation(@NotNull final JsonProperty property) {
    return new ItemPresentation() {
      @Nullable
      @Override
      public String getPresentableText() {
        return property.getName();
      }

      @Nullable
      @Override
      public String getLocationString() {
        return null;
      }

      @Nullable
      @Override
      public Icon getIcon(boolean unused) {
        if (property.getValue() instanceof JsonArray) {
          return AllIcons.Json.Property_brackets;
        }
        if (property.getValue() instanceof JsonObject) {
          return AllIcons.Json.Property_braces;
        }
        return PlatformIcons.PROPERTY_ICON;
      }
    };
  }

  @Nullable
  public static ItemPresentation getPresentation(@NotNull final JsonArray array) {
    return new ItemPresentation() {
      @Nullable
      @Override
      public String getPresentableText() {
        return JsonBundle.message("json.array");
      }

      @Nullable
      @Override
      public String getLocationString() {
        return null;
      }

      @Nullable
      @Override
      public Icon getIcon(boolean unused) {
        return AllIcons.Json.Array;
      }
    };
  }

  @Nullable
  public static ItemPresentation getPresentation(@NotNull final JsonObject object) {
    return new ItemPresentation() {
      @Nullable
      @Override
      public String getPresentableText() {
        return JsonBundle.message("json.object");
      }

      @Nullable
      @Override
      public String getLocationString() {
        return null;
      }

      @Nullable
      @Override
      public Icon getIcon(boolean unused) {
        return AllIcons.Json.Object;
      }
    };
  }

  private static final String ourEscapesTable = "\"\"\\\\//b\bf\fn\nr\rt\t";

  @NotNull
  public static List> getTextFragments(@NotNull JsonStringLiteral literal) {
    List> result = literal.getUserData(STRING_FRAGMENTS);
    if (result == null) {
      result = new ArrayList>();
      final String text = literal.getText();
      final int length = text.length();
      int pos = 1, unescapedSequenceStart = 1;
      while (pos < length) {
        if (text.charAt(pos) == '\\') {
          if (unescapedSequenceStart != pos) {
            result.add(Pair.create(new TextRange(unescapedSequenceStart, pos), text.substring(unescapedSequenceStart, pos)));
          }
          if (pos == length - 1) {
            result.add(Pair.create(new TextRange(pos, pos + 1), "\\"));
            break;
          }
          final char next = text.charAt(pos + 1);
          switch (next) {
            case '"':
            case '\\':
            case '/':
            case 'b':
            case 'f':
            case 'n':
            case 'r':
            case 't':
              final int idx = ourEscapesTable.indexOf(next);
              result.add(Pair.create(new TextRange(pos, pos + 2), ourEscapesTable.substring(idx + 1, idx + 2)));
              pos += 2;
              break;
            case 'u':
              int i = pos + 2;
              for (; i < pos + 6; i++) {
                if (i == length || !StringUtil.isHexDigit(text.charAt(i))) {
                  break;
                }
              }
              result.add(Pair.create(new TextRange(pos, i), text.substring(pos, i)));
              pos = i;
              break;
            default:
              result.add(Pair.create(new TextRange(pos, pos + 2), text.substring(pos, pos + 2)));
              pos += 2;
          }
          unescapedSequenceStart = pos;
        }
        else {
          pos++;
        }
      }
      final int contentEnd = text.charAt(0) == text.charAt(length - 1) ? length - 1 : length;
      if (unescapedSequenceStart < contentEnd) {
        result.add(Pair.create(new TextRange(unescapedSequenceStart, length), text.substring(unescapedSequenceStart, contentEnd)));
      }
      result = Collections.unmodifiableList(result);
      literal.putUserData(STRING_FRAGMENTS, result);
    }
    return result;
  }

  public static void delete(@NotNull JsonProperty property) {
    final ASTNode myNode = property.getNode();
    JsonPsiChangeUtils.removeCommaSeparatedFromList(myNode, myNode.getTreeParent());
  }

  @Nullable
  public static JsonProperty findProperty(@NotNull JsonObject object, @NotNull String name) {
    final Collection properties = PsiTreeUtil.findChildrenOfType(object, JsonProperty.class);
    for (JsonProperty property : properties) {
      if (property.getName().equals(name)) {
        return property;
      }
    }
    return null;
  }

  @NotNull
  public static String getValue(@NotNull JsonStringLiteral literal) {
    return StringUtil.unescapeStringCharacters(JsonPsiUtil.stripQuotes(literal.getText()));
  }

  public static boolean getValue(@NotNull JsonBooleanLiteral literal) {
    return literal.textMatches("true");
  }

  public static double getValue(@NotNull JsonNumberLiteral literal) {
    return Double.parseDouble(literal.getText());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy