public string?TryLookupResourceName(string?typeString, LanguageExpression nameExpression)
        {
            if (typeString is null)
            {
                var nameString        = ExpressionsEngine.SerializeExpression(nameExpression);
                var resourceKeySuffix = EscapeIdentifier($"_{nameString}");

                var matchingResources = assignedResourceNames.Where(kvp => kvp.Key.EndsWith(resourceKeySuffix, StringComparison.OrdinalIgnoreCase));
                if (matchingResources.Count() == 1)
                {
                    // only return a value if we're sure about the match
                    return(matchingResources.First().Value);
                }

                return(null);
            }

            // it's valid to include a trailing slash, so we need to normalize it
            typeString = typeString.TrimEnd('/');

            var assignedResourceKey = GetResourceNameKey(typeString, nameExpression);

            if (!assignedResourceNames.TryGetValue(assignedResourceKey, out var name))
            {
                return(null);
            }

            return(name);
        }
Beispiel #2
0
        public static LanguageExpression ParseExpression(string value)
        {
            if (ExpressionsEngine.IsLanguageExpression(value))
            {
                return(ExpressionsEngine.ParseLanguageExpression(value));
            }

            return(new JTokenExpression(value));
        }
Beispiel #3
0
        public static IEnumerable <JObject> FlattenAndNormalizeResource(JToken resourceJtoken)
        {
            var resource = resourceJtoken as JObject ?? throw new ConversionFailedException($"Unable to read resource", resourceJtoken);

            var(parentType, parentName, _) = ParseResource(resource);

            var childResources = GetProperty(resource, "resources");

            if (childResources != null)
            {
                childResources.Remove();
            }

            yield return(resource);

            var childResourcesArray = childResources?.Value as JArray;

            if (childResourcesArray is null)
            {
                yield break;
            }

            foreach (var childResource in childResourcesArray)
            {
                var childResourceObject = childResource as JObject ?? throw new ConversionFailedException($"Unable to read child resource", childResource);

                var(childType, childName, _) = ParseResource(childResourceObject);

                if (GetProperty(resource, "copy") is { } copyProperty)
                {
                    childResourceObject["copy"] = copyProperty.Value;
                }
                if (GetProperty(resource, "condition") is { } conditionProperty)
                {
                    childResourceObject["condition"] = conditionProperty.Value;
                }

                // child may sometimes be specified using the fully-qualified type and name
                if (!StringComparer.OrdinalIgnoreCase.Equals(parentType.Split("/")[0], childType.Split("/")[0]))
                {
                    childResourceObject["type"] = $"{parentType}/{childType}";
                    childResourceObject["name"] = ExpressionsEngine.SerializeExpression(ExpressionHelpers.Concat(ExpressionHelpers.ParseExpression(parentName), new JTokenExpression("/"), ExpressionHelpers.ParseExpression(childName)));
                }

                foreach (var result in FlattenAndNormalizeResource(childResourceObject))
                {
                    // recurse
                    yield return(result);
                }
            }
        }
        public static void VisitExpressions <TToken>(TToken input, Action <LanguageExpression> visitFunc)
            where TToken : JToken
        {
            var visitor = new LanguageExpressionVisitor
            {
                OnFunctionExpression = visitFunc,
                OnJTokenExpression   = visitFunc,
            };

            void VisitLanguageExpressions(string value)
            {
                if (ExpressionsEngine.IsLanguageExpression(value))
                {
                    var expression = ExpressionsEngine.ParseLanguageExpression(value);
                    expression.Accept(visitor);
                }
            }

            if (input is JValue jValue && jValue.ToObject <string>() is { } value)
            {
                VisitLanguageExpressions(value);
                return;
            }

            JsonUtility.WalkJsonRecursive(
                input,
                objectAction: @object =>
            {
                foreach (var property in @object.Properties())
                {
                    VisitLanguageExpressions(property.Name);
                }
            },
                tokenAction: token =>
            {
                if (token.Type == JTokenType.String && token.ToObject <string>() is { } value)
                {
                    VisitLanguageExpressions(value);
                }
            });
        private string GetResourceNameKey(string typeString, LanguageExpression nameExpression)
        {
            var nameString = ExpressionsEngine.SerializeExpression(nameExpression);

            return(EscapeIdentifier($"{typeString}_{nameString}"));
        }
Beispiel #6
0
        public static LanguageExpression FlattenStringOperations(LanguageExpression original)
        {
            if (original is not FunctionExpression functionExpression)
            {
                return(original);
            }

            // convert a 'format' to a 'concat' function
            if (functionExpression.NameEquals("format"))
            {
                var formatString      = (functionExpression.Parameters[0] as JTokenExpression)?.Value.Value <string>() ?? throw new ArgumentException($"Unable to read format statement {ExpressionsEngine.SerializeExpression(functionExpression)} as string");
                var formatHoleMatches = Regex.Matches(formatString, "{([0-9]+)}");

                var concatExpressions = new List <LanguageExpression>();
                var nextStart         = 0;
                for (var i = 0; i < formatHoleMatches.Count; i++)
                {
                    var match    = formatHoleMatches[i];
                    var position = match.Groups[1].Index;
                    var length   = match.Groups[1].Length;
                    var intValue = int.Parse(match.Groups[1].Value);

                    // compensate for the {
                    if (nextStart < position - 1)
                    {
                        var betweenPortion = formatString.Substring(nextStart, position - 1 - nextStart);
                        concatExpressions.Add(new JTokenExpression(betweenPortion));
                    }

                    // replace it with the appropriately-numbered expression
                    concatExpressions.Add(functionExpression.Parameters[intValue + 1]);

                    // compensate for the }
                    nextStart = position + length + 1;
                }

                if (nextStart < formatString.Length)
                {
                    var betweenPortion = formatString.Substring(nextStart, formatString.Length - nextStart);
                    concatExpressions.Add(new JTokenExpression(betweenPortion));
                }

                // overwrite the original expression
                functionExpression = Concat(concatExpressions.ToArray());
            }

            // flatten nested 'concat' functions
            if (functionExpression.NameEquals("concat"))
            {
                var concatExpressions = new List <LanguageExpression>();
                foreach (var parameter in functionExpression.Parameters)
                {
                    // recurse
                    var flattenedParameter = FlattenStringOperations(parameter);

                    if (flattenedParameter is FunctionExpression childFunction && childFunction.NameEquals("concat"))
                    {
                        // concat directly inside a concat - break it out
                        concatExpressions.AddRange(childFunction.Parameters);
                        continue;
                    }

                    concatExpressions.Add(flattenedParameter);
                }

                // overwrite the original expression
                functionExpression = Concat(CombineConcatArguments(concatExpressions).ToArray());
            }

            // just return the inner portion if there's only one concat entry
            if (functionExpression.NameEquals("concat") && functionExpression.Parameters.Length == 1)
            {
                return(functionExpression.Parameters[0]);
            }

            return(functionExpression);
        }