Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 19 additions & 20 deletions src/main/java/dev/toonformat/jtoon/decoder/ArrayDecoder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dev.toonformat.jtoon.decoder;

import dev.toonformat.jtoon.Delimiter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -11,7 +13,7 @@
/**
* Handles decoding of TOON arrays to JSON format.
*/
public class ArrayDecoder {
public final class ArrayDecoder {

private ArrayDecoder() {
throw new UnsupportedOperationException("Utility class cannot be instantiated");
Expand All @@ -26,8 +28,8 @@ private ArrayDecoder() {
* @param context decode an object to deal with lines, delimiter and options
* @return parsed array with delimiter
*/
protected static List<Object> parseArray(String header, int depth, DecodeContext context) {
String arrayDelimiter = extractDelimiterFromHeader(header, context);
static List<Object> parseArray(String header, int depth, DecodeContext context) {
Delimiter arrayDelimiter = extractDelimiterFromHeader(header, context);

return parseArrayWithDelimiter(header, depth, arrayDelimiter, context);
}
Expand All @@ -40,15 +42,16 @@ protected static List<Object> parseArray(String header, int depth, DecodeContext
* @param context decode an object to deal with lines, delimiter and options
* @return extracted delimiter from header
*/
protected static String extractDelimiterFromHeader(String header, DecodeContext context) {
static Delimiter extractDelimiterFromHeader(String header, DecodeContext context) {
Matcher matcher = ARRAY_HEADER_PATTERN.matcher(header);
if (matcher.find() && matcher.groupCount() == 3) {
if (matcher.find()) {
String delimiter = matcher.group(3);
if (delimiter != null) {
if ("\t".equals(delimiter)) {
return "\t";
} else if ("|".equals(delimiter)) {
return "|";
return Delimiter.TAB;
}
if ("|".equals(delimiter)) {
return Delimiter.PIPE;
}
}
}
Expand All @@ -67,7 +70,7 @@ protected static String extractDelimiterFromHeader(String header, DecodeContext
* @param context decode an object to deal with lines, delimiter and options
* @return parsed array
*/
protected static List<Object> parseArrayWithDelimiter(String header, int depth, String arrayDelimiter, DecodeContext context) {
static List<Object> parseArrayWithDelimiter(String header, int depth, Delimiter arrayDelimiter, DecodeContext context) {
Matcher tabularMatcher = TABULAR_HEADER_PATTERN.matcher(header);
Matcher arrayMatcher = ARRAY_HEADER_PATTERN.matcher(header);

Expand Down Expand Up @@ -130,7 +133,7 @@ protected static List<Object> parseArrayWithDelimiter(String header, int depth,
* @param header header
* @param actualLength actual length
*/
protected static void validateArrayLength(String header, int actualLength) {
static void validateArrayLength(String header, int actualLength) {
Integer declaredLength = extractLengthFromHeader(header);
if (declaredLength != null && declaredLength != actualLength) {
throw new IllegalArgumentException(
Expand All @@ -147,12 +150,8 @@ protected static void validateArrayLength(String header, int actualLength) {
*/
private static Integer extractLengthFromHeader(String header) {
Matcher matcher = ARRAY_HEADER_PATTERN.matcher(header);
if (matcher.find() && matcher.groupCount() > 2) {
try {
return Integer.parseInt(matcher.group(2));
} catch (NumberFormatException e) {
return null;
}
if (matcher.find()) {
return Integer.parseInt(matcher.group(2));
}
return null;
}
Expand All @@ -164,7 +163,7 @@ private static Integer extractLengthFromHeader(String header) {
* @param arrayDelimiter array delimiter
* @return parsed array values
*/
protected static List<Object> parseArrayValues(String values, String arrayDelimiter) {
static List<Object> parseArrayValues(String values, Delimiter arrayDelimiter) {
List<Object> result = new ArrayList<>();
List<String> rawValues = parseDelimitedValues(values, arrayDelimiter);
for (String value : rawValues) {
Expand All @@ -181,12 +180,12 @@ protected static List<Object> parseArrayValues(String values, String arrayDelimi
* @param arrayDelimiter array delimiter
* @return parsed delimited values
*/
protected static List<String> parseDelimitedValues(String input, String arrayDelimiter) {
static List<String> parseDelimitedValues(String input, Delimiter arrayDelimiter) {
List<String> result = new ArrayList<>();
StringBuilder stringBuilder = new StringBuilder();
boolean inQuotes = false;
boolean escaped = false;
char delimiterChar = arrayDelimiter.charAt(0);
char delimiterChar = arrayDelimiter.toString().charAt(0);

int i = 0;
while (i < input.length()) {
Expand Down Expand Up @@ -220,7 +219,7 @@ protected static List<String> parseDelimitedValues(String input, String arrayDel
}

// Add final value
if (!stringBuilder.isEmpty() || input.endsWith(arrayDelimiter)) {
if (!stringBuilder.isEmpty() || input.endsWith(arrayDelimiter.toString())) {
result.add(stringBuilder.toString().trim());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.toonformat.jtoon.decoder;

import dev.toonformat.jtoon.DecodeOptions;
import dev.toonformat.jtoon.Delimiter;

/**
* Deals with the main attributes used to decode TOON to JSON format
Expand All @@ -18,7 +19,7 @@ public class DecodeContext {
/**
* Delimiter used to split array elements.
*/
protected String delimiter;
protected Delimiter delimiter;
/**
* Current line being decoded.
*/
Expand Down
16 changes: 8 additions & 8 deletions src/main/java/dev/toonformat/jtoon/decoder/DecodeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* Handles indentation, depth, conflicts, and validation for other decode classes.
*/
public class DecodeHelper {
public final class DecodeHelper {

private DecodeHelper() {
throw new UnsupportedOperationException("Utility class cannot be instantiated");
Expand Down Expand Up @@ -76,7 +76,7 @@ private static int computeLeadingSpaces(String line, DecodeContext context) {
* @param line the line string to parse
* @return true or false depending on if the line is blank or not
*/
protected static boolean isBlankLine(String line) {
static boolean isBlankLine(String line) {
return line.trim().isEmpty();
}

Expand All @@ -87,7 +87,7 @@ protected static boolean isBlankLine(String line) {
* @param content the content string to parse
* @return the unquoted colon
*/
protected static int findUnquotedColon(String content) {
static int findUnquotedColon(String content) {
boolean inQuotes = false;
boolean escaped = false;

Expand Down Expand Up @@ -115,7 +115,7 @@ protected static int findUnquotedColon(String content) {
* @param context decode an object to deal with lines, delimiter, and options
* @return index aiming for the next non-blank line
*/
protected static int findNextNonBlankLine(int startIndex, DecodeContext context) {
static int findNextNonBlankLine(int startIndex, DecodeContext context) {
int index = startIndex;
while (index < context.lines.length && isBlankLine(context.lines[index])) {
index++;
Expand All @@ -132,7 +132,7 @@ protected static int findNextNonBlankLine(int startIndex, DecodeContext context)
* @param context decode an object to deal with lines, delimiter, and options
* @throws IllegalArgumentException in case there's a expansion conflict
*/
protected static void checkFinalValueConflict(String finalSegment, Object existing, Object value, DecodeContext context) {
static void checkFinalValueConflict(String finalSegment, Object existing, Object value, DecodeContext context) {
if (existing != null && context.options.strict()) {
// Check for conflicts in strict mode
if (existing instanceof Map && !(value instanceof Map)) {
Expand All @@ -157,7 +157,7 @@ protected static void checkFinalValueConflict(String finalSegment, Object existi
* @param value present value in a map
* @param context decode an object to deal with lines, delimiter, and options
*/
protected static void checkPathExpansionConflict(Map<String, Object> map, String key, Object value, DecodeContext context) {
static void checkPathExpansionConflict(Map<String, Object> map, String key, Object value, DecodeContext context) {
if (!context.options.strict()) {
return;
}
Expand All @@ -172,7 +172,7 @@ protected static void checkPathExpansionConflict(Map<String, Object> map, String
* @param context decode an object to deal with lines, delimiter, and options
* @return the depth of the next non-blank line, or null if none exists
*/
protected static Integer findNextNonBlankLineDepth(DecodeContext context) {
static Integer findNextNonBlankLineDepth(DecodeContext context) {
int nextLineIdx = context.currentLine;
while (nextLineIdx < context.lines.length && isBlankLine(context.lines[nextLineIdx])) {
nextLineIdx++;
Expand All @@ -191,7 +191,7 @@ protected static Integer findNextNonBlankLineDepth(DecodeContext context) {
* @param context decode an object to deal with lines, delimiter, and options
* @throws IllegalArgumentException in case the next depth is equal to 0
*/
protected static void validateNoMultiplePrimitivesAtRoot(DecodeContext context) {
static void validateNoMultiplePrimitivesAtRoot(DecodeContext context) {
int lineIndex = context.currentLine;
while (lineIndex < context.lines.length && isBlankLine(context.lines[lineIndex])) {
lineIndex++;
Expand Down
35 changes: 19 additions & 16 deletions src/main/java/dev/toonformat/jtoon/decoder/KeyDecoder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.toonformat.jtoon.decoder;

import dev.toonformat.jtoon.Delimiter;
import dev.toonformat.jtoon.PathExpansion;
import dev.toonformat.jtoon.util.StringEscaper;

Expand All @@ -13,9 +14,11 @@
/**
* Handles decoding of key values/arrays to JSON format.
*/
public class KeyDecoder {
public final class KeyDecoder {

private KeyDecoder() {throw new UnsupportedOperationException("Utility class cannot be instantiated");}
private KeyDecoder() {
throw new UnsupportedOperationException("Utility class cannot be instantiated");
}

/**
* Processes a keyed array line (e.g., "key[3]: value").
Expand All @@ -26,8 +29,8 @@ public class KeyDecoder {
* @param parentDepth parent depth of keyed array line
* @param context decode an object to deal with lines, delimiter and options
*/
protected static void processKeyedArrayLine(Map<String, Object> result, String content, String originalKey,
int parentDepth, DecodeContext context) {
static void processKeyedArrayLine(Map<String, Object> result, String content, String originalKey,
int parentDepth, DecodeContext context) {
String key = StringEscaper.unescape(originalKey);
String arrayHeader = content.substring(originalKey.length());
List<Object> arrayValue = ArrayDecoder.parseArray(arrayHeader, parentDepth + 1, context);
Expand All @@ -50,7 +53,7 @@ protected static void processKeyedArrayLine(Map<String, Object> result, String c
* @param value value
* @param context decode an object to deal with lines, delimiter and options
*/
protected static void expandPathIntoMap(Map<String, Object> current, String dottedKey, Object value, DecodeContext context) {
static void expandPathIntoMap(Map<String, Object> current, String dottedKey, Object value, DecodeContext context) {
String[] segments = dottedKey.split("\\.");

// Navigate/create nested structure
Expand All @@ -73,7 +76,7 @@ protected static void expandPathIntoMap(Map<String, Object> current, String dott
if (context.options.strict()) {
throw new IllegalArgumentException(
String.format("Path expansion conflict: %s is %s, cannot expand to object",
segment, existing.getClass().getSimpleName()));
segment, existing.getClass().getSimpleName()));
}
// LWW: overwrite with new nested object
Map<String, Object> nested = new LinkedHashMap<>();
Expand Down Expand Up @@ -101,7 +104,7 @@ protected static void expandPathIntoMap(Map<String, Object> current, String dott
* @param depth the depth of the value line
* @param context decode an object to deal with lines, delimiter and options
*/
protected static void processKeyValueLine(Map<String, Object> result, String content, int depth, DecodeContext context) {
static void processKeyValueLine(Map<String, Object> result, String content, int depth, DecodeContext context) {
int colonIdx = DecodeHelper.findUnquotedColon(content);

if (colonIdx > 0) {
Expand All @@ -127,8 +130,8 @@ protected static void processKeyValueLine(Map<String, Object> result, String con
* @param depth the depth of the value pair
* @param context decode an object to deal with lines, delimiter and options
*/
protected static void parseKeyValuePairIntoMap(Map<String, Object> map, String key, String value,
int depth, DecodeContext context) {
static void parseKeyValuePairIntoMap(Map<String, Object> map, String key, String value,
int depth, DecodeContext context) {
String unescapedKey = StringEscaper.unescape(key);

Object parsedValue = parseKeyValue(value, depth, context);
Expand All @@ -144,7 +147,7 @@ protected static void parseKeyValuePairIntoMap(Map<String, Object> map, String k
* @param context decode an object to deal with lines, delimiter and options
* @return true if a key should be expanded or false if not
*/
protected static boolean shouldExpandKey(String key, DecodeContext context) {
static boolean shouldExpandKey(String key, DecodeContext context) {
if (context.options.expandPaths() != PathExpansion.SAFE) {
return false;
}
Expand Down Expand Up @@ -238,8 +241,8 @@ private static void putKeyValueIntoMap(Map<String, Object> map, String originalK
* @param context decode an object to deal with lines, delimiter, and options
* @return parsed a key-value pair
*/
protected static Object parseKeyValuePair(String key, String value, int depth, boolean parseRootFields,
DecodeContext context) {
static Object parseKeyValuePair(String key, String value, int depth, boolean parseRootFields,
DecodeContext context) {
Map<String, Object> obj = new LinkedHashMap<>();
parseKeyValuePairIntoMap(obj, key, value, depth, context);

Expand All @@ -258,7 +261,7 @@ protected static Object parseKeyValuePair(String key, String value, int depth, b
* @param context decode an object to deal with lines, delimiter, and options
* @return parsed keyed array value
*/
protected static Object parseKeyedArrayValue(Matcher keyedArray, String content, int depth, DecodeContext context) {
static Object parseKeyedArrayValue(Matcher keyedArray, String content, int depth, DecodeContext context) {
String originalKey = keyedArray.group(1).trim();
String key = StringEscaper.unescape(originalKey);
String arrayHeader = content.substring(keyedArray.group(1).length());
Expand Down Expand Up @@ -292,7 +295,7 @@ protected static Object parseKeyedArrayValue(Matcher keyedArray, String content,
* @param context decode an object to deal with lines, delimiter and options
* @return true if the field was processed as a keyed array, false otherwise
*/
protected static boolean parseKeyedArrayField(String fieldContent, Map<String, Object> item, int depth, DecodeContext context) {
static boolean parseKeyedArrayField(String fieldContent, Map<String, Object> item, int depth, DecodeContext context) {
Matcher keyedArray = KEYED_ARRAY_PATTERN.matcher(fieldContent);
if (!keyedArray.matches()) {
return false;
Expand All @@ -303,7 +306,7 @@ protected static boolean parseKeyedArrayField(String fieldContent, Map<String, O
String arrayHeader = fieldContent.substring(keyedArray.group(1).length());

// For nested arrays in list items, default to comma delimiter if not specified
String nestedArrayDelimiter = ArrayDecoder.extractDelimiterFromHeader(arrayHeader, context);
Delimiter nestedArrayDelimiter = ArrayDecoder.extractDelimiterFromHeader(arrayHeader, context);
var arrayValue = ArrayDecoder.parseArrayWithDelimiter(arrayHeader, depth + 2, nestedArrayDelimiter, context);

// Handle path expansion for array keys
Expand All @@ -326,7 +329,7 @@ protected static boolean parseKeyedArrayField(String fieldContent, Map<String, O
* @param context decode an object to deal with lines, delimiter and options
* @return true if the field was processed as a key-value pair, false otherwise
*/
protected static boolean parseKeyValueField(String fieldContent, Map<String, Object> item, int depth, DecodeContext context) {
static boolean parseKeyValueField(String fieldContent, Map<String, Object> item, int depth, DecodeContext context) {
int colonIdx = DecodeHelper.findUnquotedColon(fieldContent);
if (colonIdx <= 0) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.toonformat.jtoon.decoder;

import dev.toonformat.jtoon.Delimiter;
import dev.toonformat.jtoon.util.StringEscaper;

import java.util.LinkedHashMap;
Expand All @@ -12,7 +13,7 @@
/**
* Handles decoding of TOON list item to JSON format.
*/
public class ListItemDecoder {
public final class ListItemDecoder {

private ListItemDecoder() {throw new UnsupportedOperationException("Utility class cannot be instantiated");}

Expand Down Expand Up @@ -67,7 +68,7 @@ public static Object parseListItem(String content, int depth, DecodeContext cont
// Check for standalone array (e.g., "[2]: 1,2")
if (itemContent.startsWith("[")) {
// For nested arrays in list items, default to comma delimiter if not specified
String nestedArrayDelimiter = ArrayDecoder.extractDelimiterFromHeader(itemContent, context);
Delimiter nestedArrayDelimiter = ArrayDecoder.extractDelimiterFromHeader(itemContent, context);
// parseArrayWithDelimiter handles currentLine increment internally
// For inline arrays, it increments. For multi-line arrays, parseListArray
// handles it.
Expand All @@ -85,7 +86,7 @@ public static Object parseListItem(String content, int depth, DecodeContext cont
String arrayHeader = itemContent.substring(keyedArray.group(1).length());

// For nested arrays in list items, default to comma delimiter if not specified
String nestedArrayDelimiter = ArrayDecoder.extractDelimiterFromHeader(arrayHeader, context);
Delimiter nestedArrayDelimiter = ArrayDecoder.extractDelimiterFromHeader(arrayHeader, context);
List<Object> arrayValue = ArrayDecoder.parseArrayWithDelimiter(arrayHeader, depth + 2, nestedArrayDelimiter, context);

Map<String, Object> item = new LinkedHashMap<>();
Expand Down
Loading
Loading