├── .github ├── CONTRIBUTING.md └── workflows │ └── gradle.yml ├── .gitignore ├── LICENSE ├── README.md ├── RELEASING.md ├── compiler ├── build.gradle └── src │ ├── main │ ├── java │ │ ├── module-info.java │ │ └── net │ │ │ └── jbock │ │ │ ├── annotated │ │ │ ├── AbstractMethodsFinder.java │ │ │ ├── Item.java │ │ │ ├── ItemListFactory.java │ │ │ ├── ItemListValidator.java │ │ │ ├── Items.java │ │ │ ├── ItemsFactory.java │ │ │ ├── Option.java │ │ │ ├── Parameter.java │ │ │ ├── UniqueNameSet.java │ │ │ └── VarargsParameter.java │ │ │ ├── common │ │ │ ├── Annotations.java │ │ │ ├── Constants.java │ │ │ ├── SafeElements.java │ │ │ ├── SafeTypes.java │ │ │ ├── SnakeName.java │ │ │ ├── Suppliers.java │ │ │ ├── TypeTool.java │ │ │ ├── Util.java │ │ │ └── ValidationFailure.java │ │ │ ├── convert │ │ │ ├── Mapping.java │ │ │ ├── MappingFinder.java │ │ │ ├── map │ │ │ │ ├── AutoMappings.java │ │ │ │ ├── AutoOrEnumMapper.java │ │ │ │ ├── ConverterValidator.java │ │ │ │ └── MappingFactory.java │ │ │ └── match │ │ │ │ ├── ListMatcher.java │ │ │ │ ├── Match.java │ │ │ │ ├── MatchFinder.java │ │ │ │ ├── Matcher.java │ │ │ │ ├── OptionalMatcher.java │ │ │ │ └── OptionalPrimitive.java │ │ │ ├── processor │ │ │ ├── CommandStep.java │ │ │ ├── JbockProcessor.java │ │ │ ├── MethodStep.java │ │ │ ├── ProcessorComponent.java │ │ │ ├── SourceElement.java │ │ │ └── SourceFileGenerator.java │ │ │ ├── validate │ │ │ ├── CommandProcessor.java │ │ │ ├── OptionValidator.java │ │ │ ├── ParameterValidator.java │ │ │ ├── ValidateComponent.java │ │ │ └── VarargsParameterValidator.java │ │ │ └── writing │ │ │ ├── CodeBlocks.java │ │ │ ├── CommandRepresentation.java │ │ │ ├── ContextComponent.java │ │ │ ├── CreateModelMethod.java │ │ │ ├── GeneratedAnnotation.java │ │ │ ├── GeneratedTypes.java │ │ │ ├── HasCommandRepresentation.java │ │ │ ├── ImplClass.java │ │ │ ├── OptEnum.java │ │ │ ├── OptionNamesMethod.java │ │ │ ├── OptionStatesMethod.java │ │ │ ├── ParseMethod.java │ │ │ ├── ParseOrExitMethod.java │ │ │ ├── ParserClass.java │ │ │ ├── ParserType.java │ │ │ └── ParserTypeFactory.java │ └── resources │ │ └── META-INF │ │ ├── gradle │ │ └── incremental.annotation.processors │ │ └── services │ │ └── javax.annotation.processing.Processor │ └── test │ ├── java │ └── net │ │ └── jbock │ │ ├── common │ │ └── SnakeNameTest.java │ │ └── processor │ │ ├── BasicFullTest.java │ │ ├── ConverterTest.java │ │ ├── DependsOnGeneratedTypeTest.java │ │ ├── GeneratingProcessor.java │ │ ├── InheritanceTest.java │ │ ├── ParseOrExitFullTest.java │ │ ├── PositionalTest.java │ │ ├── Processor.java │ │ ├── ProcessorTest.java │ │ ├── SuperCommandTest.java │ │ └── TypeToolTest.java │ └── resources │ └── mockito-extensions │ └── org.mockito.plugins.MockMaker ├── examples ├── build.gradle └── src │ ├── main │ └── java │ │ ├── examples │ │ └── dustin │ │ │ └── commandline │ │ │ └── jbock │ │ │ └── Main.java │ │ ├── module-info.java │ │ └── net │ │ └── jbock │ │ └── examples │ │ ├── AdditionArguments.java │ │ ├── AllCharactersArguments.java │ │ ├── AllDoublesArguments.java │ │ ├── AllFlagsArguments.java │ │ ├── AllFloatsArguments.java │ │ ├── AllIntegersArguments.java │ │ ├── AllLongsArguments.java │ │ ├── BigIntegerConverter.java │ │ ├── ClusteredShortOptions.java │ │ ├── ComplicatedMapperArguments.java │ │ ├── CpArguments.java │ │ ├── CurlArguments.java │ │ ├── CustomConverterCommand.java │ │ ├── EscapeSequenceCommand.java │ │ ├── EvilArguments.java │ │ ├── ExtremelySimpleArguments.java │ │ ├── GitCommand.java │ │ ├── GradleArguments.java │ │ ├── HelplessArguments.java │ │ ├── HelplessSuperArguments.java │ │ ├── ListIntegerArguments.java │ │ ├── MvArguments.java │ │ ├── NoNameArguments.java │ │ ├── OptionalIntArgumentsOptional.java │ │ ├── PositionalArguments.java │ │ ├── PrimitiveArguments.java │ │ ├── PrimitiveOptionalsArguments.java │ │ ├── PsArguments.java │ │ ├── RequiredArguments.java │ │ ├── RestArguments.java │ │ ├── RmArguments.java │ │ ├── SimpleArguments.java │ │ ├── SuperArguments.java │ │ ├── TarArguments.java │ │ └── VariousArguments.java │ └── test │ ├── java │ ├── examples │ │ └── dustin │ │ │ └── commandline │ │ │ └── jbock │ │ │ └── MainTest.java │ └── net │ │ └── jbock │ │ └── examples │ │ ├── AdditionArgumentsTest.java │ │ ├── AllCharactersArgumentsTest.java │ │ ├── AllDoublesArgumentsTest.java │ │ ├── AllFlagsArgumentsTest.java │ │ ├── AllFloatsArgumentsTest.java │ │ ├── AllIntegersArgumentsTest.java │ │ ├── AllLongsArgumentsTest.java │ │ ├── ClusteredShortOptionsTest.java │ │ ├── ComplicatedMapperArgumentsTest.java │ │ ├── CpArgumentsTest.java │ │ ├── CurlArgumentsTest.java │ │ ├── CustomConverterCommandTest.java │ │ ├── EscapeSequenceCommandTest.java │ │ ├── EvilArgumentsTest.java │ │ ├── ExtremelySimpleArgumentsTest.java │ │ ├── GitCommandTest.java │ │ ├── GradleArgumentsFooTest.java │ │ ├── GradleArgumentsTest.java │ │ ├── HelplessArgumentsTest.java │ │ ├── HelplessSuperArgumentsTest.java │ │ ├── ListIntegerArgumentsTest.java │ │ ├── MvArgumentsTest.java │ │ ├── NoNameArgumentsTest.java │ │ ├── OptionalIntArgumentsOptionalTest.java │ │ ├── PositionalArgumentsTest.java │ │ ├── PrimitiveArgumentsTest.java │ │ ├── PrimitiveOptionalsArgumentsTest.java │ │ ├── PsArgumentsTest.java │ │ ├── RequiredArgumentsTest.java │ │ ├── RestArgumentsTest.java │ │ ├── RmArgumentsTest.java │ │ ├── SimpleArgumentsTest.java │ │ ├── SuperArgumentsTest.java │ │ ├── TarArgumentsTest.java │ │ ├── VariousArgumentsTest.java │ │ └── fixture │ │ ├── ParserTestFixture.java │ │ └── TestOutputStream.java │ └── resources │ └── mockito-extensions │ └── org.mockito.plugins.MockMaker ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── jbock ├── build.gradle └── src │ ├── main │ └── java │ │ ├── module-info.java │ │ └── net │ │ └── jbock │ │ ├── Command.java │ │ ├── Option.java │ │ ├── Parameter.java │ │ ├── SuperCommand.java │ │ ├── VarargsParameter.java │ │ ├── contrib │ │ ├── AnsiStyle.java │ │ ├── ConverterStore.java │ │ ├── EnumConverter.java │ │ ├── MoreConverters.java │ │ ├── StandardConverters.java │ │ ├── StandardErrorHandler.java │ │ ├── Synopsis.java │ │ └── UsageDocumentation.java │ │ ├── model │ │ ├── Arity.java │ │ ├── CommandModel.java │ │ ├── Item.java │ │ ├── ItemType.java │ │ ├── Multiplicity.java │ │ ├── Option.java │ │ └── Parameter.java │ │ ├── parse │ │ ├── AbstractParser.java │ │ ├── OptionState.java │ │ ├── OptionStateModeFlag.java │ │ ├── OptionStateNonRepeatable.java │ │ ├── OptionStateRepeatable.java │ │ ├── OptionStateUtil.java │ │ ├── ParseResult.java │ │ ├── StandardParser.java │ │ ├── SuperParser.java │ │ └── VarargsParameterParser.java │ │ └── util │ │ ├── AtFileError.java │ │ ├── AtFileReadError.java │ │ ├── AtFileSyntaxError.java │ │ ├── ConverterFailure.java │ │ ├── ConverterReturnedNull.java │ │ ├── ConverterThrewException.java │ │ ├── ErrAtFile.java │ │ ├── ErrConvert.java │ │ ├── ErrMissingItem.java │ │ ├── ErrToken.java │ │ ├── ErrTokenType.java │ │ ├── ExConvert.java │ │ ├── ExFailure.java │ │ ├── ExMissingItem.java │ │ ├── ExToken.java │ │ ├── ParseRequest.java │ │ ├── ParseRequestExpand.java │ │ ├── ParseRequestSimple.java │ │ ├── ParsingFailed.java │ │ └── StringConverter.java │ └── test │ └── java │ └── net │ └── jbock │ ├── contrib │ └── StandardConvertersTest.java │ ├── model │ └── CommandModelTest.java │ ├── parse │ ├── StandardParserTest.java │ ├── SuperParserTest.java │ └── VarargsParameterParserTest.java │ └── util │ ├── ParseRequestExpandTest.java │ └── ParseRequestTest.java ├── release └── settings.gradle /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Pull request are very welcome! 2 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-java@v4 13 | with: 14 | distribution: 'temurin' 15 | java-version: 22 16 | cache: 'gradle' 17 | - run: ./gradlew compiler:test examples:test 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .idea 3 | *.iml 4 | *~ 5 | /dependency-reduced-pom.xml 6 | .gradle 7 | /gradlew.bat 8 | /core/out 9 | /compiler/out 10 | /examples/out 11 | /gradle.properties 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 H90 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | ### RELEASING 2 | 3 | 1. Export these environment variables: `OSS_USER`, `OSS_PASS` (login for http://oss.sonatype.org/) 4 | 1. Export these environment variables: `ORG_GRADLE_PROJECT_signingKey`, `ORG_GRADLE_PROJECT_signingPassword`. 5 | 6 | `ORG_GRADLE_PROJECT_signingKey` is an ascii-armored encrypted gpg private key, so this variable contains a multiline string. 7 | It can be initialized like this: 8 | 9 | ````sh 10 | export ORG_GRADLE_PROJECT_signingKey=`cat secret.asc` 11 | ```` 12 | 13 | Now you can run `./release core ${MY_VERSION}` or `./release annotations ${MY_VERSION}`. 14 | 15 | -------------------------------------------------------------------------------- /compiler/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module net.jbock.compiler { 2 | 3 | provides javax.annotation.processing.Processor with net.jbock.processor.JbockProcessor; 4 | 5 | requires java.compiler; 6 | requires io.jbock.auto.common; 7 | requires io.jbock.javapoet; 8 | requires io.jbock.util; 9 | requires io.jbock.simple; 10 | requires net.jbock; 11 | } -------------------------------------------------------------------------------- /compiler/src/main/java/net/jbock/annotated/ItemListFactory.java: -------------------------------------------------------------------------------- 1 | package net.jbock.annotated; 2 | 3 | import io.jbock.util.Either; 4 | import net.jbock.common.SnakeName; 5 | import net.jbock.common.ValidationFailure; 6 | 7 | import javax.lang.model.element.ExecutableElement; 8 | import javax.lang.model.element.Name; 9 | import java.lang.annotation.Annotation; 10 | import java.util.List; 11 | import java.util.Locale; 12 | import java.util.Objects; 13 | 14 | import static io.jbock.util.Either.left; 15 | import static io.jbock.util.Eithers.allFailures; 16 | import static java.util.stream.Collectors.toList; 17 | import static net.jbock.common.Annotations.methodLevelAnnotations; 18 | 19 | final class ItemListFactory { 20 | 21 | private final UniqueNameSet uniqueNameSet = new UniqueNameSet(); 22 | 23 | private ItemListFactory() { 24 | } 25 | 26 | static Either, List> createItemList( 27 | List methods) { 28 | return new ItemListFactory().validParameterlessAbstract(methods); 29 | } 30 | 31 | private Either, List> validParameterlessAbstract( 32 | List methods) { 33 | return methods.stream() 34 | .map(this::createItem) 35 | .collect(allFailures()); 36 | } 37 | 38 | private Either createItem( 39 | ExecutableElement method) { 40 | String enumName = enumNameFor(method.getSimpleName()); 41 | return getMethodAnnotation(method) 42 | .map(a -> Item.create(method, a, enumName)); 43 | } 44 | 45 | private String enumNameFor(Name sourceMethodName) { 46 | String enumName = "_".contentEquals(sourceMethodName) ? 47 | "_1" : // avoid potential keyword issue 48 | SnakeName.create(sourceMethodName).snake('_').toUpperCase(Locale.ROOT); 49 | return uniqueNameSet.getUniqueName(enumName); 50 | } 51 | 52 | private static Either getMethodAnnotation( 53 | ExecutableElement method) { 54 | return methodLevelAnnotations().stream() 55 | .map(method::getAnnotation) 56 | .filter(Objects::nonNull) 57 | .findFirst() 58 | .>map(Either::right) 59 | .orElseGet(() -> left(missingAnnotationError(method))); 60 | } 61 | 62 | private static ValidationFailure missingAnnotationError( 63 | ExecutableElement method) { 64 | String message = "missing annotation: add one of these annotations: " + methodLevelAnnotations().stream() 65 | .map(Class::getSimpleName).collect(toList()); 66 | message = message + " to method '" + method.getSimpleName() + "'"; 67 | return new ValidationFailure(message, method); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /compiler/src/main/java/net/jbock/annotated/Items.java: -------------------------------------------------------------------------------- 1 | package net.jbock.annotated; 2 | 3 | import java.util.Comparator; 4 | import java.util.List; 5 | 6 | import static java.util.Comparator.comparingInt; 7 | import static java.util.stream.Collectors.toList; 8 | import static net.jbock.common.Constants.instancesOf; 9 | 10 | public final class Items { 11 | 12 | private static final Comparator INDEX_COMPARATOR = comparingInt(Parameter::index); 13 | 14 | private final List