chore: replace jline:jansi-core with internal Ansi builder#682
Conversation
Adds a minimal internal ANSI escape-code builder (dev.metaschema.cli.processor.ansi.Ansi)
that covers the subset of jline:jansi functionality used by the CLI — fluent text/color
appending, bold/boldOff, reset, fgRed/fgBrightRed/fgBrightYellow/fgBrightBlue/fgBrightCyan,
fgBright(Color), and a global setEnabled toggle.
The existing Ansi import is renamed to the new package across the three call sites:
- cli-processor/CLIProcessor (version banner formatting and --no-color toggle)
- cli-processor/CallingContext (sub-command list rendering; jline's render("@|bold ...|@ ...")
is replaced with explicit fluent bold()/boldOff() calls)
- metaschema-cli/LoggingValidationHandler (severity-colored log preambles and findings)
The jline:jansi-core dependency is removed from the parent POM's dependencyManagement,
cli-processor/pom.xml, and cli-processor/module-info.java. The new ansi package is
exported from cli-processor for metaschema-cli to consume.
Motivation: jline 4.0.0 (dependabot PR metaschema-framework#677) is a breaking upgrade requiring Maven 4,
complete JPMS migration, and JNA removal. The CLI's use of jansi is limited and
well-isolated, so replacing it with ~230 lines of maintained code is lower-risk and
eliminates the dependency entirely. Test coverage: 22 unit tests in AnsiTest covering
color codes, bold, reset, chaining, format(), and the setEnabled(false) suppression path.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
💤 Files with no reviewable changes (1)
📝 WalkthroughWalkthroughRemoved the external Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
cli-processor/src/main/java/dev/metaschema/cli/processor/ansi/Ansi.java (1)
207-209: Avoid ordinal-coupled SGR mapping forColor.Line 208 derives bright color code from
color.ordinal(). That creates a fragile coupling where enum reordering silently changes emitted ANSI codes.♻️ Suggested refactor
- public Ansi fgBright(`@NonNull` Color color) { - return emit(ESC + (90 + color.ordinal()) + "m"); - } + public Ansi fgBright(`@NonNull` Color color) { + return emit(ESC + color.getBrightCode() + "m"); + } public enum Color { - /** Black (code 30, bright 90). */ - BLACK, - /** Red (code 31, bright 91). */ - RED, - /** Green (code 32, bright 92). */ - GREEN, - /** Yellow (code 33, bright 93). */ - YELLOW, - /** Blue (code 34, bright 94). */ - BLUE, - /** Magenta (code 35, bright 95). */ - MAGENTA, - /** Cyan (code 36, bright 96). */ - CYAN, - /** White (code 37, bright 97). */ - WHITE; + /** Black (code 30, bright 90). */ + BLACK(90), + /** Red (code 31, bright 91). */ + RED(91), + /** Green (code 32, bright 92). */ + GREEN(92), + /** Yellow (code 33, bright 93). */ + YELLOW(93), + /** Blue (code 34, bright 94). */ + BLUE(94), + /** Magenta (code 35, bright 95). */ + MAGENTA(95), + /** Cyan (code 36, bright 96). */ + CYAN(96), + /** White (code 37, bright 97). */ + WHITE(97); + + private final int brightCode; + + Color(int brightCode) { + this.brightCode = brightCode; + } + + int getBrightCode() { + return brightCode; + } }Also applies to: 217-237
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli-processor/src/main/java/dev/metaschema/cli/processor/ansi/Ansi.java` around lines 207 - 209, The fgBright method (and the similar bgBright and other SGR-emitting methods around it) wrongly computes bright SGR codes using color.ordinal(), which is brittle if the Color enum order changes; update these methods to use a stable mapping from Color to its SGR base code instead of ordinal arithmetic—either add a method on the Color enum (e.g., getAnsiBaseCode() or getForegroundBrightCode()/getBackgroundBrightCode()) that returns explicit integer SGR values for each enum constant, or implement a switch/map in Ansi (referencing fgBright, bgBright and the other SGR emitters) that maps each Color to the correct hard-coded bright code and then emit ESC + code + "m".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli-processor/src/test/java/dev/metaschema/cli/processor/ansi/AnsiTest.java`:
- Around line 19-31: Add a ResourceLock to serialize access to the static
Ansi.enabled state: annotate the AnsiTest class with
`@ResourceLock`("Ansi.enabled") (in the same place as
`@Execution`(ExecutionMode.SAME_THREAD)) so the ensureEnabled() and
restoreEnabled() methods operate under the lock, and apply the same
`@ResourceLock`("Ansi.enabled") to the other test class/block referenced in the
file (the one around lines 139-164) to prevent cross-test interference with the
Ansi.enabled static field.
---
Nitpick comments:
In `@cli-processor/src/main/java/dev/metaschema/cli/processor/ansi/Ansi.java`:
- Around line 207-209: The fgBright method (and the similar bgBright and other
SGR-emitting methods around it) wrongly computes bright SGR codes using
color.ordinal(), which is brittle if the Color enum order changes; update these
methods to use a stable mapping from Color to its SGR base code instead of
ordinal arithmetic—either add a method on the Color enum (e.g.,
getAnsiBaseCode() or getForegroundBrightCode()/getBackgroundBrightCode()) that
returns explicit integer SGR values for each enum constant, or implement a
switch/map in Ansi (referencing fgBright, bgBright and the other SGR emitters)
that maps each Color to the correct hard-coded bright code and then emit ESC +
code + "m".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 98934ce0-936c-401a-aab1-aba0b53f1233
📒 Files selected for processing (8)
cli-processor/pom.xmlcli-processor/src/main/java/dev/metaschema/cli/processor/CLIProcessor.javacli-processor/src/main/java/dev/metaschema/cli/processor/CallingContext.javacli-processor/src/main/java/dev/metaschema/cli/processor/ansi/Ansi.javacli-processor/src/main/java/module-info.javacli-processor/src/test/java/dev/metaschema/cli/processor/ansi/AnsiTest.javametaschema-cli/src/main/java/dev/metaschema/cli/util/LoggingValidationHandler.javapom.xml
💤 Files with no reviewable changes (2)
- cli-processor/pom.xml
- pom.xml
| @Execution(ExecutionMode.SAME_THREAD) | ||
| class AnsiTest { | ||
| private static final String ESC = "\u001B"; | ||
|
|
||
| @BeforeEach | ||
| void ensureEnabled() { | ||
| Ansi.setEnabled(true); | ||
| } | ||
|
|
||
| @AfterEach | ||
| void restoreEnabled() { | ||
| Ansi.setEnabled(true); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Checking JUnit parallel configuration:"
fd -i 'junit-platform.properties' | xargs -r rg -n -C2 'junit\.jupiter\.execution\.parallel|junit\.jupiter\.testinstance'
fd -i 'pom.xml' | xargs -r rg -n -C2 'junit\.jupiter\.execution\.parallel|surefire|failsafe|parallel'
echo
echo "Checking for global Ansi.setEnabled usage in tests:"
rg -n --type=java -C2 '\bAnsi\.setEnabled\s*\('Repository: metaschema-framework/metaschema-java
Length of output: 5491
Add @ResourceLock for the shared Ansi.enabled static state.
The @Execution(ExecutionMode.SAME_THREAD) annotation on this class prevents parallel execution within AnsiTest, but the repository has global parallel test execution enabled (see pom.xml: junit.jupiter.execution.parallel.enabled = true). Concurrent tests in other classes can still interfere with the static Ansi.enabled field modified in ensureEnabled() and restoreEnabled(), causing potential test flakiness. Add @ResourceLock("Ansi.enabled") to isolate access to this shared state.
Also applies to: 139-164
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@cli-processor/src/test/java/dev/metaschema/cli/processor/ansi/AnsiTest.java`
around lines 19 - 31, Add a ResourceLock to serialize access to the static
Ansi.enabled state: annotate the AnsiTest class with
`@ResourceLock`("Ansi.enabled") (in the same place as
`@Execution`(ExecutionMode.SAME_THREAD)) so the ensureEnabled() and
restoreEnabled() methods operate under the lock, and apply the same
`@ResourceLock`("Ansi.enabled") to the other test class/block referenced in the
file (the one around lines 139-164) to prevent cross-test interference with the
Ansi.enabled static field.
PMD's AvoidUsingVolatile rule flags the volatile boolean; AtomicBoolean is idiomatic for thread-safe flag flipping and passes the same tests.
6a885eb
into
metaschema-framework:develop
Summary
Replaces `org.jline:jansi-core` with a small internal ANSI escape-code builder (`dev.metaschema.cli.processor.ansi.Ansi`) and removes the dependency. Motivated by dependabot PR #677 (jline 4.0.0), which is a major breaking upgrade (Maven 4 required, complete JPMS migration, JNA provider removed). The CLI's use of jansi is limited and well-isolated, so replacing it with maintained in-tree code is lower-risk than the 4.0.0 migration and eliminates the dependency chain entirely.
Changes
New code (`cli-processor/.../ansi/`):
Migrated call sites (import-only except as noted):
Dependency removal:
Follow-up
After merge, close dependabot PR #677 (jline 4.0.0) — no longer applicable.
Test Plan
Summary by CodeRabbit
Refactor
Chores
Tests