|
29 | 29 | import java.util.LinkedHashSet; |
30 | 30 | import java.util.List; |
31 | 31 | import java.util.Map; |
| 32 | +import java.util.NoSuchElementException; |
32 | 33 | import java.util.Optional; |
33 | 34 | import java.util.Set; |
34 | 35 | import java.util.TreeMap; |
35 | 36 | import java.util.function.BiConsumer; |
| 37 | +import java.util.function.BiFunction; |
36 | 38 | import java.util.function.Function; |
37 | 39 | import java.util.stream.Collectors; |
38 | 40 |
|
@@ -584,6 +586,75 @@ default <T> T to(Reified<T> type) { |
584 | 586 | return map; |
585 | 587 | } |
586 | 588 |
|
| 589 | + default String resolve(@Nonnull String text) { |
| 590 | + return resolve(text, "${", "}"); |
| 591 | + } |
| 592 | + |
| 593 | + default String resolve(@Nonnull String text, boolean ignoreMissing) { |
| 594 | + return resolve(text, "${", "}", ignoreMissing); |
| 595 | + } |
| 596 | + |
| 597 | + default String resolve(@Nonnull String text, @Nonnull String startDelim, |
| 598 | + @Nonnull String endDelim) { |
| 599 | + return resolve(text, startDelim, endDelim, false); |
| 600 | + } |
| 601 | + |
| 602 | + default String resolve(@Nonnull String text, @Nonnull String startDelim, @Nonnull String endDelim, |
| 603 | + boolean ignoreMissing) { |
| 604 | + if (text.length() == 0) { |
| 605 | + return ""; |
| 606 | + } |
| 607 | + |
| 608 | + BiFunction<Integer, BiFunction<Integer, Integer, RuntimeException>, RuntimeException> err = ( |
| 609 | + start, ex) -> { |
| 610 | + String snapshot = text.substring(0, start); |
| 611 | + int line = Math.max(1, (int) snapshot.chars().filter(ch -> ch == '\n').count()); |
| 612 | + int column = start - snapshot.lastIndexOf('\n'); |
| 613 | + return ex.apply(line, column); |
| 614 | + }; |
| 615 | + |
| 616 | + StringBuilder buffer = new StringBuilder(); |
| 617 | + int offset = 0; |
| 618 | + int start = text.indexOf(startDelim); |
| 619 | + while (start >= 0) { |
| 620 | + int end = text.indexOf(endDelim, start + startDelim.length()); |
| 621 | + if (end == -1) { |
| 622 | + throw err.apply(start, (line, column) -> new IllegalArgumentException( |
| 623 | + "found '" + startDelim + "' expecting '" + endDelim + "' at " + line + ":" |
| 624 | + + column)); |
| 625 | + } |
| 626 | + buffer.append(text.substring(offset, start)); |
| 627 | + String key = text.substring(start + startDelim.length(), end); |
| 628 | + String value; |
| 629 | + try { |
| 630 | + // seek |
| 631 | + String[] path = key.split("\\."); |
| 632 | + Value src = path[0].equals(name()) ? this : get(path[0]); |
| 633 | + for (int i = 1; i < path.length; i++) { |
| 634 | + src = src.get(path[i]); |
| 635 | + } |
| 636 | + value = src.value(); |
| 637 | + } catch (Err.Missing x) { |
| 638 | + if (ignoreMissing) { |
| 639 | + value = text.substring(start, end + endDelim.length()); |
| 640 | + } else { |
| 641 | + throw err.apply(start, (line, column) -> new NoSuchElementException( |
| 642 | + "Missing " + startDelim + key + endDelim + " at " + line + ":" + column)); |
| 643 | + } |
| 644 | + } |
| 645 | + buffer.append(value); |
| 646 | + offset = end + endDelim.length(); |
| 647 | + start = text.indexOf(startDelim, offset); |
| 648 | + } |
| 649 | + if (buffer.length() == 0) { |
| 650 | + return text; |
| 651 | + } |
| 652 | + if (offset < text.length()) { |
| 653 | + buffer.append(text.substring(offset)); |
| 654 | + } |
| 655 | + return buffer.toString(); |
| 656 | + } |
| 657 | + |
587 | 658 | /* *********************************************************************************************** |
588 | 659 | * Factory methods |
589 | 660 | * *********************************************************************************************** |
|
0 commit comments