blob: 367b95b3fd03b4c919b19b405b4fce70e3fbc8df [file]
/** @file
Utilities to help with parsing YAML files with good error reporting.
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
*/
#pragma once
#include <vector>
#include <string_view>
#include <yaml-cpp/yaml.h>
#include <swoc/bwf_fwd.h>
namespace ts
{
namespace Yaml
{
constexpr std::string_view YAML_FLOAT_TAG_URI{"tag:yaml.org,2002:float"};
constexpr std::string_view YAML_INT_TAG_URI{"tag:yaml.org,2002:int"};
constexpr std::string_view YAML_STR_TAG_URI{"tag:yaml.org,2002:str"};
constexpr std::string_view YAML_BOOL_TAG_URI{"tag:yaml.org,2002:bool"};
constexpr std::string_view YAML_NULL_TAG_URI{"tag:yaml.org,2002:null"};
// Put an emitter into JSON output mode.
//
// yaml-cpp has no JSON output mode. The nearest equivalent is flow style with every scalar double quoted. For the
// node shapes the callers here emit -- maps, sequences, scalars and nulls, carrying no tags, anchors or aliases --
// that parses as JSON except for null: yaml-cpp writes `~`, which JSON parsers reject. LowerNull writes the
// literal `null` instead. YAML resolves `~` and `null` to the same value, so the output still reads as YAML.
//
// Parses as JSON is the whole guarantee. It is not type-faithful JSON: `DoubleQuoted` quotes every scalar, so
// numbers and booleans arrive as strings -- `"12"` rather than `12`, `"true"` rather than `true`. A consumer
// validating against a schema that declares `integer` or `boolean` will reject that, and no manipulator here
// changes it. Preserving scalar types needs a real JSON serializer, not a yaml-cpp emitter.
//
// This is not a general YAML to JSON converter. A node that carries a tag, an anchor or an alias still emits YAML
// syntax that JSON does not accept.
//
// Every emitter whose output reaches a JSON consumer must go through here. Setting only some of the manipulators
// gives output that looks like JSON and parses correctly until some node is null.
//
inline void
configure_json_emitter(YAML::Emitter &emitter)
{
emitter.SetNullFormat(YAML::LowerNull);
emitter << YAML::DoubleQuoted << YAML::Flow;
}
// A class that is a wrapper for a YAML::Node that corresponds to a map in a YAML input file.
// It's purpose is to make sure all keys in the map are processed.
//
class Map
{
public:
// A YAML::ParserException will be thrown if 'map' isn't actually a map.
//
explicit Map(const YAML::Node &map);
// Get the node for a key. Throw a YAML::Exception if 'key' is not in the map. The node for each key in the
// map must be gotten at least once. The lifetime of the char array referenced by passed key must be as long
// as this instance.
//
YAML::Node operator[](std::string_view key);
// Call this after the last call to the [] operator. Will throw a YAML::ParserException if instance not
// already marked bad, and all keys in the map were not accessed at least once with the [] operator. The
// 'what' of the exception will list the keys that were not accessed as invalid for the map.
//
void done();
// Mark instance as bad.
//
void
bad()
{
_bad = true;
}
// No copy/move.
//
Map(Map const &) = delete;
Map &operator=(Map const &) = delete;
private:
YAML::Node _map;
std::vector<std::string_view> _used_key;
bool _bad{false};
};
} // end namespace Yaml
} // end namespace ts
namespace swoc
{
// This needs to be in namespace "swoc" or "YAML" or ADL doesn't find the overload.
extern BufferWriter &bwformat(BufferWriter &w, bwf::Spec const &spec, YAML::Mark const &mark);
} // namespace swoc