dynamic dynamic::merge_diff(const dynamic& source, const dynamic& target) {
  if (!source.isObject() || source.type() != target.type()) {
    return target;
  }

  dynamic diff = object;

  // added/modified keys
  for (const auto& pair : target.items()) {
    auto it = source.find(pair.first);
    if (it == source.items().end()) {
      diff[pair.first] = pair.second;
    } else {
      diff[pair.first] = merge_diff(source[pair.first], target[pair.first]);
    }
  }

  // removed keys
  for (const auto& pair : source.items()) {
    auto it = target.find(pair.first);
    if (it == target.items().end()) {
      diff[pair.first] = nullptr;
    }
  }

  return diff;
}
Exemplo n.º 2
0
SettingsMap::SettingsMap(const dynamic& d) {
  if (!d.isObject()) {
    throw BistroException("Can only create settings map from an object");
  }
  for (const auto& pair : d.items()) {
    const string& name = pair.first.asString().toStdString();
    set(name, pair.second);
  }
}
Exemplo n.º 3
0
 Optional<SchemaError> validate(ValidationContext&,
                                const dynamic& value) const override {
   if (value.isObject()) {
     for (const auto& prop : properties_) {
       auto* p = value.get_ptr(prop);
       if (!value.get_ptr(prop)) {
         return makeError("to have property", prop, value);
       }
     }
   }
   return none;
 }
Exemplo n.º 4
0
  Optional<SchemaError> validate(ValidationContext& vc,
                                 const dynamic& value) const override {
    if (!value.isObject()) {
      return none;
    }
    for (const auto& pair : value.items()) {
      if (!pair.first.isString()) {
        continue;
      }
      const fbstring& key = pair.first.getString();
      auto it = propertyValidators_.find(key);
      bool matched = false;
      if (it != propertyValidators_.end()) {
        if (auto se = vc.validate(it->second.get(), pair.second)) {
          return se;
        }
        matched = true;
      }

      const std::string& strkey = key.toStdString();
      for (const auto& ppv : patternPropertyValidators_) {
        if (boost::regex_search(strkey, ppv.first)) {
          if (auto se = vc.validate(ppv.second.get(), pair.second)) {
            return se;
          }
          matched = true;
        }
      }
      if (matched) {
        continue;
      }
      if (!allowAdditionalProperties_) {
        return makeError("no more additional properties", value);
      }
      if (additionalPropertyValidator_) {
        if (auto se =
                vc.validate(additionalPropertyValidator_.get(), pair.second)) {
          return se;
        }
      }
    }
    return none;
  }
Exemplo n.º 5
0
 Optional<SchemaError> validate(ValidationContext& vc,
                                const dynamic& value) const override {
   if (!value.isObject()) {
     return none;
   }
   for (const auto& pair : propertyDep_) {
     if (value.count(pair.first)) {
       for (const auto& prop : pair.second) {
         if (!value.count(prop)) {
           return makeError("property", prop, value);
         }
       }
     }
   }
   for (const auto& pair : schemaDep_) {
     if (value.count(pair.first)) {
       if (auto se = vc.validate(pair.second.get(), value)) {
         return se;
       }
     }
   }
   return none;
 }
Exemplo n.º 6
0
 DependencyValidator(SchemaValidatorContext& context, const dynamic& schema) {
   if (!schema.isObject()) {
     return;
   }
   for (const auto& pair : schema.items()) {
     if (!pair.first.isString()) {
       continue;
     }
     if (pair.second.isArray()) {
       auto p = make_pair(pair.first.getString(), std::vector<fbstring>());
       for (const auto& item : pair.second) {
         if (item.isString()) {
           p.second.push_back(item.getString());
         }
       }
       propertyDep_.emplace_back(std::move(p));
     }
     if (pair.second.isObject()) {
       schemaDep_.emplace_back(
           make_pair(pair.first.getString(),
                     SchemaValidator::make(context, pair.second)));
     }
   }
 }
Exemplo n.º 7
0
void SchemaValidator::loadSchema(SchemaValidatorContext& context,
                                 const dynamic& schema) {
  if (!schema.isObject() || schema.empty()) {
    return;
  }

  // Check for $ref, if we have one we won't apply anything else. Refs are
  // pointers to other parts of the json, e.g. #/foo/bar points to the schema
  // located at root["foo"]["bar"].
  if (const auto* p = schema.get_ptr("$ref")) {
    // We only support absolute refs, i.e. those starting with '#'
    if (p->isString() && p->stringPiece()[0] == '#') {
      auto it = context.refs.find(p->getString());
      if (it != context.refs.end()) {
        validators_.emplace_back(make_unique<RefValidator>(it->second));
        return;
      }

      // This is a ref, but we haven't loaded it yet. Find where it is based on
      // the root schema.
      std::vector<std::string> parts;
      split("/", p->stringPiece(), parts);
      const auto* s = &context.schema; // First part is '#'
      for (size_t i = 1; s && i < parts.size(); ++i) {
        // Per the standard, we must replace ~1 with / and then ~0 with ~
        boost::replace_all(parts[i], "~1", "/");
        boost::replace_all(parts[i], "~0", "~");
        if (s->isObject()) {
          s = s->get_ptr(parts[i]);
          continue;
        }
        if (s->isArray()) {
          try {
            const size_t pos = to<size_t>(parts[i]);
            if (pos < s->size()) {
              s = s->get_ptr(pos);
              continue;
            }
          } catch (const std::range_error& e) {
            // ignore
          }
        }
        break;
      }
      // If you have a self-recursive reference, this avoids getting into an
      // infinite recursion, where we try to load a schema that just references
      // itself, and then we try to load it again, and so on.
      // Instead we load a pointer to the schema into the refs, so that any
      // future references to it will just see that pointer and won't try to
      // keep parsing further.
      if (s) {
        auto v = make_unique<SchemaValidator>();
        context.refs[p->getString()] = v.get();
        v->loadSchema(context, *s);
        validators_.emplace_back(std::move(v));
        return;
      }
    }
  }

  // Numeric validators
  if (const auto* p = schema.get_ptr("multipleOf")) {
    validators_.emplace_back(make_unique<MultipleOfValidator>(*p));
  }
  if (const auto* p = schema.get_ptr("maximum")) {
    validators_.emplace_back(
        make_unique<ComparisonValidator>(*p,
                                         schema.get_ptr("exclusiveMaximum"),
                                         ComparisonValidator::Type::MAX));
  }
  if (const auto* p = schema.get_ptr("minimum")) {
    validators_.emplace_back(
        make_unique<ComparisonValidator>(*p,
                                         schema.get_ptr("exclusiveMinimum"),
                                         ComparisonValidator::Type::MIN));
  }

  // String validators
  if (const auto* p = schema.get_ptr("maxLength")) {
    validators_.emplace_back(
        make_unique<SizeValidator<std::greater_equal<int64_t>>>(
            *p, dynamic::Type::STRING));
  }
  if (const auto* p = schema.get_ptr("minLength")) {
    validators_.emplace_back(
        make_unique<SizeValidator<std::less_equal<int64_t>>>(
            *p, dynamic::Type::STRING));
  }
  if (const auto* p = schema.get_ptr("pattern")) {
    validators_.emplace_back(make_unique<StringPatternValidator>(*p));
  }

  // Array validators
  const auto* items = schema.get_ptr("items");
  const auto* additionalItems = schema.get_ptr("additionalItems");
  if (items || additionalItems) {
    validators_.emplace_back(
        make_unique<ArrayItemsValidator>(context, items, additionalItems));
  }
  if (const auto* p = schema.get_ptr("maxItems")) {
    validators_.emplace_back(
        make_unique<SizeValidator<std::greater_equal<int64_t>>>(
            *p, dynamic::Type::ARRAY));
  }
  if (const auto* p = schema.get_ptr("minItems")) {
    validators_.emplace_back(
        make_unique<SizeValidator<std::less_equal<int64_t>>>(
            *p, dynamic::Type::ARRAY));
  }
  if (const auto* p = schema.get_ptr("uniqueItems")) {
    validators_.emplace_back(make_unique<ArrayUniqueValidator>(*p));
  }

  // Object validators
  const auto* properties = schema.get_ptr("properties");
  const auto* patternProperties = schema.get_ptr("patternProperties");
  const auto* additionalProperties = schema.get_ptr("additionalProperties");
  if (properties || patternProperties || additionalProperties) {
    validators_.emplace_back(make_unique<PropertiesValidator>(
        context, properties, patternProperties, additionalProperties));
  }
  if (const auto* p = schema.get_ptr("maxProperties")) {
    validators_.emplace_back(
        make_unique<SizeValidator<std::greater_equal<int64_t>>>(
            *p, dynamic::Type::OBJECT));
  }
  if (const auto* p = schema.get_ptr("minProperties")) {
    validators_.emplace_back(
        make_unique<SizeValidator<std::less_equal<int64_t>>>(
            *p, dynamic::Type::OBJECT));
  }
  if (const auto* p = schema.get_ptr("required")) {
    validators_.emplace_back(make_unique<RequiredValidator>(*p));
  }

  // Misc validators
  if (const auto* p = schema.get_ptr("dependencies")) {
    validators_.emplace_back(make_unique<DependencyValidator>(context, *p));
  }
  if (const auto* p = schema.get_ptr("enum")) {
    validators_.emplace_back(make_unique<EnumValidator>(*p));
  }
  if (const auto* p = schema.get_ptr("type")) {
    validators_.emplace_back(make_unique<TypeValidator>(*p));
  }
  if (const auto* p = schema.get_ptr("allOf")) {
    validators_.emplace_back(make_unique<AllOfValidator>(context, *p));
  }
  if (const auto* p = schema.get_ptr("anyOf")) {
    validators_.emplace_back(make_unique<AnyOfValidator>(
        context, *p, AnyOfValidator::Type::ONE_OR_MORE));
  }
  if (const auto* p = schema.get_ptr("oneOf")) {
    validators_.emplace_back(make_unique<AnyOfValidator>(
        context, *p, AnyOfValidator::Type::EXACTLY_ONE));
  }
  if (const auto* p = schema.get_ptr("not")) {
    validators_.emplace_back(make_unique<NotValidator>(context, *p));
  }
}