Beispiel #1
0
        private static ContainerOrTerminalNode ParseFeature(Feature feature, CharacterPositionFinder finder, LineInfo locationAfterFeature)
        {
            var start = GetLineInfo(feature.Location);
            var end   = locationAfterFeature;

            var spanStart = finder.GetCharacterPosition(start);
            var spanEnd   = spanStart + finder.GetLineLength(start);

            var locationInside = feature.Tags.Select(_ => _.Location).Concat(feature.Children.Select(_ => _.Location)).OrderBy(_ => _.Line).ThenBy(_ => _.Column).FirstOrDefault();

            if (locationInside != null)
            {
                var lineInfo = GetLineInfo(locationInside);
                var position = finder.GetCharacterPosition(lineInfo) - 1;
                spanEnd = position;
            }

            var container = new Container
            {
                Type         = nameof(Feature),
                Name         = feature.Name,
                LocationSpan = new LocationSpan(start, end),
                HeaderSpan   = new CharacterSpan(spanStart, spanEnd),
                FooterSpan   = CharacterSpan.None,                   // TODO: FIX
            };

            container.Children.AddRange(ParseScenarioDefinitions(feature, finder, locationAfterFeature));
            container.Children.AddRange(ParseTags(feature, finder, locationAfterFeature));

            return(container);
        }
Beispiel #2
0
 public static void Fill(File file, CharacterPositionFinder finder)
 {
     foreach (var root in file.Children)
     {
         AdjustChildren(root, finder);
     }
 }
Beispiel #3
0
        private static void AdjustChildren(Container container, CharacterPositionFinder finder)
        {
            var children = container.Children;

            for (var index = 0; index < children.Count; index++)
            {
                AdjustNode(children, index, finder);
            }
        }
Beispiel #4
0
        public static File Parse(string filePath, string encoding)
        {
            var encodingToUse = Encoding.GetEncoding(encoding);

            File file;

            using (var finder = CharacterPositionFinder.CreateFrom(filePath, encodingToUse))
            {
                file = ParseCore(filePath, finder, encodingToUse);

                Resorter.Resort(file);

                GapFiller.Fill(file, finder);
            }

            return(file);
        }
Beispiel #5
0
        private static ContainerOrTerminalNode ParseStep(Step step, CharacterPositionFinder finder, LineInfo locationAfterDefinition)
        {
            var start = GetLineInfo(step.Location);
            var end   = locationAfterDefinition;

            var spanStart = finder.GetCharacterPosition(start);
            var spanEnd   = spanStart + finder.GetLineLength(start);

            var node = new TerminalNode
            {
                Type         = nameof(Step),
                Name         = step.Keyword + step.Text,
                LocationSpan = new LocationSpan(start, end),
                Span         = new CharacterSpan(spanStart, spanEnd),             // TODO: FIX
            };

            return(node);
        }
Beispiel #6
0
        private static ContainerOrTerminalNode ParseTag(Tag tag, CharacterPositionFinder finder, LineInfo locationAfterDefinition)
        {
            var start = GetLineInfo(tag.Location);
            var end   = locationAfterDefinition;

            var spanStart = finder.GetCharacterPosition(start);
            var spanEnd   = spanStart + finder.GetLineLength(start);

            var container = new Container
            {
                Type         = nameof(Tag),
                Name         = tag.Name,
                LocationSpan = new LocationSpan(start, end),
                HeaderSpan   = new CharacterSpan(spanStart, spanEnd),
                FooterSpan   = CharacterSpan.None,                   // TODO: FIX
            };

            return(container);
        }
Beispiel #7
0
        public static File ParseCore(string filePath, CharacterPositionFinder finder, Encoding encoding)
        {
            var text          = SystemFile.ReadAllText(filePath, encoding);
            var lastCharacter = text.Length - 1;

            var file = new File
            {
                Name         = filePath,
                FooterSpan   = CharacterSpan.None,              // there is no footer
                LocationSpan = lastCharacter >= 0
                                               ? new LocationSpan(finder.GetLineInfo(0), finder.GetLineInfo(lastCharacter))
                                               : new LocationSpan(LineInfo.None, LineInfo.None),
            };

            try
            {
                var parser   = new GherkinParser();
                var document = parser.Parse(filePath);

                var root = new Container
                {
                    Type         = nameof(GherkinDocument),
                    Name         = string.Empty,
                    LocationSpan = file.LocationSpan,
                    HeaderSpan   = new CharacterSpan(0, 0),                                      // there is no header
                    FooterSpan   = new CharacterSpan(Math.Max(0, lastCharacter), lastCharacter), // there is no footer
                };

                file.Children.Add(root);

                var feature = document.Feature;
                if (feature != null)
                {
                    // get locations ordered so that we know the position of the feature
                    var locations = document.Comments.Select(_ => _.Location).ToList();
                    locations.Add(feature.Location);

                    var sortedLocations = locations.OrderBy(_ => _.Line).ThenBy(_ => _.Column).ToList();

                    var positionAfterFeature = sortedLocations.IndexOf(feature.Location) + 1;

                    var location = positionAfterFeature < sortedLocations.Count - 1
                                    ? GetLineInfo(locations[positionAfterFeature + 1])
                                    : file.LocationSpan.End;

                    var parsedChild = ParseFeature(feature, finder, location);
                    root.Children.Add(parsedChild);
                }
            }
            catch (Exception ex)
            {
                // try to adjust location span to include full file content
                // but ignore empty files as parsing errors
                var lines = SystemFile.ReadLines(filePath).Count();
                if (lines == 0)
                {
                    file.LocationSpan = new LocationSpan(LineInfo.None, LineInfo.None);
                }
                else
                {
                    file.ParsingErrors.Add(new ParsingError
                    {
                        ErrorMessage = ex.Message,
                        Location     = LineInfo.None,
                    });

                    file.LocationSpan = new LocationSpan(new LineInfo(1, 0), new LineInfo(lines + 1, 0));
                }
            }

            return(file);
        }
Beispiel #8
0
        private static IEnumerable <ContainerOrTerminalNode> ParseTags(Feature feature, CharacterPositionFinder finder, LineInfo locationAfterFeature)
        {
            var locations       = feature.Tags.Select(_ => _.Location).ToList();
            var sortedLocations = locations.OrderBy(_ => _.Line).ThenBy(_ => _.Column).ToList();

            var children = new List <ContainerOrTerminalNode>();

            foreach (var tag in feature.Tags)
            {
                var positionAfterDefinition = sortedLocations.IndexOf(tag.Location) + 1;

                var location = positionAfterDefinition < sortedLocations.Count - 1
                    ? GetLineInfo(locations[positionAfterDefinition + 1])
                    : locationAfterFeature;

                var parsedChild = ParseTag(tag, finder, location);
                children.Add(parsedChild);
            }

            return(children);
        }
Beispiel #9
0
        private static IEnumerable <ContainerOrTerminalNode> ParseSteps(ScenarioDefinition definition, CharacterPositionFinder finder, LineInfo locationAfterDefinition)
        {
            var locations       = definition.Steps.Select(_ => _.Location).ToList();
            var sortedLocations = locations.OrderBy(_ => _.Line).ThenBy(_ => _.Column).ToList();

            var children = new List <ContainerOrTerminalNode>();

            foreach (var step in definition.Steps)
            {
                var positionAfterStep = sortedLocations.IndexOf(step.Location) + 1;

                var location = positionAfterStep < sortedLocations.Count - 1
                    ? GetLineInfo(locations[positionAfterStep + 1])
                    : locationAfterDefinition;

                var parsedChild = ParseStep(step, finder, location);
                children.Add(parsedChild);
            }

            return(children);
        }
Beispiel #10
0
        private static void AdjustNode(IList <ContainerOrTerminalNode> parentChildren, int indexInParentChildren, CharacterPositionFinder finder)
        {
            var child = parentChildren[indexInParentChildren];

            if (indexInParentChildren < parentChildren.Count - 1)
            {
                var nextSibling = parentChildren[indexInParentChildren + 1];

                var indexBefore = finder.GetCharacterPosition(nextSibling.LocationSpan.Start) - 1;
                var newEndPos   = finder.GetLineInfo(indexBefore);

                child.LocationSpan = new LocationSpan(child.LocationSpan.Start, newEndPos);
            }

            if (child is Container c)
            {
                var start = c.HeaderSpan.End + 1;

                AdjustChildren(c, finder);

                var end = finder.GetCharacterPosition(c.LocationSpan.End);
                c.FooterSpan = new CharacterSpan(start, end);
            }
            else if (child is TerminalNode t)
            {
                var start = finder.GetCharacterPosition(t.LocationSpan.Start);
                var end   = finder.GetCharacterPosition(t.LocationSpan.End);
                t.Span = new CharacterSpan(start, end);
            }
        }