Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
rmannibucau committed Mar 23, 2023
0 parents commit da7a982
Show file tree
Hide file tree
Showing 16 changed files with 1,140 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
target
.idea
*.iws
*.ipr
*.iml
.settings
.classpath
.project
ignored.*
generated
generated_*
.sdkmanrc
99 changes: 99 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.yupiik.yuc</groupId>
<artifactId>yuc</artifactId>
<version>1.0.0-SNAPSHOT</version>

<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<fusion.version>1.0.1</fusion.version>
</properties>

<dependencies>
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-build-api</artifactId>
<version>${fusion.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-processor</artifactId>
<version>${fusion.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-api</artifactId>
<version>${fusion.version}</version>
</dependency>
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-cli</artifactId>
<version>${fusion.version}</version>
</dependency>
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-json</artifactId>
<version>${fusion.version}</version>
</dependency>
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-handlebars</artifactId>
<version>${fusion.version}</version>
</dependency>
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>2.4.0</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-testing</artifactId>
<version>${fusion.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.release}</source>
<target>${maven.compiler.release}</target>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.geronimo.arthur</groupId>
<artifactId>arthur-maven-plugin</artifactId>
<version>1.0.5</version>
<configuration>
<main>io.yupiik.yuc.Yuc</main>
<graalVersion>22.3.0.r17</graalVersion>
<enableAllSecurityServices>false</enableAllSecurityServices>
<allowIncompleteClasspath>false</allowIncompleteClasspath>
<buildStaticImage>true</buildStaticImage>
</configuration>
</plugin>
</plugins>
</build>
</project>
19 changes: 19 additions & 0 deletions src/main/java/io/yupiik/yuc/Yuc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.yupiik.yuc;

import io.yupiik.fusion.framework.api.main.Launcher;

import java.util.stream.Stream;

public final class Yuc {
private Yuc() {
// no-op
}

public static void main(final String... args) {
// force default command for now
final var implicitCommand = "default";
Launcher.main(args.length == 0 ?
new String[]{implicitCommand} :
Stream.concat(Stream.of(implicitCommand), Stream.of(args)).toArray(String[]::new));
}
}
105 changes: 105 additions & 0 deletions src/main/java/io/yupiik/yuc/command/DefaultCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package io.yupiik.yuc.command;

import io.yupiik.fusion.framework.build.api.cli.Command;
import io.yupiik.fusion.framework.build.api.configuration.Property;
import io.yupiik.fusion.framework.build.api.configuration.RootConfiguration;
import io.yupiik.fusion.json.JsonMapper;
import io.yupiik.fusion.json.internal.parser.BufferProvider;
import io.yupiik.fusion.json.internal.parser.JsonParser;
import io.yupiik.yuc.command.configuration.ColorScheme;
import io.yupiik.yuc.formatter.JsonVisitor;
import io.yupiik.yuc.formatter.SimpleWriter;
import io.yupiik.yuc.formatter.impl.DefaultFormatter;
import io.yupiik.yuc.formatter.impl.HandlebarFormatter;
import io.yupiik.yuc.formatter.impl.PrettyFormatter;
import io.yupiik.yuc.io.IO;
import org.fusesource.jansi.internal.CLibrary;

import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;

@Command(name = "default", description = "Format the output as a prettified JSON.")
public class DefaultCommand implements Runnable {
private final Conf conf;
private final IO io;
private final JsonMapper jsonMapper;

public DefaultCommand(final Conf conf, final IO io, final JsonMapper jsonMapper) {
this.conf = conf;
this.io = io;
this.jsonMapper = jsonMapper;
}

@Override
public void run() {
final var charset = Charset.forName(conf.charset());
final var input = io.openInput(charset, conf.input());
try (final var parser = new JsonParser(input, conf.bufferProviderSize(), new BufferProvider(conf.bufferProviderSize()), true);
final var writer = io.openOutput(charset, conf.output())) {
final var visitor = newVisitor(writer);
while (parser.hasNext()) {
switch (parser.next()) {
case START_ARRAY -> visitor.onStartArray();
case END_ARRAY -> visitor.onEndArray();
case START_OBJECT -> visitor.onStartObject();
case END_OBJECT -> visitor.onEndObject();
case KEY_NAME -> visitor.onKey(parser.getString());
case VALUE_STRING -> visitor.onString(parser.getString());
case VALUE_TRUE -> visitor.onBoolean(true);
case VALUE_FALSE -> visitor.onBoolean(false);
case VALUE_NUMBER -> visitor.onNumber(parser.getBigDecimal());
case VALUE_NULL -> visitor.onNull();
}
}
visitor.onEnd();
if (conf.appendEol()) {
writer.write('\n');
}
} catch (final IOException e) {
throw new IllegalStateException(e);
}
}

private JsonVisitor newVisitor(final Writer writer) {
final var output = new SimpleWriter(writer);
return switch (conf.outputType()) {
case HANDLEBAR -> new HandlebarFormatter(output, conf.handlebar(), jsonMapper);
case PRETTY -> new PrettyFormatter(output, getColorScheme());
default -> new DefaultFormatter(output, getColorScheme());
};
}

private ColorScheme getColorScheme() {
return (conf.colored() != null && conf.colored()) || (conf.colored() == null && isTty()) ? conf.colorScheme() : ColorScheme.NONE;
}

private boolean isTty() {
return !System.getProperty("os.name", "win").contains("win") &&
(switch (conf.output()) {
case "&1", "-" -> CLibrary.isatty(1) == 1;
case "&2" -> CLibrary.isatty(2) == 1;
default -> false;
});
}

public enum OutputType {
INLINE,
PRETTY,
HANDLEBAR
}

@RootConfiguration("-")
public record Conf(
@Property(defaultValue = "\"{{this}}\"", documentation = "If `true` output is colorized.") String handlebar,
@Property(defaultValue = "io.yupiik.yuc.command.configuration.ColorScheme.DEFAULT", documentation = "If `true` output is colorized.") ColorScheme colorScheme,
@Property(defaultValue = "null", documentation = "If `true` output is colorized.") Boolean colored,
@Property(defaultValue = "true", documentation = "If `true` an EOL is appended to the output stream.") boolean appendEol,
@Property(defaultValue = "DefaultCommand.OutputType.PRETTY", documentation = "Output type.") OutputType outputType,
@Property(defaultValue = "16384", documentation = "JSON parser buffer provider size.") int bufferProviderSize,
@Property(defaultValue = "true", documentation = "Should the JSON be prettified.") boolean pretty,
@Property(defaultValue = "\"UTF-8\"", documentation = "Charset to use to read the input stream.") String charset,
@Property(defaultValue = "\"-\"", documentation = "Output the command should use, default to `stdout` if set to `-` else a file path.") String output,
@Property(defaultValue = "\"-\"", documentation = "Input the command should format, default to `stdin` if set to `-` else a file path.") String input) {
}
}
70 changes: 70 additions & 0 deletions src/main/java/io/yupiik/yuc/command/configuration/ColorScheme.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.yupiik.yuc.command.configuration;

import io.yupiik.fusion.framework.build.api.configuration.Property;

// to get all colors (or install colortest):
// for x in {0..8}; do for i in {30..37}; do for a in {40..47}; do echo -ne "\e[$x;$i;$a""m\$x;$i;$a""m\e[0;37;40m "; done; echo; done; done; echo ""
public record ColorScheme(
@Property(defaultValue = "\"0\"", documentation = "Reset color suffix.") String reset,
@Property(defaultValue = "\"1;37\"", documentation = "Structure color prefix.") String object,
@Property(defaultValue = "\"1;37\"", documentation = "Structure color prefix.") String array,
@Property(defaultValue = "\"1;37\"", documentation = "Comma color prefix.") String comma,
@Property(value = "null", defaultValue = "\"1;30\"", documentation = "null color prefix.") String nullColor,
@Property(value = "true", defaultValue = "\"3;37\"", documentation = "True color prefix.") String trueColor,
@Property(value = "false", defaultValue = "\"3;37\"", documentation = "False color prefix.") String falseColor,
@Property(defaultValue = "\"1;34\"", documentation = "Key color prefix.") String key,
@Property(defaultValue = "\"0;32\"", documentation = "string color prefix.") String string,
@Property(defaultValue = "\"3;37\"", documentation = "Number color prefix.") String number
) {
public static final ColorScheme DEFAULT = new ColorScheme(
"0", "1;37", "1;37", "1;37",
"1;30m", "3;37m", "3;37",
"1;34", "0;32", "3;37");
public static final ColorScheme NONE = new ColorScheme(
"", "", "", "", "", "", "", "", "", "");
private static final String PREFIX = new String(new char[]{27, '['});

private boolean enabled() {
return NONE != this;
}

public String onArray(final String value) {
return format(array, value);
}

public String onObject(final String value) {
return format(object, value);
}

public String onTrue() {
return format(trueColor, "true");
}

public String onFalse() {
return format(falseColor, "false");
}

public String onString(final String value) {
return format(string, value);
}

public String onKey(final String value) {
return format(key, value);
}

public String onNull() {
return format(nullColor, "null");
}

public String onNumber(final String value) {
return format(number, value);
}

public String onComma() {
return format(comma, ",");
}

private String format(final String marker, final String value) {
return (enabled() ? PREFIX + marker + 'm' : "") + value + (enabled() ? PREFIX + reset + 'm' : "");
}
}
25 changes: 25 additions & 0 deletions src/main/java/io/yupiik/yuc/formatter/JsonVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.yupiik.yuc.formatter;

public interface JsonVisitor {
void onStartArray();

void onEndArray();

void onStartObject();

void onEndObject();

void onKey(String name);

void onString(String value);

void onBoolean(boolean value);

void onNumber(Number value);

void onNull();

default void onEnd() {
// no-op
}
}
14 changes: 14 additions & 0 deletions src/main/java/io/yupiik/yuc/formatter/SimpleWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.yupiik.yuc.formatter;

import java.io.IOException;
import java.io.Writer;

public record SimpleWriter(Writer delegate) {
public void write(final String value) {
try {
delegate.write(value);
} catch (final IOException e) {
throw new IllegalStateException(e);
}
}
}

0 comments on commit da7a982

Please sign in to comment.