Beispiel #1
0
        /// <summary>Parse a string which can contain tokens, and validate that it's valid.</summary>
        /// <param name="rawValue">The raw string which may contain tokens.</param>
        /// <param name="tokenContext">The tokens available for this content pack.</param>
        /// <param name="error">An error phrase indicating why parsing failed (if applicable).</param>
        /// <param name="parsed">The parsed value.</param>
        private bool TryParseTokenString(string rawValue, IContext tokenContext, out string error, out TokenString parsed)
        {
            // parse
            parsed = new TokenString(rawValue, tokenContext);

            // validate unknown tokens
            if (parsed.InvalidTokens.Any())
            {
                error  = $"found unknown tokens ({string.Join(", ", parsed.InvalidTokens.OrderBy(p => p))})";
                parsed = null;
                return(false);
            }

            // validate tokens
            foreach (TokenName tokenName in parsed.Tokens)
            {
                IToken token = tokenContext.GetToken(tokenName, enforceContext: false);
                if (token == null)
                {
                    error  = $"{{{{{tokenName}}}}} can't be used as a token because that token could not be found."; // should never happen
                    parsed = null;
                    return(false);
                }
                if (token.CanHaveMultipleValues(tokenName))
                {
                    error  = $"{{{{{tokenName}}}}} can't be used as a token because it can have multiple values.";
                    parsed = null;
                    return(false);
                }
            }

            // looks OK
            error = null;
            return(true);
        }
Beispiel #2
0
        /// <summary>Parse a JSON structure which can contain tokens, and validate that it's valid.</summary>
        /// <param name="rawJson">The raw JSON structure which may contain tokens.</param>
        /// <param name="tokenContext">The tokens available for this content pack.</param>
        /// <param name="migrator">The migrator which validates and migrates content pack data.</param>
        /// <param name="error">An error phrase indicating why parsing failed (if applicable).</param>
        /// <param name="parsed">The parsed value, which may be legitimately <c>null</c> even if successful.</param>
        private bool TryParseJsonTokens(JToken rawJson, IContext tokenContext, IMigration migrator, out string error, out TokenisableJToken parsed)
        {
            if (rawJson == null)
            {
                error  = null;
                parsed = null;
                return(true);
            }

            // parse
            parsed = new TokenisableJToken(rawJson, tokenContext);
            if (!migrator.TryMigrate(parsed, out error))
            {
                return(false);
            }

            // validate tokens
            TokenString[] tokenStrings = parsed.GetTokenStrings().ToArray();
            if (tokenStrings.Any())
            {
                // validate unknown tokens
                string[] unknownTokens = tokenStrings.SelectMany(p => p.InvalidTokens).OrderBy(p => p).ToArray();
                if (unknownTokens.Any())
                {
                    error  = $"found unknown tokens ({string.Join(", ", unknownTokens)})";
                    parsed = null;
                    return(false);
                }

                // validate tokens
                foreach (TokenName tokenName in tokenStrings.SelectMany(p => p.Tokens))
                {
                    IToken token = tokenContext.GetToken(tokenName, enforceContext: false);
                    if (token == null)
                    {
                        error  = $"{{{{{tokenName}}}}} can't be used as a token because that token could not be found."; // should never happen
                        parsed = null;
                        return(false);
                    }

                    if (token.CanHaveMultipleValues(tokenName))
                    {
                        error  = $"{{{{{tokenName}}}}} can't be used as a token because it can have multiple values.";
                        parsed = null;
                        return(false);
                    }
                }
            }

            // looks OK
            if (parsed.Value.Type == JTokenType.Null)
            {
                parsed = null;
            }
            error = null;
            return(true);
        }
Beispiel #3
0
        /// <summary>Parse a boolean <see cref="PatchConfig.Enabled"/> value from a string which can contain tokens, and validate that it's valid.</summary>
        /// <param name="rawValue">The raw string which may contain tokens.</param>
        /// <param name="tokenContext">The tokens available for this content pack.</param>
        /// <param name="migrator">The migrator which validates and migrates content pack data.</param>
        /// <param name="error">An error phrase indicating why parsing failed (if applicable).</param>
        /// <param name="parsed">The parsed value.</param>
        private bool TryParseEnabled(string rawValue, IContext tokenContext, IMigration migrator, out string error, out bool parsed)
        {
            parsed = false;

            // analyse string
            if (!this.TryParseStringTokens(rawValue, tokenContext, migrator, out error, out ITokenString tokenString))
            {
                return(false);
            }

            // validate & extract tokens
            string text = rawValue;

            if (tokenString.HasAnyTokens)
            {
                // only one token allowed
                if (!tokenString.IsSingleTokenOnly)
                {
                    error = "can't be treated as a true/false value because it contains multiple tokens.";
                    return(false);
                }

                // parse token
                LexTokenToken lexToken = tokenString.GetTokenPlaceholders(recursive: false).Single();
                IToken        token    = tokenContext.GetToken(lexToken.Name, enforceContext: false);
                ITokenString  input    = new TokenString(lexToken.InputArg, tokenContext);

                // check token options
                InvariantHashSet allowedValues = token?.GetAllowedValues(input);
                if (token == null || token.IsMutable || !token.IsReady)
                {
                    error = $"can only use static tokens in this field, consider using a {nameof(PatchConfig.When)} condition instead.";
                    return(false);
                }
                if (allowedValues == null || !allowedValues.All(p => bool.TryParse(p, out _)))
                {
                    error = "that token isn't restricted to 'true' or 'false'.";
                    return(false);
                }
                if (token.CanHaveMultipleValues(input))
                {
                    error = "can't be treated as a true/false value because that token can have multiple values.";
                    return(false);
                }

                text = token.GetValues(input).First();
            }

            // parse text
            if (!bool.TryParse(text, out parsed))
            {
                error = $"can't parse {tokenString.Raw} as a true/false value.";
                return(false);
            }
            return(true);
        }
Beispiel #4
0
        /// <summary>Parse a boolean <see cref="PatchConfig.Enabled"/> value from a string which can contain tokens, and validate that it's valid.</summary>
        /// <param name="rawValue">The raw string which may contain tokens.</param>
        /// <param name="tokenContext">The tokens available for this content pack.</param>
        /// <param name="error">An error phrase indicating why parsing failed (if applicable).</param>
        /// <param name="parsed">The parsed value.</param>
        private bool TryParseEnabled(string rawValue, IContext tokenContext, out string error, out bool parsed)
        {
            parsed = false;

            // analyse string
            if (!this.TryParseTokenString(rawValue, tokenContext, out error, out TokenString tokenString))
            {
                return(false);
            }

            // validate & extract tokens
            string text = rawValue;

            if (tokenString.HasAnyTokens)
            {
                // only one token allowed
                if (!tokenString.IsSingleTokenOnly)
                {
                    error = "can't be treated as a true/false value because it contains multiple tokens.";
                    return(false);
                }

                // check token options
                TokenName        tokenName     = tokenString.Tokens.First();
                IToken           token         = tokenContext.GetToken(tokenName, enforceContext: false);
                InvariantHashSet allowedValues = token?.GetAllowedValues(tokenName);
                if (token == null || token.IsMutable || !token.IsValidInContext)
                {
                    error = $"can only use static tokens in this field, consider using a {nameof(PatchConfig.When)} condition instead.";
                    return(false);
                }
                if (allowedValues == null || !allowedValues.All(p => p == true.ToString() || p == false.ToString()))
                {
                    error = "that token isn't restricted to 'true' or 'false'.";
                    return(false);
                }
                if (token.CanHaveMultipleValues(tokenName))
                {
                    error = "can't be treated as a true/false value because that token can have multiple values.";
                    return(false);
                }

                text = token.GetValues(tokenName).First();
            }

            // parse text
            if (!bool.TryParse(text, out parsed))
            {
                error = $"can't parse {tokenString.Raw} as a true/false value.";
                return(false);
            }
            return(true);
        }