/********* ** Public methods *********/ /// <summary>Get an immutable set for the given values.</summary> /// <param name="values">The values for which to get a set.</param> public static IInvariantSet From(IEnumerable <string> values) { // shortcut predefined values switch (values) { // already an invariant set case IInvariantSet set: return(set); // use predefined set if possible case IList <string> list: switch (list.Count) { case 0: return(InvariantSets.Empty); case 1: return(InvariantSets.FromValue(list[0])); case 2 when bool.TryParse(list[0], out bool left) && bool.TryParse(list[1], out bool right): if (left != right) { return(InvariantSets.Boolean); } return(left ? InvariantSets.True : InvariantSets.False); } break; } // create custom set IInvariantSet result = values is MutableInvariantSet mutableSet ? mutableSet.GetImmutable() : new InvariantSet(values); return(result.Count == 0 ? InvariantSets.Empty : result); }
/// <summary>Get unique, trimmed, comma-separated values from a token string.</summary> /// <param name="tokenStr">The token string to parse.</param> /// <param name="normalize">Normalize a value.</param> /// <exception cref="InvalidOperationException">The token string is not ready (<see cref="IContextual.IsReady"/> is false).</exception> public static IInvariantSet SplitValuesUnique(this ITokenString?tokenStr, Func <string, string>?normalize = null) { if (tokenStr?.IsReady is false) { throw new InvalidOperationException($"Can't get values from a non-ready token string (raw value: {tokenStr.Raw})."); } if (string.IsNullOrWhiteSpace(tokenStr?.Value)) { return(InvariantSets.Empty); } string[] values = tokenStr.Value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (normalize != null) { for (int i = 0; i < values.Length; i++) { values[i] = normalize(values[i]); } } return(InvariantSets.From(values)); }
/********* ** Private methods *********/ /// <summary>Parse a raw config schema for a content pack.</summary> /// <param name="rawSchema">The raw config schema.</param> /// <param name="logWarning">The callback to invoke on each validation warning, passed the field name and reason respectively.</param> /// <param name="formatVersion">The content format version.</param> private InvariantDictionary <ConfigField> LoadConfigSchema(InvariantDictionary <ConfigSchemaFieldConfig?>?rawSchema, Action <string, string> logWarning, ISemanticVersion formatVersion) { InvariantDictionary <ConfigField> schema = new(); if (rawSchema == null || !rawSchema.Any()) { return(schema); } foreach (string rawKey in rawSchema.Keys) { ConfigSchemaFieldConfig?field = rawSchema[rawKey]; if (field is null) { continue; } // validate format if (string.IsNullOrWhiteSpace(rawKey)) { logWarning(rawKey, "the config field name can't be empty."); continue; } if (rawKey.Contains(InternalConstants.PositionalInputArgSeparator) || rawKey.Contains(InternalConstants.NamedInputArgSeparator)) { logWarning(rawKey, $"the name '{rawKey}' can't have input arguments ({InternalConstants.PositionalInputArgSeparator} or {InternalConstants.NamedInputArgSeparator} character)."); continue; } // validate reserved keys if (Enum.TryParse <ConditionType>(rawKey, true, out _)) { logWarning(rawKey, $"can't use {rawKey} as a config field, because it's a reserved condition key."); continue; } // read allowed/default values IInvariantSet allowValues = this.ParseCommaDelimitedField(field.AllowValues); IInvariantSet defaultValues = this.ParseCommaDelimitedField(field.Default); // pre-1.7 behaviour if (formatVersion.IsOlderThan("1.7")) { // allowed values are required if (!allowValues.Any()) { logWarning(rawKey, $"no {nameof(ConfigSchemaFieldConfig.AllowValues)} specified (and format version is less than 1.7)."); continue; } // inject default if needed if (!defaultValues.Any() && !field.AllowBlank) { defaultValues = InvariantSets.FromValue(allowValues.First()); } } // validate allowed values if (!field.AllowBlank && !defaultValues.Any()) { logWarning(rawKey, $"if {nameof(field.AllowBlank)} is false, you must specify {nameof(field.Default)}."); continue; } if (allowValues.Any() && defaultValues.Any()) { IInvariantSet invalidValues = defaultValues.GetWithout(allowValues); if (invalidValues.Any()) { logWarning(rawKey, $"default values '{string.Join(", ", invalidValues)}' are not allowed according to {nameof(ConfigSchemaFieldConfig.AllowValues)}."); continue; } } // validate allow multiple if (!field.AllowMultiple && defaultValues.Count > 1) { logWarning(rawKey, $"can't have multiple default values because {nameof(ConfigSchemaFieldConfig.AllowMultiple)} is false."); continue; } // add to schema schema[rawKey] = new ConfigField( allowValues: allowValues, defaultValues: defaultValues, value: InvariantSets.Empty, allowBlank: field.AllowBlank, allowMultiple: field.AllowMultiple, description: field.Description, section: field.Section ); } return(schema); }