private static object ParseValueToken(this string valueTemplate, int startAt, IReadOnlyCollection <string> validKeys, IEnumerable <string> path, StringComparison keyComparisonType, out int next) { var first = startAt; startAt++; while (startAt < valueTemplate.Length && valueTemplate[startAt] != '}') { startAt++; } if (startAt == valueTemplate.Length || valueTemplate[startAt] != '}') { next = startAt; return(new TextToken(valueTemplate.Substring(first, next - first))); } next = startAt + 1; var rawText = valueTemplate.Substring(first, next - first); var tagContent = rawText.Substring(1, next - (first + 2)); if (tagContent.Length == 0 || !tagContent.IsValidKey(validKeys, keyComparisonType)) { var key = path.SingleOrDefault(tagContent.StartsWith); if (key != null) { rawText = ValueToken.Cycled(key); } if (tagContent.Length > 2) { var unescapedTagContent = tagContent.Substring(1, tagContent.Length - 1); if (unescapedTagContent.Length != 0 && unescapedTagContent.IsValidKey(validKeys, keyComparisonType)) { return(new TextToken(tagContent)); } } return(new TextToken(rawText)); } return(new ValueToken(rawText)); }
private static void RenderValueToken(ValueToken valueToken, TextWriter output, IDictionary <string, string> data, ImmutableArray <string> path, StringComparison keyComparisonType) { var value = data[valueToken.Key]; if (value != null) { var key = data.Keys.Single(x => string.Compare(valueToken.Key, x, keyComparisonType) == 0); path = path.Add(key); var template = value.Parse(data, path, keyComparisonType); value = template.Render(data, path, keyComparisonType); #pragma warning disable CA1307 // Specify StringComparison if (data.Keys.Any(x => value.Contains(ValueToken.Cycled(x)))) #pragma warning restore CA1307 // Specify StringComparison { value = ValueToken.Cycled(key); } data[valueToken.Key] = value; output.Write(value); } }