///|
/// Settings for one service conversion. Service and protocol IDs, version and
/// omission policy are validated before conversion begins.
pub struct Config {
service : ServiceId
protocol : ProtocolId?
version : OpenApiVersion
prefix_headers : PrefixHeadersPolicy
forbid_greedy_labels : Bool
remove_greedy_parameter_suffix : Bool
ignore_unsupported_traits : Bool
tags : Bool
supported_tags : Array[String]?
keep_unused_components : Bool
json_content_type : String
default_blob_format : String
external_docs : Array[String]
disable_integer_format : Bool
alphanumeric_only_refs : Bool
use_strings_for_arbitrary_precision : Bool
combine_error_responses : Bool
schema : @jsonschema.Config
substitutions : Map[String, Json]
json_add : Map[String, Json]
}
///|
pub fn Config::new(
service : ServiceId,
protocol~ : ProtocolId? = None,
version~ : OpenApiVersion = V3_0_2,
prefix_headers~ : PrefixHeadersPolicy = Fail,
forbid_greedy_labels~ : Bool = false,
remove_greedy_parameter_suffix~ : Bool = false,
ignore_unsupported_traits~ : Bool = false,
tags~ : Bool = false,
supported_tags~ : Array[String]? = None,
keep_unused_components~ : Bool = false,
json_content_type~ : String = "application/json",
default_blob_format~ : String = "byte",
external_docs~ : Array[String] = [
"Homepage", "API Reference", "User Guide", "Developer Guide", "Reference", "Guide",
],
disable_integer_format~ : Bool = false,
alphanumeric_only_refs~ : Bool = false,
use_strings_for_arbitrary_precision~ : Bool = false,
combine_error_responses~ : Bool = false,
schema~ : @jsonschema.Config = @jsonschema.Config::new(),
substitutions~ : Map[String, Json] = Map([]),
json_add~ : Map[String, Json] = Map([]),
) -> Config {
{
service,
protocol,
version,
prefix_headers,
forbid_greedy_labels,
remove_greedy_parameter_suffix,
ignore_unsupported_traits,
tags,
supported_tags,
keep_unused_components,
json_content_type,
default_blob_format,
external_docs,
disable_integer_format,
alphanumeric_only_refs,
use_strings_for_arbitrary_precision,
combine_error_responses,
schema,
substitutions,
json_add,
}
}
///|
pub fn Config::service(self : Config) -> ServiceId {
self.service
}
///|
pub fn Config::version(self : Config) -> OpenApiVersion {
self.version
}
///|
fn setting_string(
fields : Map[String, Json],
key : String,
fallback : String,
) -> String raise OpenApiError {
match fields.get(key) {
None => fallback
Some(String(value)) => value
_ =>
raise InvalidConfiguration(
"OpenAPI setting `" + key + "` must be a string",
)
}
}
///|
fn setting_bool(
fields : Map[String, Json],
key : String,
) -> Bool raise OpenApiError {
match fields.get(key) {
None | Some(False) => false
Some(True) => true
_ =>
raise InvalidConfiguration(
"OpenAPI setting `" + key + "` must be a boolean",
)
}
}
///|
fn setting_strings(
fields : Map[String, Json],
key : String,
fallback : Array[String],
) -> Array[String] raise OpenApiError {
match fields.get(key) {
None => fallback
Some(Array(values)) => {
let out : Array[String] = []
for value in values {
guard value is String(text) else {
raise InvalidConfiguration(
"OpenAPI setting `" + key + "` must contain strings",
)
}
out.push(text)
}
out
}
_ =>
raise InvalidConfiguration(
"OpenAPI setting `" + key + "` must be an array",
)
}
}
///|
fn setting_object(
fields : Map[String, Json],
key : String,
) -> Map[String, Json] raise OpenApiError {
match fields.get(key) {
None => Map([])
Some(Object(values)) => values
_ =>
raise InvalidConfiguration(
"OpenAPI setting `" + key + "` must be an object",
)
}
}
///|
/// Parse the settings of the `openapi` build plugin. This performs no I/O.
pub fn Config::from_json(settings : Json) -> Config raise OpenApiError {
guard settings is Object(fields) else {
raise InvalidConfiguration("OpenAPI settings must be an object")
}
let service_text = setting_string(fields, "service", "")
guard ServiceId::parse(service_text) is Some(service) else {
raise InvalidConfiguration(
"OpenAPI requires a valid root `service` shape ID",
)
}
let protocol = match fields.get("protocol") {
None => None
Some(String(value)) => {
guard ProtocolId::parse(value) is Some(id) else {
raise InvalidConfiguration(
"OpenAPI requires a valid root `protocol` trait ID",
)
}
Some(id)
}
_ =>
raise InvalidConfiguration("OpenAPI setting `protocol` must be a string")
}
guard OpenApiVersion::parse(setting_string(fields, "version", "3.0.2"))
is Some(version) else {
raise InvalidConfiguration("OpenAPI supports versions 3.0.2 and 3.1.0")
}
let prefix_headers = match
setting_string(fields, "onHttpPrefixHeaders", "FAIL") {
"FAIL" => Fail
"WARN" => Warn
_ => raise InvalidConfiguration("onHttpPrefixHeaders must be FAIL or WARN")
}
let combine_error_responses = match fields.get("onErrorStatusConflict") {
None => false
Some(String("oneOf")) => true
_ => raise InvalidConfiguration("onErrorStatusConflict must be oneOf")
}
let schema = @jsonschema.Config::new(
map_strategy=setting_string(fields, "mapStrategy", "propertyNames"),
union_strategy=setting_string(fields, "unionStrategy", "oneOf"),
enum_strategy=setting_string(fields, "enumStrategy", "enum"),
use_json_name=setting_bool(fields, "useJsonName"),
default_timestamp_format=setting_string(
fields, "defaultTimestampFormat", "date-time",
),
support_non_numeric_floats=setting_bool(fields, "supportNonNumericFloats"),
schema_document_extensions=Json::object(
setting_object(fields, "schemaDocumentExtensions"),
),
definition_pointer="#/components/schemas",
add_reference_descriptions=setting_bool(fields, "addReferenceDescriptions"),
disable_default_values=setting_bool(fields, "disableDefaultValues"),
disable_int_enums=setting_bool(fields, "disableIntEnums"),
use_integer_type=setting_bool(fields, "useIntegerType"),
)
Config::new(
service,
protocol~,
version~,
prefix_headers~,
schema~,
forbid_greedy_labels=setting_bool(fields, "forbidGreedyLabels"),
remove_greedy_parameter_suffix=setting_bool(
fields, "removeGreedyParameterSuffix",
),
ignore_unsupported_traits=setting_bool(fields, "ignoreUnsupportedTraits"),
tags=setting_bool(fields, "tags"),
supported_tags=if fields.contains("supportedTags") {
Some(setting_strings(fields, "supportedTags", []))
} else {
None
},
keep_unused_components=setting_bool(fields, "keepUnusedComponents"),
json_content_type=setting_string(
fields, "jsonContentType", "application/json",
),
default_blob_format=setting_string(fields, "defaultBlobFormat", "byte"),
external_docs=setting_strings(fields, "externalDocs", [
"Homepage", "API Reference", "User Guide", "Developer Guide", "Reference",
"Guide",
]),
disable_integer_format=setting_bool(fields, "disableIntegerFormat"),
alphanumeric_only_refs=setting_bool(fields, "alphanumericOnlyRefs"),
use_strings_for_arbitrary_precision=setting_bool(
fields, "useStringsForArbitraryPrecision",
),
combine_error_responses~,
substitutions=setting_object(fields, "substitutions"),
json_add=setting_object(fields, "jsonAdd"),
)
}