docs: def is_valid(self, field_name: str, value, kg: dict) -> Optional[dict]:
          """
          Check if this value is valid for the given name property according to input knowledge graph and ontology.
          If is valid, then return a dict with key @id or @value for ObjectProperty or DatatypeProperty.
          No schema checked by this function.
  
          :param field_name: name of the property, if prefix is omitted, then use default namespace
          :param value: the value that try to add
          :param kg: the knowledge graph that perform adding action
          :return: None if the value isn't valid for the property, otherwise return {key: value}, key is @id for
              ObjectProperty and @value for DatatypeProperty.
          """
          # property
          uri = self.__is_valid_uri_resolve(field_name, kg.get("@context"))
          property_ = self.get_entity(uri)
          if not isinstance(property_, OntologyProperty):
              logging.warning("Property is not OntologyProperty, ignoring it:  %s", uri)
              return None
          if not self.__is_valid_domain(property_, kg):
              logging.warning("Property does not have valid domain, ignoring it:  %s", uri)
              return None
          # check if is valid range
          # first determine the input value type
          if isinstance(property_, OntologyDatatypeProperty):
              types = self.__is_valid_determine_value_type(value)
          else:
              if isinstance(value, dict):
                  try:
                      types = map(self.get_entity, value['@type'])
                  except KeyError:
                      return None  # input entity without type
              elif self.__is_schema_org_datatype(property_):
                  if self.expanded_jsonld:
                      return {'@value': self.__serialize_type(value)}
                  else:
                      return value
              else:
                  return {'@id': self.__serialize_type(value)}
          # check if is a valid range
          if any(property_.is_legal_object(type_) for type_ in types):
              if isinstance(property_, OntologyObjectProperty):
                  return value
              elif self.expanded_jsonld:
                  return {'@value': self.__serialize_type(value)}
              else:
                  return self.__serialize_type(value)
          return None