docs: String compactIri(String iri, Object value, boolean relativeToVocab, boolean reverse) {
          // 1)
          if (iri == null) {
              return null;
          }
  
          // 2)
          if (relativeToVocab && getInverse().containsKey(iri)) {
              // 2.1)
              String defaultLanguage = (String) this.get(JsonLdConsts.LANGUAGE);
              if (defaultLanguage == null) {
                  defaultLanguage = JsonLdConsts.NONE;
              }
  
              // 2.2)
              final List<String> containers = new ArrayList<String>();
              // 2.3)
              String typeLanguage = JsonLdConsts.LANGUAGE;
              String typeLanguageValue = JsonLdConsts.NULL;
  
              // 2.4)
              if (value instanceof Map
                      && ((Map<String, Object>) value).containsKey(JsonLdConsts.INDEX)) {
                  containers.add(JsonLdConsts.INDEX);
              }
  
              // 2.5)
              if (reverse) {
                  typeLanguage = JsonLdConsts.TYPE;
                  typeLanguageValue = JsonLdConsts.REVERSE;
                  containers.add(JsonLdConsts.SET);
              }
              // 2.6)
              else if (value instanceof Map
                      && ((Map<String, Object>) value).containsKey(JsonLdConsts.LIST)) {
                  // 2.6.1)
                  if (!((Map<String, Object>) value).containsKey(JsonLdConsts.INDEX)) {
                      containers.add(JsonLdConsts.LIST);
                  }
                  // 2.6.2)
                  final List<Object> list = (List<Object>) ((Map<String, Object>) value)
                          .get(JsonLdConsts.LIST);
                  // 2.6.3)
                  String commonLanguage = (list.size() == 0) ? defaultLanguage : null;
                  String commonType = null;
                  // 2.6.4)
                  for (final Object item : list) {
                      // 2.6.4.1)
                      String itemLanguage = JsonLdConsts.NONE;
                      String itemType = JsonLdConsts.NONE;
                      // 2.6.4.2)
                      if (JsonLdUtils.isValue(item)) {
                          // 2.6.4.2.1)
                          if (((Map<String, Object>) item).containsKey(JsonLdConsts.LANGUAGE)) {
                              itemLanguage = (String) ((Map<String, Object>) item)
                                      .get(JsonLdConsts.LANGUAGE);
                          }
                          // 2.6.4.2.2)
                          else if (((Map<String, Object>) item).containsKey(JsonLdConsts.TYPE)) {
                              itemType = (String) ((Map<String, Object>) item).get(JsonLdConsts.TYPE);
                          }
                          // 2.6.4.2.3)
                          else {
                              itemLanguage = JsonLdConsts.NULL;
                          }
                      }
                      // 2.6.4.3)
                      else {
                          itemType = JsonLdConsts.ID;
                      }
                      // 2.6.4.4)
                      if (commonLanguage == null) {
                          commonLanguage = itemLanguage;
                      }
                      // 2.6.4.5)
                      else if (!commonLanguage.equals(itemLanguage) && JsonLdUtils.isValue(item)) {
                          commonLanguage = JsonLdConsts.NONE;
                      }
                      // 2.6.4.6)
                      if (commonType == null) {
                          commonType = itemType;
                      }
                      // 2.6.4.7)
                      else if (!commonType.equals(itemType)) {
                          commonType = JsonLdConsts.NONE;
                      }
                      // 2.6.4.8)
                      if (JsonLdConsts.NONE.equals(commonLanguage)
                              && JsonLdConsts.NONE.equals(commonType)) {
                          break;
                      }
                  }
                  // 2.6.5)
                  commonLanguage = (commonLanguage != null) ? commonLanguage : JsonLdConsts.NONE;
                  // 2.6.6)
                  commonType = (commonType != null) ? commonType : JsonLdConsts.NONE;
                  // 2.6.7)
                  if (!JsonLdConsts.NONE.equals(commonType)) {
                      typeLanguage = JsonLdConsts.TYPE;
                      typeLanguageValue = commonType;
                  }
                  // 2.6.8)
                  else {
                      typeLanguageValue = commonLanguage;
                  }
              }
              // 2.7)
              else {
                  // 2.7.1)
                  if (value instanceof Map
                          && ((Map<String, Object>) value).containsKey(JsonLdConsts.VALUE)) {
                      // 2.7.1.1)
                      if (((Map<String, Object>) value).containsKey(JsonLdConsts.LANGUAGE)
                              && !((Map<String, Object>) value).containsKey(JsonLdConsts.INDEX)) {
                          containers.add(JsonLdConsts.LANGUAGE);
                          typeLanguageValue = (String) ((Map<String, Object>) value)
                                  .get(JsonLdConsts.LANGUAGE);
                      }
                      // 2.7.1.2)
                      else if (((Map<String, Object>) value).containsKey(JsonLdConsts.TYPE)) {
                          typeLanguage = JsonLdConsts.TYPE;
                          typeLanguageValue = (String) ((Map<String, Object>) value)
                                  .get(JsonLdConsts.TYPE);
                      }
                  }
                  // 2.7.2)
                  else {
                      typeLanguage = JsonLdConsts.TYPE;
                      typeLanguageValue = JsonLdConsts.ID;
                  }
                  // 2.7.3)
                  containers.add(JsonLdConsts.SET);
              }
  
              // 2.8)
              containers.add(JsonLdConsts.NONE);
              // 2.9)
              if (typeLanguageValue == null) {
                  typeLanguageValue = JsonLdConsts.NULL;
              }
              // 2.10)
              final List<String> preferredValues = new ArrayList<String>();
              // 2.11)
              if (JsonLdConsts.REVERSE.equals(typeLanguageValue)) {
                  preferredValues.add(JsonLdConsts.REVERSE);
              }
              // 2.12)
              if ((JsonLdConsts.REVERSE.equals(typeLanguageValue)
                      || JsonLdConsts.ID.equals(typeLanguageValue)) && (value instanceof Map)
                      && ((Map<String, Object>) value).containsKey(JsonLdConsts.ID)) {
                  // 2.12.1)
                  final String result = this.compactIri(
                          (String) ((Map<String, Object>) value).get(JsonLdConsts.ID), null, true,
                          true);
                  if (termDefinitions.containsKey(result)
                          && ((Map<String, Object>) termDefinitions.get(result))
                                  .containsKey(JsonLdConsts.ID)
                          && ((Map<String, Object>) value).get(JsonLdConsts.ID)
                                  .equals(((Map<String, Object>) termDefinitions.get(result))
                                          .get(JsonLdConsts.ID))) {
                      preferredValues.add(JsonLdConsts.VOCAB);
                      preferredValues.add(JsonLdConsts.ID);
                  }
                  // 2.12.2)
                  else {
                      preferredValues.add(JsonLdConsts.ID);
                      preferredValues.add(JsonLdConsts.VOCAB);
                  }
              }
              // 2.13)
              else {
                  preferredValues.add(typeLanguageValue);
              }
              preferredValues.add(JsonLdConsts.NONE);
  
              // 2.14)
              final String term = selectTerm(iri, containers, typeLanguage, preferredValues);
              // 2.15)
              if (term != null) {
                  return term;
              }
          }
  
          // 3)
          if (relativeToVocab && this.containsKey(JsonLdConsts.VOCAB)) {
              // determine if vocab is a prefix of the iri
              final String vocab = (String) this.get(JsonLdConsts.VOCAB);
              // 3.1)
              if (iri.indexOf(vocab) == 0 && !iri.equals(vocab)) {
                  // use suffix as relative iri if it is not a term in the
                  // active context
                  final String suffix = iri.substring(vocab.length());
                  if (!termDefinitions.containsKey(suffix)) {
                      return suffix;
                  }
              }
          }
  
          // 4)
          String compactIRI = null;
          // 5)
          for (final String term : termDefinitions.keySet()) {
              final Map<String, Object> termDefinition = (Map<String, Object>) termDefinitions
                      .get(term);
              // 5.1)
              if (term.contains(":")) {
                  continue;
              }
              // 5.2)
              if (termDefinition == null || iri.equals(termDefinition.get(JsonLdConsts.ID))
                      || !iri.startsWith((String) termDefinition.get(JsonLdConsts.ID))) {
                  continue;
              }
  
              // 5.3)
              final String candidate = term + ":"
                      + iri.substring(((String) termDefinition.get(JsonLdConsts.ID)).length());
              // 5.4)
              compactIRI = _iriCompactionStep5point4(iri, value, compactIRI, candidate,
                      termDefinitions);
          }
  
          // 6)
          if (compactIRI != null) {
              return compactIRI;
          }
  
          // 7)
          if (!relativeToVocab) {
              return JsonLdUrl.removeBase(this.get(JsonLdConsts.BASE), iri);
          }
  
          // 8)
          return iri;
      }