/// <summary> /// Adds each found property and any associated warnings to token it belongs to /// </summary> /// <param name="currentToken">token to add warning to</param> /// <param name="foundPropertySets">property sets which have been found (list of list of tokens, where the inner list represents key, key value seperator and value)</param> private void AddPropertiesAndWarnings(Token currentToken, List<List<Token>> foundPropertySets) { foreach (var propertyTokenSet in foundPropertySets) { //check for errors if (propertyTokenSet.Count == 1) { if (IsPropertyNameValueSeperatorDelimeter(propertyTokenSet[0])) currentToken.AddWarning("Property added with no key or value"); else currentToken.AddWarning(String.Format("Properties declaration contains no value for the key {0}", propertyTokenSet[0].Text)); } else if (propertyTokenSet.Count == 2) { if (IsPropertyNameValueSeperatorDelimeter(propertyTokenSet[0])) currentToken.AddWarning(String.Format("A property has been added with the value {0} but no key", propertyTokenSet[1].Text)); else if (IsPropertyNameValueSeperatorDelimeter(propertyTokenSet[1])) currentToken.AddWarning(String.Format("Properties declaration contains no value for the key {0}", propertyTokenSet[0].Text)); else currentToken.AddWarning(String.Format("Can not determine key value seperator. {0} and {1} supplied", propertyTokenSet[0].Text, propertyTokenSet[1].Text)); } else { string propertyName = propertyTokenSet[0].Text; if (_delimeterSet.IsDelimeterAllowedProperty(currentToken.Text, propertyName)) { string propertyValue = propertyTokenSet[2].Text; currentToken[propertyName] = propertyValue; } else currentToken.AddWarning(String.Format("The property '{0}' is not allowed on this delimeter.", propertyName)); } } }
public void ConstructHtml_WHEN_Token_Does_Not_Have_Alt_Property_Name_THEN_Returns_Empty_String() { dynamic t = new Token(TokenType.Delimiter, "#img", 1, 1); t.IsStartingDelimeter = true; var parseRule = new AltParseRule(); string htmlFragment = parseRule.ConstructHtml(t); htmlFragment.ShouldEqual(String.Empty); }
public void Transform_GIVEN_globalParseRule_For_StyleClass_WHEN_token_is_for_Bold_And_Is_Starting_Delimeter_With_No_Properties_THEN_Returns_HTML_For_Bold() { Token t = new Token(TokenType.Delimiter, "#b", 1, 1); t.IsStartingDelimeter = true; var parseRule = new DelimeterParseRule("Bold", DefaultDelimeterValues.Bold, "b"); string html = parseRule.TransformToHtml(t, new PropertyParseRule[]{new StyleClassParseRule()}); html.ShouldEqual("<b>"); }
public void TransformToHtml_WHEN_Token_IsStartingDelimeter_Is_True_And_IsEndingDelimeter_Is_False_THEN_Returns_Html_For_Anchor() { Token t = new Token(TokenType.Delimiter, "#a", 1, 1); t.IsStartingDelimeter = true; t.IsEndingDelimeter = false; var parseRule = new AnchorParseRule(); string html = parseRule.TransformToHtml(t, new PropertyParseRule[0]); html.ShouldStartWith("<a"); }
public void TransformToHtml_WHEN_Token_IsStartingDelimeter_Is_False_And_IsEndingDelimeter_Is_True_THEN_Returns_Html_For_Closing_Image() { Token t = new Token(TokenType.Delimiter, "#a", 1, 1); t.IsStartingDelimeter = false; t.IsEndingDelimeter = true; var parseRule = new ImageParseRule(); string html = parseRule.TransformToHtml(t, new PropertyParseRule[0]); html.ShouldEqual("</img>"); }
public void ConstructHtml_WHEN_Token_Has_StyleClass_Property_Name_THEN_Return_HTML_For_class() { const string CssClass = "ABC"; dynamic t = new Token(TokenType.Delimiter, "#b", 1, 1); t.StyleClass = CssClass; t.IsStartingDelimeter = true; var styleClassParseRule = new StyleClassParseRule(); string htmlFragment = styleClassParseRule.ConstructHtml(t); htmlFragment.ShouldEqual(String.Format("class='{0}'", CssClass)); }
public void ConstructHtml_WHEN_Token_Has_Alt_Property_Name_THEN_Return_HTML_For_alt() { const string ImgSrc = "a.jpg"; dynamic t = new Token(TokenType.Delimiter, "#img", 1, 1); t.Alt = ImgSrc; t.IsStartingDelimeter = true; var parseRule = new AltParseRule(); string htmlFragment = parseRule.ConstructHtml(t); htmlFragment.ShouldEqual(String.Format("alt='{0}'", ImgSrc)); }
public void ConstructHtml_WHEN_Token_Has_Url_Property_Name_THEN_Return_HTML_For_href() { const string Url = "http://www.jumbleblocks.com"; dynamic t = new Token(TokenType.Delimiter, "#a", 1, 1); t.Url = Url; t.IsStartingDelimeter = true; var hrefParseRule = new HrefParseRule(); string htmlFragment = hrefParseRule.ConstructHtml(t); htmlFragment.ShouldEqual(String.Format("href='{0}'", Url)); }
public void TransformToHtml_WHEN_Token_IsStartingDelimter_Is_True_And_Has_Property_Named_Url_THEN_Constructs_Anchor_Start_With_Href() { const string Url = "http://www.jumbleblocks.com/"; dynamic t = new Token(TokenType.Delimiter, "#a", 1, 1); t.IsStartingDelimeter = true; t.IsEndingDelimeter = false; t.Url = Url; var parseRule = new AnchorParseRule(); string html = parseRule.TransformToHtml(t, new PropertyParseRule[0]); html.ShouldEqual(String.Format("<a href='{0}'>", Url)); }
public void TransformToHtml_WHEN_Token_IsStartingDelimter_Is_True_And_Has_Property_Named_Scr_THEN_Constructs_Anchor_Start_With_Src() { const string Src = "a.jpg"; dynamic t = new Token(TokenType.Delimiter, "#a", 1, 1); t.IsStartingDelimeter = true; t.IsEndingDelimeter = false; t.Src = Src; var parseRule = new ImageParseRule(); string html = parseRule.TransformToHtml(t, new PropertyParseRule[0]); html.ShouldEqual(String.Format("<img src='{0}'>", Src)); }
public void Transform_GIVEN_globalParseRule_StyleClass_WHEN_token_is_for_Bold_And_Is_Starting_Delimeter_With_Property_For_StyleClass_With_Value_ABC_THEN_Returns_HTML_For_Bold_With_Class_Attribute() { const string CssClass = "ABC"; dynamic t = new Token(TokenType.Delimiter, "#b", 1, 1); t.StyleClass = CssClass; t.IsStartingDelimeter = true; var parseRule = new DelimeterParseRule("Bold", DefaultDelimeterValues.Bold, "b"); string html = parseRule.TransformToHtml(t, new PropertyParseRule[] { new StyleClassParseRule() }); html.ShouldEqual(String.Format("<b class='{0}'>", CssClass)); }
public void Transform_GIVEN_globalParseRule_For_StyleClass_Which_Outputs_id_And_localParseRule_For_StyleClass_Which_Outputs_class_WHEN_Token_Is_For_Bold_THEN_Returns_Result_Of_LocalPropertyParseRule_Which_Is_Bold_With_Class_Attribute() { const string CssClass = "ABC"; dynamic t = new Token(TokenType.Delimiter, "#b", 1, 1); t.StyleClass = CssClass; t.IsStartingDelimeter = true; var styleClassRule = new StyleClassParseRule(); var parseRule = new DelimeterParseRule("Bold", DefaultDelimeterValues.Bold, "b"); parseRule.AddPropertyParseRule(styleClassRule); string html = parseRule.TransformToHtml(t, new PropertyParseRule[] { new PropertyParseRule(styleClassRule.PropertyName, "id") }); html.ShouldEqual(String.Format("<b class='{0}'>", CssClass)); }
public void Transform_WHEN_token_TokenType_Is_Delimeter_AND_Is_For_BOLD_And_Token_Is_For_Opening_Bold_THEN_Returns_HTML_To_Start_Bold() { Token t = new Token(TokenType.Delimiter, "#b", 1, 1); t.IsStartingDelimeter = true; var parseRule = new DelimeterParseRule("Bold", DefaultDelimeterValues.Bold, "b"); string html = parseRule.TransformToHtml(t, new List<PropertyParseRule>(0)); html.ShouldEqual("<b>"); }
/// <summary> /// Appends text to list of tokens that already exists. /// /// If previous token was text, then appends to that, otherwise appends as it's own token /// </summary> /// <param name="tokens">tokens to append to</param> /// <param name="currentToken">current token</param> /// <param name="allowCurrentTokenToBeAppended">if true if the previous token is not a TEXT then allows current token to be appended to stream, if false only allows token to be combined with previous token if that previous token is TEXT</param> private void AppendTextToTokens(List<Token> tokens, Token currentToken) { Token previousToken = tokens.LastOrDefault(); if (previousToken != null && previousToken.IsText && !previousToken.HasWarnings) previousToken.Text += currentToken.Text; else if(!IsEscapeDelimieter(currentToken)) { if(currentToken.TokenType != TokenType.Text) currentToken.ChangeTokenTypeToText(); tokens.Add(currentToken); } }
public void Transform_WHEN_token_TokenType_Is_Not_Delimeter_THEN_Throws_InvalidOperationException() { Token t = new Token(TokenType.Text, "text", 1, 1); var parseRule = new DelimeterParseRule("Bold", DefaultDelimeterValues.Bold, "b"); parseRule.TransformToHtml(t, new List<PropertyParseRule>(0)); }
/// <summary> /// Checks to see if a given token (representing a closing delimeter has properties. If it does then adds warning to that token /// </summary> /// <param name="closingToken">token representing delimeter</param> /// <param name="tokenStream">remaining token stream</param> private void WarnIfClosingTokenHasProperties(Token closingToken, IWaneTokenStream tokenStream) { //check for closing token properties Token possiblePropertyToken = tokenStream.Peek(); if (possiblePropertyToken != null && IsPropertiesStartDelimeter(possiblePropertyToken)) { //check if has full properties List<Token> propertyTokens = GetRawTokensUntilAndIncludingEndingDelimeter(possiblePropertyToken, tokenStream); if (propertyTokens.Count > 0) closingToken.AddWarning("Can not put properties on closing delimeters."); } }
/// <summary> /// Checks to see if token represents the properties start delimeter /// </summary> /// <param name="token">Token to check</param> /// <returns>true if is, otherwise false</returns> private bool IsPropertiesStartDelimeter(Token token) { return token.IsDelimeter && _delimeterSet.IsPropertiesStartDelimeter(token.Text); }
public void Transform_WHEN_globalPropertyParseRules_Is_Null_THEN_Throws_ArgumentNullException() { Token t = new Token(TokenType.Delimiter, "#b", 1, 1); var parseRule = new DelimeterParseRule("Bold", DefaultDelimeterValues.Bold, "b"); parseRule.TransformToHtml(t, null); }
/// <summary> /// Handles a custom delimeter from it's start until it's end. /// Also handles tokens within those custom delimeters /// </summary> /// <param name="currentToken">current token (which is a delimeter)</param> /// <param name="tokenStream"></param> private List<Token> HandleCustomDelimeter(Token currentToken, IWaneTokenStream tokenStream) { if (!IsCustomDelimeter(currentToken)) throw new ArgumentException("Expected custome delimeter", "currentToken"); var tokens = new List<Token>(); currentToken.IsStartingDelimeter = true; tokens.Add(currentToken); //find ending delimeter List<Token> tokensToInspect = GetRawTokensUntilAndIncludingEndingDelimeter(currentToken, tokenStream); if (tokensToInspect.Count > 0) { //remove ending token else this will not be processed properly Token closingToken = tokensToInspect.Last(); tokensToInspect.RemoveAt(tokensToInspect.Count - 1); var internalStream = new WaneEnumerableTokenStream(tokensToInspect); //get and remove properties ExtractPropertiesFromTokenListAndApplyToCurrentToken(currentToken, internalStream); if (!internalStream.IsEndOfStream) { List<Token> procesedInternalStreamTokens = ProcessTokenStream(internalStream); tokens.AddRange(procesedInternalStreamTokens); } //add closing delimeter token closingToken.IsEndingDelimeter = true; tokens.Add(closingToken); WarnIfClosingTokenHasProperties(closingToken, tokenStream); } else { //no closing delimeter currentToken.ChangeTokenTypeToText(); currentToken.AddWarning("Delimeter start does not have a matching end delimeter, or the actual start delimeter has been escaped"); } return tokens; }
/// <summary> /// Gets a sub stream of tokens to parse /// </summary> /// <param name="findEndingTokenFor">searches for a matching token in the stream, the match will be the end of the sub-stream (or then end of the text will be)</param> /// <param name="tokenStream">token stream being read from</param> /// <returns>sub stream of tokens, or empty list if no ending delimeter</returns> private List<Token> GetRawTokensUntilAndIncludingEndingDelimeter(Token findEndingTokenFor, IWaneTokenStream tokenStream) { var subStream = new List<Token>(); bool hasFoundEndingToken = false; string endingDelimeter = _delimeterSet.GetEndingDelimterForStartingDelimeter(findEndingTokenFor.Text); Token endingToken = tokenStream.Find(endingDelimeter); if (endingToken != null) { while (!tokenStream.IsEndOfStream && !hasFoundEndingToken) { Token token = tokenStream.ReadNextToken(); subStream.Add(token); hasFoundEndingToken = token.Text == endingToken.Text; } } return subStream; }
/// <summary> /// Extracts tokens which represent properties for a given token and apply put those properties onto the token /// </summary> /// <param name="currentToken">token that will have properties added to it</param> /// <param name="tokenStream">token stream to inspect</param> private void ExtractPropertiesFromTokenListAndApplyToCurrentToken(Token currentToken, IWaneTokenStream tokenStream) { if (IsPropertiesStartDelimeter(tokenStream.Peek())) { List<Token> rawPropertyTokens = GetRawTokensUntilAndIncludingEndingDelimeter(tokenStream.Peek(), tokenStream); if (rawPropertyTokens.Count == 0) currentToken.AddWarning("Properties start delimeter found, but could not find ending properties delimeter."); else if(rawPropertyTokens.Count == 2) currentToken.AddWarning("Properties declaration contains no key value pairs. Could not construct properties."); else ProcessProperties(currentToken, rawPropertyTokens); } }
/// <summary> /// Determines if a token causes the next token to be escaped /// </summary> /// <param name="currentToken">the current token to check if it's an escape char, and if the escape char is escaping</param> /// <param name="tokenStream">remaining token stream</param> /// <returns>true if causes escape, otherwise false</returns> private bool DelimeterCausesEscape(Token currentToken, IWaneTokenStream tokenStream) { if (IsEscapeDelimieter(currentToken)) { Token nextToken = tokenStream.Peek(); if (nextToken.IsDelimeter) return true; else currentToken.ChangeTokenTypeToText(); } return false; }
/// <summary> /// Creates a token from the provided index and length /// </summary> /// <param name="nextIndexAndLength">index (Item1) and length (Item2) of next delimeter or new line</param> /// <returns>Token</returns> private Token CreateToken(Tuple<int, int> nextIndexAndLength) { Token token = null; if(nextIndexAndLength.Item1 == 0) { token = CreateTokenFromPosition(nextIndexAndLength); } else { //looking at text up to delimeter string foundText = Text.Substring(0, nextIndexAndLength.Item1); token = new Token(TokenType.Text, foundText, LinePosition + 1, CharPositionInLine + 1); } return token; }
/// <summary> /// Removes text which has been tokenised from the text in the reader /// Also updates line and char position counts /// </summary> /// <param name="token">Token containing the text to remove</param> private void RemoveTokenisedTextAndUpdatePositions(Token token) { Text = Text.Remove(0, token.Text.Length); if (token.TokenType == TokenType.NewLine) { LinePosition++; CharPositionInLine = 0; } else CharPositionInLine += token.Text.Length; }
/// <summary> /// Checks to see if token represents the seperator between property name and property value delimeter /// </summary> /// <param name="token">Token to check</param> /// <returns>true if is, otherwise false</returns> private bool IsPropertyNameValueSeperatorDelimeter(Token token) { return token.IsDelimeter && _delimeterSet.IsPropertyNameValueSeperatorDelimeter(token.Text); }
/// <summary> /// Checks to see if token is custom delimeter /// </summary> /// <param name="token">token to check</param> /// <returns>true if is custom, otherwise false</returns> private bool IsCustomDelimeter(Token token) { return token.IsDelimeter && _delimeterSet.IsCustomDelimeter(token.Text); }
private void ProcessProperties(Token currentToken, List<Token> propertyTokens) { //get rid of start and end. propertyTokens.RemoveAt(0); propertyTokens.RemoveAt(propertyTokens.Count - 1); List<List<Token>> foundPropertySets = FindPropertySets(propertyTokens); //check each property set has name, name value seperator and value AddPropertiesAndWarnings(currentToken, foundPropertySets); }
/// <summary> /// Checks to see if the token is an escape delimeter /// </summary> /// <param name="token">token to check</param> /// <returns>true if is, otherwise false</returns> private bool IsEscapeDelimieter(Token token) { return token.IsDelimeter && _delimeterSet.IsEscapeDelimeter(token.Text); }
/// <summary> /// Parses a given token to HTML using the parse rules supplied to the delimeter set /// </summary> /// <param name="token">token to add</param> /// <returns>html fragment as a string</returns> public string ParseToHtml(Token token) { DelimeterParseRule parseRule = _parseRules.SingleOrDefault(pr => pr.Delimeter.Equals(token.Text, StringComparison.CurrentCultureIgnoreCase)); if (parseRule == null) return String.Empty; else return parseRule.TransformToHtml(token, _globalPropertyParseRules); }