public void SupportsAlternateDelimiters(
                string input,
                int firstIndex,
                int lastIndex,
                string startDelimiter,
                string endDelimiter)
            {
                // Given
                Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(input));
                IShortcodeCollection shortcodeCollection = new TestShortcodeCollection();

                shortcodeCollection.Add("name", typeof(TestShortcode));
                ShortcodeParser parser = new ShortcodeParser(
                    startDelimiter,
                    endDelimiter,
                    shortcodeCollection);

                // When
                List <ShortcodeLocation> result = parser.Parse(stream);

                // Then
                result.Single().FirstIndex.ShouldBe(firstIndex);
                result.Single().LastIndex.ShouldBe(lastIndex);
            }
Exemplo n.º 2
0
 protected ParserState(ShortcodeParser shortcodeParser)
 {
     _shortcodeParser = shortcodeParser;
     _textParser      = shortcodeParser.TextParser;
 }
 public ParsingAttributesState(ShortcodeParser shortcodeParser) : base(shortcodeParser)
 {
 }
Exemplo n.º 4
0
 public LookingForTagState(ShortcodeParser shortcodeParser) : base(shortcodeParser)
 {
 }
Exemplo n.º 5
0
        /// <inheritdoc />
        public IShortcodeResult Execute(KeyValuePair <string, string>[] args, string content, IDocument document, IExecutionContext context)
        {
            ConvertingDictionary dictionary = args.ToDictionary(
                context,
                "Class",
                "HeaderRows",
                "FooterRows",
                "HeaderCols",
                "HeaderClass",
                "BodyClass",
                "FooterClass");

            string[] lines = content
                             .Trim()
                             .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
                             .Select(x => x.Trim())
                             .ToArray();

            // Table
            XElement table = new XElement(
                "table",
                dictionary.XAttribute("class"));
            int line = 0;

            // Header
            int      headerRows = dictionary.Get("HeaderRows", 0);
            XElement header     = null;

            for (int c = 0; c < headerRows && line < lines.Length; c++, line++)
            {
                // Create the section
                if (c == 0)
                {
                    header = new XElement(
                        "thead",
                        dictionary.XAttribute("class", "HeaderClass"));
                    table.Add(header);
                }

                // Create the current row
                XElement row = new XElement("tr");
                header.Add(row);

                // Add the columns
                foreach (string col in ShortcodeParser.SplitArguments(lines[line], 0).ToValueArray())
                {
                    row.Add(new XElement("th", col));
                }
            }

            // Body
            int      bodyRows = lines.Length - line - dictionary.Get("FooterRows", 0);
            XElement body     = null;

            for (int c = 0; c < bodyRows && line < lines.Length; c++, line++)
            {
                // Create the section
                if (c == 0)
                {
                    body = new XElement(
                        "tbody",
                        dictionary.XAttribute("class", "BodyClass"));
                    table.Add(body);
                }

                // Create the current row
                XElement row = new XElement("tr");
                body.Add(row);

                // Add the columns
                int th = dictionary.Get("HeaderCols", 0);
                foreach (string col in ShortcodeParser.SplitArguments(lines[line], 0).ToValueArray())
                {
                    row.Add(new XElement(th-- > 0 ? "th" : "td", col));
                }
            }

            // Footer
            XElement footer = null;

            for (int c = 0; line < lines.Length; c++, line++)
            {
                // Create the section
                if (c == 0)
                {
                    footer = new XElement(
                        "tfoot",
                        dictionary.XAttribute("class", "FooterClass"));
                    table.Add(footer);
                }

                // Create the current row
                XElement row = new XElement("tr");
                footer.Add(row);

                // Add the columns
                int th = dictionary.Get("HeaderCols", 0);
                foreach (string col in ShortcodeParser.SplitArguments(lines[line], 0).ToValueArray())
                {
                    row.Add(new XElement(th-- > 0 ? "th" : "td", col));
                }
            }

            return(context.GetShortcodeResult(table.ToString()));
        }
        // The inputStream will be disposed if this returns <c>true</c> but will not otherwise
        private bool ProcessShortcodes(Stream inputStream, IDocument input, IExecutionContext context, out IDocument result)
        {
            // Parse the input stream looking for shortcodes
            ShortcodeParser parser = new ShortcodeParser(_startDelimiter, _endDelimiter, context.Shortcodes);

            if (!inputStream.CanSeek)
            {
                inputStream = new SeekableStream(inputStream, true);
            }
            List <ShortcodeLocation> locations = parser.Parse(inputStream);

            // Reset the position because we're going to use the stream again when we do replacements
            inputStream.Position = 0;

            // Return the original document if we didn't find any
            if (locations.Count == 0)
            {
                result = null;
                return(false);
            }

            // Otherwise, create a shortcode instance for each named shortcode
            Dictionary <string, IShortcode> shortcodes =
                locations
                .Select(x => x.Name)
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .ToDictionary(x => x, x => context.Shortcodes.CreateInstance(x), StringComparer.OrdinalIgnoreCase);

            // Execute each of the shortcodes in order
            List <InsertingStreamLocation> insertingLocations = locations
                                                                .Select(x =>
            {
                // Execute the shortcode
                IShortcodeResult shortcodeResult = shortcodes[x.Name].Execute(x.Arguments, x.Content, input, context);

                // Merge output metadata with the current input document
                // Creating a new document is the easiest way to ensure all the metadata from shortcodes gets accumulated correctly
                if (shortcodeResult?.Metadata != null)
                {
                    input = context.GetDocument(input, shortcodeResult.Metadata);
                }

                // Recursively parse shortcodes
                Stream shortcodeResultStream = shortcodeResult?.Stream;
                if (shortcodeResultStream != null)
                {
                    // Don't process nested shortcodes if it's the raw shortcode
                    if (!x.Name.Equals(nameof(Core.Shortcodes.Contents.Raw), StringComparison.OrdinalIgnoreCase))
                    {
                        if (!shortcodeResultStream.CanSeek)
                        {
                            shortcodeResultStream = new SeekableStream(shortcodeResultStream, true);
                        }
                        if (ProcessShortcodes(shortcodeResultStream, input, context, out IDocument nestedResult))
                        {
                            input = nestedResult;
                            shortcodeResultStream = nestedResult.GetStream();      // Will get disposed in the replacement operation below
                        }
                        else
                        {
                            shortcodeResultStream.Position = 0;
                        }
                    }
                    return(new InsertingStreamLocation(x.FirstIndex, x.LastIndex, shortcodeResultStream));
                }

                return(new InsertingStreamLocation(x.FirstIndex, x.LastIndex, null));
            })
                                                                .ToList();

            // Dispose any shortcodes that implement IDisposable
            foreach (IDisposable disposableShortcode
                     in shortcodes.Values.Select(x => x as IDisposable).Where(x => x != null))
            {
                disposableShortcode.Dispose();
            }

            // Construct a new stream with the shortcode results inserted
            // We have to use all TextWriter/TextReaders over the streams to ensure consistent encoding
            Stream resultStream = context.GetContentStream();

            char[] buffer = new char[4096];
            using (TextWriter writer = new StreamWriter(resultStream, Encoding.UTF8, 4096, true))
            {
                // The input stream will get disposed when the reader is
                using (TextReader reader = new StreamReader(inputStream))
                {
                    int position = 0;
                    int length   = 0;
                    foreach (InsertingStreamLocation insertingLocation in insertingLocations)
                    {
                        // Copy up to the start of this shortcode
                        length = insertingLocation.FirstIndex - position;
                        Read(reader, writer, length, ref buffer);
                        position += length;

                        // Copy the shortcode content to the result stream
                        if (insertingLocation.Stream != null)
                        {
                            // This will dispose the shortcode content stream when done
                            using (TextReader insertingReader = new StreamReader(insertingLocation.Stream))
                            {
                                Read(insertingReader, writer, null, ref buffer);
                            }
                        }

                        // Skip the shortcode text
                        length = insertingLocation.LastIndex - insertingLocation.FirstIndex + 1;
                        Read(reader, null, length, ref buffer);
                        position += length;
                    }

                    // Copy remaining
                    Read(reader, writer, null, ref buffer);
                }
            }
            result = context.GetDocument(input, resultStream);
            return(true);
        }
Exemplo n.º 7
0
 public ParsingCloseTagState(ShortcodeParser shortcodeParser)
     : base(shortcodeParser)
 {
 }
Exemplo n.º 8
0
 public void Parse_NullContentReturnsEmptyString(
     ShortcodeParser sut
     )
 {
     sut.Parse(null, null).Should().Be(MvcHtmlString.Empty);
 }
Exemplo n.º 9
0
 public ParsingOpenTagState(ShortcodeParser shortcodeParser)
     : base(shortcodeParser)
 {
 }