Initial commit

This commit is contained in:
Alexander Söderberg 2020-08-30 20:53:00 +02:00
commit 0303da531e
No known key found for this signature in database
GPG key ID: C0207FF7EA146678
12 changed files with 1004 additions and 0 deletions

12
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: Sauilitired
patreon: IntellectualSites # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://paypal.me/Sauilitired']# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

11
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "maven" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

54
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,54 @@
name: "CodeQL"
on:
push:
branches: [master, ]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 18 * * 3'
jobs:
analyse:
name: Analyse
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
with:
languages: java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

24
.github/workflows/maven.yml vendored Normal file
View file

@ -0,0 +1,24 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn -B package --file pom.xml

213
.gitignore vendored Normal file
View file

@ -0,0 +1,213 @@
# Created by https://www.toptal.com/developers/gitignore/api/jetbrains+all,maven,eclipse,java,git
# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains+all,maven,eclipse,java,git
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig
# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
modules.xml
.idea/misc.xml
*.ipr
# Sonarlint plugin
.idea/sonarlint
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# End of https://www.toptal.com/developers/gitignore/api/jetbrains+all,maven,eclipse,java,git

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 IntellectualSites
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

132
pom.xml Normal file
View file

@ -0,0 +1,132 @@
<?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>com.intellectualsites</groupId>
<artifactId>Commands</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<inceptionYear>2020</inceptionYear>
<licenses>
<license>
<name>MIT License</name>
<url>https://raw.githubusercontent.com/Sauilitired/Commands/master/LICENSE</url>
</license>
</licenses>
<name>Commands</name>
<description>Commands for Java</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<distributionManagement>
<repository>
<id>intellectualsites</id>
<name>IntellectualSites</name>
<url>https://mvn.intellectualsites.com/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>intellectualsites-snapshots</id>
<name>IntellectualSites Snapshots</name>
<url>https://mvn.intellectualsites.com/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<build>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>intellectualsites</serverId>
<nexusUrl>https://mvn.intellectualsites.com/</nexusUrl>
<skipStaging>true</skipStaging>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,85 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands;
import com.intellectualsites.commands.components.CommandComponent;
import javax.annotation.Nonnull;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
/**
* A command consists out of a chain of {@link com.intellectualsites.commands.components.CommandComponent command components}.
*/
public class Command {
private final CommandComponent<?>[] components;
private Command(@Nonnull final CommandComponent<?>[] commandComponents) {
this.components = Objects.requireNonNull(commandComponents, "Command components may not be null");
if (this.components.length == 0){
throw new IllegalArgumentException("At least one command component is required");
}
// Enforce ordering of command components
boolean foundOptional = false;
for (final CommandComponent<?> component : this.components) {
if (foundOptional && component.isRequired()) {
throw new IllegalArgumentException(String.format("Command component '%s' cannot be placed after an optional component", component.getName()));
} else if (!component.isRequired()) {
foundOptional = true;
}
}
}
/**
* Return a copy of the command component array
*
* @return Copy of the command component array
*/
@Nonnull public CommandComponent<?>[] getComponents() {
final CommandComponent<?>[] commandComponents = new CommandComponent<?>[this.components.length];
System.arraycopy(this.components, 0, commandComponents, 0, this.components.length);
return commandComponents;
}
/**
* Get the longest chain of similar components for
* two commands
*
* @return List containing the longest shared component chain
*/
public List<CommandComponent<?>> getSharedComponentChain(@Nonnull final Command other) {
final List<CommandComponent<?>> commandComponents = new LinkedList<>();
for (int i = 0; i < this.components.length && i < other.components.length; i++) {
if (this.components[i].equals(other.components[i])) {
commandComponents.add(this.components[i]);
} else {
break;
}
}
return commandComponents;
}
}

View file

@ -0,0 +1,155 @@
package com.intellectualsites.commands;
import com.google.common.base.Objects;
import com.intellectualsites.commands.components.CommandComponent;
import com.intellectualsites.commands.components.StaticComponent;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Tree containing all commands and command paths
*/
public class CommandTree {
private final Node<CommandComponent<?>> internalTree = new Node<>(null);
private CommandTree() {
}
/**
* Create a new command tree instance
*
* @return New command tree
*/
@Nonnull public static CommandTree newTree() {
return new CommandTree();
}
/**
* Insert a new command into the command tree
*
* @param command Command to insert
*/
public void insertCommand(@Nonnull final Command command) {
Node<CommandComponent<?>> node = this.internalTree;
for (final CommandComponent<?> component : command.getComponents()) {
Node<CommandComponent<?>> tempNode = node.getChild(component);
if (tempNode == null) {
tempNode = node.addChild(component);
}
node = tempNode;
}
if (node.getValue() != null) {
node.getValue().setOwningCommand(command);
}
}
/**
* Go through all commands and register them, and verify the
* command tree contracts
*/
public void verifyAndRegister() {
// All top level commands are supposed to be registered in the command manager
this.internalTree.children.stream().map(Node::getValue).forEach(commandComponent -> {
if (!(commandComponent instanceof StaticComponent)) {
throw new IllegalStateException("Top level command component cannot be a variable");
}
// TODO: Register in the command handler
});
this.checkAmbiguity(this.internalTree);
// Verify that all leaf nodes have command registered
this.getLeaves(this.internalTree).forEach(leaf -> {
if (leaf.getOwningCommand() == null) {
// TODO: Custom exception type
throw new IllegalStateException("Leaf node does not have associated owning command");
}
});
}
private void checkAmbiguity(@Nonnull final Node<CommandComponent<?>> node) {
if (node.isLeaf()) {
return;
}
final int size = node.children.size();
for (final Node<CommandComponent<?>> child : node.children) {
if (child.getValue() != null && !child.getValue().isRequired() && size > 1) {
// TODO: Use a custom exception type here
throw new IllegalStateException("Ambiguous command node found: " + node.getValue());
}
}
node.children.forEach(this::checkAmbiguity);
}
private List<CommandComponent<?>> getLeaves(@Nonnull final Node<CommandComponent<?>> node) {
final List<CommandComponent<?>> leaves = new LinkedList<>();
if (node.isLeaf()) {
if (node.getValue() != null) {
leaves.add(node.getValue());
}
} else {
node.children.forEach(child -> leaves.addAll(getLeaves(child)));
}
return leaves;
}
private static final class Node<T> {
private final List<Node<T>> children = new LinkedList<>();
private final T value;
private Node(@Nullable final T value) {
this.value = value;
}
private List<Node<T>> getChildren() {
return Collections.unmodifiableList(this.children);
}
@Nonnull private Node<T> addChild(@Nonnull final T child) {
final Node<T> node = new Node<>(child);
this.children.add(node);
return node;
}
@Nullable private Node<T> getChild(@Nonnull final T type) {
for (final Node<T> child : this.children) {
if (type.equals(child.getValue())) {
return child;
}
}
return null;
}
private boolean isLeaf() {
return this.children.isEmpty();
}
@Nullable public T getValue() {
return this.value;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Node<?> node = (Node<?>) o;
return Objects.equal(getChildren(), node.getChildren()) &&
Objects.equal(getValue(), node.getValue());
}
@Override
public int hashCode() {
return Objects.hashCode(getChildren(), getValue());
}
}
}

View file

@ -0,0 +1,226 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components;
import com.intellectualsites.commands.Command;
import com.intellectualsites.commands.parser.ComponentParser;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* A component that belongs to a command
*
* @param <T> The type that the component parses into
*/
public class CommandComponent<T> {
private static final Pattern NAME_PATTERN = Pattern.compile("[A-Za-z0-9]+");
/**
* Indicates whether or not the component is required
* or not. All components prior to any other required
* component must also be required, such that the predicate
* ( c_i required)({c_0, ..., c_i-1} required) holds true,
* where {c_0, ..., c_n-1} is the set of command components.
*/
private final boolean required;
/**
* The command component name. This might be exposed
* to command senders and so should be choosen carefully.
*/
private final String name;
/**
* The parser that is used to parse the command input
* into the corresponding command type
*/
private final ComponentParser<T> parser;
private Command owningCommand;
CommandComponent(final boolean required, @Nonnull final String name,
@Nonnull final ComponentParser<T> parser) {
this.required = required;
this.name = Objects.requireNonNull(name, "Name may not be null");
if (!NAME_PATTERN.asPredicate().test(name)) {
throw new IllegalArgumentException("Name must be alphanumeric");
}
this.parser = Objects.requireNonNull(parser, "Parser may not be null");
}
/**
* Create a new command component
*
* @param clazz Argument class
* @param <T> Argument Type
* @return Component builder
*/
@Nonnull public static <T> CommandComponent.Builder<T> ofType(@Nonnull final Class<T> clazz) {
return new Builder<>();
}
/**
* Check whether or not the command component is required
*
* @return {@code true} if the component is required, {@code false} if not
*/
public boolean isRequired() {
return this.required;
}
/**
* Get the command component name;
*
* @return Component name
*/
@Nonnull public String getName() {
return this.name;
}
/**
* Get the parser that is used to parse the command input
* into the corresponding command type
*
* @return Command parser
*/
@Nonnull public ComponentParser<T> getParser() {
return this.parser;
}
@Nonnull @Override public String toString() {
return String.format("CommandComponent{name=%s}", this.name);
}
/**
* Get the owning command
*
* @return Owning command
*/
@Nullable public Command getOwningCommand() {
return this.owningCommand;
}
/**
* Set the owning command
*
* @param owningCommand Owning command
*/
public void setOwningCommand(@Nonnull final Command owningCommand) {
if (this.owningCommand != null) {
throw new IllegalStateException("Cannot replace owning command");
}
this.owningCommand = owningCommand;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final CommandComponent<?> that = (CommandComponent<?>) o;
return isRequired() == that.isRequired() && com.google.common.base.Objects.equal(getName(), that.getName());
}
@Override
public int hashCode() {
return com.google.common.base.Objects.hashCode(isRequired(), getName());
}
public static class Builder<T> {
private String name;
private boolean required = true;
private ComponentParser<T> parser;
private Builder() {
}
/**
* Set the component name. Must be alphanumeric
*
* @param name Alphanumeric component name
* @return Builder instance
*/
@Nonnull public Builder<T> named(@Nonnull final String name) {
this.name = name;
return this;
}
/**
* Indicates that the component is required.
* All components prior to any other required
* component must also be required, such that the predicate
* ( c_i required)({c_0, ..., c_i-1} required) holds true,
* where {c_0, ..., c_n-1} is the set of command components.
*
* @return Builder instance
*/
@Nonnull public Builder<T> asRequired() {
this.required = true;
return this;
}
/**
* Indicates that the component is optional.
* All components prior to any other required
* component must also be required, such that the predicate
* ( c_i required)({c_0, ..., c_i-1} required) holds true,
* where {c_0, ..., c_n-1} is the set of command components.
*
* @return Builder instance
*/
@Nonnull public Builder<T> asOptional() {
this.required = false;
return this;
}
/**
* Set the component parser
*
* @param parser Component parser
* @return Builder instance
*/
@Nonnull public Builder<T> withParser(@Nonnull final ComponentParser<T> parser) {
this.parser = Objects.requireNonNull(parser, "Parser may not be null");
return this;
}
/**
* Construct a command component from the builder settings
*
* @return Constructed component
*/
@Nonnull public CommandComponent<T> build() {
return new CommandComponent<>(this.required, this.name, this.parser);
}
}
}

View file

@ -0,0 +1,44 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.components;
import com.intellectualsites.commands.parser.ComponentParser;
import javax.annotation.Nonnull;
public final class StaticComponent extends CommandComponent<String> {
private StaticComponent(final boolean required, @Nonnull final String name, @Nonnull final String ... aliases) {
super(required, name, new StaticComponentParser(name, aliases));
}
private static final class StaticComponentParser implements ComponentParser<String> {
private StaticComponentParser(@Nonnull final String name, @Nonnull final String ... aliases) {
}
}
}

View file

@ -0,0 +1,27 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package com.intellectualsites.commands.parser;
public interface ComponentParser<T> {
}