All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrewrite.yaml.YamlParser Maven / Gradle / Ivy

There is a newer version: 8.40.3
Show newest version
/*
 * Copyright 2020 the original author or authors.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openrewrite.yaml; import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Timer; import org.intellij.lang.annotations.Language; import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.lang.Nullable; import org.openrewrite.marker.Markers; import org.openrewrite.yaml.tree.Yaml; import org.yaml.snakeyaml.events.DocumentEndEvent; import org.yaml.snakeyaml.events.Event; import org.yaml.snakeyaml.events.ScalarEvent; import org.yaml.snakeyaml.parser.Parser; import org.yaml.snakeyaml.parser.ParserImpl; import org.yaml.snakeyaml.reader.StreamReader; import org.yaml.snakeyaml.scanner.Scanner; import org.yaml.snakeyaml.scanner.ScannerImpl; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Stack; import java.util.stream.Stream; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static org.openrewrite.Tree.randomId; public class YamlParser implements org.openrewrite.Parser { @Override public List parse(@Language("yml") String... sources) { return parse(new InMemoryExecutionContext(), sources); } @Override public List parseInputs(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { return acceptedInputs(sourceFiles).stream() .map(sourceFile -> { Timer.Builder timer = Timer.builder("rewrite.parse") .description("The time spent parsing a YAML file") .tag("file.type", "YAML"); Timer.Sample sample = Timer.start(); try (InputStream is = sourceFile.getSource()) { Yaml.Documents yaml = parseFromInput(sourceFile.getRelativePath(relativeTo), is); sample.stop(MetricsHelper.successTags(timer).register(Metrics.globalRegistry)); return yaml; } catch (Throwable t) { sample.stop(MetricsHelper.errorTags(timer, t).register(Metrics.globalRegistry)); ctx.getOnError().accept(t); return null; } }) .filter(Objects::nonNull) .collect(toList()); } private Yaml.Documents parseFromInput(Path sourceFile, InputStream source) { try (FormatPreservingReader reader = new FormatPreservingReader(new InputStreamReader(source))) { StreamReader streamReader = new StreamReader(reader); Scanner scanner = new ScannerImpl(streamReader); Parser parser = new ParserImpl(scanner); int lastEnd = 0; List documents = new ArrayList<>(); Yaml.Document document = null; Stack blockStack = new Stack<>(); for (Event event = parser.getEvent(); event != null; event = parser.getEvent()) { String fmt = reader.prefix(lastEnd, event); switch (event.getEventId()) { case DocumentEnd: if (((DocumentEndEvent) event).getExplicit()) { assert document != null; documents.add(document.withEnd(new Yaml.Document.End( randomId(), fmt, Markers.EMPTY ))); lastEnd = event.getEndMark().getIndex(); } else { documents.add(document); } break; case DocumentStart: document = new Yaml.Document( randomId(), fmt, Markers.EMPTY, event.getEndMark().getIndex() - event.getStartMark().getIndex() > 0, emptyList(), null ); lastEnd = event.getEndMark().getIndex(); break; case MappingStart: blockStack.push(new MappingBuilder(fmt)); break; case Scalar: ScalarEvent scalar = (ScalarEvent) event; Yaml.Scalar.Style style; switch (scalar.getScalarStyle()) { case DOUBLE_QUOTED: style = Yaml.Scalar.Style.DOUBLE_QUOTED; break; case SINGLE_QUOTED: style = Yaml.Scalar.Style.SINGLE_QUOTED; break; case LITERAL: style = Yaml.Scalar.Style.LITERAL; break; case FOLDED: style = Yaml.Scalar.Style.FOLDED; break; case PLAIN: default: style = Yaml.Scalar.Style.PLAIN; break; } blockStack.peek().push(new Yaml.Scalar(randomId(), fmt, Markers.EMPTY, style, scalar.getValue())); lastEnd = event.getEndMark().getIndex(); break; case SequenceEnd: case MappingEnd: Yaml.Block mappingOrSequence = blockStack.pop().build(); if (blockStack.isEmpty()) { //noinspection ConstantConditions document = document.withBlocks(Stream.concat( document.getBlocks().stream(), Stream.of(mappingOrSequence) ).collect(toList())); } else { blockStack.peek().push(mappingOrSequence); } break; case SequenceStart: blockStack.push(new SequenceBuilder(fmt)); break; case Alias: case StreamEnd: case StreamStart: break; } } return new Yaml.Documents(randomId(), "", Markers.EMPTY, sourceFile, documents); } catch (IOException e) { throw new UncheckedIOException(e); } } @Override public boolean accept(Path path) { String fileName = path.toString(); return fileName.endsWith(".yml") || fileName.endsWith(".yaml"); } private interface BlockBuilder { Yaml.Block build(); void push(Yaml.Block block); } private static class MappingBuilder implements BlockBuilder { private final String prefix; private final List entries = new ArrayList<>(); @Nullable private Yaml.Scalar key; private MappingBuilder(String prefix) { this.prefix = prefix; } public void push(Yaml.Block block) { if (key == null && block instanceof Yaml.Scalar) { key = (Yaml.Scalar) block; } else { String keySuffix = block.getPrefix(); block = block.withPrefix(keySuffix.substring(keySuffix.lastIndexOf(':') + 1)); String keyPrefix = key.getPrefix(); key = key.withPrefix(""); String beforeMappingValueIndicator = keySuffix.substring(0, keySuffix.lastIndexOf(':')); String entryPrefix = keyPrefix.substring(keyPrefix.lastIndexOf(':') + 1); entries.add(new Yaml.Mapping.Entry(randomId(), entryPrefix, Markers.EMPTY, key, beforeMappingValueIndicator, block)); key = null; } } public Yaml.Mapping build() { return new Yaml.Mapping(randomId(), prefix, Markers.EMPTY, entries); } } private static class SequenceBuilder implements BlockBuilder { private final String prefix; private final List entries = new ArrayList<>(); private SequenceBuilder(String prefix) { this.prefix = prefix; } @Override public void push(Yaml.Block block) { String entryPrefix = block.getPrefix(); block = block.withPrefix(entryPrefix.substring(entryPrefix.lastIndexOf('-') + 1)); entryPrefix = entryPrefix.substring(0, entryPrefix.lastIndexOf('-')); entries.add(new Yaml.Sequence.Entry(randomId(), entryPrefix, Markers.EMPTY, block)); } public Yaml.Sequence build() { return new Yaml.Sequence(randomId(), prefix, Markers.EMPTY, entries); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy