FeedTomlParser.java
package net.sasasin.sreader.service.feed.toml;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.tomlj.Toml;
import org.tomlj.TomlParseError;
import org.tomlj.TomlParseResult;
import org.tomlj.TomlPosition;
import org.tomlj.TomlVersion;
/**
* TOML 1.0 syntax parsing via TomlJ. Domain schema and enum rules are handled by later pipeline
* stages.
*/
final class FeedTomlParser {
ParsedFeedToml parse(String input) {
Objects.requireNonNull(input, "input must not be null");
// Explicit TOML 1.0: sreader feed files target the stable 1.0 data model, not HEAD drafts.
TomlParseResult result = Toml.parse(input, TomlVersion.V1_0_0);
List<FeedTomlIssue> syntaxIssues = new ArrayList<>();
int sequence = 0;
for (TomlParseError error : result.errors()) {
syntaxIssues.add(toIssue(error, sequence++));
}
return new ParsedFeedToml(result, syntaxIssues);
}
private static FeedTomlIssue toIssue(TomlParseError error, int sequence) {
TomlPosition position = error.position();
FeedTomlPosition feedPosition = FeedTomlPosition.of(position.line(), position.column());
return FeedTomlIssue.syntax(feedPosition, normalizeMessage(error.getMessage()), sequence);
}
private static String normalizeMessage(String rawMessage) {
if (rawMessage == null || rawMessage.isBlank()) {
return "invalid TOML syntax";
}
String message = rawMessage.toLowerCase(java.util.Locale.ROOT);
if (message.contains("duplicate")
|| message.contains("defined")
|| message.contains("already exists")) {
return "duplicate TOML key";
}
if (message.contains("escape")) {
return "invalid TOML string escape";
}
if (message.contains("unterminated")) {
return "unterminated TOML string";
}
return "invalid TOML syntax";
}
}