diff --git a/.eclipse/org.eclipse.jdt.core.prefs b/.eclipse/org.eclipse.jdt.core.prefs index 4e8e2c33..cc3e405e 100644 --- a/.eclipse/org.eclipse.jdt.core.prefs +++ b/.eclipse/org.eclipse.jdt.core.prefs @@ -25,7 +25,7 @@ org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning org.eclipse.jdt.core.compiler.problem.deadCode=warning org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled -org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled org.eclipse.jdt.core.compiler.problem.discouragedReference=warning org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=error @@ -127,7 +127,7 @@ org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=84 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 @@ -136,6 +136,7 @@ org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=true org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=0 diff --git a/.eclipse/org.eclipse.jdt.ui.prefs b/.eclipse/org.eclipse.jdt.ui.prefs index bfe2939c..ccf98e6a 100644 --- a/.eclipse/org.eclipse.jdt.ui.prefs +++ b/.eclipse/org.eclipse.jdt.ui.prefs @@ -70,7 +70,7 @@ org.eclipse.jdt.ui.keywordthis=false org.eclipse.jdt.ui.ondemandthreshold=9999 org.eclipse.jdt.ui.overrideannotation=true org.eclipse.jdt.ui.staticondemandthreshold=9999 -org.eclipse.jdt.ui.text.custom_code_templates= +org.eclipse.jdt.ui.text.custom_code_templates= sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false sp_cleanup.add_missing_annotations=true diff --git a/.github/actions/.bats/bats b/.github/actions/.bats/bats new file mode 160000 index 00000000..902578da --- /dev/null +++ b/.github/actions/.bats/bats @@ -0,0 +1 @@ +Subproject commit 902578da790fbcb035747d2964747f192f6e1603 diff --git a/.github/actions/.bats/test_helper/bats-assert b/.github/actions/.bats/test_helper/bats-assert new file mode 160000 index 00000000..e2d855bc --- /dev/null +++ b/.github/actions/.bats/test_helper/bats-assert @@ -0,0 +1 @@ +Subproject commit e2d855bc78619ee15b0c702b5c30fb074101159f diff --git a/.github/actions/.bats/test_helper/bats-support b/.github/actions/.bats/test_helper/bats-support new file mode 160000 index 00000000..9bf10e87 --- /dev/null +++ b/.github/actions/.bats/test_helper/bats-support @@ -0,0 +1 @@ +Subproject commit 9bf10e876dd6b624fe44423f0b35e064225f7556 diff --git a/.github/actions/create-github-release/action.yml b/.github/actions/create-github-release/action.yml new file mode 100644 index 00000000..1d72cd3a --- /dev/null +++ b/.github/actions/create-github-release/action.yml @@ -0,0 +1,21 @@ +name: Create GitHub Release +description: Create the release on GitHub with a changelog +inputs: + milestone: + required: true + token: + required: true +runs: + using: composite + steps: + - name: Generate Changelog + uses: spring-io/github-changelog-generator@v0.0.10 + with: + milestone: ${{ inputs.milestone }} + token: ${{ inputs.token }} + config-file: .github/actions/create-github-release/changelog-generator.yml + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md diff --git a/.github/actions/create-github-release/changelog-generator.yml b/.github/actions/create-github-release/changelog-generator.yml new file mode 100644 index 00000000..2ce74a09 --- /dev/null +++ b/.github/actions/create-github-release/changelog-generator.yml @@ -0,0 +1,2 @@ +changelog: + repository: spring-io/spring-javaformat diff --git a/.github/actions/deduce-versions/action.yml b/.github/actions/deduce-versions/action.yml new file mode 100644 index 00000000..b8e197c4 --- /dev/null +++ b/.github/actions/deduce-versions/action.yml @@ -0,0 +1,22 @@ +name: 'Deduce Versions' +description: 'Deduce the version to stage and the next SNAPSHOT version' +inputs: + current-version: + required: true + release-type: + required: true +outputs: + release-version: + value: ${{ steps.deduce-versions.outputs.release-version }} + next-version: + value: ${{ steps.deduce-versions.outputs.next-version }} +runs: + using: composite + steps: + - name: Deduce Versions + id: deduce-versions + shell: bash + run: . ${{ github.action_path }}/deduce-versions.sh; deduce_versions + env: + CURRENT_VERSION: "${{ inputs.current-version }}" + RELEASE_TYPE: "${{ inputs.release-type }}" diff --git a/.github/actions/deduce-versions/deduce-versions.sh b/.github/actions/deduce-versions/deduce-versions.sh new file mode 100755 index 00000000..6a3d14e0 --- /dev/null +++ b/.github/actions/deduce-versions/deduce-versions.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +# Get the next milestone release for the given number by inspecting current tags +get_next_milestone_release() { + [[ -n $1 ]] || { echo "missing get_next_milestone_release() version argument" >&2; return 1; } + get_next_tag_based_release "$1" "M" +} + +# Get the next RC release for the given number by inspecting current tags +get_next_rc_release() { + [[ -n $1 ]] || { echo "missing get_next_rc_release() version argument" >&2; return 1; } + get_next_tag_based_release "$1" "RC" +} + +# Get the next release for the given number +get_next_release() { + [[ -n $1 ]] || { echo "missing get_next_release() version argument" >&2; return 1; } + if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then + local join="." + else + local join="-" + fi + local version + local result + version=$( strip_snapshot_suffix "$1" ) + if [[ -n $2 ]]; then + result="${version}${join}${2}" + else + result="${version}" + fi + echo $result +} + +# Get the next milestone or RC release for the given number by inspecting current tags +get_next_tag_based_release() { + [[ -n $1 ]] || { echo "missing get_next_tag_based_release() version argument" >&2; return 1; } + [[ -n $2 ]] || { echo "missing get_next_tag_based_release() tag type argument" >&2; return 1; } + if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then + local join="." + else + local join="-" + fi + local version + local last + version=$( strip_snapshot_suffix "$1" ) + git fetch --tags --all > /dev/null + last=$( git tag --list "v${version}${join}${2}*" | sed -E "s/^.*${2}([0-9]+)$/\1/g" | sort -rn | head -n1 ) + if [[ -z $last ]]; then + last="0" + fi + last="${version}${join}${2}${last}" + bump_version_number "$last" +} + +# Remove any "-SNAPSHOT" or ".BUILD-SNAPSHOT" suffix +strip_snapshot_suffix() { + [[ -n $1 ]] || { echo "missing get_relase_version() argument" >&2; return 1; } + if [[ $1 =~ ^(.*)\.BUILD-SNAPSHOT$ ]]; then + echo "${BASH_REMATCH[1]}" + elif [[ $1 =~ ^(.*)-SNAPSHOT$ ]]; then + echo "${BASH_REMATCH[1]}" + else + echo "$1" + fi +} + +# Bump version number by incrementing the last numeric, RC or M token +bump_version_number() { + local version=$1 + [[ -n $version ]] || { echo "missing bump_version_number() argument" >&2; return 1; } + if [[ $version =~ ^(.*(\.|-)([A-Za-z]+))([0-9]+)$ ]]; then + local prefix=${BASH_REMATCH[1]} + local suffix=${BASH_REMATCH[4]} + (( suffix++ )) + echo "${prefix}${suffix}" + return 0; + fi + local suffix + if [[ $version =~ ^(.*)(\-SNAPSHOT)$ ]]; then + version=${BASH_REMATCH[1]} + suffix="-SNAPSHOT" + fi + tokens=(${version//\./ }) + local bumpIndex + for i in "${!tokens[@]}"; do + if [[ "${tokens[$i]}" =~ ^[0-9]+$ ]] ; then + bumpIndex=$i + fi + done + [[ -n $bumpIndex ]] || { echo "unsupported version number" >&2; return 1; } + (( tokens[bumpIndex]++ )) + local bumpedVersion + IFS=. eval 'bumpedVersion="${tokens[*]}"' + echo "${bumpedVersion}${suffix}" +} + +# Deduce versions +deduce_versions() { + [[ -n ${GITHUB_OUTPUT} ]] || { echo "missing GITHUB_OUTPUT environment variable" >&2; return 1; } + [[ -n ${CURRENT_VERSION} ]] || { echo "missing CURRENT_VERSION environment variable" >&2; return 1; } + [[ -n ${RELEASE_TYPE} ]] || { echo "missing RELEASE_TYPE environment variable" >&2; return 1; } + if [[ ${RELEASE_TYPE,,} = "milestone" ]]; then + releaseVersion=$( get_next_milestone_release ${CURRENT_VERSION}) + nextVersion=${CURRENT_VERSION} + elif [[ ${RELEASE_TYPE,,} = "release-candidate" ]]; then + releaseVersion=$( get_next_rc_release ${CURRENT_VERSION}) + nextVersion=${CURRENT_VERSION} + elif [[ ${RELEASE_TYPE,,} = "release" ]]; then + releaseVersion=$( get_next_release ${CURRENT_VERSION}) + nextVersion=$( bump_version_number ${CURRENT_VERSION}) + else + echo "Unknown release type '${RELEASE_TYPE}'" >&2; exit 1; + fi + echo "release-version=${releaseVersion}" >> "$GITHUB_OUTPUT" + echo "next-version=${nextVersion}" >> "$GITHUB_OUTPUT" +} diff --git a/.github/actions/deduce-versions/test.sh b/.github/actions/deduce-versions/test.sh new file mode 100755 index 00000000..0a8e4130 --- /dev/null +++ b/.github/actions/deduce-versions/test.sh @@ -0,0 +1 @@ +../.bats/bats/bin/bats test/*.bats \ No newline at end of file diff --git a/.github/actions/deduce-versions/test/bump_version.bats b/.github/actions/deduce-versions/test/bump_version.bats new file mode 100644 index 00000000..5efd9f0b --- /dev/null +++ b/.github/actions/deduce-versions/test/bump_version.bats @@ -0,0 +1,58 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +@test "bump_version_number() should bump '.M'" { + run bump_version_number "1.2.0.M2" + assert_output "1.2.0.M3" +} + +@test "bump_version_number() should bump '.RC'" { + run bump_version_number "1.2.0.RC3" + assert_output "1.2.0.RC4" +} + +@test "bump_version_number() should bump '-M'" { + run bump_version_number "1.2.0-M2" + assert_output "1.2.0-M3" +} + +@test "bump_version_number() should bump '-RC'" { + run bump_version_number "1.2.0-RC3" + assert_output "1.2.0-RC4" +} + +@test "bump_version_number() should bump without suffix" { + run bump_version_number "1.2.0" + assert_output "1.2.1" +} + +@test "bump_version_number() should bump '.RELEASE'" { + run bump_version_number "1.2.0.RELEASE" + assert_output "1.2.1.RELEASE" +} + +@test "bump_version_number() should bump '-SNAPSHOT'" { + run bump_version_number "1.2.0-SNAPSHOT" + assert_output "1.2.1-SNAPSHOT" +} + +@test "bump_version_number() should bump '.BUILD-SNAPSHOT'" { + run bump_version_number "1.2.0.BUILD-SNAPSHOT" + assert_output "1.2.1.BUILD-SNAPSHOT" +} + +@test "bump_version_number() when missing argument should fail" { + run bump_version_number + assert_output "missing bump_version_number() argument" + assert [ "$status" -eq 1 ] +} + +@test "bump_version_number() when bad argument should fail" { + run bump_version_number "foo.bar.baz" + assert_output "unsupported version number" + assert [ "$status" -eq 1 ] +} diff --git a/.github/actions/deduce-versions/test/deduce_versions.bats b/.github/actions/deduce-versions/test/deduce_versions.bats new file mode 100644 index 00000000..2ffbf599 --- /dev/null +++ b/.github/actions/deduce-versions/test/deduce_versions.bats @@ -0,0 +1,96 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +teardown() { + rm .githuboutput | true +} + +@test "deduce_versions() when 'milestone' should export versions" { + repo=$( mock_git_repo "v1.2.3-M1" ) + cd "$repo" + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="milestone" + run deduce_versions + readarray -t githuboutput < .githuboutput + assert [ "$status" -eq 0 ] + assert [ "${githuboutput[0]}" = "release-version=1.2.3-M2" ] + assert [ "${githuboutput[1]}" = "next-version=1.2.3-SNAPSHOT" ] +} + +@test "deduce_versions() when 'release-candidate' should export versions" { + repo=$( mock_git_repo "v1.2.3-M1" "v1.2.3-M2" "v1.2.3-RC1" ) + cd "$repo" + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="release-candidate" + run deduce_versions + readarray -t githuboutput < .githuboutput + assert [ "$status" -eq 0 ] + assert [ "${githuboutput[0]}" = "release-version=1.2.3-RC2" ] + assert [ "${githuboutput[1]}" = "next-version=1.2.3-SNAPSHOT" ] +} + +@test "deduce_versions() when 'release' should export versions" { + repo=$( mock_git_repo "v1.2.3-M1" "v1.2.3-M2" "v1.2.3-RC1" ) + cd "$repo" + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="release" + run deduce_versions + readarray -t githuboutput < .githuboutput + assert [ "$status" -eq 0 ] + assert [ "${githuboutput[0]}" = "release-version=1.2.3" ] + assert [ "${githuboutput[1]}" = "next-version=1.2.4-SNAPSHOT" ] +} + +@test "deduce_versions() when no GITHUB_OUTPUT should fail" { + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="release" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "missing GITHUB_OUTPUT environment variable" +} + +@test "deduce_versions() when no CURRENT_VERSION should fail" { + GITHUB_OUTPUT=".githuboutput" + RELEASE_TYPE="release" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "missing CURRENT_VERSION environment variable" +} + +@test "deduce_versions() when no RELEASE_TYPE should fail" { + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "missing RELEASE_TYPE environment variable" +} + +@test "deduce_versions() when wrong RELEASE_TYPE should fail" { + GITHUB_OUTPUT=".githuboutput" + CURRENT_VERSION="1.2.3-SNAPSHOT" + RELEASE_TYPE="nope" + run deduce_versions + assert [ "$status" -eq 1 ] + assert_output "Unknown release type 'nope'" +} + +mock_git_repo() { + local tmpdir=$(mktemp -d $BATS_TMPDIR/gitrepo.XXXXXX) >&2 + mkdir -p "$tmpdir" >&2 + cd "$tmpdir" >&2 + git init >&2 + echo "foo" > foo.txt + git add foo.txt >&2 + git commit -m'Initial commit' >&2 + for tag in "$@"; do + git tag "$tag" >&2 + done + echo "$tmpdir" +} \ No newline at end of file diff --git a/.github/actions/deduce-versions/test/get_next_release.bats b/.github/actions/deduce-versions/test/get_next_release.bats new file mode 100644 index 00000000..b9be5c0e --- /dev/null +++ b/.github/actions/deduce-versions/test/get_next_release.bats @@ -0,0 +1,119 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +@test "get_next_milestone_release() when has no version should fail" { + run get_next_milestone_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_milestone_release() version argument" +} + +@test "get_next_rc_release() when has no version should fail" { + run get_next_rc_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_rc_release() version argument" +} + +@test "get_next_tag_based_release() when has no version should fail" { + run get_next_tag_based_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_tag_based_release() version argument" +} + +@test "get_next_tag_based_release() when has no tag type should fail" { + run get_next_tag_based_release "1.2.3" + assert [ "$status" -eq 1 ] + assert_output "missing get_next_tag_based_release() tag type argument" +} + +@test "get_next_milestone_release() when has no tag should return M1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_milestone_release "1.2.3-SNAPSHOT" + assert_output "1.2.3-M1" +} + +@test "get_next_rc_release() when has no tag should return RC1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_rc_release "1.2.3-SNAPSHOT" + assert_output "1.2.3-RC1" +} + +@test "get_next_tag_based_release() when has no tag and dash SNAPSHOT suffix should return dashed X1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_tag_based_release "1.2.3-SNAPSHOT" "X" + assert_output "1.2.3-X1" +} + +@test "get_next_tag_based_release() when has no tag and dash BUILD-SNAPSHOT suffix should return dashed X1" { + repo=$( mock_git_repo ) + cd "$repo" + run get_next_tag_based_release "1.2.3.BUILD-SNAPSHOT" "X" + assert_output "1.2.3.X1" +} + +@test "get_next_tag_based_release() when has tags and dashed should return dashed X tag+1" { + repo=$( mock_git_repo "v1.2.3-X1" "v1.2.3-X3" "v1.2.3-X2" ) + cd "$repo" + run get_next_tag_based_release "1.2.3-SNAPSHOT" "X" + assert_output "1.2.3-X4" +} + +@test "get_next_tag_based_release() when has tags and dashed should return dot X tag+1" { + repo=$( mock_git_repo "v1.2.3.X1" "v1.2.3.X3" "v1.2.3.X2" ) + cd "$repo" + run get_next_tag_based_release "1.2.3.BUILD-SNAPSHOT" "X" + assert_output "1.2.3.X4" +} + +@test "get_next_tag_based_release() when has multiple tags should return version match tag+1" { + repo=$( mock_git_repo "v1.5.0.A1" "v1.5.0.A2" "v1.5.0.B1" "v2.0.0.A1" "v2.0.0.B1" "v2.0.0.B2" ) + cd "$repo" + run get_next_tag_based_release "1.5.0.BUILD-SNAPSHOT" "A" + assert_output "1.5.0.A3" + run get_next_tag_based_release "1.5.0.BUILD-SNAPSHOT" "B" + assert_output "1.5.0.B2" + run get_next_tag_based_release "2.0.0.BUILD-SNAPSHOT" "A" + assert_output "2.0.0.A2" + run get_next_tag_based_release "2.0.0.BUILD-SNAPSHOT" "B" + assert_output "2.0.0.B3" +} + +@test "get_next_release() should return next release version with release suffix" { + run get_next_release "1.5.0.BUILD-SNAPSHOT" "RELEASE" + assert_output "1.5.0.RELEASE" + run get_next_release "1.5.0-SNAPSHOT" "RELEASE" + assert_output "1.5.0-RELEASE" +} + +@test "get_next_release() should return next release version" { + run get_next_release "1.5.0.BUILD-SNAPSHOT" + assert_output "1.5.0" + run get_next_release "1.5.0-SNAPSHOT" + assert_output "1.5.0" +} + +@test "get_next_release() when has no version should fail" { + run get_next_release + assert [ "$status" -eq 1 ] + assert_output "missing get_next_release() version argument" +} + +mock_git_repo() { + local tmpdir=$(mktemp -d $BATS_TMPDIR/gitrepo.XXXXXX) >&2 + mkdir -p "$tmpdir" >&2 + cd "$tmpdir" >&2 + git init >&2 + echo "foo" > foo.txt + git add foo.txt >&2 + git commit -m'Initial commit' >&2 + for tag in "$@"; do + git tag "$tag" >&2 + done + echo "$tmpdir" +} diff --git a/.github/actions/deduce-versions/test/strip_snapshot_suffix.bats b/.github/actions/deduce-versions/test/strip_snapshot_suffix.bats new file mode 100644 index 00000000..bef64867 --- /dev/null +++ b/.github/actions/deduce-versions/test/strip_snapshot_suffix.bats @@ -0,0 +1,21 @@ +#!./test/libs/bats/bin/bats + +load '../../.bats/test_helper/bats-support/load' +load '../../.bats/test_helper/bats-assert/load' + +source "$PWD/deduce-versions.sh" + +@test "strip_snapshot_suffix() should strip '-SNAPSHOT" { + run strip_snapshot_suffix "1.2.0-SNAPSHOT" + assert_output "1.2.0" +} + +@test "strip_snapshot_suffix() should strip '.BUILD-SNAPSHOT" { + run strip_snapshot_suffix "1.2.0.BUILD-SNAPSHOT" + assert_output "1.2.0" +} + +@test "strip_snapshot_suffix() when no suffix should return unchanged" { + run strip_snapshot_suffix "1.2.0" + assert_output "1.2.0" +} diff --git a/.github/actions/publish-eclipse-update-site/action.yml b/.github/actions/publish-eclipse-update-site/action.yml new file mode 100644 index 00000000..4235c9e8 --- /dev/null +++ b/.github/actions/publish-eclipse-update-site/action.yml @@ -0,0 +1,22 @@ +name: 'Publish Eclipse Update Site ' +inputs: + version: + required: true + build-number: + required: true + artifactory-username: + required: true + artifactory-password: + required: true +runs: + using: composite + steps: + - name: Stage + id: stage + shell: bash + run: . ${{ github.action_path }}/publish-eclipse-update-site.sh; + env: + VERSION: "${{ inputs.version }}" + BUILD_NUMBER: "${{ inputs.build-number }}" + ARTIFACTORY_USERNAME: "${{ inputs.artifactory-username }}" + ARTIFACTORY_PASSWORD: "${{ inputs.artifactory-password }}" diff --git a/ci/scripts/publish-eclipse-update-site-pom-template.xml b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site-pom-template.xml similarity index 99% rename from ci/scripts/publish-eclipse-update-site-pom-template.xml rename to .github/actions/publish-eclipse-update-site/publish-eclipse-update-site-pom-template.xml index 859a3101..6ee635e0 100755 --- a/ci/scripts/publish-eclipse-update-site-pom-template.xml +++ b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site-pom-template.xml @@ -25,7 +25,7 @@ -##respositories## +##repositories## ${project.build.directory}/repository true diff --git a/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site.sh b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site.sh new file mode 100644 index 00000000..9ddcee29 --- /dev/null +++ b/.github/actions/publish-eclipse-update-site/publish-eclipse-update-site.sh @@ -0,0 +1,51 @@ +buildInfo=$( jfrog rt curl api/build/spring-javaformat-${VERSION}/${BUILD_NUMBER} ) +groupId=$( echo ${buildInfo} | jq -r '.buildInfo.modules[0].id' | sed 's/\(.*\):.*:.*/\1/' ) +version=$( echo ${buildInfo} | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) + +echo "Publishing ${buildName}/${buildNumber} (${groupId}:${version}) to Eclipse Update Site" + +jfrog rt dl --build spring-javaformat-${VERSION}/${BUILD_NUMBER} '**/io.spring.javaformat.eclipse.site*.zip' + +curl \ + -s \ + --connect-timeout 240 \ + --max-time 2700 \ + -u ${ARTIFACTORY_USERNAME}:${ARTIFACTORY_PASSWORD} \ + -f \ + -H "X-Explode-Archive: true" \ + -X PUT \ + -T "io/spring/javaformat/io.spring.javaformat.eclipse.site/${version}/io.spring.javaformat.eclipse.site-${version}.zip" \ + "https://repo.spring.io/javaformat-eclipse-update-site/${version}/" > /dev/null || { echo "Failed to publish" >&2; exit 1; } + +releasedVersions=$( curl -s -f -X GET https://repo.spring.io/api/storage/javaformat-eclipse-update-site | jq -r '.children[] | .uri' | cut -c 2- | grep '[0-9].*' | sort -V ) + +repositories="" +while read -r releasedVersion; do + echo "Adding repository for ${releasedVersion}" + repositories="${repositories}https://repo.spring.io/javaformat-eclipse-update-site/${releasedVersion}p2" +done <<< "${releasedVersions}" + +sed "s|##repositories##|${repositories}|" ${GITHUB_ACTION_PATH}/publish-eclipse-update-site-pom-template.xml > publish-eclipse-update-site-pom.xml +./mvnw -f publish-eclipse-update-site-pom.xml clean package || { echo "Failed to publish" >&2; exit 1; } + +curl \ + -s \ + --connect-timeout 240 \ + --max-time 2700 \ + -u ${ARTIFACTORY_USERNAME}:${ARTIFACTORY_PASSWORD} \ + -f \ + -X PUT \ + -T "target/repository/content.jar" \ + "https://repo.spring.io/javaformat-eclipse-update-site/" > /dev/null || { echo "Failed to publish" >&2; exit 1; } + +curl \ + -s \ + --connect-timeout 240 \ + --max-time 2700 \ + -u ${ARTIFACTORY_USERNAME}:${ARTIFACTORY_PASSWORD} \ + -f \ + -X PUT \ + -T "target/repository/artifacts.jar" \ + "https://repo.spring.io/javaformat-eclipse-update-site/" > /dev/null || { echo "Failed to publish" >&2; exit 1; } + +echo "Publish complete" diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 00000000..c1d38d98 --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,16 @@ +name: 'Setup' +runs: + using: composite + steps: + - name: Set Up Utilities + shell: bash + run: sudo apt-get update && sudo apt-get -y install libxml2-utils + - name: Set Up Java + uses: actions/setup-java@v4 + with: + distribution: 'liberica' + java-version: '17' + cache: maven + - name: Disable Java Problem Matcher + shell: bash + run: echo "::remove-matcher owner=java::" diff --git a/.github/actions/stage-code/action.yml b/.github/actions/stage-code/action.yml new file mode 100644 index 00000000..1fc1f060 --- /dev/null +++ b/.github/actions/stage-code/action.yml @@ -0,0 +1,22 @@ +name: 'Stage ' +inputs: + current-version: + required: true + release-version: + required: true + next-version: + required: true +outputs: + distribution-repository: + value: ${{ steps.stage.outputs.distribution-repository }} +runs: + using: composite + steps: + - name: Stage + id: stage + shell: bash + run: . ${{ github.action_path }}/stage.sh; + env: + CURRENT_VERSION: "${{ inputs.current-version }}" + RELEASE_VERSION: "${{ inputs.release-version }}" + NEXT_VERSION: "${{ inputs.next-version }}" diff --git a/.github/actions/stage-code/stage.sh b/.github/actions/stage-code/stage.sh new file mode 100644 index 00000000..6ac9c2f0 --- /dev/null +++ b/.github/actions/stage-code/stage.sh @@ -0,0 +1,32 @@ +repository=${GITHUB_WORKSPACE}/distribution-repository + +echo "Staging ${RELEASE_VERSION} to ${repository} (next version will be ${NEXT_VERSION})" + +./mvnw versions:set --batch-mode --no-transfer-progress -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false +./mvnw org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata --batch-mode --no-transfer-progress +./mvnw --projects io.spring.javaformat:spring-javaformat-vscode-extension --batch-mode --no-transfer-progress -P '!formatter-dependencies' antrun:run@update-version frontend:install-node-and-npm frontend:npm@update-package-lock + +git config user.name "Spring Builds" > /dev/null +git config user.email "spring-builds@users.noreply.github.com" > /dev/null +git add pom.xml > /dev/null +git commit -m"Release v${RELEASE_VERSION}" > /dev/null +git tag -a "v${RELEASE_VERSION}" -m"Release v${RELEASE_VERSION}" > /dev/null + +./mvnw clean deploy --batch-mode --no-transfer-progress -U -Dfull -DaltDeploymentRepository=distribution::file://${repository} + +git reset --hard HEAD^ > /dev/null +if [[ ${NEXT_VERSION} != ${CURRENT_VERSION} ]]; then + echo "Setting next development version (v${NEXT_VERSION})" + ./mvnw versions:set --batch-mode --no-transfer-progress -DnewVersion=${NEXT_VERSION} -DgenerateBackupPoms=false + ./mvnw org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata --batch-mode --no-transfer-progress + ./mvnw --projects io.spring.javaformat:spring-javaformat-vscode-extension --batch-mode --no-transfer-progress -P '!formatter-dependencies' antrun:run@update-version frontend:npm@update-package-lock + sed -i "s/:release-version:.*/:release-version: ${RELEASE_VERSION}/g" README.adoc + sed -i "s/spring-javaformat-gradle-plugin:.*/spring-javaformat-gradle-plugin:${NEXT_VERSION}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle + sed -i "s/spring-javaformat-checkstyle:.*/spring-javaformat-checkstyle:${NEXT_VERSION}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle + sed -i "s|.*|${NEXT_VERSION}|" samples/spring-javaformat-maven-sample/pom.xml + git add -u . > /dev/null + git commit -m"Next development version (v${NEXT_VERSION})" > /dev/null +fi; + +echo "Staged the following files:" +find ${repository} diff --git a/.github/artifacts.spec b/.github/artifacts.spec new file mode 100644 index 00000000..0f6c3aac --- /dev/null +++ b/.github/artifacts.spec @@ -0,0 +1,23 @@ +{ + "files": [ + { + "aql": { + "items.find": { + "$and": [ + { + "@build.name": "${buildName}", + "@build.number": "${buildNumber}", + "name": { + "$nmatch": "*.zip" + }, + "name": { + "$nmatch": "*.zip.asc" + } + } + ] + } + }, + "target": "nexus/" + } + ] +} diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 00000000..0c4b142e --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,2 @@ +require: + members: false diff --git a/.github/images/setup-idea-dependency.png b/.github/images/setup-idea-dependency.png new file mode 100644 index 00000000..06958617 Binary files /dev/null and b/.github/images/setup-idea-dependency.png differ diff --git a/.github/images/setup-idea-library.png b/.github/images/setup-idea-library.png new file mode 100644 index 00000000..d3563c7c Binary files /dev/null and b/.github/images/setup-idea-library.png differ diff --git a/.github/images/setup-idea-plugin-module.png b/.github/images/setup-idea-plugin-module.png new file mode 100644 index 00000000..694a1370 Binary files /dev/null and b/.github/images/setup-idea-plugin-module.png differ diff --git a/.github/images/setup-idea-plugin-sdk.png b/.github/images/setup-idea-plugin-sdk.png new file mode 100644 index 00000000..3766bdb0 Binary files /dev/null and b/.github/images/setup-idea-plugin-sdk.png differ diff --git a/.github/workflows/build-and-deploy-snapshot.yml b/.github/workflows/build-and-deploy-snapshot.yml new file mode 100644 index 00000000..d269a903 --- /dev/null +++ b/.github/workflows/build-and-deploy-snapshot.yml @@ -0,0 +1,30 @@ +name: Build and Deploy Snapshot +on: + push: + branches: + - main +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} +jobs: + build-and-deploy-snapshot: + name: Build and Deploy Snapshot + runs-on: ubuntu-latest + if: ${{ github.repository == 'spring-io/spring-javaformat' }} + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up + uses: ./.github/actions/setup + - name: Build + run: ./mvnw clean deploy --batch-mode --no-transfer-progress --update-snapshots -DaltDeploymentRepository=distribution::file://$(pwd)/distribution-repository + - name: Deploy + uses: spring-io/artifactory-deploy-action@v0.0.1 + with: + folder: 'distribution-repository' + uri: 'https://repo.spring.io' + repository: 'libs-snapshot-local' + build-name: spring-javaformat + username: ${{ secrets.ARTIFACTORY_USERNAME }} + password: ${{ secrets.ARTIFACTORY_PASSWORD }} + signing-key: ${{ secrets.GPG_PRIVATE_KEY }} + signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/build-pull-request.yml b/.github/workflows/build-pull-request.yml new file mode 100644 index 00000000..9e085b69 --- /dev/null +++ b/.github/workflows/build-pull-request.yml @@ -0,0 +1,16 @@ +name: Build Pull Request +on: pull_request +permissions: + contents: read +jobs: + build: + name: Build Pull Request + runs-on: ubuntu-latest + if: ${{ github.repository == 'spring-io/spring-javaformat' }} + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up + uses: ./.github/actions/setup + - name: Build + run: ./mvnw clean install --batch-mode --no-transfer-progress --update-snapshots diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml new file mode 100644 index 00000000..e1faac58 --- /dev/null +++ b/.github/workflows/promote.yml @@ -0,0 +1,92 @@ +name: Promote +run-name: >- + Promote of version ${{ inputs.version }} (build number ${{ inputs.build-number}}) by ${{ github.actor }} to '${{ inputs.environment }}' environment' +on: + workflow_call: + inputs: + environment: + type: string + required: true + version: + type: string + required: true + build-number: + type: string + required: true + workflow_dispatch: + inputs: + environment: + description: Environment + type: environment + required: true + version: + description: The version number to promote + type: string + required: true + build-number: + description: The build number to promote + type: string + required: true +jobs: + promote: + environment: ${{ inputs.environment }} + name: Promote + runs-on: ubuntu-latest + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up JFrog CLI + uses: jfrog/setup-jfrog-cli@ff5cb544114ffc152db9cea1cd3d5978d5074946 # v4.5.11 + env: + JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} + - name: Check Maven Central Sync Status + id: check-sync-status + run: | + url=${{ format('https://repo.maven.apache.org/maven2/io/spring/javaformat/spring-javaformat/{0}/spring-javaformat-{0}.pom', inputs.version) }} + status_code=$( curl --write-out '%{http_code}' --head --silent --output /dev/null ${url} ) + if [ "${status_code}" != 200 ] && [ "${status_code}" != 404 ]; then + echo "Unexpected status code ${status_code}" + exit 1 + fi + echo "status-code=${status_code}" >> $GITHUB_OUTPUT + - name: Download Release Artifacts + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + run: jf rt download --spec ./.github/artifacts.spec --spec-vars 'buildName=${{ format('spring-javaformat-{0}', inputs.version) }};buildNumber=${{ inputs.build-number }}' + - name: Sync to Maven Central + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + uses: spring-io/nexus-sync-action@v0.0.1 + with: + username: ${{ secrets.OSSRH_S01_TOKEN_USERNAME }} + password: ${{ secrets.OSSRH_S01_TOKEN_PASSWORD }} + staging-profile-name: ${{ secrets.OSSRH_S01_STAGING_PROFILE }} + create: true + upload: true + close: true + release: true + generate-checksums: true + - name: Await Maven Central Sync + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + run: | + url=${{ format('https://repo.maven.apache.org/maven2/io/spring/javaformat/spring-javaformat/{0}/spring-javaformat-{0}.pom', inputs.version) }} + echo "Waiting for $url" + until curl --fail --head --silent $url > /dev/null + do + echo "." + sleep 60 + done + echo "$url is available" + - name: Promote Build + if: ${{ steps.check-sync-status.outputs.status-code == '404' }} + run: jfrog rt build-promote ${{ format('spring-javaformat-{0}', inputs.version)}} ${{ inputs.build-number }} libs-release-local + - name: Publish Eclipse Update Site + uses: ./.github/actions/publish-eclipse-update-site + with: + version: ${{ inputs.version }} + build-number: ${{ inputs.build-number }} + artifactory-username: ${{ secrets.ARTIFACTORY_USERNAME }} + artifactory-password: ${{ secrets.ARTIFACTORY_PASSWORD }} + - name: Create GitHub Release + uses: ./.github/actions/create-github-release + with: + milestone: ${{ inputs.version }} + token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..c80a4091 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +name: Release +run-name: >- + Release of '${{ github.ref_name }}' branch to '${{ inputs.environment }}' environment by ${{ github.actor }} +on: + workflow_dispatch: + inputs: + environment: + description: Environment + type: environment + required: true +jobs: + stage: + name: Stage + runs-on: ubuntu-latest + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up + uses: ./.github/actions/setup + - name: Get Current Version + id: get-version + run: echo "current-version=$(xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml)" >> $GITHUB_OUTPUT + - name: Deduce Versions + id: deduce-versions + uses: ./.github/actions/deduce-versions + with: + current-version: ${{ steps.get-version.outputs.current-version }} + release-type: ${{ inputs.environment }} + - name: Stage Code + id: stage-code + uses: ./.github/actions/stage-code + with: + current-version: ${{ steps.get-version.outputs.current-version }} + release-version: ${{ steps.deduce-versions.outputs.release-version }} + next-version: ${{ steps.deduce-versions.outputs.next-version }} + - name: Deploy to Staging + uses: spring-io/artifactory-deploy-action@v0.0.1 + with: + folder: distribution-repository + uri: 'https://repo.spring.io' + repository: 'libs-staging-local' + build-name: ${{ format('spring-javaformat-{0}', steps.deduce-versions.outputs.release-version)}} + username: ${{ secrets.ARTIFACTORY_USERNAME }} + password: ${{ secrets.ARTIFACTORY_PASSWORD }} + signing-key: ${{ secrets.GPG_PRIVATE_KEY }} + signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} + - name: Push + run: git push origin HEAD --tags + outputs: + release-version: ${{ steps.deduce-versions.outputs.release-version }} + release-build-number: ${{ github.run_number }} + promote: + name: Promote + needs: stage + uses: ./.github/workflows/promote.yml + with: + environment: ${{ inputs.environment }} + version: ${{needs.stage.outputs.release-version}} + build-number: ${{ needs.stage.outputs.release-build-number }} diff --git a/.github/workflows/rollback.yml b/.github/workflows/rollback.yml new file mode 100644 index 00000000..43e04a4d --- /dev/null +++ b/.github/workflows/rollback.yml @@ -0,0 +1,41 @@ +name: Rollback +run-name: >- + Rollback of version ${{ inputs.version }} (build number ${{ inputs.build-number}}) by ${{ github.actor }} +on: + workflow_dispatch: + inputs: + environment: + description: Environment + type: environment + required: true + version: + description: The version number to roll back + type: string + required: true + build-number: + description: The build number to roll back + type: string + required: true +jobs: + rollback: + environment: ${{ inputs.environment }} + name: Roll Back + runs-on: ubuntu-latest + steps: + - name: Check Out + uses: actions/checkout@v4 + - name: Set Up JFrog CLI + uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.1.2 + env: + JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} + - name: Delete Staged Artifacts + run: | + url=${{ format('libs-staging-local/io/spring/javaformat/spring-javaformat/{0}/spring-javaformat-{0}.pom', inputs.version) }} + artifact_count=$( jf rt s ${url} --count ) + if [ "${artifact_count}" != 1 ]; then + echo "Unexpected aretifact count ${artifact_count}" + exit 1 + fi + build_name=${{ format('spring-javaformat-{0}', inputs.version)}} + build_number=${{ inputs.build-number }} + jf rt delete --build ${build_name}/${build_number} diff --git a/.gitignore b/.gitignore index e43e9edb..20cd4cfc 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ target *.ipr *.iws spring-javaformat-eclipse/io.spring.javaformat.eclipse/lib +spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/lib +spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/lib spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib .gradle spring-javaformat-gradle/spring-javaformat-gradle-plugin/bin @@ -20,3 +22,12 @@ spring-javaformat/spring-javaformat-checkstyle/bin spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/bin build.log pid +.factorypath + +# npm +node_modules/ + +# vscode +spring-javaformat-vscode/spring-javaformat/out/ +spring-javaformat-vscode/spring-javaformat/runtime/ +*.vsix diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..64d1aa9d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule ".github/actions/.bats/bats"] + path = .github/actions/.bats/bats + url = https://github.com/bats-core/bats-core.git + tag = v1.11.0 +[submodule ".github/actions/.bats/test_helper/bats-support"] + path = .github/actions/.bats/test_helper/bats-support + url = https://github.com/bats-core/bats-support.git + tag = v0.3.0 +[submodule ".github/actions/.bats/test_helper/bats-assert"] + path = .github/actions/.bats/test_helper/bats-assert + url = https://github.com/bats-core/bats-assert.git + tag = v2.1.0 diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100755 index b20a55a7..00000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.3"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + " .jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar old mode 100755 new mode 100644 index e89f07c2..bf82ff01 Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100755 new mode 100644 index 1703626c..6686a643 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,18 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/.sdkmanrc b/.sdkmanrc new file mode 100644 index 00000000..83ec5a0a --- /dev/null +++ b/.sdkmanrc @@ -0,0 +1,3 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +java=17.0.14-librca diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 4979277d..a7e07f62 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -3,27 +3,36 @@ Spring Java Format is released under the Apache 2.0 license. If you would like to contribute something, or simply want to hack on the code this document should help you get started. + + == Code of Conduct This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct]. By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. -== Sign the Contributor License Agreement -Before we accept a non-trivial patch or pull request we will need you to https://cla.pivotal.io/sign/spring[sign the Contributor License Agreement]. -Signing the contributor's agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. -Active contributors might be asked to join the core team, and given the ability to merge pull requests. -== Working with the code + +== Include a Signed-off-by Trailer +All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin[Developer Certificate of Origin (DCO)]. +For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring]. + + + +== Working With the Code If you don't have an IDE preference we would recommend that you use https://spring.io/tools/sts[Spring Tools Suite] or https://eclipse.org[Eclipse] when working with the code. We use the https://eclipse.org/m2e/[M2Eclipse] eclipse plugin for maven support. Other IDEs and tools should also work without issue. -=== Building from source -To build the source you will need to install JDK 1.8. -==== Default build + +=== Building From Source +To build the source you will need to install JDK 17. + + + +==== Default Build The project can be built from the root directory using the standard maven command: [indent=0] @@ -33,7 +42,9 @@ The project can be built from the root directory using the standard maven comman NOTE: You may need to increase the amount of memory available to Maven by setting a `MAVEN_OPTS` environment variable with the value `-Xmx512m` -=== Importing into eclipse + + +=== Importing Into Eclipse You can import the code into any Eclipse based distribution as long as it had the https://eclipse.org/m2e/[M2Eclipse] eclipse plugin. If you don't already have m2eclipse installed it is available from the "Eclipse marketplace". @@ -46,24 +57,157 @@ Once imported, you can apply eclipse settings by running: NOTE: You'll need to close the `spring-javaformat-formatter-eclipse` and `spring-javaformat-formatter-eclipse-runtime` projects following import since they contain rewritten packages that aren't supported by the IDE -=== Importing into other IDEs + + +=== Importing Into IntelliJ IDEA +You can import the code as a maven project into IntelliJ IDEA. + + + +==== Module Dependencies +When IntelliJ IDEA parses `pom.xml`, it automatically creates inter-module dependencies if dependent libraries are coming from other modules within the project. +However, when dependent modules perform repackaging (e.g. `spring-javaformat-formatter-eclipse-runtime` module), the current module cannot resolve all classes by module dependencies because repackaging (shade & binary manipulation) moves around classes. +Therefore, you need to manually update the dependencies from the module to the produced jars. + +Following modules perform repackaging. + +* `spring-javaformat-formatter-eclipse` +* `spring-javaformat-formatter-eclipse-runtime` + +Modules that depend on these modules need jar dependencies instead of module dependencies. + + + +===== Setting up Jar Dependencies +The following steps define jar-based project libraries on IDE and add them to the modules that need jar dependencies. + +*Add a jar file-based project library* + +* "Project Settings" -> "Libraries" +* Click "+" sign, then select "Java" +* Specify the jar file + +For example, you can specify the jar file in the target directory(`/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/target/spring-javaformat-formatter-eclipse-runtime-0.0.28-SNAPSHOT.jar`) +or one in the local maven repository(`~/.m2/repository/io/spring/javaformat/spring-javaformat-formatter-eclipse-runtime/0.0.28-SNAPSHOT/spring-javaformat-formatter-eclipse-runtime-0.0.28-SNAPSHOT.jar`). + +image::.github/images/setup-idea-library.png[Setup IntelliJ IDEA library] + +*Add library dependencies to modules* + +* "Project Settings" -> "Modules" +* Select a module that depends on repackaging modules +* Click "+" sign and "2 Library" +* "Choose Libraries" and select necessary libraries that have added in the previous step +* Move up the added libraries higher than the module dependencies (or remove the module dependencies) + +image::.github/images/setup-idea-dependency.png[Setup IntelliJ IDEA Dependencies] + + + +=== Setting up IntelliJ IDEA Plugin Development + + + +==== Download Images +To develop the `spring-javaformat-intellij-idea-plugin` module, you need an IntelliJ IDEA application on your local machine. + +* Open the `pom.xml` in `spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime`. +* Check `intellij.binary` and `intellij.source` properties to find out the appropriate IntelliJ IDEA version. +* Download the binary from the url in `intellij.binary`. +(For OSX, replace the `.tar.gz` to `.dmg` to download the image file.) +* Install the image to the local machine +* Download the source files from github specified in `intellij.source` and unzip it. + + + +==== Setup SDK +* Open "Project Structure" - "Platform Settings" - "SDKs" +* Click "+" sign, "Add Intellij Platform Plugin SDK..." +* Specify the installed intellij image. (`/applications/IntelliJ IDEA CE` for OSX) +* On the right panel, "Sourcepath", Click "+" sign, specify unzipped intellij source directory +* Specify "Sandbox Home" directory + +image::.github/images/setup-idea-plugin-sdk.png[Setup IntelliJ IDEA Plugin SDK] + +Please see the https://plugins.jetbrains.com/docs/intellij/setting-up-environment.html[IntelliJ IDEA reference] for how to setup a plugin development in details. + + + +==== Convert to Plugin Module +The imported `spring-javaformat-intellij-idea-plugin` module is recognized as a java module. +This needs to be converted to a plugin module. + +* Open `spring-javaformat-intellij-idea-plugin.iml` in `spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin` +* Change `type="JAVA_MODULE"` to `type="PLUGIN_MODULE"` + +[source,xml] +---- + +---- + +Reference https://stackoverflow.com/questions/18278440/how-to-import-and-run-existing-plugins-from-intellij-community-edition-repo[how to convert existing module to a plugin module] + +* Open "Project Structure" - "Modules" +* Check `spring-javaformat-intellij-idea-plugin` icon turns to a plugin icon +* "Plugin Deployment" - "Path to META-INF/plugin.xml" +* Specify `spring-javaformat/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources` + +image::.github/images/setup-idea-plugin-module.png[Setup IntelliJ IDEA Plugin Module] + + + +=== Setting up Gradle Plugin Development +`spring-javaformat-gradle-plugin` module is a gradle plugin and requires gradle related classes. + +To add gradle classes, convert this module to a gradle project. + +* On the project pain, right-click `build.gradle` in `spring-javaformat-gradle-plugin` module +* Select "Import Gradle Project" + + + +=== Setting up Visual Studio Code Extension Development +The `spring-javaformat-vscode-extension` extension consists of a formatter written in Java and an extension written in TypeScript. +If you want to work on the TypeScript code it can opened directly with Visual Studio Code. + +Maven delegates to `npm run package` to actually generate the extension. + +Code is formatted with prettier. +If you need to reform the code you can run `npx prettier --write .` + +There is a basic test included with the project, but since it needs UI elements it doesn't run as part of the regular build. +If you make changes to the extension, you should run "`Extension Tests`" from vscode. + + + +=== Importing Into Other IDEs Maven is well supported by most Java IDEs. Refer to your vendor documentation. -== Understanding the code + + +== Understanding the Code There are quite a few moving parts to this project and the build is quite complex. -At the top level there are 5 projects: +At the top level there are 6 projects: * `spring-javaformat` - The main formatter project * `spring-javaformat-eclipse` - The Eclipse plugin * `spring-javaformat-gradle` - The Gradle plugin * `spring-javaformat-intellij` - The IntelliJ IDEA plugin * `spring-javaformat-maven` - The Maven plugin +* `spring-javaformat-vscode` - The Visual Studo Code extension Under `spring-javaformat` the following projects are defined: * `spring-javaformat-checkstyle` - The checkstyle plugin * `spring-javaformat-formatter` - The main formatter code -* `spring-javaformat-formatter-eclipse` - The eclipse formatter (repackaged and slightly adapted) +* `spring-javaformat-formatter-test-support` - Support classes for tests +* `spring-javaformat-formatter-tests` - Tests for the formatter (external so that they we can test Java 8 and 11) +* `spring-javaformat-formatter-shader` - Shader support classes +* `spring-javaformat-formatter-shaded` - A shaded version of the formatter with all dependencies included +* `spring-javaformat-formatter-eclipse-jdk8` - The eclipse JDK 8 formatter (repackaged and slightly adapted) +* `spring-javaformat-formatter-eclipse-jdk17` - The eclipse JDK 17 formatter (repackaged and slightly adapted) +* `spring-javaformat-formatter-eclipse-jdt-jdk8` - The eclipse JDT import for JDK 8 +* `spring-javaformat-formatter-eclipse-jdt-jdk17` - The eclipse JDT import for JDK 17 * `spring-javaformat-formatter-eclipse-rewriter` - Internal utility used to modify eclipse code * `spring-javaformat-formatter-eclipse-runtime` - Eclipse runtime JAR for use when running outside of Eclipse diff --git a/README.adoc b/README.adoc index 3cd1fcf0..907d9a2c 100644 --- a/README.adoc +++ b/README.adoc @@ -1,22 +1,27 @@ -:release-version: 0.0.20 -:checkstyle-version: 8.29 +:release-version: 0.0.47 +:checkstyle-version: 9.3 == Spring Java Format -=== What is this? + + +=== What is This? A set of plugins that can be applied to any Java project to provide a consistent "`Spring`" style. The set currently consists of: * A source formatter that applies wrapping and whitespace conventions -* A checkstyle plugin that enforces consistency across a codebase +* A Checkstyle plugin that enforces consistency across a codebase Since the aim of this project is to provide consistency, each plugin is not generally configurable. You need to change your code to match the required conventions. You can't configure the plugin conventions to match your style! + + === Maven -==== Source Formatting + +==== Source Formatting For source formatting, add the `spring-javaformat-maven-plugin` to your `build` plugins as follows: [source,xml,indent=0,subs="normal"] @@ -71,9 +76,13 @@ NOTE: The source formatter does not fundamentally change your code. For example, it will not change the order of import statements. It is effectively limited to adding or removing whitespace and line feeds. -=== Checkstyle +TIP: You can use `-Dspring-javaformat.validate.skip=true` or `-Dspring-javaformat.apply.skip=true` command line arguments to temporarily skip the validation or format goals. +If you want to skip both, you can use `-Dspring-javaformat.skip=true`. -To enforce checksyle conventions add the checkstyle plugin and include a dependency on `spring-javaformat-checkstyle`: + + +==== Checkstyle +To enforce Checkstyle conventions, add the Checkstyle plugin and include a dependency on `spring-javaformat-checkstyle`: [source,xml,indent=0,subs="normal"] ---- @@ -82,7 +91,7 @@ To enforce checksyle conventions add the checkstyle plugin and include a depende org.apache.maven.plugins maven-checkstyle-plugin - 3.0.0 + 3.1.1 com.puppycrawl.tools @@ -114,74 +123,114 @@ To enforce checksyle conventions add the checkstyle plugin and include a depende ---- -=== Gradle -==== Source Formatting -For source formatting, add the `spring-javaformat-gradle-plugin` to your `build` plugins as follows: + +=== Gradle +A plugin is provided. +To use it, first update `settings.gradle` to add Maven Central as a plugin repository: [source,groovy,indent=0,subs="normal"] ---- - buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:{release-version}") - } +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() } +} +---- - apply plugin: 'io.spring.javaformat' +The plugin can then be added in the usual way in `build.gradle`: + +[source,groovy,indent=0,subs="normal"] +---- +plugins { + id "io.spring.javaformat" version "{release-version}" +} ---- +==== Source Formatting The plugin adds `format` and `checkFormat` tasks to your project. -The `checkFormat` task is automatically applied when running the standard Gradle `check` task. +The `checkFormat` task is automatically executed when running the standard Gradle `check` task. -In case you want to exclude a package from being checked, for example if you generate sources, you can do this by adding following configuration: +In case you want to exclude a package from being checked, for example if you generate sources, add configuration similar to the following: [source,groovy,indent=0,subs="normal"] ---- -tasks.withType(io.spring.javaformat.gradle.CheckTask) { - exclude "package/to/exclude" +tasks.withType(io.spring.javaformat.gradle.tasks.CheckFormat) { + exclude "package/to/exclude" } ---- + + ==== Checkstyle -To enforce checksyle conventions add the checkstyle plugin and include a dependency on `spring-javaformat-checkstyle`: +To enforce Checkstyle conventions, apply the Checkstyle plugin in addition to the `io.spring.javaformat` plugin: [source,groovy,indent=0,subs="normal"] ---- -apply plugin: 'checkstyle' +plugins { + id "io.spring.javaformat" version "{release-version}" + id "checkstyle" +} +---- +The Spring Java Format plugin will react to the Checkstyle plugin being applied and configure the necessary dependencies in the `checkstyle` configuration. + +You should also configure Checkstyle's tool version: + +[source,groovy,indent=0,subs="normal"] +---- checkstyle { toolVersion = "{checkstyle-version}" } +---- -dependencies { - checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:{release-version}") +To configure Checkstyle to use the default Spring checks, add the following configuration: + +[source,groovy,indent=0,subs="normal"] +---- +springJavaFormat { + checkstyle { + applyDefaultConfig() + } } ---- -Your `checkstyle.xml` file should look then like this: +Alternatively, provide your own `checkstyle.xml` that configures the `io.spring.javaformat.checkstyle.SpringChecks` module. -[source,xml,indent=0] +If you want to use both Spring Java Format and Checkstyle but you do not want to use Spring Java Format's checks, disable the aforementioned dependency configuration: + +[source,groovy,indent=0,subs="normal"] ---- - - - - - +springJavaFormat { + checkstyle { + configureDependencies = false + } +} +---- + + + +=== Java 8 Support +By default, the formatter requires Java 17. +If you are working on an older project, you can use a variation of the formatter based off Eclipse 2021-03 (the latest Eclipse JDT version built with Java 8). + +To use the Java 8 version, add a file called `.springjavaformatconfig` to the root of your project with the following content: + +[source,properties] +---- +java-baseline=8 ---- + === Eclipse The Eclipse plugin provides a custom formatter implementation and automatically applies project specific settings. The plugin is automatically activated whenever the Maven or Gradle plugins are discovered in a project build script. -If you need to customize the project specific settings that the plugin applies you should add a `.eclipse` folder in the root of your project. +If you need to customize the project specific settings that the plugin applies, you should add a `.eclipse` folder in the root of your project. All `.prefs` files from this folder will be copied to the project `.settings` folders. -Usually you'll provide your own `org.eclipse.jdt.core.prefs` and `org.eclipse.jdt.ui.prefs` files. +Usually, you'll provide your own `org.eclipse.jdt.core.prefs` and `org.eclipse.jdt.ui.prefs` files. You can also add a `.eclipse/eclipse.properties` file to customize the following items: @@ -192,31 +241,117 @@ You can also add a `.eclipse/eclipse.properties` file to customize the following To install the plugin use the `io.spring.javaformat.eclipse.site` zip file. You can download the latest version from -https://repo.spring.io/release/io/spring/javaformat/io.spring.javaformat.eclipse.site/{release-version}[repo.spring.io] -or use the https://dl.bintray.com/spring/javaformat-eclipse/[update site]. +https://repo1.maven.org/maven2/io/spring/javaformat/io.spring.javaformat.eclipse.site/{release-version}[Maven Central] +or use the `https://repo.spring.io/javaformat-eclipse-update-site/` as an Eclipse update site (do not use the `/ui/native/` links that you are redirected to when using a web browser). + + === IntelliJ IDEA -The IntelliJ plugin provides custom formatter support for IDEA. -The plugin is automatically activated whenever the Maven or Gradle plugins are discovered in a project build script. -A Spring Java Format icon (image:spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/resources/spring-javaformat/formatOn.png[title="Icon"]) will also be displayed in the status bar to indicate the formatter is active. +The IntelliJ IDEA plugin provides custom formatter support for IntelliJ IDEA. +The plugin is automatically activated whenever the Maven or Gradle plugins are discovered in a project build script or if a `.springjavaformatconfig` file. +A Spring Java Format icon (image:spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources/spring-javaformat/formatOn.png[title="Icon"]) will also be displayed in the status bar to indicate the formatter is active. You can use the standard `code` -> `reformat code` action to format the code. -To install the plugin use the `spring-javaformat-intellij-plugin` jar file. -You can download the latest version from https://repo.spring.io/release/io/spring/javaformat/spring-javaformat-intellij-plugin/{release-version}[repo.spring.io]. +To install the plugin, use the `spring-javaformat-intellij-idea-plugin` jar file. +You can download the latest version from https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-intellij-idea-plugin/{release-version}[Maven Central]. + + + +==== Enable the Plugin +The plugin is automatically enabled when one or more of the following conditions match: + +* `.springjavaformatconfig` file exists +* For a Maven-based project, `spring-javaformat-maven-plugin` plugin is defined in `pom.xml` +* For a Gradle-based project, `io.spring.javaformat` plugin is applied + + + +==== CheckStyle-IDEA plugin +The https://plugins.jetbrains.com/plugin/1065-checkstyle-idea[CheckStyle-IDEA plugin] provides Checkstyle integration for IntelliJ IDEA. + +To configure the plugin, create your own Checkstyle configuration file with the following content: + +[source,xml,indent=0] +---- + + + + + +---- + +Once the configuration file is created, configure your IDE to use it: + +* Download `spring-javaformat-checkstyle-{release-version}.jar` from https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-checkstyle/{release-version}[Maven Central]. +* Download `spring-javaformat-config-{release-version}.jar` from https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-config/{release-version}[Maven Central]. +* Open `Preferences` - `Tools` - `Checkstyle` +* Add `spring-javaformat-checkstyle-{release-version}.jar` and `spring-javaformat-config-{release-version}.jar` to the `Third-Party Checks` +* Specify the appropriate `Checkstyle version` +* Add and enable your Checkstyle configuration file + + + +=== Visual Studio Code +The Visual Studio Code extension provides custom formatter support for Microsoft Visual Studio Code. +The extension uses the https://code.visualstudio.com/api/references/vscode-api#DocumentFormattingEditProvider[`DocumentFormattingEditProvider`] API. +Once installed it may be activated by using the "`Format Document`" action available in the editor context menu or from the Command Palette. + +To install the extension, select "`Install from VSIX`" in the extensions panel and choose the `spring-javaformat-vscode-extension` vsix file. +You can download the latest version from https://repo1.maven.org/maven2/io/spring/javaformat/spring-javaformat-vscode-extension/{release-version}[Maven Central]. + + + +=== About the Conventions +Most of the coding conventions and style come from the Spring Framework and Spring Boot projects. +Spring Framework manually formats code, whereas Spring Boot uses automatic formatting. + + + +=== Indenting With Spaces +By default, tabs are used for indenting formatted code. +We strongly recommend that this default is not changed, especially for official Spring projects. +If, however, you feel that you can't live with tabs, switching to spaces is the one configuration option that we do support. + +To use spaces rather than tabs, add a file called `.springjavaformatconfig` to the root of your project with the following content: + +[source,properties] +---- +indentation-style=spaces +---- + -=== About the conventions -Most of the coding conventions and style comes from the Spring Framework and Spring Boot projects. -Spring Framework manually formats code, where as Spring Boot uses automatic formatting. === Tips Formatting and Checkstyle alone are not enough to produce truly consistent code. Here are some tips that we've found useful when developing Spring Boot. -==== Disabling formatting for blocks of code + + +==== Excluding Specific Checks +If you want most `SpringChecks` but need to exclude one or two, you can do something like this in your `checkstyle.xml`: + +[source,xml,indent=0] +---- + + + + + + + +---- + + + +==== Disabling Formatting For Blocks of Code Some code isn't particularly amenable to automatic formatting. For example, Spring Security configurations often work better when manually formatted. -If you need to disable formatting for a specific block of code you can enclose it in a `@formatter:off` / `@formatter:on` set: +If you need to disable formatting for a specific block of code, you can enclose it in a `@formatter:off` / `@formatter:on` set: [source,java] ---- @@ -227,46 +362,56 @@ If you need to disable formatting for a specific block of code you can enclose i // @formatter:on ---- + + ==== Wrapping The source formatter uses 120 chars for wrapping. This aims to strike a balance between making use of available horizontal space in your IDE and avoiding unwanted additional wrapping when viewing code on GitHub and the like. If you're used to longer lines, 120 chars can take some getting used to. Specifically, if -you have many nesting levels things can start to look quite bad. Generally, if you see -code bunched up to the right of your screen you should take that as a signal to use the +you have many nesting levels, things can start to look quite bad. Generally, if you see +code bunched up to the right of your screen, you should take that as a signal to use the "`extract method`" refactor. Extracting small private methods will improve formatting and it helps when reading the code and debugging. + + ==== Whitespace Keeping whitespace lines out of method bodies can help make the code easier to scan. -If blank lines are only included between methods it becomes easier to see the overall structure of the class. -If you find you need whitespace inside your method, consider if extracting a private method might give a better result. +If blank lines are only included between methods, it becomes easier to see the overall structure of the class. +If you find you need whitespace inside your method, consider whether extracting a private method might give a better result. + + ==== Comments Try to add javadoc for each public method and constant. Private methods shouldn't generally need javadoc, unless it provides a natural place to document unusual behavior. -The checkstyle rules will enforce that all public classes have javadoc. +The Checkstyle rules will enforce that all public classes have javadoc. They will also ensure that `@author` tags are well formed. + + ==== Final Private members should be `final` whenever possible. -Local variable and parameters should generally not be explicitly declared as final since it adds so much noise. +Local variables and parameters should generally not be explicitly declared as final since it adds so much noise. + + -==== Read-down methods, fields and parameters +==== Read-down Methods, Fields and Parameters Methods don't need to be organized by scope. There's no need to group all `private`, `protected` and `public` methods together. -Instead try to make your code easy to read when scanning the file from top to bottom. -In other words, try to have methods only reference method further down in the file. +Instead, try to make your code easy to read when scanning the file from top to bottom. +In other words, try to have methods only reference methods further down in the file. Keep private methods as close to the thing that calls them as possible. -It's also recommend that you try to keep consistent ordering with fields and constructor parameters. +It's also recommended that you try to keep consistent ordering with fields and constructor parameters. For example: [source,java,indent=0,subs="normal"] ---- -class Name { +public class Name { private final String first; diff --git a/ci/README.adoc b/ci/README.adoc deleted file mode 100644 index bdf75bd5..00000000 --- a/ci/README.adoc +++ /dev/null @@ -1,18 +0,0 @@ -== Concourse pipeline - -Ensure that you've setup the target and can login - -[source] ----- -$ fly -t spring-javaformat login -n spring-javaformat -c https://ci.spring.io ----- - -The pipeline can be deployed using the following command: - -[source] ----- -$ fly -t spring-javaformat set-pipeline -p spring-javaformat -c ci/pipeline.yml -l ci/parameters.yml ----- - -NOTE: This assumes that you have credhub integration configured with the appropriate -secrets. diff --git a/ci/images/README.adoc b/ci/images/README.adoc deleted file mode 100644 index 84eae160..00000000 --- a/ci/images/README.adoc +++ /dev/null @@ -1,21 +0,0 @@ -== CI Images - -These images are used by CI to run the actual builds. - -To build the image locally run the following from this directory: - ----- -$ docker build --no-cache -f /Dockerfile . ----- - -For example - ----- -$ docker build --no-cache -f spring-boot-ci-image/Dockerfile . ----- - -To test run: - ----- -$ docker run -it --entrypoint /bin/bash ✈ ----- diff --git a/ci/images/docker-lib.sh b/ci/images/docker-lib.sh deleted file mode 100755 index 4c7b1d58..00000000 --- a/ci/images/docker-lib.sh +++ /dev/null @@ -1,112 +0,0 @@ -# Based on: https://github.com/concourse/docker-image-resource/blob/master/assets/common.sh - -DOCKER_LOG_FILE=${DOCKER_LOG_FILE:-/tmp/docker.log} -SKIP_PRIVILEGED=${SKIP_PRIVILEGED:-false} -STARTUP_TIMEOUT=${STARTUP_TIMEOUT:-120} - -sanitize_cgroups() { - mkdir -p /sys/fs/cgroup - mountpoint -q /sys/fs/cgroup || \ - mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup - - mount -o remount,rw /sys/fs/cgroup - - sed -e 1d /proc/cgroups | while read sys hierarchy num enabled; do - if [ "$enabled" != "1" ]; then - # subsystem disabled; skip - continue - fi - - grouping="$(cat /proc/self/cgroup | cut -d: -f2 | grep "\\<$sys\\>")" || true - if [ -z "$grouping" ]; then - # subsystem not mounted anywhere; mount it on its own - grouping="$sys" - fi - - mountpoint="/sys/fs/cgroup/$grouping" - - mkdir -p "$mountpoint" - - # clear out existing mount to make sure new one is read-write - if mountpoint -q "$mountpoint"; then - umount "$mountpoint" - fi - - mount -n -t cgroup -o "$grouping" cgroup "$mountpoint" - - if [ "$grouping" != "$sys" ]; then - if [ -L "/sys/fs/cgroup/$sys" ]; then - rm "/sys/fs/cgroup/$sys" - fi - - ln -s "$mountpoint" "/sys/fs/cgroup/$sys" - fi - done - - if ! test -e /sys/fs/cgroup/systemd ; then - mkdir /sys/fs/cgroup/systemd - mount -t cgroup -o none,name=systemd none /sys/fs/cgroup/systemd - fi -} - -start_docker() { - mkdir -p /var/log - mkdir -p /var/run - - if [ "$SKIP_PRIVILEGED" = "false" ]; then - sanitize_cgroups - - # check for /proc/sys being mounted readonly, as systemd does - if grep '/proc/sys\s\+\w\+\s\+ro,' /proc/mounts >/dev/null; then - mount -o remount,rw /proc/sys - fi - fi - - local mtu=$(cat /sys/class/net/$(ip route get 8.8.8.8|awk '{ print $5 }')/mtu) - local server_args="--mtu ${mtu}" - local registry="" - - server_args="${server_args}" - - for registry in $3; do - server_args="${server_args} --insecure-registry ${registry}" - done - - if [ -n "$4" ]; then - server_args="${server_args} --registry-mirror $4" - fi - - try_start() { - dockerd --data-root /scratch/docker ${server_args} >$DOCKER_LOG_FILE 2>&1 & - echo $! > /tmp/docker.pid - - sleep 1 - - echo waiting for docker to come up... - until docker info >/dev/null 2>&1; do - sleep 1 - if ! kill -0 "$(cat /tmp/docker.pid)" 2>/dev/null; then - return 1 - fi - done - } - - export server_args DOCKER_LOG_FILE - declare -fx try_start - trap stop_docker EXIT - - if ! timeout ${STARTUP_TIMEOUT} bash -ce 'while true; do try_start && break; done'; then - echo Docker failed to start within ${STARTUP_TIMEOUT} seconds. - return 1 - fi -} - -stop_docker() { - local pid=$(cat /tmp/docker.pid) - if [ -z "$pid" ]; then - return 0 - fi - - kill -TERM $pid -} - diff --git a/ci/images/setup.sh b/ci/images/setup.sh deleted file mode 100755 index bd10576e..00000000 --- a/ci/images/setup.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -set -ex - -########################################################### -# UTILS -########################################################### - -apt-get update -apt-get install --no-install-recommends -y ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq -rm -rf /var/lib/apt/lists/* - -curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.2/concourse-java.sh > /opt/concourse-java.sh - - -########################################################### -# JAVA -########################################################### -JDK_URL="https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u212-b04/OpenJDK8U-jdk_x64_linux_hotspot_8u212b04.tar.gz" - -mkdir -p /opt/openjdk -cd /opt/openjdk -curl -L ${JDK_URL} | tar zx --strip-components=1 -test -f /opt/openjdk/bin/java -test -f /opt/openjdk/bin/javac - - -########################################################### -# DOCKER -########################################################### - -cd / -curl -L https://download.docker.com/linux/static/stable/x86_64/docker-18.06.1-ce.tgz | tar zx -mv /docker/* /bin/ -chmod +x /bin/docker* - -export ENTRYKIT_VERSION=0.4.0 -curl -L https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz | tar zx -chmod +x entrykit && \ -mv entrykit /bin/entrykit && \ -entrykit --symlink diff --git a/ci/images/spring-javaformat-ci-image/Dockerfile b/ci/images/spring-javaformat-ci-image/Dockerfile deleted file mode 100644 index 669b31eb..00000000 --- a/ci/images/spring-javaformat-ci-image/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:bionic-20181018 - -ADD setup.sh /setup.sh -RUN ./setup.sh - -ENV JAVA_HOME /opt/openjdk -ENV PATH $JAVA_HOME/bin:$PATH -ADD docker-lib.sh /docker-lib.sh - -ENTRYPOINT [ "switch", "shell=/bin/bash", "--", "codep", "/bin/docker daemon" ] diff --git a/ci/parameters.yml b/ci/parameters.yml deleted file mode 100644 index 1c908148..00000000 --- a/ci/parameters.yml +++ /dev/null @@ -1,8 +0,0 @@ -github-repo: "https://github.com/spring-io/spring-javaformat.git" -github-repo-name: "spring-io/spring-javaformat" -docker-hub-organization: "springci" -artifactory-server: "https://repo.spring.io" -branch: "master" -build-name: "spring-javaformat" -bintray-subject: "spring" -bintray-repo: "jars" diff --git a/ci/pipeline.yml b/ci/pipeline.yml deleted file mode 100644 index 2c3bdbad..00000000 --- a/ci/pipeline.yml +++ /dev/null @@ -1,212 +0,0 @@ -resource_types: -- name: artifactory-resource - type: docker-image - source: - repository: springio/artifactory-resource - tag: 0.0.8 -- name: pull-request - type: docker-image - source: - repository: jtarchie/pr -resources: -- name: git-repo - type: git - icon: github-circle - source: - uri: ((github-repo)) - username: ((github-username)) - password: ((github-password)) - branch: ((branch)) - ignore_paths: ["ci/images/*"] -- name: git-pull-request - type: pull-request - icon: source-pull - source: - access_token: ((github-ci-pull-request-token)) - repo: ((github-repo-name)) - base: ((branch)) - ignore_paths: ["ci/*"] -- name: ci-images-git-repo - type: git - icon: github-circle - source: - uri: ((github-repo)) - branch: ((branch)) - paths: ["ci/images/*"] -- name: spring-javaformat-ci-image - type: docker-image - icon: docker - source: - repository: ((docker-hub-organization))/spring-javaformat-ci-image - username: ((docker-hub-username)) - password: ((docker-hub-password)) - tag: ((branch)) -- name: artifactory-repo - type: artifactory-resource - icon: package-variant - source: - uri: ((artifactory-server)) - username: ((artifactory-username)) - password: ((artifactory-password)) - build_name: ((build-name)) -- name: github-release - type: github-release - icon: briefcase-download - source: - owner: spring-io - repository: spring-javaformat - access_token: ((github-ci-release-token)) -jobs: -- name: build-spring-javaformat-ci-images - plan: - - get: ci-images-git-repo - trigger: true - - put: spring-javaformat-ci-image - params: - build: ci-images-git-repo/ci/images - dockerfile: ci-images-git-repo/ci/images/spring-javaformat-ci-image/Dockerfile -- name: build - serial: true - public: true - plan: - - get: spring-javaformat-ci-image - - get: git-repo - trigger: true - - do: - - task: build-project - privileged: true - timeout: 1h30m - image: spring-javaformat-ci-image - file: git-repo/ci/tasks/build-project.yml - - put: artifactory-repo - params: &artifactory-params - repo: libs-snapshot-local - build_number: "${BUILD_ID}" - folder: distribution-repository - build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}" - build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}" - disable_checksum_uploads: true -- name: build-pull-requests - serial: true - public: true - plan: - - get: spring-javaformat-ci-image - - get: git-repo - resource: git-pull-request - trigger: true - version: every - - do: - - put: git-pull-request - params: - path: git-repo - status: pending - - task: build-project - timeout: 1h30m - image: spring-javaformat-ci-image - file: git-repo/ci/tasks/build-pr-project.yml - on_success: - put: git-pull-request - params: - path: git-repo - status: success - on_failure: - put: git-pull-request - params: - path: git-repo - status: failure -- name: stage-release - serial: true - plan: - - get: spring-javaformat-ci-image - - get: git-repo - trigger: false - - task: stage - image: spring-javaformat-ci-image - file: git-repo/ci/tasks/stage.yml - params: - RELEASE_TYPE: RELEASE - - put: artifactory-repo - params: - <<: *artifactory-params - repo: libs-staging-local - - put: git-repo - params: - repository: stage-git-repo -- name: promote-release - serial: true - plan: - - get: spring-javaformat-ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [stage-release] - params: - save_build_info: true - - task: promote - image: spring-javaformat-ci-image - file: git-repo/ci/tasks/promote.yml - params: - RELEASE_TYPE: RELEASE - ARTIFACTORY_SERVER: ((artifactory-server)) - ARTIFACTORY_USERNAME: ((artifactory-username)) - ARTIFACTORY_PASSWORD: ((artifactory-password)) - BINTRAY_SUBJECT: ((bintray-subject)) - BINTRAY_REPO: ((bintray-repo)) -- name: sync-to-maven-central - serial: true - plan: - - get: spring-javaformat-ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [promote-release] - params: - save_build_info: true - - task: sync-to-maven-central - image: spring-javaformat-ci-image - file: git-repo/ci/tasks/sync-to-maven-central.yml - params: - BINTRAY_USERNAME: ((bintray-username)) - BINTRAY_API_KEY: ((bintray-api-key)) - BINTRAY_SUBJECT: ((bintray-subject)) - BINTRAY_REPO: ((bintray-repo)) - SONATYPE_USER_TOKEN: ((sonatype-user-token)) - SONATYPE_PASSWORD_TOKEN: ((sonatype-user-token-password)) - - task: generate-release-notes - file: git-repo/ci/tasks/generate-release-notes.yml - params: - GITHUB_USERNAME: ((github-username)) - GITHUB_TOKEN: ((github-ci-release-token)) - - put: github-release - params: - name: generated-release-notes/tag - tag: generated-release-notes/tag - body: generated-release-notes/release-notes.md -- name: publish-eclipse-update-site - serial: true - plan: - - get: spring-javaformat-ci-image - - get: git-repo - trigger: false - - get: artifactory-repo - trigger: false - passed: [sync-to-maven-central] - params: - save_build_info: true - - task: publish-eclipse-update-site - image: spring-javaformat-ci-image - file: git-repo/ci/tasks/publish-eclipse-update-site.yml - params: - BINTRAY_USERNAME: ((bintray-username)) - BINTRAY_API_KEY: ((bintray-api-key)) -groups: -- name: "Build" - jobs: ["build"] -- name: "Release" - jobs: ["stage-release", "promote-release", "sync-to-maven-central", "publish-eclipse-update-site"] -- name: "CI Images" - jobs: ["build-spring-javaformat-ci-images"] -- name: "Build Pull Requests" - jobs: ["build-pull-requests"] diff --git a/ci/scripts/build-project.sh b/ci/scripts/build-project.sh deleted file mode 100755 index bc833d36..00000000 --- a/ci/scripts/build-project.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e - -source $(dirname $0)/common.sh -repository=$(pwd)/distribution-repository - -pushd git-repo > /dev/null -run_maven clean deploy -U -Dfull -DaltDeploymentRepository=distribution::default::file://${repository} -popd > /dev/null diff --git a/ci/scripts/common.sh b/ci/scripts/common.sh deleted file mode 100644 index 0198d39a..00000000 --- a/ci/scripts/common.sh +++ /dev/null @@ -1,4 +0,0 @@ -source /opt/concourse-java.sh - -setup_symlinks -cleanup_maven_repo "io.spring.javaformat" diff --git a/ci/scripts/generate-release-notes.sh b/ci/scripts/generate-release-notes.sh deleted file mode 100755 index 50333908..00000000 --- a/ci/scripts/generate-release-notes.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -e - -version=$( cat version/version ) - -java -jar /github-release-notes-generator.jar \ - --releasenotes.github.username=${GITHUB_USERNAME} \ - --releasenotes.github.password=${GITHUB_TOKEN} \ - --releasenotes.github.organization=spring-io \ - --releasenotes.github.repository=spring-javaformat \ - ${version} generated-release-notes/release-notes.md - -echo ${version} > generated-release-notes/version -echo v${version} > generated-release-notes/tag diff --git a/ci/scripts/promote.sh b/ci/scripts/promote.sh deleted file mode 100755 index f555e16a..00000000 --- a/ci/scripts/promote.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -set -e - -source $(dirname $0)/common.sh - -buildName=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.name' ) -buildNumber=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.number' ) -groupId=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/\(.*\):.*:.*/\1/' ) -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) - - -if [[ ${RELEASE_TYPE} = "M" ]]; then - targetRepo="libs-milestone-local" -elif [[ ${RELEASE_TYPE} = "RC" ]]; then - targetRepo="libs-milestone-local" -elif [[ ${RELEASE_TYPE} = "RELEASE" ]]; then - targetRepo="libs-release-local" -else - echo "Unknown release type ${RELEASE_TYPE}" >&2; exit 1; -fi - -echo "Promoting ${buildName}/${buildNumber} to ${targetRepo}" - -curl \ - -s \ - --connect-timeout 240 \ - --max-time 900 \ - -u ${ARTIFACTORY_USERNAME}:${ARTIFACTORY_PASSWORD} \ - -H "Content-type:application/json" \ - -d "{\"status\": \"staged\", \"sourceRepo\": \"libs-staging-local\", \"targetRepo\": \"${targetRepo}\"}" \ - -f \ - -X \ - POST "${ARTIFACTORY_SERVER}/api/build/promote/${buildName}/${buildNumber}" > /dev/null || { echo "Failed to promote" >&2; exit 1; } - -if [[ ${RELEASE_TYPE} = "RELEASE" ]]; then - curl \ - -s \ - --connect-timeout 240 \ - --max-time 2700 \ - -u ${ARTIFACTORY_USERNAME}:${ARTIFACTORY_PASSWORD} \ - -H "Content-type:application/json" \ - -d "{\"sourceRepos\": [\"libs-release-local\"], \"targetRepo\" : \"spring-distributions\", \"async\":\"true\"}" \ - -f \ - -X \ - POST "${ARTIFACTORY_SERVER}/api/build/distribute/${buildName}/${buildNumber}" > /dev/null || { echo "Failed to distribute" >&2; exit 1; } - - echo "Waiting for artifacts to be published" - artifactsPublished=false - WAIT_TIME=5 - counter=0 - while [ $artifactsPublished == "false" ] && [ $counter -lt 120 ]; do - result=$( curl -s https://api.bintray.com/packages/"${BINTRAY_SUBJECT}"/"${BINTRAY_REPO}"/"${groupId}" ) - versions=$( echo "$result" | jq -r '.versions' ) - exists=$( echo "$versions" | grep "$version" -o || true ) - if [ "$exists" = "$version" ]; then - artifactsPublished=true - fi - counter=$(( counter + 1 )) - sleep $WAIT_TIME - done - if [[ $artifactsPublished = "false" ]]; then - echo "Failed to publish" - exit 1 - else - curl \ - -s \ - -u ${BINTRAY_USERNAME}:${BINTRAY_API_KEY} \ - -H "Content-Type: application/json" \ - -d '[ { "name": "gradle-plugin", "values": ["io.spring.javaformat:io.spring.javaformat:spring-javaformat-gradle-plugin"] } ]' \ - -X POST \ - https://api.bintray.com/packages/${BINTRAY_SUBJECT}/${BINTRAY_REPO}/${groupId}/versions/${version}/attributes > /dev/null || { echo "Failed to add attributes" >&2; exit 1; } - fi -fi - - -echo "Promotion complete" diff --git a/ci/scripts/publish-eclipse-update-site.sh b/ci/scripts/publish-eclipse-update-site.sh deleted file mode 100755 index 507ee3fa..00000000 --- a/ci/scripts/publish-eclipse-update-site.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -set -e - -source $(dirname $0)/common.sh - -buildName=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.name' ) -buildNumber=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.number' ) -groupId=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/\(.*\):.*:.*/\1/' ) -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) - -echo "Publishing ${buildName}/${buildNumber} to Eclipse Update Site" -# We need to push twice for some reason otherwise we get out of date versions -for i in {1..2}; do - curl \ - -s \ - --connect-timeout 240 \ - --max-time 2700 \ - -u ${BINTRAY_USERNAME}:${BINTRAY_API_KEY} \ - -f \ - -X PUT \ - -T "artifactory-repo/io/spring/javaformat/io.spring.javaformat.eclipse.site/${version}/io.spring.javaformat.eclipse.site-${version}.zip" \ - "https://api.bintray.com/content/spring/javaformat-eclipse/update-site/${version}/${version}/site.zip?explode=1&publish=1" > /dev/null || { echo "Failed to publish" >&2; exit 1; } - releasedVersions=$( curl -f -X GET https://api.bintray.com/packages/spring/javaformat-eclipse/update-site | jq -r '.versions[]' ) - sleep 30 -done - -respositories="" -while read -r releasedVersion; do - echo "Adding repository for ${releasedVersion}" - respositories="${respositories}https://dl.bintray.com/spring/javaformat-eclipse/${releasedVersion}p2" -done <<< "${releasedVersions}" - -pushd git-repo > /dev/null -sed "s|##respositories##|${respositories}|" ci/scripts/publish-eclipse-update-site-pom-template.xml > publish-eclipse-update-site-pom.xml -run_maven -f publish-eclipse-update-site-pom.xml clean package || { echo "Failed to publish" >&2; exit 1; } - -curl \ - -s \ - --connect-timeout 240 \ - --max-time 2700 \ - -u ${BINTRAY_USERNAME}:${BINTRAY_API_KEY} \ - -f \ - -X PUT \ - -T "target/repository/content.jar" \ - "https://api.bintray.com/content/spring/javaformat-eclipse/content.jar" > /dev/null || { echo "Failed to publish" >&2; exit 1; } - -curl \ - -s \ - --connect-timeout 240 \ - --max-time 2700 \ - -u ${BINTRAY_USERNAME}:${BINTRAY_API_KEY} \ - -f \ - -X PUT \ - -T "target/repository/artifacts.jar" \ - "https://api.bintray.com/content/spring/javaformat-eclipse/artifacts.jar" > /dev/null || { echo "Failed to publish" >&2; exit 1; } - -popd > /dev/null - -echo "Publish complete" diff --git a/ci/scripts/stage.sh b/ci/scripts/stage.sh deleted file mode 100755 index cd61a0b7..00000000 --- a/ci/scripts/stage.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -e - -source $(dirname $0)/common.sh -repository=$(pwd)/distribution-repository - -pushd git-repo > /dev/null -git fetch --tags --all > /dev/null -popd > /dev/null - -git clone git-repo stage-git-repo > /dev/null - -pushd stage-git-repo > /dev/null - -snapshotVersion=$( xmllint --xpath '/*[local-name()="project"]/*[local-name()="version"]/text()' pom.xml ) -if [[ ${RELEASE_TYPE} = "RELEASE" ]]; then - stageVersion=$( strip_snapshot_suffix $snapshotVersion) - nextVersion=$( bump_version_number $snapshotVersion) -else - echo "Unknown release type ${RELEASE_TYPE}" >&2; exit 1; -fi - -echo "Staging ${stageVersion} (next version will be ${nextVersion})" -run_maven versions:set -DnewVersion=${stageVersion} -DgenerateBackupPoms=false -run_maven org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata - -git config user.name "Spring Buildmaster" > /dev/null -git config user.email "buildmaster@springframework.org" > /dev/null -git add pom.xml > /dev/null -git commit -m"Release v${stageVersion}" > /dev/null -git tag -a "v${stageVersion}" -m"Release v${stageVersion}" > /dev/null - -run_maven clean deploy -U -Dfull -DaltDeploymentRepository=distribution::default::file://${repository} - -git reset --hard HEAD^ > /dev/null -echo "Setting next development version (v$nextVersion)" -run_maven versions:set -DnewVersion=$nextVersion -DgenerateBackupPoms=false -run_maven org.eclipse.tycho:tycho-versions-plugin:update-eclipse-metadata -sed -i "s/:release-version:.*/:release-version: ${stageVersion}/g" README.adoc -sed -i "s/spring-javaformat-gradle-plugin:.*/spring-javaformat-gradle-plugin:${nextVersion}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle -sed -i "s/spring-javaformat-checkstyle:.*/spring-javaformat-checkstyle:${nextVersion}\"\)/g" samples/spring-javaformat-gradle-sample/build.gradle -sed -i "s|.*|${nextVersion}|" samples/spring-javaformat-maven-sample/pom.xml -git add -u . > /dev/null -git commit -m"Next development version (v${nextVersion})" > /dev/null - -echo "DONE" - -popd > /dev/null diff --git a/ci/scripts/sync-to-maven-central.sh b/ci/scripts/sync-to-maven-central.sh deleted file mode 100755 index 0692c057..00000000 --- a/ci/scripts/sync-to-maven-central.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e - -buildName=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.name' ) -buildNumber=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.number' ) -groupId=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/\(.*\):.*:.*/\1/' ) -version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) - -echo "Syncing ${buildName}/${buildNumber} to Maven Central" - curl \ - -s \ - --connect-timeout 240 \ - --max-time 2700 \ - -u ${BINTRAY_USERNAME}:${BINTRAY_API_KEY} \ - -H "Content-Type: application/json" -d "{\"username\": \"${SONATYPE_USER_TOKEN}\", \"password\": \"${SONATYPE_PASSWORD_TOKEN}\"}" \ - -f \ - -X \ - POST "https://api.bintray.com/maven_central_sync/${BINTRAY_SUBJECT}/${BINTRAY_REPO}/${groupId}/versions/${version}" > /dev/null || { echo "Failed to sync" >&2; exit 1; } -echo "Sync complete" -echo $version > version/version \ No newline at end of file diff --git a/ci/tasks/build-pr-project.yml b/ci/tasks/build-pr-project.yml deleted file mode 100644 index 9430bc00..00000000 --- a/ci/tasks/build-pr-project.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -platform: linux -inputs: -- name: git-repo -outputs: -- name: distribution-repository -caches: -- path: maven -- path: gradle -run: - path: git-repo/ci/scripts/build-project.sh \ No newline at end of file diff --git a/ci/tasks/build-project.yml b/ci/tasks/build-project.yml deleted file mode 100644 index 649e2e4b..00000000 --- a/ci/tasks/build-project.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -platform: linux -inputs: -- name: git-repo -outputs: -- name: distribution-repository -caches: -- path: maven -- path: gradle -run: - path: bash - args: - - -ec - - | - source /docker-lib.sh - start_docker - ${PWD}/git-repo/ci/scripts/build-project.sh - diff --git a/ci/tasks/generate-release-notes.yml b/ci/tasks/generate-release-notes.yml deleted file mode 100644 index dc078363..00000000 --- a/ci/tasks/generate-release-notes.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -platform: linux -image_resource: - type: docker-image - source: - repository: springio/github-release-notes-generator - tag: '0.0.2' -inputs: -- name: git-repo -- name: version -outputs: -- name: generated-release-notes -params: - GITHUB_USERNAME: - GITHUB_TOKEN: -run: - path: git-repo/ci/scripts/generate-release-notes.sh diff --git a/ci/tasks/promote.yml b/ci/tasks/promote.yml deleted file mode 100644 index 3b27505b..00000000 --- a/ci/tasks/promote.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -platform: linux -inputs: -- name: git-repo -- name: artifactory-repo -params: - RELEASE_TYPE: - ARTIFACTORY_SERVER: - ARTIFACTORY_USERNAME: - ARTIFACTORY_PASSWORD: - BINTRAY_SUBJECT: - BINTRAY_REPO: -run: - path: git-repo/ci/scripts/promote.sh diff --git a/ci/tasks/publish-eclipse-update-site.yml b/ci/tasks/publish-eclipse-update-site.yml deleted file mode 100644 index 080e429f..00000000 --- a/ci/tasks/publish-eclipse-update-site.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -platform: linux -inputs: -- name: git-repo -- name: artifactory-repo -params: - BINTRAY_USERNAME: - BINTRAY_API_KEY: -run: - path: git-repo/ci/scripts/publish-eclipse-update-site.sh diff --git a/ci/tasks/stage.yml b/ci/tasks/stage.yml deleted file mode 100644 index 191af62c..00000000 --- a/ci/tasks/stage.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -platform: linux -inputs: -- name: git-repo -outputs: -- name: stage-git-repo -- name: distribution-repository -caches: -- path: maven -- path: gradle -params: - RELEASE_TYPE: -run: - path: git-repo/ci/scripts/stage.sh diff --git a/ci/tasks/sync-to-maven-central.yml b/ci/tasks/sync-to-maven-central.yml deleted file mode 100644 index 49a95f03..00000000 --- a/ci/tasks/sync-to-maven-central.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -platform: linux -inputs: -- name: git-repo -- name: artifactory-repo -outputs: -- name: version -params: - BINTRAY_USERNAME: - BINTRAY_API_KEY: - BINTRAY_SUBJECT: - BINTRAY_REPO: - SONATYPE_USER_TOKEN: - SONATYPE_PASSWORD_TOKEN: -run: - path: git-repo/ci/scripts/sync-to-maven-central.sh diff --git a/mvnw b/mvnw index d560832b..b7f06462 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# https://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.1.1 # # Required ENV vars: # ------------------ @@ -27,7 +27,6 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -36,6 +35,10 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi @@ -58,9 +61,9 @@ case "`uname`" in # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" + JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME else - export JAVA_HOME="/Library/Java/Home" + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME fi fi ;; @@ -72,36 +75,8 @@ if [ -z "$JAVA_HOME" ] ; then fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` [ -n "$CLASSPATH" ] && @@ -110,8 +85,6 @@ fi # For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" [ -n "$JAVA_HOME" ] && JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" fi @@ -145,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`which java`" + JAVACMD="`\\unset -f command; \\command -v java`" fi fi @@ -159,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" @@ -184,7 +154,7 @@ find_maven_basedir() { fi # end of workaround done - echo "${basedir}" + printf '%s' "$(cd "$basedir"; pwd)" } # concatenates all lines of a file @@ -194,11 +164,16 @@ concat_lines() { fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +BASE_DIR=$(find_maven_basedir "$(dirname $0)") if [ -z "$BASE_DIR" ]; then exit 1; fi +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. @@ -212,16 +187,16 @@ else echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." fi if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" fi while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;; esac done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" + echo "Downloading from: $wrapperUrl" fi wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" if $cygwin; then @@ -229,42 +204,49 @@ else fi if command -v wget > /dev/null; then + QUIET="--quiet" if [ "$MVNW_VERBOSE" = true ]; then echo "Found wget ... using wget" + QUIET="" fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" fi + [ $? -eq 0 ] || rm -f "$wrapperJarPath" elif command -v curl > /dev/null; then + QUIET="--silent" if [ "$MVNW_VERBOSE" = true ]; then echo "Found curl ... using curl" + QUIET="" fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L fi - + [ $? -eq 0 ] || rm -f "$wrapperJarPath" else if [ "$MVNW_VERBOSE" = true ]; then echo "Falling back to using Java to download" fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" # For Cygwin, switch paths to Windows format before running javac if $cygwin; then + javaSource=`cygpath --path --windows "$javaSource"` javaClass=`cygpath --path --windows "$javaClass"` fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then if [ "$MVNW_VERBOSE" = true ]; then echo " - Compiling MavenWrapperDownloader.java ..." fi # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") + ("$JAVA_HOME/bin/javac" "$javaSource") fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ -e "$javaClass" ]; then # Running the downloader if [ "$MVNW_VERBOSE" = true ]; then echo " - Running MavenWrapperDownloader.java ..." @@ -278,16 +260,10 @@ fi # End of extension ########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` [ -n "$CLASSPATH" ] && @@ -296,10 +272,16 @@ if $cygwin; then MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 index d06ac67f..cba1f040 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,172 +1,187 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" - ) - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.1.1 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 10aa5d0b..c07e765a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,11 +5,11 @@ 4.0.0 io.spring.javaformat spring-javaformat-build - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT pom Spring JavaFormat Build Spring JavaFormat - https://github.com/spring-io/spring-javaformat/# + https://github.com/spring-io/spring-javaformat/ Apache License, Version 2.0 @@ -31,40 +31,48 @@ ${basedir} UTF-8 1.8 - https://download.eclipse.org/releases/2019-12/201912181000/ - https://dl.bintray.com/eclipse-cs/eclipse-cs/8.18.0 + https://download.eclipse.org/releases/2021-03/202103171000/ + https://download.eclipse.org/releases/2024-03/202403131000/ + https://checkstyle.org/eclipse-cs-update-site/ true 1.8.1 1.0b3 - 5.2 + 9.6 3.8.0 - 8.29 - 3.4 - 2.4.7 - 3.5.0 + 9.3 + 2.4.21 + 2.17.1 + 3.8.8 ${maven-core.version} - 3.5 - 2.8.47 - 4.12 + 3.8.2 + 3.6.28 + 5.8.1 3.21.0-GA 1.2 + 4.0.3 1.16.0 + 1.16.0 3.0.3 - 1.4.0 - 1.4.0 + 4.0.4 + 4.0.4 + + com.github.eirslett + frontend-maven-plugin + 1.12.1 + com.github.wvengen proguard-maven-plugin - 2.0.14 + 2.6.0 - net.sf.proguard - proguard-base - 5.3 + com.guardsquare + proguard-core + 9.0.7 runtime @@ -72,17 +80,17 @@ com.googlecode.maven-download-plugin download-maven-plugin - 1.4.1 + 1.6.8 org.apache.maven.plugins maven-antrun-plugin - 1.8 + 3.1.0 org.apache.maven.plugins maven-checkstyle-plugin - 3.1.0 + 3.2.1 com.puppycrawl.tools @@ -94,27 +102,27 @@ org.apache.maven.plugins maven-clean-plugin - 3.1.0 + 3.2.0 org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.10.1 org.apache.maven.plugins maven-deploy-plugin - 2.8.2 + 3.0.0 org.apache.maven.plugins maven-dependency-plugin - 3.1.1 + 3.5.0 org.apache.maven.plugins maven-failsafe-plugin - 2.22.1 + 2.22.2 @@ -127,37 +135,37 @@ org.apache.maven.plugins maven-install-plugin - 2.5.2 + 3.1.0 org.apache.maven.plugins maven-invoker-plugin - 3.2.0 + 3.4.0 org.apache.maven.plugins maven-jar-plugin - 3.1.1 + 3.3.0 org.apache.maven.plugins maven-plugin-plugin - 3.6.0 + 3.7.1 org.apache.maven.plugins maven-shade-plugin - 3.2.1 + 3.4.1 org.apache.maven.plugins maven-site-plugin - 3.7.1 + 3.12.1 org.apache.maven.plugins maven-surefire-plugin - 2.22.1 + 2.22.2 **/*Tests.java @@ -171,32 +179,36 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.2.1 org.apache.maven.plugins maven-javadoc-plugin - 3.1.0 + 3.4.1 + + 8 + -Xdoclint:none + org.apache.maven.plugins maven-resources-plugin - 3.1.0 + 3.3.0 org.codehaus.mojo versions-maven-plugin - 2.7 + 2.14.2 org.codehaus.mojo exec-maven-plugin - 1.6.0 + 3.1.0 org.codehaus.mojo build-helper-maven-plugin - 3.0.0 + 3.3.0 org.eclipse.tycho @@ -212,7 +224,8 @@ **/Abstract*.java ${ui.test.vmargs} - 7200 + 7200 + false @@ -222,16 +235,14 @@ ${tycho.version} - org.eclipse.tycho.extras + org.eclipse.tycho tycho-buildtimestamp-jgit - ${tycho-extras.version} + ${tycho.version} jgit - - pom.xml - + pom.xml warning @@ -279,6 +290,11 @@ cocoa x86_64 + + macosx + cocoa + aarch64 + @@ -304,53 +320,35 @@ - - org.apache.maven.plugins - - - maven-checkstyle-plugin - - - [2.17,) - + org.apache.maven.plugins + maven-checkstyle-plugin + [2.17,) check - + - - org.codehaus.mojo - - - flatten-maven-plugin - - - [1.0.0,) - + org.codehaus.mojo + flatten-maven-plugin + [1.0.0,) flatten - + - - org.eclipse.tycho - - - tycho-versions-plugin - - - [1.1.0,) - + org.eclipse.tycho + tycho-versions-plugin + [1.1.0,) update-eclipse-metadata @@ -358,22 +356,35 @@ - + + + + + + org.apache.maven.plugins + maven-antrun-plugin + [1.8,) + + run + + + + - org.apache.maven.plugins + com.github.eirslett - maven-antrun-plugin + frontend-maven-plugin - [1.8,) + [1.12.1,) - run + npx @@ -393,6 +404,11 @@ ${java.version} ${java.version} + -Werror + -Xlint:deprecation + -Xlint:rawtypes + -Xlint:unchecked + -Xlint:varargs @@ -450,7 +466,6 @@ src/checkstyle/checkstyle-suppressions.xml src/checkstyle/checkstyle-header.txt checkstyle.build.directory=${project.build.directory} - UTF-8 true true true @@ -466,9 +481,26 @@ - junit - junit - ${junit.version} + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + + + org.junit + junit-bom + 5.8.1 + pom + import com.puppycrawl.tools @@ -506,46 +538,6 @@ groovy ${groovy.version} - - org.gradle - gradle-base-services - ${gradle.version} - - - org.gradle - gradle-base-services-groovy - ${gradle.version} - - - org.gradle - gradle-core - ${gradle.version} - - - org.gradle - gradle-language-java - ${gradle.version} - - - org.gradle - gradle-language-jvm - ${gradle.version} - - - org.gradle - gradle-platform-jvm - ${gradle.version} - - - org.gradle - gradle-plugins - ${gradle.version} - - - org.gradle - gradle-tooling-api - ${gradle.version} - org.javassist javassist @@ -566,13 +558,28 @@ picocontainer ${picocontainer.version} + + org.codehaus.plexus + plexus-utils + ${plexus-utils.version} + + + org.testcontainers + testcontainers + ${testcontainers.version} + + + org.testcontainers + junit-jupiter + ${testcontainers.version} + - junit - junit + org.junit.jupiter + junit-jupiter test @@ -586,24 +593,13 @@ test - - - eclipse - p2 - ${eclipse.repository} - - - eclipse-checkstyle - p2 - ${eclipse.checkstyle.repository} - - spring-javaformat - spring-javaformat-maven - spring-javaformat-gradle spring-javaformat-eclipse - spring-javaformat-intellij + spring-javaformat-gradle + spring-javaformat-intellij-idea + spring-javaformat-maven + spring-javaformat-vscode @@ -615,7 +611,7 @@ - -Xmx512m -XX:MaxPermSize=256m -XstartOnFirstThread + -Xmx512m -XstartOnFirstThread @@ -627,7 +623,7 @@ - -Xmx512m -XX:MaxPermSize=256m + -Xmx512m diff --git a/samples/spring-javaformat-gradle-sample/build.gradle b/samples/spring-javaformat-gradle-sample/build.gradle index f33893db..3fa4c986 100644 --- a/samples/spring-javaformat-gradle-sample/build.gradle +++ b/samples/spring-javaformat-gradle-sample/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } dependencies { - classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.21-SNAPSHOT") + classpath("io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.48-SNAPSHOT") } } @@ -25,5 +25,5 @@ checkstyle { } dependencies { - checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.21-SNAPSHOT") + checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:0.0.48-SNAPSHOT") } diff --git a/samples/spring-javaformat-gradle-sample/gradle/wrapper/gradle-wrapper.properties b/samples/spring-javaformat-gradle-sample/gradle/wrapper/gradle-wrapper.properties index a452b450..4d9ca164 100644 --- a/samples/spring-javaformat-gradle-sample/gradle/wrapper/gradle-wrapper.properties +++ b/samples/spring-javaformat-gradle-sample/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Apr 26 21:27:14 PDT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip diff --git a/samples/spring-javaformat-gradle-sample/src/main/java/sample/SampleApplication.java b/samples/spring-javaformat-gradle-sample/src/main/java/sample/SampleApplication.java index a01d0bb3..480785d1 100644 --- a/samples/spring-javaformat-gradle-sample/src/main/java/sample/SampleApplication.java +++ b/samples/spring-javaformat-gradle-sample/src/main/java/sample/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/samples/spring-javaformat-maven-sample/.checkstyle b/samples/spring-javaformat-maven-sample/.checkstyle new file mode 100644 index 00000000..5783bc0d --- /dev/null +++ b/samples/spring-javaformat-maven-sample/.checkstyle @@ -0,0 +1,7 @@ + + + + + + + diff --git a/samples/spring-javaformat-maven-sample/pom.xml b/samples/spring-javaformat-maven-sample/pom.xml index 972bc27e..9354db42 100644 --- a/samples/spring-javaformat-maven-sample/pom.xml +++ b/samples/spring-javaformat-maven-sample/pom.xml @@ -8,7 +8,7 @@ 0.0.1-SNAPSHOT UTF-8 - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT diff --git a/samples/spring-javaformat-maven-sample/src/main/java/sample/SampleApplication.java b/samples/spring-javaformat-maven-sample/src/main/java/sample/SampleApplication.java index a01d0bb3..480785d1 100644 --- a/samples/spring-javaformat-maven-sample/src/main/java/sample/SampleApplication.java +++ b/samples/spring-javaformat-maven-sample/src/main/java/sample/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml index 060102a2..5204ad42 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/feature.xml @@ -2,7 +2,7 @@ @@ -22,7 +22,7 @@ id="io.spring.javaformat.eclipse" download-size="0" install-size="0" - version="0.0.21.qualifier" + version="0.0.48.qualifier" unpack="false"/> diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml index 32de4826..7b294c42 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.feature/pom.xml @@ -6,12 +6,13 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT io.spring.javaformat.eclipse.feature eclipse-feature - Spring JavaFormat Eclipse Feature + Spring JavaFormat Eclipse Plugin Feature ${basedir}/../.. + 17 diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml index 28aa0273..325568f3 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/category.xml @@ -3,7 +3,7 @@ Maven Integration for Eclipse (maven-eclipse-plugin support) - + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product index 48ddcdd7..4fc99abc 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/io.spring.javaformat.eclipse.product @@ -1,7 +1,7 @@ - + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml index 660fbb53..5d4e2f97 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.site/pom.xml @@ -6,13 +6,14 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT io.spring.javaformat.eclipse.site eclipse-repository - Spring JavaFormat Eclipse Site + Spring JavaFormat Eclipse Plugin Site ${basedir}/../.. + 17 @@ -21,7 +22,6 @@ tycho-packaging-plugin ${project.artifactId} - true diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF index 33d56a43..650cb7b0 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/META-INF/MANIFEST.MF @@ -1,15 +1,18 @@ Manifest-Version: 1.0 Fragment-Host: io.spring.javaformat.eclipse +Import-Package: org.junit, + org.junit.jupiter.api, + org.junit.jupiter.api.io Bundle-ManifestVersion: 2 -Bundle-Name: Spring Java Format Tests +Bundle-Name: Spring Java Format Plugin Tests Bundle-SymbolicName: io.spring.javaformat.eclipse.tests Automatic-Module-Name: io.spring.javaformat.eclipse.tests -Bundle-Version: 0.0.21.qualifier -Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Require-Bundle: org.junit;bundle-version="4.12" +Bundle-Version: 0.0.48.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ClassPath: ., lib/assertj-core.jar, lib/byte-buddy-agent.jar, lib/byte-buddy.jar, lib/mockito-core.jar, - lib/objenesis.jar + lib/objenesis.jar, + lib/junit-jupiter-api.jar diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/build.properties b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/build.properties index f084befe..b62f58dd 100755 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/build.properties +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/build.properties @@ -6,4 +6,5 @@ bin.includes = META-INF/,\ lib/byte-buddy-agent.jar,\ lib/byte-buddy.jar,\ lib/mockito-core.jar,\ - lib/objenesis.jar + lib/objenesis.jar,\ + lib/junit-jupiter-api.jar diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/.gitignore b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/.gitignore @@ -0,0 +1 @@ +* diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/assertj-core.jar b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/assertj-core.jar deleted file mode 100644 index 49976cdd..00000000 Binary files a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/assertj-core.jar and /dev/null differ diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/byte-buddy-agent.jar b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/byte-buddy-agent.jar deleted file mode 100644 index 350e6cc9..00000000 Binary files a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/byte-buddy-agent.jar and /dev/null differ diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/byte-buddy.jar b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/byte-buddy.jar deleted file mode 100644 index 04c0f847..00000000 Binary files a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/byte-buddy.jar and /dev/null differ diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/mockito-core.jar b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/mockito-core.jar deleted file mode 100644 index 2e10d748..00000000 Binary files a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/mockito-core.jar and /dev/null differ diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/objenesis.jar b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/objenesis.jar deleted file mode 100644 index 7b60a8b4..00000000 Binary files a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/lib/objenesis.jar and /dev/null differ diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml index 41d285a3..532aefb8 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/pom.xml @@ -6,13 +6,15 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT io.spring.javaformat.eclipse.tests eclipse-test-plugin Spring JavaFormat Eclipse Test ${basedir}/../.. + 17 + true @@ -26,4 +28,36 @@ runtime + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + empty-javadoc-jar + package + + jar + + + javadoc + + + + + + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/MessagesTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/MessagesTests.java index db7e978c..7684c764 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/MessagesTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/MessagesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ package io.spring.javaformat.eclipse; import org.eclipse.osgi.util.NLS; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -29,7 +29,7 @@ public class MessagesTests { @Test - public void bindHasCorrectMessage() { + void bindHasCorrectMessage() { String message = NLS.bind(Messages.springFormatSettingsImportError, "reason"); assertThat(message).isEqualTo("Error importing project specific settings: reason"); } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectPropertiesTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectPropertiesTests.java index 561f7917..a8568832 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectPropertiesTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,10 @@ import java.util.Properties; import java.util.stream.Collectors; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import io.spring.javaformat.config.JavaFormatConfig; import static org.assertj.core.api.Assertions.assertThat; @@ -39,52 +40,51 @@ */ public class ProjectPropertiesTests { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); + @TempDir + public File temp; @Test - public void addFromFolderAddsEclipseProperties() throws IOException { - File folder = this.temp.newFolder(); - File file = new File(folder, "eclipse.properties"); + void addFromFolderAddsEclipseProperties() throws IOException { + File file = new File(this.temp, "eclipse.properties"); writeProperties(file, "2018"); ProjectProperties properties = new ProjectProperties(); - properties.addFromFolder(folder); + properties.addFromFolder(this.temp); assertThat(properties.get("copyright-year")).isEqualTo("2018"); } @Test - public void addFromFolderWhenAlreadySetDoesNotOverwrite() throws IOException { + void addFromFolderWhenAlreadySetDoesNotOverwrite() throws IOException { ProjectProperties properties = new ProjectProperties(); - File folder = this.temp.newFolder(); - writeProperties(new File(folder, "eclipse.properties"), "2018"); - properties.addFromFolder(folder); - folder = this.temp.newFolder(); - writeProperties(new File(folder, "eclipse.properties"), "2017"); - properties.addFromFolder(folder); + File folder1 = new File(this.temp, "1"); + folder1.mkdirs(); + writeProperties(new File(folder1, "eclipse.properties"), "2018"); + properties.addFromFolder(folder1); + File folder2 = new File(this.temp, "2"); + folder2.mkdirs(); + writeProperties(new File(folder2, "eclipse.properties"), "2017"); + properties.addFromFolder(folder2); assertThat(properties.get("copyright-year")).isEqualTo("2018"); } @Test - public void addFromEmptyFolderUsesDefaults() throws IOException { + void addFromEmptyFolderUsesDefaults() throws IOException { ProjectProperties properties = new ProjectProperties(); - File folder = this.temp.newFolder(); - properties.addFromFolder(folder); + properties.addFromFolder(this.temp); String currentYear = String.valueOf(LocalDate.now().getYear()); assertThat(properties.get("copyright-year")).isEqualTo(currentYear); } @Test - public void getModifiedContentReplacesCopyrightYear() throws IOException { - File folder = this.temp.newFolder(); - File file = new File(folder, "eclipse.properties"); - writeProperties(file, "2016-2020"); + void getModifiedContentReplacesCopyrightYear() throws IOException { + String year = "2016-2020"; + File file = new File(this.temp, "eclipse.properties"); + writeProperties(file, year); ProjectProperties properties = new ProjectProperties(); - properties.addFromFolder(folder); + properties.addFromFolder(this.temp); ProjectSettingsFiles files = new ProjectSettingsFilesLocator().locateSettingsFiles(); ProjectSettingsFile prefs = getFile(files, "org.eclipse.jdt.ui.prefs"); - String content = loadContent(properties.getModifiedContent(prefs)); - assertThat(content).contains("Copyright 2016-2020 the original author or authors"); - + String content = loadContent(properties.getModifiedContent(prefs).getContent(JavaFormatConfig.DEFAULT)); + assertThat(content).contains("Copyright " + year + " the original author or authors"); } private ProjectSettingsFile getFile(ProjectSettingsFiles files, String name) { diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFileTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFileTests.java index 50108817..769226b6 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFileTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFileTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,10 @@ import java.io.FileNotFoundException; import java.io.PrintWriter; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import io.spring.javaformat.config.JavaFormatConfig; import static org.assertj.core.api.Assertions.assertThat; @@ -34,23 +35,25 @@ */ public class ProjectSettingsFileTests { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); + @TempDir + public File temp; @Test - public void fromFileAdaptsFile() throws Exception { - File file = this.temp.newFile(); + void fromFileAdaptsFile() throws Exception { + File file = new File(this.temp, "file"); writeText(file, "test"); ProjectSettingsFile projectSettingsFile = ProjectSettingsFile.fromFile(file); assertThat(projectSettingsFile.getName()).isEqualTo(file.getName()); - assertThat(projectSettingsFile.getContent()).hasSameContentAs(new ByteArrayInputStream("test".getBytes())); + assertThat(projectSettingsFile.getContent(JavaFormatConfig.DEFAULT)) + .hasSameContentAs(new ByteArrayInputStream("test".getBytes())); } @Test - public void fromClasspathResourceAdaptsResource() throws Exception { + void fromClasspathResourceAdaptsResource() throws Exception { ProjectSettingsFile projectSettingsFile = ProjectSettingsFile.fromClasspath(getClass(), "test.txt"); assertThat(projectSettingsFile.getName()).isEqualTo("test.txt"); - assertThat(projectSettingsFile.getContent()).hasSameContentAs(new ByteArrayInputStream("test".getBytes())); + assertThat(projectSettingsFile.getContent(JavaFormatConfig.DEFAULT)) + .hasSameContentAs(new ByteArrayInputStream("test".getBytes())); } private void writeText(File file, String s) throws FileNotFoundException { diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java index 326fa114..26ca3380 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,18 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; import static org.assertj.core.api.Assertions.assertThat; @@ -36,39 +41,72 @@ */ public class ProjectSettingsFilesLocatorTests { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); + @TempDir + public File temp; @Test - public void locateSettingsFilesWhenNoFoldersShouldReturnDefault() throws IOException { + void locateSettingsFilesWhenNoFoldersReturnsDefault() throws IOException { ProjectSettingsFiles files = new ProjectSettingsFilesLocator().locateSettingsFiles(); - assertThat(files.iterator()).extracting(ProjectSettingsFile::getName).containsOnly("org.eclipse.jdt.core.prefs", - "org.eclipse.jdt.ui.prefs"); + assertThat(files.iterator()).extracting(ProjectSettingsFile::getName) + .containsOnly("org.eclipse.jdt.core.prefs", "org.eclipse.jdt.ui.prefs"); } @Test - public void locateSettingsFilesOnlyFindPrefs() throws Exception { - File folder = this.temp.newFolder(); - writeFile(folder, "foo.prefs"); - writeFile(folder, "bar.notprefs"); - ProjectSettingsFiles files = new ProjectSettingsFilesLocator(folder).locateSettingsFiles(); - assertThat(files.iterator()).extracting(ProjectSettingsFile::getName).containsOnly("org.eclipse.jdt.core.prefs", - "org.eclipse.jdt.ui.prefs", "foo.prefs"); + void locateSettingsFilesOnlyFindPrefs() throws Exception { + writeFile(this.temp, "foo.prefs"); + writeFile(this.temp, "bar.notprefs"); + ProjectSettingsFiles files = new ProjectSettingsFilesLocator(this.temp).locateSettingsFiles(); + assertThat(files.iterator()).extracting(ProjectSettingsFile::getName) + .containsOnly("org.eclipse.jdt.core.prefs", "org.eclipse.jdt.ui.prefs", "foo.prefs"); } @Test - public void locateSettingsFilesWhenMultipleFoldersFindsInEarliest() throws Exception { - File folder1 = this.temp.newFolder(); + void locateSettingsFilesWhenMultipleFoldersFindsInEarliest() throws Exception { + File folder1 = new File(this.temp, "1"); writeFile(folder1, "foo.prefs", "foo1"); - File folder2 = this.temp.newFolder(); + File folder2 = new File(this.temp, "2"); writeFile(folder2, "foo.prefs", "foo2"); writeFile(folder2, "org.eclipse.jdt.core.prefs", "core2"); ProjectSettingsFiles files = new ProjectSettingsFilesLocator(folder1, folder2).locateSettingsFiles(); Map found = new LinkedHashMap<>(); files.iterator().forEachRemaining((f) -> found.put(f.getName(), f)); - assertThat(found.get("foo.prefs").getContent()).hasSameContentAs(new ByteArrayInputStream("foo1".getBytes())); - assertThat(found.get("org.eclipse.jdt.core.prefs").getContent()) - .hasSameContentAs(new ByteArrayInputStream("core2".getBytes())); + assertThat(found.get("foo.prefs").getContent(JavaFormatConfig.DEFAULT)) + .hasSameContentAs(new ByteArrayInputStream("foo1".getBytes())); + assertThat(found.get("org.eclipse.jdt.core.prefs").getContent(JavaFormatConfig.DEFAULT)) + .hasSameContentAs(new ByteArrayInputStream("core2".getBytes())); + } + + @Test + void jdtCorePrefsFormatterWhenDefaultUsesTabs() throws IOException { + ProjectSettingsFiles files = new ProjectSettingsFilesLocator().locateSettingsFiles(); + ProjectSettingsFile file = get(files, "org.eclipse.jdt.core.prefs"); + try (InputStream content = file.getContent(JavaFormatConfig.DEFAULT)) { + Properties properties = new Properties(); + properties.load(content); + assertThat(properties.get("org.eclipse.jdt.core.javaFormatter")) + .isEqualTo("io.spring.javaformat.eclipse.formatter.jdk17.tabs"); + } + } + + @Test + void jdtCorePrefsFormatterWhenSpacesUsesSpaces() throws IOException { + ProjectSettingsFiles files = new ProjectSettingsFilesLocator().locateSettingsFiles(); + ProjectSettingsFile file = get(files, "org.eclipse.jdt.core.prefs"); + try (InputStream content = file.getContent(JavaFormatConfig.of(JavaBaseline.V8, IndentationStyle.SPACES))) { + Properties properties = new Properties(); + properties.load(content); + assertThat(properties.get("org.eclipse.jdt.core.javaFormatter")) + .isEqualTo("io.spring.javaformat.eclipse.formatter.jdk8.spaces"); + } + } + + private ProjectSettingsFile get(ProjectSettingsFiles files, String name) { + for (ProjectSettingsFile file : files) { + if (file.getName().equals(name)) { + return file; + } + } + return null; } private void writeFile(File folder, String name) throws IOException { diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java index 61bca52a..a5eb2ed1 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse.tests/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,28 @@ package io.spring.javaformat.eclipse.projectsettings; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.Collections; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.will; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -40,27 +48,62 @@ */ public class ProjectSettingsFilesTests { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); + @TempDir + public File temp; @Test - public void iteratorIteratesFiles() throws Exception { - ProjectSettingsFile file = ProjectSettingsFile.fromFile(this.temp.newFile()); + void iteratorIteratesFiles() throws Exception { + ProjectSettingsFile file = ProjectSettingsFile.fromFile(new File(this.temp, "file.prefs")); ProjectSettingsFiles files = new ProjectSettingsFiles(Collections.singleton(file), new ProjectProperties()); assertThat(files).containsOnly(file); } @Test - public void applyToProjectCopiesToDotSettings() throws Exception { - ProjectSettingsFile file = ProjectSettingsFile.fromFile(this.temp.newFile("foo.prefs")); + void applyToProjectWithoutFileCopiesToDotSettings() throws Exception { + ProjectSettingsFile file = createPrefsFile(); + ProjectSettingsFiles files = new ProjectSettingsFiles(Collections.singleton(file), new ProjectProperties()); + IProject project = mock(IProject.class); + IProgressMonitor monitor = mock(IProgressMonitor.class); + IFile projectFile = mock(IFile.class); + given(project.getFile(".settings/foo.prefs")).willReturn(projectFile); + given(projectFile.exists()).willReturn(false); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + will((invocation) -> { + invocation.getArgument(0, InputStream.class).transferTo(out); + return null; + }).given(projectFile).create(any(), anyBoolean(), any()); + files.applyToProject(project, monitor); + verify(projectFile).create(any(), eq(true), any()); + assertThat(out.toString(StandardCharsets.UTF_8)).isEqualTo("y=z\n"); + } + + @Test + void applyToProjectWithFileMergesToDotSettings() throws Exception { + ProjectSettingsFile file = createPrefsFile(); ProjectSettingsFiles files = new ProjectSettingsFiles(Collections.singleton(file), new ProjectProperties()); IProject project = mock(IProject.class); IProgressMonitor monitor = mock(IProgressMonitor.class); IFile projectFile = mock(IFile.class); given(project.getFile(".settings/foo.prefs")).willReturn(projectFile); given(projectFile.exists()).willReturn(true); + given(projectFile.getContents(true)) + .willReturn(new ByteArrayInputStream("a=b\n".getBytes(StandardCharsets.UTF_8))); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + will((invocation) -> { + invocation.getArgument(0, InputStream.class).transferTo(out); + return null; + }).given(projectFile).setContents((InputStream) any(), anyInt(), any()); files.applyToProject(project, monitor); verify(projectFile).setContents((InputStream) any(), eq(1), eq(monitor)); + assertThat(out.toString(StandardCharsets.UTF_8)) + .isEqualToNormalizingNewlines("a=b\ny=z\n"); + } + + private ProjectSettingsFile createPrefsFile() throws IOException { + File prefsFile = new File(this.temp, "foo.prefs"); + Files.copy(new ByteArrayInputStream("y=z\n".getBytes(StandardCharsets.UTF_8)), prefsFile.toPath()); + ProjectSettingsFile file = ProjectSettingsFile.fromFile(prefsFile); + return file; } } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF index 412d91ba..2e0f34c4 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/META-INF/MANIFEST.MF @@ -1,25 +1,26 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Spring Java Format +Bundle-Name: Spring Java Format Plugin Bundle-SymbolicName: io.spring.javaformat.eclipse;singleton:=true Automatic-Module-Name: io.spring.javaformat.eclipse -Bundle-Version: 0.0.21.qualifier +Bundle-Version: 0.0.48.qualifier Bundle-Activator: io.spring.javaformat.eclipse.Activator -Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-RequiredExecutionEnvironment: JavaSE-11 Require-Bundle: org.eclipse.ui, org.eclipse.core.resources, org.eclipse.core.runtime, org.eclipse.ui.ide, - org.slf4j.api;bundle-version="1.7.0", org.eclipse.jdt.core, org.eclipse.jface.text, org.eclipse.m2e.jdt;resolution:=optional, org.eclipse.m2e.core;resolution:=optional, org.eclipse.m2e.maven.runtime;resolution:=optional, - org.eclipse.buildship.core;bundle-version="[3.0.0,3.3.0)";resolution:=optional, - net.sf.eclipsecs.core;bundle-version="8.18.0";resolution:=optional + org.eclipse.buildship.core;resolution:=optional, + net.sf.eclipsecs.core;resolution:=optional Bundle-ClassPath: ., - lib/spring-javaformat-formatter-eclipse.jar, + lib/spring-javaformat-config.jar, lib/spring-javaformat-formatter.jar, - lib/spring-javaformat-checkstyle.jar + lib/spring-javaformat-checkstyle.jar, + lib/spring-javaformat-formatter-eclipse-jdt-jdk17.jar, + lib/spring-javaformat-formatter-eclipse-jdt-jdk8.jar Bundle-ActivationPolicy: lazy diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties index caa69f13..9bd6565a 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/build.properties @@ -3,7 +3,8 @@ bin.includes = META-INF/,\ .,\ plugin.xml,\ lifecycle-mapping-metadata.xml,\ - lib/spring-javaformat-formatter-eclipse.jar,\ - lib/spring-javaformat-formatter.jar, - lib/spring-javaformat-checkstyle.jar - + lib/spring-javaformat-checkstyle.jar,\ + lib/spring-javaformat-config.jar,\ + lib/spring-javaformat-formatter.jar,\ + lib/spring-javaformat-formatter-eclipse-jdt-jdk17.jar,\ + lib/spring-javaformat-formatter-eclipse-jdt-jdk8.jar diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml index bdcdc212..f9864bd4 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/plugin.xml @@ -3,39 +3,48 @@ + class="io.spring.javaformat.eclipse.formatter.SpringCodeFormatterJdk17Tabs" + id="io.spring.javaformat.eclipse.formatter.jdk17.tabs" + name="Spring (tabs)"> + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml index 3516d63e..3ccfe109 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/pom.xml @@ -6,16 +6,23 @@ io.spring.javaformat spring-javaformat-eclipse - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT io.spring.javaformat.eclipse eclipse-plugin - Spring JavaFormat Eclipse Parent + Spring JavaFormat Eclipse Plugin ${basedir}/../.. + 17 + + io.spring.javaformat + spring-javaformat-config + runtime + ${project.version} + io.spring.javaformat spring-javaformat-formatter @@ -29,4 +36,48 @@ ${project.version} + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + io.spring.javaformat + spring-javaformat-config + ${project.version} + + + io.spring.javaformat + spring-javaformat-formatter + ${project.version} + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-jdt-jdk8 + ${project.version} + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-jdt-jdk17 + ${project.version} + + + + + + diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java index 199c2e0c..bef6af6b 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Activator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,10 @@ package io.spring.javaformat.eclipse; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Plugin; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; @@ -33,17 +37,27 @@ public class Activator extends AbstractUIPlugin { private static Activator plugin; + private final List javaCorePlugins = new ArrayList<>(); + public Activator() { + this.javaCorePlugins.add(new io.spring.javaformat.eclipse.jdt.jdk8.core.JavaCore()); + this.javaCorePlugins.add(new io.spring.javaformat.eclipse.jdt.jdk17.core.JavaCore()); } @Override public void start(BundleContext context) throws Exception { super.start(context); plugin = this; + for (Plugin javaCorePlugin : this.javaCorePlugins) { + javaCorePlugin.start(context); + } } @Override public void stop(BundleContext context) throws Exception { + for (Plugin javaCorePlugin : this.javaCorePlugins) { + javaCorePlugin.stop(context); + } plugin = null; super.stop(context); } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Executor.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Executor.java index c5c0ec77..7782afd3 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Executor.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Executor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Messages.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Messages.java index 8db3c5dc..3fc7ab01 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Messages.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Startup.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Startup.java index bf20fc1a..c19e50e9 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Startup.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/Startup.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatter.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatter.java index fc0862da..d26d70bd 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatter.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,16 +22,21 @@ import org.eclipse.jface.text.IRegion; import org.eclipse.text.edits.TextEdit; +import io.spring.javaformat.config.JavaFormatConfig; import io.spring.javaformat.formatter.Formatter; /** - * Eclipse {@link CodeFormatter} for Spring formatting. + * Eclipse {@link CodeFormatter} base class for Spring formatting. * * @author Phillip Webb */ -public class SpringCodeFormatter extends CodeFormatter { +public abstract class SpringCodeFormatter extends CodeFormatter { - private Formatter delegate = new Formatter(); + private final Formatter delegate; + + public SpringCodeFormatter(JavaFormatConfig javaFormatConfig) { + this.delegate = new Formatter(javaFormatConfig); + } @Override public TextEdit format(int kind, String source, int offset, int length, int indentationLevel, diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Spaces.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Spaces.java new file mode 100644 index 00000000..d0682ff2 --- /dev/null +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Spaces.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.eclipse.formatter; + +import org.eclipse.jdt.core.formatter.CodeFormatter; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Eclipse {@link CodeFormatter} for Spring formatting with spaces. + * + * @author Phillip Webb + */ +public class SpringCodeFormatterJdk17Spaces extends SpringCodeFormatter { + + public SpringCodeFormatterJdk17Spaces() { + super(JavaFormatConfig.of(JavaBaseline.V17, IndentationStyle.SPACES)); + } + +} diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Tabs.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Tabs.java new file mode 100644 index 00000000..718e9846 --- /dev/null +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk17Tabs.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.eclipse.formatter; + +import org.eclipse.jdt.core.formatter.CodeFormatter; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Eclipse {@link CodeFormatter} for Spring formatting with tabs. + * + * @author Phillip Webb + */ +public class SpringCodeFormatterJdk17Tabs extends SpringCodeFormatter { + + public SpringCodeFormatterJdk17Tabs() { + super(JavaFormatConfig.of(JavaBaseline.V17, IndentationStyle.TABS)); + } + +} diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk8Spaces.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk8Spaces.java new file mode 100644 index 00000000..536c85ef --- /dev/null +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk8Spaces.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.eclipse.formatter; + +import org.eclipse.jdt.core.formatter.CodeFormatter; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Eclipse {@link CodeFormatter} for Spring formatting with spaces. + * + * @author Phillip Webb + */ +public class SpringCodeFormatterJdk8Spaces extends SpringCodeFormatter { + + public SpringCodeFormatterJdk8Spaces() { + super(JavaFormatConfig.of(JavaBaseline.V8, IndentationStyle.SPACES)); + } + +} diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk8Tabs.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk8Tabs.java new file mode 100644 index 00000000..0750be23 --- /dev/null +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/formatter/SpringCodeFormatterJdk8Tabs.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.eclipse.formatter; + +import org.eclipse.jdt.core.formatter.CodeFormatter; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Eclipse {@link CodeFormatter} for Spring formatting with tabs. + * + * @author Phillip Webb + */ +public class SpringCodeFormatterJdk8Tabs extends SpringCodeFormatter { + + public SpringCodeFormatterJdk8Tabs() { + super(JavaFormatConfig.of(JavaBaseline.V8, IndentationStyle.TABS)); + } + +} diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/gradle/GradleProjectSettingsConfigurator.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/gradle/GradleProjectSettingsConfigurator.java index 0984935d..9ab4bb69 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/gradle/GradleProjectSettingsConfigurator.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/gradle/GradleProjectSettingsConfigurator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.Collection; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -76,8 +77,7 @@ private void configureProject(IProject project, IProgressMonitor monitor) throws Optional build = workspace.getBuild(project); if (build.isPresent()) { ModelProvider modelProvider = ((InternalGradleBuild) build.get()).getModelProvider(); - Collection rootProjects = modelProvider.fetchModels(EclipseProject.class, - FetchStrategy.FORCE_RELOAD, this.tokenSource, monitor); + Collection rootProjects = getRootProjects(monitor, modelProvider); EclipseProject eclipseProject = findProjectByName(rootProjects, project.getName()); if (hasSpringFormatPlugin(eclipseProject)) { ProjectSettingsFilesLocator locator = new ProjectSettingsFilesLocator(getSearchFolders(rootProjects)); @@ -86,6 +86,13 @@ private void configureProject(IProject project, IProgressMonitor monitor) throws } } + @SuppressWarnings("unchecked") + private Collection getRootProjects(IProgressMonitor monitor, ModelProvider modelProvider) { + Object models = modelProvider.fetchModels(EclipseProject.class, FetchStrategy.FORCE_RELOAD, this.tokenSource, + monitor); + return (Collection) ((models instanceof Map) ? ((Map) models).values() : models); + } + private EclipseProject findProjectByName(Iterable candidates, String name) { for (EclipseProject candidate : candidates) { if (name.equals(candidate.getName())) { diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/m2e/MavenProjectSettingsConfigurator.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/m2e/MavenProjectSettingsConfigurator.java index 5cc7aacd..62e94e26 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/m2e/MavenProjectSettingsConfigurator.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/m2e/MavenProjectSettingsConfigurator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,13 +43,13 @@ public void configure(ProjectConfigurationRequest request, IProgressMonitor moni new Executor(Messages.springFormatSettingsImportError).run(() -> { List searchFolders = getSearchFolders(request); ProjectSettingsFiles settingsFiles = new ProjectSettingsFilesLocator(searchFolders).locateSettingsFiles(); - settingsFiles.applyToProject(request.getProject(), monitor); + settingsFiles.applyToProject(request.mavenProjectFacade().getProject(), monitor); }); } private List getSearchFolders(ProjectConfigurationRequest request) { List files = new ArrayList<>(); - MavenProject project = request.getMavenProject(); + MavenProject project = request.mavenProject(); while (project != null && project.getBasedir() != null) { files.add(project.getBasedir()); project = project.getParent(); diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectProperties.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectProperties.java index d6cfc61e..982777bd 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectProperties.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,9 @@ package io.spring.javaformat.eclipse.projectsettings; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Collections; @@ -74,26 +68,13 @@ private void addFromProperties(Properties properties) { }); } - public InputStream getModifiedContent(ProjectSettingsFile file) throws IOException { + public ProjectSettingsFile getModifiedContent(ProjectSettingsFile file) throws IOException { if (file.getName().equals("org.eclipse.jdt.ui.prefs")) { - String content = loadContent(file); - content = content.replace("Copyright the original author or authors", - "Copyright " + get(COPYRIGHT_YEAR) + " the original author or authors"); - return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); - } - return file.getContent(); - } - - private String loadContent(ProjectSettingsFile file) throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContent()))) { - StringWriter writer = new StringWriter(); - char[] buffer = new char[4096]; - int read = 0; - while ((read = reader.read(buffer)) >= 0) { - writer.write(buffer, 0, read); - } - return writer.toString(); + return file.withUpdatedContent( + (javaFormatConfig, content) -> content.replace("Copyright the original author or authors", + "Copyright " + get(COPYRIGHT_YEAR) + " the original author or authors")); } + return file; } String get(String name) { diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFile.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFile.java index c7570b80..ec7ef383 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFile.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,18 @@ package io.spring.javaformat.eclipse.projectsettings; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.function.BiFunction; + +import io.spring.javaformat.config.JavaFormatConfig; /** * A project settings file that can be copied to the project {@code .settings} folder. @@ -32,7 +40,7 @@ final class ProjectSettingsFile { private final ContentSupplier contentSupplier; - private ProjectSettingsFile(String name, ContentSupplier contentSupplier) { + ProjectSettingsFile(String name, ContentSupplier contentSupplier) { this.name = name; this.contentSupplier = contentSupplier; } @@ -48,11 +56,34 @@ public String getName() { /** * Return a new {@link InputStream} that can be used to access the content of the * file. + * @param javaFormatConfig the java format config to apply * @return the file contents * @throws IOException if the file cannot be opened */ - public InputStream getContent() throws IOException { - return this.contentSupplier.getContent(); + public InputStream getContent(JavaFormatConfig javaFormatConfig) throws IOException { + return this.contentSupplier.getContent(javaFormatConfig); + } + + /** + * Return a new {@link ProjectSettingsFile} where the original content is updated by + * the given operation. + * @param operation the operation to update the content + * @return a new {@link ProjectSettingsFile} instance + */ + public ProjectSettingsFile withUpdatedContent(BiFunction operation) { + return new ProjectSettingsFile(this.name, (javaFormatConfig) -> { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(this.contentSupplier.getContent(javaFormatConfig)))) { + StringWriter writer = new StringWriter(); + char[] buffer = new char[4096]; + int read = 0; + while ((read = reader.read(buffer)) >= 0) { + writer.write(buffer, 0, read); + } + String content = operation.apply(javaFormatConfig, writer.toString()); + return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); + } + }); } /** @@ -61,7 +92,7 @@ public InputStream getContent() throws IOException { * @return a new {@link ProjectSettingsFile} */ public static ProjectSettingsFile fromFile(File file) { - return new ProjectSettingsFile(file.getName(), () -> new FileInputStream(file)); + return new ProjectSettingsFile(file.getName(), (javaFormatConfig) -> new FileInputStream(file)); } /** @@ -71,13 +102,13 @@ public static ProjectSettingsFile fromFile(File file) { * @return a new {@link ProjectSettingsFile} */ public static ProjectSettingsFile fromClasspath(Class sourceClass, String name) { - return new ProjectSettingsFile(name, () -> sourceClass.getResourceAsStream(name)); + return new ProjectSettingsFile(name, (javaFormatConfig) -> sourceClass.getResourceAsStream(name)); } @FunctionalInterface - private interface ContentSupplier { + interface ContentSupplier { - InputStream getContent() throws IOException; + InputStream getContent(JavaFormatConfig javaFormatConfig) throws IOException; } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFiles.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFiles.java index 270cf025..2b40f5ae 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFiles.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFiles.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,19 +17,32 @@ package io.spring.javaformat.eclipse.projectsettings; import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; +import io.spring.javaformat.config.JavaFormatConfig; + /** * A collection of {@link ProjectSettingsFile project setting files}. * @@ -64,17 +77,72 @@ public Iterator iterator() { * @throws CoreException on eclipse file creation failure */ public void applyToProject(IProject project, IProgressMonitor monitor) throws IOException, CoreException { + JavaFormatConfig javaFormatConfig = getJavaFormatConfig(project); for (ProjectSettingsFile file : this) { + file = this.projectProperties.getModifiedContent(file); IFile destination = project.getFile(".settings/" + file.getName()); - try (InputStream content = this.projectProperties.getModifiedContent(file)) { + try (InputStream content = file.getContent(javaFormatConfig)) { if (!destination.exists()) { destination.create(new BufferedInputStream(content), true, monitor); } else { - destination.setContents(new BufferedInputStream(content), IResource.FORCE, monitor); + Properties properties = new OrderedProperties(); + try (InputStream existingContent = destination.getContents(true)) { + if (existingContent != null) { + properties.load(existingContent); + } + } + properties.load(content); + destination.setContents( + new ByteArrayInputStream(stripTimestamp(properties).getBytes(StandardCharsets.UTF_8)), + IResource.FORCE, monitor); } } } } + private String stripTimestamp(Properties properties) throws IOException { + try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { + properties.store(output, null); + String string = output.toString(StandardCharsets.UTF_8); + String separator = System.getProperty("line.separator"); + return string.substring(string.indexOf(separator) + separator.length()); + } + } + + private JavaFormatConfig getJavaFormatConfig(IProject project) { + try { + IPath location = project.getLocation(); + File file = (location != null) ? location.toFile() : null; + return JavaFormatConfig.findFrom(file); + } + catch (Exception ex) { + return JavaFormatConfig.DEFAULT; + } + } + + static class OrderedProperties extends Properties { + + private static final long serialVersionUID = 1L; + + @Override + public Set> entrySet() { + Set> set = new TreeSet>(new MapEntryKeyComparator()); + set.addAll(super.entrySet()); + return set; + }; + + } + + private static class MapEntryKeyComparator implements Comparator> { + + @Override + public int compare(Entry o1, Entry o2) { + Object k1 = o1.getKey(); + Object k2 = o2.getKey(); + return String.valueOf(k1).compareTo(String.valueOf(k2)); + } + + } + } diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java index 78385a60..e5d5f412 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/ProjectSettingsFilesLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ import java.util.LinkedHashMap; import java.util.Map; +import io.spring.javaformat.config.JavaFormatConfig; + /** * Locates project settings files to be applied to projects. * @@ -29,9 +31,11 @@ */ public class ProjectSettingsFilesLocator { + private static final String JDT_CORE_PREFS = "org.eclipse.jdt.core.prefs"; + private static final String[] SOURCE_FOLDERS = { "eclipse", ".eclipse" }; - private static final String[] DEFAULT_FILES = { "org.eclipse.jdt.core.prefs", "org.eclipse.jdt.ui.prefs" }; + private static final String[] DEFAULT_FILES = { JDT_CORE_PREFS, "org.eclipse.jdt.ui.prefs" }; private final File[] searchFolders; @@ -52,11 +56,36 @@ public ProjectSettingsFiles locateSettingsFiles() throws IOException { } } for (String file : DEFAULT_FILES) { - putIfAbsent(files, ProjectSettingsFile.fromClasspath(getClass(), file)); + putIfAbsent(files, getDefaultSettingsFile(file)); } return new ProjectSettingsFiles(files.values(), projectProperties); } + private ProjectSettingsFile getDefaultSettingsFile(String file) { + ProjectSettingsFile settingsFile = ProjectSettingsFile.fromClasspath(getClass(), file); + if (settingsFile.getName().equals(JDT_CORE_PREFS)) { + settingsFile = settingsFile.withUpdatedContent(this::updateFormatter); + } + return settingsFile; + } + + private String updateFormatter(JavaFormatConfig javaFormatConfig, String content) { + String formatterId = getFormatterId(javaFormatConfig); + if (formatterId != null) { + return content.replace( + "org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter.jdk17.tabs", + "org.eclipse.jdt.core.javaFormatter=" + formatterId); + } + return content; + } + + private String getFormatterId(JavaFormatConfig config) { + String jdk = config.getJavaBaseline().name().substring(1); + jdk = (!"11".equals(jdk)) ? jdk : "17"; + String indentation = config.getIndentationStyle().name().toLowerCase(); + return "io.spring.javaformat.eclipse.formatter.jdk" + jdk + "." + indentation; + } + private void add(ProjectProperties projectProperties, Map files, File folder) throws IOException { if (folder.exists() && folder.isDirectory()) { diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs index 0a505b83..c08217ef 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.core.prefs @@ -11,9 +11,7 @@ org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -25,7 +23,7 @@ org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning org.eclipse.jdt.core.compiler.problem.deadCode=warning org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled -org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled org.eclipse.jdt.core.compiler.problem.discouragedReference=warning org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=error @@ -47,7 +45,7 @@ org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=default org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning -org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled @@ -84,12 +82,12 @@ org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore -org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=info org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=disabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled org.eclipse.jdt.core.compiler.problem.unusedImport=warning @@ -101,312 +99,8 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference= org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning -org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=info org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.processAnnotations=disabled -org.eclipse.jdt.core.compiler.source=1.8 -org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 -org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 -org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 -org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=0 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false -org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false -org.eclipse.jdt.core.formatter.comment.format_block_comments=true -org.eclipse.jdt.core.formatter.comment.format_header=false -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=true -org.eclipse.jdt.core.formatter.comment.format_source_code=false -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true -org.eclipse.jdt.core.formatter.comment.indent_root_tags=false -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert -org.eclipse.jdt.core.formatter.comment.line_length=90 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=2 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false -org.eclipse.jdt.core.formatter.indentation.size=4 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false -org.eclipse.jdt.core.formatter.lineSplit=90 -org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=tab -org.eclipse.jdt.core.formatter.tabulation.size=4 -org.eclipse.jdt.core.formatter.use_on_off_tags=true -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false -org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true -org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true -org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter +org.eclipse.jdt.core.javaFormatter=io.spring.javaformat.eclipse.formatter.jdk17.tabs diff --git a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs index 0c0e8653..23d79e64 100644 --- a/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs +++ b/spring-javaformat-eclipse/io.spring.javaformat.eclipse/src/io/spring/javaformat/eclipse/projectsettings/org.eclipse.jdt.ui.prefs @@ -1,3 +1,4 @@ +cleanup.add_all=false cleanup.add_default_serial_version_id=true cleanup.add_generated_serial_version_id=false cleanup.add_missing_annotations=true @@ -103,6 +104,9 @@ sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class= sp_cleanup.qualify_static_member_accesses_with_declaring_class=true sp_cleanup.qualify_static_method_accesses_with_declaring_class=false sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=true +sp_cleanup.remove_redundant_semicolons=true +sp_cleanup.remove_redundant_type_arguments=true sp_cleanup.remove_trailing_whitespaces=true sp_cleanup.remove_trailing_whitespaces_all=true sp_cleanup.remove_trailing_whitespaces_ignore_empty=false diff --git a/spring-javaformat-eclipse/pom.xml b/spring-javaformat-eclipse/pom.xml index 0b5d8fb3..7bed9c79 100644 --- a/spring-javaformat-eclipse/pom.xml +++ b/spring-javaformat-eclipse/pom.xml @@ -6,16 +6,38 @@ io.spring.javaformat spring-javaformat-build - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-eclipse pom - Spring JavaFormat Eclipse + Spring JavaFormat Eclipse Parent ${basedir}/.. + 17 + + + eclipse-jdk17 + p2 + ${eclipse.jdk17.repository} + + + eclipse-checkstyle + p2 + ${eclipse.checkstyle.repository} + + + + org.apache.maven.plugins + maven-javadoc-plugin + + 8 + -Xdoclint:none + false + + org.eclipse.tycho tycho-maven-plugin @@ -62,7 +84,6 @@ - diff --git a/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml b/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml new file mode 100644 index 00000000..1c2e0383 --- /dev/null +++ b/spring-javaformat-gradle/io.spring.javaformat.gradle.plugin/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat-gradle + 0.0.48-SNAPSHOT + + io.spring.javaformat + io.spring.javaformat.gradle.plugin + pom + Spring JavaFormat Gradle Plugin Marker Artifact + + ${basedir}/../.. + + + + io.spring.javaformat + spring-javaformat-gradle-plugin + ${project.version} + + + diff --git a/spring-javaformat-gradle/pom.xml b/spring-javaformat-gradle/pom.xml index 67cd0660..681a1645 100644 --- a/spring-javaformat-gradle/pom.xml +++ b/spring-javaformat-gradle/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-gradle pom @@ -32,5 +32,6 @@ spring-javaformat-gradle-plugin + io.spring.javaformat.gradle.plugin diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/build.gradle index 21a62bc8..e088814b 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/build.gradle +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/build.gradle @@ -8,9 +8,9 @@ repositories { } dependencies { - compile fileTree(dir: 'target/dependencies/compile', include: '*.jar') - testCompile gradleTestKit() - testCompile fileTree(dir: 'target/dependencies/test', include: '*.jar') + implementation fileTree(dir: 'target/dependencies/compile', include: '*.jar') + testImplementation gradleTestKit() + testImplementation fileTree(dir: 'target/dependencies/test', include: '*.jar') } jar { @@ -20,11 +20,15 @@ jar { } test { + useJUnitPlatform() testLogging { events "passed", "skipped", "failed" } } +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + eclipseJdt { inputFile = rootProject.file('../../.eclipse/org.eclipse.jdt.core.prefs') doLast { @@ -57,4 +61,10 @@ artifacts { archives javadocJar } - +tasks.withType(JavaCompile) { + options.compilerArgs.add("-Werror") + options.compilerArgs.add("-Xlint:deprecation") + options.compilerArgs.add("-Xlint:rawtypes") + options.compilerArgs.add("-Xlint:unchecked") + options.compilerArgs.add("-Xlint:varargs") +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.jar index 91ca28c8..e708b1c0 100644 Binary files a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.jar and b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties index 16d28051..070cb702 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew index cccdd3d5..22cf4de8 100755 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015-2023 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew.bat b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew.bat index e95643d6..18a320c0 100755 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew.bat +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015-2023 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml index 5d85579d..3170b015 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-gradle - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-gradle-plugin pom @@ -115,6 +115,12 @@ spring-javaformat-formatter-shaded ${project.version} + + + io.spring.javaformat + spring-javaformat-checkstyle + ${project.version} + diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatExtension.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatExtension.java new file mode 100644 index 00000000..2f173b99 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatExtension.java @@ -0,0 +1,90 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.gradle; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.inject.Inject; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.plugins.quality.CheckstyleExtension; +import org.gradle.api.provider.Property; +import org.gradle.api.resources.TextResource; + +/** + * DSL extension for Spring Java Format. + * + * @author Andy Wilkinson + */ +public abstract class SpringJavaFormatExtension { + + private final Checkstyle checkstyle; + + @Inject + public SpringJavaFormatExtension(Project project) { + this.checkstyle = project.getObjects().newInstance(Checkstyle.class, project); + this.checkstyle.getConfigureDependencies().convention(true); + } + + public Checkstyle getCheckstyle() { + return this.checkstyle; + } + + public void checkstyle(Action action) { + action.execute(this.checkstyle); + } + + public abstract static class Checkstyle { + + private final Project project; + + @Inject + public Checkstyle(Project project) { + this.project = project; + } + + /** + * Property that controls whether Checkstyle's dependencies should be configured to + * use Spring Java Format's checks. + * @return the property + */ + public abstract Property getConfigureDependencies(); + + /** + * Applies Spring Java Format's default Checkstyle config, enabling all Spring checks. + * @see CheckstyleExtension#setConfig(TextResource) + */ + public void applyDefaultConfig() { + CheckstyleExtension extension = this.project.getExtensions().getByType(CheckstyleExtension.class); + StringWriter defaultConfig = new StringWriter(); + PrintWriter writer = new PrintWriter(defaultConfig); + writer.println(""); + writer.println(""); + writer.println(""); + writer.println(" "); + writer.println(" "); + writer.println(""); + extension.setConfig(this.project.getResources().getText().fromString(defaultConfig.toString())); + } + + } + +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatPlugin.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatPlugin.java index 4bf4c437..4dc2f423 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatPlugin.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/SpringJavaFormatPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,18 +17,33 @@ package io.spring.javaformat.gradle; import java.io.File; +import java.util.ArrayList; +import java.util.List; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.DependencySet; import org.gradle.api.plugins.JavaBasePlugin; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.plugins.quality.CheckstyleExtension; +import org.gradle.api.plugins.quality.CheckstylePlugin; import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.api.tasks.TaskProvider; + +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.formatter.Formatter; +import io.spring.javaformat.gradle.tasks.CheckFormat; +import io.spring.javaformat.gradle.tasks.Format; +import io.spring.javaformat.gradle.tasks.FormatterTask; /** * Spring Format Gradle Plugin. * * @author Phillip Webb + * @author Andy Wilkinson */ public class SpringJavaFormatPlugin implements Plugin { @@ -38,38 +53,90 @@ public class SpringJavaFormatPlugin implements Plugin { public void apply(Project project) { this.project = project; addSourceTasks(); + SpringJavaFormatExtension extension = registerExtension(); + new CheckstyleConfigurer(project, extension).apply(); + } + + private SpringJavaFormatExtension registerExtension() { + SpringJavaFormatExtension extension = this.project.getExtensions().create("springJavaFormat", SpringJavaFormatExtension.class); + return extension; } private void addSourceTasks() { this.project.getPlugins().withType(JavaBasePlugin.class, (plugin) -> { - Task formatAll = this.project.task(FormatTask.NAME); - formatAll.setDescription(FormatTask.DESCRIPTION); - Task checkAll = this.project.task(CheckTask.NAME); - checkAll.setDescription(CheckTask.DESCRIPTION); - this.project.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkAll); - this.project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() - .all((sourceSet) -> addSourceTasks(sourceSet, checkAll, formatAll)); + TaskContainer tasks = this.project.getTasks(); + TaskProvider formatAllProvider = tasks.register(Format.NAME); + formatAllProvider.configure((formatAll) -> formatAll.setDescription(Format.DESCRIPTION)); + TaskProvider checkAllProvider = tasks.register(CheckFormat.NAME); + checkAllProvider.configure((checkAll) -> checkAll.setDescription(CheckFormat.DESCRIPTION)); + tasks.named(JavaBasePlugin.CHECK_TASK_NAME).configure((check) -> check.dependsOn(checkAllProvider)); + this.project.getExtensions() + .getByType(JavaPluginExtension.class) + .getSourceSets() + .all((sourceSet) -> addSourceTasks(sourceSet, checkAllProvider, formatAllProvider)); }); } - private void addSourceTasks(SourceSet sourceSet, Task checkAll, Task formatAll) { - CheckTask checkTask = addSourceTask(sourceSet, CheckTask.class, CheckTask.NAME, CheckTask.DESCRIPTION); - checkTask.setReportLocation( - new File(this.project.getBuildDir(), "reports/format/" + sourceSet.getName() + "/check-format.txt")); - checkAll.dependsOn(checkTask); - FormatTask formatSourceSet = addSourceTask(sourceSet, FormatTask.class, FormatTask.NAME, - FormatTask.DESCRIPTION); - formatSourceSet.conventionMapping("encoding", () -> "UTF-8"); - formatAll.dependsOn(formatSourceSet); + private void addSourceTasks(SourceSet sourceSet, TaskProvider checkAllProvider, + TaskProvider formatAllProvider) { + TaskProvider checkTaskProvider = addFormatterTask(sourceSet, CheckFormat.class, CheckFormat.NAME, + CheckFormat.DESCRIPTION); + checkTaskProvider.configure((checkTask) -> checkTask.setReportLocation( + new File(this.project.getBuildDir(), "reports/format/" + sourceSet.getName() + "/check-format.txt"))); + checkAllProvider.configure((checkAll) -> checkAll.dependsOn(checkTaskProvider)); + TaskProvider formatTaskProvider = addFormatterTask(sourceSet, Format.class, Format.NAME, + Format.DESCRIPTION); + formatTaskProvider.configure((format) -> format.conventionMapping("encoding", () -> "UTF-8")); + formatAllProvider.configure((formatAll) -> formatAll.dependsOn(formatTaskProvider)); } - private T addSourceTask(SourceSet sourceSet, Class taskType, String name, - String desc) { + private TaskProvider addFormatterTask(SourceSet sourceSet, Class taskType, + String name, String desc) { String taskName = sourceSet.getTaskName(name, null); - T task = this.project.getTasks().create(taskName, taskType); - task.setDescription(desc + " for " + sourceSet.getName()); - task.setSource(sourceSet.getAllJava()); - return task; + TaskProvider provider = this.project.getTasks().register(taskName, taskType); + provider.configure((task) -> { + task.setDescription(desc + " for " + sourceSet.getName()); + task.setSource(sourceSet.getAllJava()); + JavaFormatConfig config = JavaFormatConfig.findFrom(this.project.getProjectDir()); + task.getIndentationStyle().convention(config.getIndentationStyle()); + task.getJavaBaseline().convention(config.getJavaBaseline()); + }); + return provider; + } + + private static final class CheckstyleConfigurer { + + private final Project project; + + private final SpringJavaFormatExtension extension; + + private CheckstyleConfigurer(Project project, SpringJavaFormatExtension extension) { + this.project = project; + this.extension = extension; + } + + private void apply() { + this.project.getPlugins().withType(CheckstylePlugin.class).configureEach((checkstylePlugin) -> { + CheckstyleExtension checkstyle = this.project.getExtensions().getByType(CheckstyleExtension.class); + DependencySet checkstyleDependencies = this.project.getConfigurations().getByName("checkstyle").getDependencies(); + checkstyleDependencies.addAllLater(this.project.provider(() -> checkstyleDependencies(checkstyle))); + }); + } + + private List checkstyleDependencies(CheckstyleExtension checkstyle) { + List dependencies = new ArrayList<>(); + if (configuringCheckstyleDependencies()) { + dependencies.add(this.project.getDependencies().create("com.puppycrawl.tools:checkstyle:" + checkstyle.getToolVersion())); + dependencies.add(this.project.getDependencies().create("io.spring.javaformat:spring-javaformat-checkstyle:" + + Formatter.class.getPackage().getImplementationVersion())); + } + return dependencies; + } + + private boolean configuringCheckstyleDependencies() { + return Boolean.TRUE.equals(this.extension.getCheckstyle().getConfigureDependencies().get()); + } + } } diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/CheckTask.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java similarity index 80% rename from spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/CheckTask.java rename to spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java index d5a645fc..d6504edf 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/CheckTask.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/CheckFormat.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.javaformat.gradle; +package io.spring.javaformat.gradle.tasks; import java.io.File; import java.io.IOException; @@ -24,13 +24,10 @@ import java.util.List; import java.util.stream.Collectors; -import org.gradle.api.GradleException; -import org.gradle.api.file.FileTree; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.VerificationException; import io.spring.javaformat.formatter.FileEdit; @@ -40,7 +37,7 @@ * @author Phillip Webb */ @CacheableTask -public class CheckTask extends FormatterTask { +public class CheckFormat extends FormatterTask { /** * The name of the task. @@ -56,8 +53,9 @@ public class CheckTask extends FormatterTask { @TaskAction public void checkFormatting() throws IOException, InterruptedException { - List problems = formatFiles().filter(FileEdit::hasEdits).map(FileEdit::getFile) - .collect(Collectors.toList()); + List problems = formatFiles().filter(FileEdit::hasEdits) + .map(FileEdit::getFile) + .collect(Collectors.toList()); this.reportLocation.getParentFile().mkdirs(); if (!problems.isEmpty()) { StringBuilder message = new StringBuilder("Formatting violations found in the following files:\n"); @@ -65,19 +63,13 @@ public void checkFormatting() throws IOException, InterruptedException { message.append("\nRun `format` to fix."); Files.write(this.reportLocation.toPath(), Collections.singletonList(message.toString()), StandardOpenOption.CREATE); - throw new GradleException(message.toString()); + throw new VerificationException(message.toString()); } else { this.reportLocation.createNewFile(); } } - @Override - @PathSensitive(PathSensitivity.RELATIVE) - public FileTree getSource() { - return super.getSource(); - } - @OutputFile public File getReportLocation() { return this.reportLocation; diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/FormatTask.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/Format.java similarity index 81% rename from spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/FormatTask.java rename to spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/Format.java index 9e529e69..b1f6b312 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/FormatTask.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/Format.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,13 @@ * limitations under the License. */ -package io.spring.javaformat.gradle; +package io.spring.javaformat.gradle.tasks; import java.io.IOException; import org.gradle.api.GradleException; +import org.gradle.api.file.FileTree; +import org.gradle.api.tasks.OutputFiles; import org.gradle.api.tasks.TaskAction; import io.spring.javaformat.formatter.FileEdit; @@ -29,7 +31,7 @@ * * @author Phillip Webb */ -public class FormatTask extends FormatterTask { +public class Format extends FormatterTask { /** * The name of the task. @@ -51,4 +53,9 @@ public void format() throws IOException, InterruptedException { } } + @OutputFiles + public FileTree getOutputFiles() { + return super.getSource(); + } + } diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/FormatterTask.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/FormatterTask.java similarity index 52% rename from spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/FormatterTask.java rename to spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/FormatterTask.java index d3ed5e9c..b99ded44 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/FormatterTask.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/main/java/io/spring/javaformat/gradle/tasks/FormatterTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,23 @@ * limitations under the License. */ -package io.spring.javaformat.gradle; +package io.spring.javaformat.gradle.tasks; import java.nio.charset.Charset; import java.util.stream.Stream; +import org.gradle.api.file.FileTree; +import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.SourceTask; +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; import io.spring.javaformat.formatter.FileEdit; import io.spring.javaformat.formatter.FileFormatter; @@ -31,10 +39,19 @@ * * @author Phillip Webb */ -abstract class FormatterTask extends SourceTask { +public abstract class FormatterTask extends SourceTask { private String encoding; + private final Property indentationStyle; + + private final Property javaBaseline; + + FormatterTask() { + this.indentationStyle = getProject().getObjects().property(IndentationStyle.class); + this.javaBaseline = getProject().getObjects().property(JavaBaseline.class); + } + /** * Get the file encoding in use. * @return the encoding the file encoding @@ -53,12 +70,38 @@ public void setEncoding(String encoding) { this.encoding = encoding; } + /** + * The indentation style used for formatting. + * @return the indentation style + */ + @Input + public Property getIndentationStyle() { + return this.indentationStyle; + } + + /** + * The Java baseline used for formatting. + * @return the Java baseline + */ + @Input + public Property getJavaBaseline() { + return this.javaBaseline; + } + + @Override + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + public FileTree getSource() { + return super.getSource(); + } + /** * Format the source files and provide a {@link Stream} of {@link FileEdit} instances. * @return the file edits */ protected final Stream formatFiles() { - FileFormatter formatter = new FileFormatter(); + JavaFormatConfig javaFormatConfig = JavaFormatConfig.of(this.javaBaseline.get(), this.indentationStyle.get()); + FileFormatter formatter = new FileFormatter(javaFormatConfig); Charset encoding = (getEncoding() != null ? Charset.forName(getEncoding()) : Charset.defaultCharset()); return formatter.formatFiles(getSource().getFiles(), encoding); } diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java index fa25b82b..3f413277 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckTaskTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,44 +18,46 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; -import java.util.Collections; +import java.util.Arrays; import java.util.stream.Stream; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import io.spring.javaformat.gradle.tasks.CheckFormat; import io.spring.javaformat.gradle.testkit.GradleBuild; +import io.spring.javaformat.gradle.testkit.GradleBuildExtension; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link CheckTask}. + * Tests for {@link CheckFormat}. * * @author Phillip Webb */ +@ExtendWith(GradleBuildExtension.class) public class CheckTaskTests { - @Rule - public final GradleBuild gradleBuild = new GradleBuild(); + private final GradleBuild gradleBuild = new GradleBuild(); - @Rule - public final TemporaryFolder temp = new TemporaryFolder(); + @TempDir + public File temp; @Test - public void checkOk() throws IOException { + void checkOk() throws IOException { BuildResult result = this.gradleBuild.source("src/test/resources/check-ok").build("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } @Test - public void whenFirstInvocationSucceedsThenSecondInvocationIsUpToDate() throws IOException { + void whenFirstInvocationSucceedsThenSecondInvocationIsUpToDate() throws IOException { GradleBuild gradleBuild = this.gradleBuild.source("src/test/resources/check-ok"); BuildResult result = gradleBuild.build("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); @@ -64,25 +66,61 @@ public void whenFirstInvocationSucceedsThenSecondInvocationIsUpToDate() throws I } @Test - public void whenFirstInvocationSucceedsAndSourceIsModifiedThenSecondInvocationSucceeds() throws IOException { - copyFolder(new File("src/test/resources/check-ok").toPath(), this.temp.getRoot().toPath()); - GradleBuild gradleBuild = this.gradleBuild.source(this.temp.getRoot()); + void whenFirstInvocationSucceedsAndSourceIsModifiedThenSecondInvocationSucceeds() throws IOException { + copyNormalizedFolder(new File("src/test/resources/check-ok").toPath(), this.temp.toPath()); + GradleBuild gradleBuild = this.gradleBuild.source(this.temp); BuildResult result = gradleBuild.build("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); - Files.write(new File(this.temp.getRoot(), "src/main/java/simple/Simple.java").toPath(), - Collections.singletonList("// A change to the file"), StandardOpenOption.APPEND); + Files.write(new File(this.temp, "src/main/java/simple/Simple.java").toPath(), + "// A change to the file\n".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND); result = gradleBuild.build("--debug", "check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } @Test - public void checkBad() throws IOException { + void whenFirstInvocationSucceedsAndIndentationStyleIsChangedThenSecondInvocationFails() throws IOException { + GradleBuild gradleBuild = this.gradleBuild.source("src/test/resources/check-ok"); + BuildResult result = gradleBuild.build("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Files.write(new File(this.gradleBuild.getProjectDir(), ".springjavaformatconfig").toPath(), + Arrays.asList("indentation-style=spaces")); + result = gradleBuild.buildAndFail("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); + } + + @Test + void whenFirstInvocationFailsAndIndentationStyleIsChangedThenSecondInvocationSucceeds() throws IOException { + GradleBuild gradleBuild = this.gradleBuild.source("src/test/resources/check-spaces"); + BuildResult result = gradleBuild.buildAndFail("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); + Files.write(new File(this.gradleBuild.getProjectDir(), ".springjavaformatconfig").toPath(), + Arrays.asList("indentation-style=spaces")); + result = gradleBuild.build("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + void whenFirstInvocationSucceedsAndJavaBaselineIsChangedThenSecondInvocationSucceedsAndThirdIsUpToDate() + throws IOException { + GradleBuild gradleBuild = this.gradleBuild.source("src/test/resources/check-ok"); + BuildResult result = gradleBuild.build("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Files.write(new File(this.gradleBuild.getProjectDir(), ".springjavaformatconfig").toPath(), + Arrays.asList("java-baseline=8")); + result = gradleBuild.build("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + result = gradleBuild.build("check"); + assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE); + } + + @Test + void checkBad() throws IOException { BuildResult result = this.gradleBuild.source("src/test/resources/check-bad").buildAndFail("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); } @Test - public void whenFirstInvocationFailsThenSecondInvocationFails() throws IOException { + void whenFirstInvocationFailsThenSecondInvocationFails() throws IOException { GradleBuild gradleBuild = this.gradleBuild.source("src/test/resources/check-bad"); BuildResult result = gradleBuild.buildAndFail("check"); assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); @@ -90,14 +128,17 @@ public void whenFirstInvocationFailsThenSecondInvocationFails() throws IOExcepti assertThat(result.task(":checkFormatMain").getOutcome()).isEqualTo(TaskOutcome.FAILED); } - private void copyFolder(Path source, Path target) throws IOException { + private void copyNormalizedFolder(Path source, Path target) throws IOException { try (Stream stream = Files.walk(source)) { stream.forEach((child) -> { try { Path relative = source.relativize(child); Path destination = target.resolve(relative); - if (!destination.toFile().isDirectory()) { - Files.copy(child, destination, StandardCopyOption.REPLACE_EXISTING); + if (!Files.isDirectory(child)) { + String content = new String(Files.readAllBytes(child), StandardCharsets.UTF_8); + String normalized = content.replace("\n\r", "\n").replace('\r', '\n'); + Files.createDirectories(destination.getParent()); + Files.write(destination, normalized.getBytes(StandardCharsets.UTF_8)); } } catch (Exception ex) { diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckstyleTests.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckstyleTests.java new file mode 100644 index 00000000..8995edad --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/CheckstyleTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.gradle; + +import org.gradle.testkit.runner.BuildResult; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import io.spring.javaformat.gradle.testkit.GradleBuild; +import io.spring.javaformat.gradle.testkit.GradleBuildExtension; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(GradleBuildExtension.class) +class CheckstyleTests { + + private final GradleBuild gradleBuild = new GradleBuild(); + + @Test + void configureCheckstyle() { + BuildResult result = this.gradleBuild.source("src/test/resources/checkstyle-configure").build("checkstyleDependencies"); + assertThat(result.getOutput()).contains("io.spring.javaformat:spring-javaformat-checkstyle:"); + assertThat(result.getOutput()).contains("com.puppycrawl.tools:checkstyle:8.45.1"); + } + + @Test + void configureCheckstyleWithCustomToolVersion() { + BuildResult result = this.gradleBuild.source("src/test/resources/checkstyle-configure-with-custom-tool-version").build("checkstyleDependencies"); + assertThat(result.getOutput()).contains("io.spring.javaformat:spring-javaformat-checkstyle:"); + assertThat(result.getOutput()).contains("com.puppycrawl.tools:checkstyle:10.26.1"); + } + + @Test + void doNotConfigureCheckstyle() { + BuildResult result = this.gradleBuild.source("src/test/resources/checkstyle-do-not-configure").build("checkstyleDependencies"); + assertThat(result.getOutput()).doesNotContain("spring-javaformat-checkstyle"); + } + + @Test + void applyDefaultConfigToCheckstyle() { + BuildResult result = this.gradleBuild.source("src/test/resources/checkstyle-apply-default-config").build("checkstyleConfig"); + assertThat(result.getOutput()).contains(""); + } + +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/FormatTaskTests.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/FormatTaskTests.java index cbd2c623..e3d29e16 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/FormatTaskTests.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/FormatTaskTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,33 +19,85 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.util.Arrays; import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.GradleRunner; import org.gradle.testkit.runner.TaskOutcome; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import io.spring.javaformat.gradle.tasks.Format; import io.spring.javaformat.gradle.testkit.GradleBuild; +import io.spring.javaformat.gradle.testkit.GradleBuildExtension; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link FormatTask}. + * Tests for {@link Format}. * * @author Phillip Webb */ +@ExtendWith(GradleBuildExtension.class) public class FormatTaskTests { - @Rule - public final GradleBuild gradleBuild = new GradleBuild(); + private final GradleBuild gradleBuild = new GradleBuild(); @Test - public void checkOk() throws IOException { + void checkOk() throws IOException { BuildResult result = this.gradleBuild.source("src/test/resources/format").build("format"); assertThat(result.task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); File formattedFile = new File(this.gradleBuild.getProjectDir(), "src/main/java/simple/Simple.java"); String formattedContent = new String(Files.readAllBytes(formattedFile.toPath())); - assertThat(formattedContent).contains("class Simple {"); + assertThat(formattedContent).contains("class Simple {").contains(" public static void main"); + } + + @Test + void checkUpToDate() throws IOException { + GradleRunner runner = this.gradleBuild.source("src/test/resources/format").prepareRunner("format"); + // Format that changes files + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + // Format of already formatted files + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + // Up-to-date + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE); + } + + @Test + void notUpToDateWhenJavaBaselineChanges() throws IOException { + GradleRunner runner = this.gradleBuild.source("src/test/resources/format").prepareRunner("format"); + // Format that changes files + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + // Format of already formatted files + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + // Up-to-date + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE); + Files.write(new File(this.gradleBuild.getProjectDir(), ".springjavaformatconfig").toPath(), + Arrays.asList("java-baseline=8")); + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + void notUpToDateWhenIndentationStyleChanges() throws IOException { + GradleRunner runner = this.gradleBuild.source("src/test/resources/format").prepareRunner("format"); + // Format that changes files + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + // Format of already formatted files + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + // Up-to-date + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE); + Files.write(new File(this.gradleBuild.getProjectDir(), ".springjavaformatconfig").toPath(), + Arrays.asList("indentation-style=spaces")); + assertThat(runner.build().task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + void checkSpacesOk() throws IOException { + BuildResult result = this.gradleBuild.source("src/test/resources/format-spaces").build("format"); + assertThat(result.task(":formatMain").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + File formattedFile = new File(this.gradleBuild.getProjectDir(), "src/main/java/simple/Simple.java"); + String formattedContent = new String(Files.readAllBytes(formattedFile.toPath())); + assertThat(formattedContent).contains("class Simple {").contains(" public static void main"); } } diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuild.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuild.java index 61e7653f..1414da78 100644 --- a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuild.java +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuild.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,13 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.stream.Stream; @@ -31,28 +33,23 @@ import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; -import org.gradle.internal.impldep.com.google.common.base.Charsets; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.GradleRunner; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; +import org.gradle.util.GradleVersion; import org.xml.sax.InputSource; import io.spring.javaformat.formatter.Formatter; -import io.spring.javaformat.formatter.eclipse.Preparator; -import io.spring.javaformat.org.eclipse.jdt.core.formatter.CodeFormatter; + +import static org.assertj.core.api.Assertions.assertThat; /** - * A {@link TestRule} for running a Gradle build using {@link GradleRunner}. + * A {@code GradleBuild} is used to run a Gradle build using {@link GradleRunner}. * * @author Andy Wilkinson + * @author Scott Frederick * @author Phillip Webb */ -public class GradleBuild implements TestRule { - - private final TemporaryFolder temp = new TemporaryFolder(); +public class GradleBuild { private File source; @@ -60,44 +57,15 @@ public class GradleBuild implements TestRule { private String gradleVersion; - @Override - public Statement apply(Statement base, Description description) { - return this.temp.apply(new Statement() { - - @Override - public void evaluate() throws Throwable { - before(); - try { - base.evaluate(); - } - finally { - after(); - } - } - - }, description); - } - - private void before() throws IOException { - this.projectDir = this.temp.newFolder(); - } - - private void after() { - GradleBuild.this.source = null; - } - - private String getPluginClasspath() { - return absolutePath("build/classes/java/main") + "," + absolutePath("build/resources/main") + "," - + pathOfJarContaining(Formatter.class) + "," + pathOfJarContaining(Preparator.class) + "," - + pathOfJarContaining(CodeFormatter.class); - } + private GradleVersion expectDeprecationWarnings; - private String absolutePath(String path) { - return new File(path).getAbsolutePath(); + void before() throws IOException { + this.projectDir = Files.createTempDirectory("gradle-").toFile(); } - private String pathOfJarContaining(Class type) { - return type.getProtectionDomain().getCodeSource().getLocation().getPath(); + void after() throws IOException { + this.source = null; + Files.walk(this.projectDir.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); } public GradleBuild source(String source) { @@ -114,7 +82,12 @@ public GradleBuild source(File source) { public BuildResult build(String... arguments) { try { - return prepareRunner(arguments).build(); + BuildResult result = prepareRunner(arguments).build(); + if (this.expectDeprecationWarnings == null || (this.gradleVersion != null + && this.expectDeprecationWarnings.compareTo(GradleVersion.version(this.gradleVersion)) > 0)) { + assertThat(result.getOutput()).doesNotContain("Deprecated").doesNotContain("deprecated"); + } + return result; } catch (Exception ex) { throw new RuntimeException(ex); @@ -135,7 +108,7 @@ public GradleRunner prepareRunner(String... arguments) throws IOException { File buildFile = new File(this.projectDir, "build.gradle"); String scriptContent = new String(Files.readAllBytes(buildFile.toPath())).replace("{version}", getSpringFormatVersion()); - Files.write(buildFile.toPath(), scriptContent.getBytes(Charsets.UTF_8)); + Files.write(buildFile.toPath(), scriptContent.getBytes(StandardCharsets.UTF_8)); GradleRunner gradleRunner = GradleRunner.create().withProjectDir(this.projectDir).withDebug(true); if (this.gradleVersion != null) { gradleRunner.withGradleVersion(this.gradleVersion); @@ -148,6 +121,19 @@ public GradleRunner prepareRunner(String... arguments) throws IOException { return gradleRunner.withArguments(allArguments); } + private String getPluginClasspath() { + return absolutePath("build/classes/java/main") + "," + absolutePath("build/resources/main") + "," + + pathOfJarContaining(Formatter.class); + } + + private String absolutePath(String path) { + return new File(path).getAbsolutePath(); + } + + private String pathOfJarContaining(Class type) { + return type.getProtectionDomain().getCodeSource().getLocation().getPath(); + } + private void copyFolder(Path source, Path target) throws IOException { try (Stream stream = Files.walk(source)) { stream.forEach((child) -> { diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuildExtension.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuildExtension.java new file mode 100644 index 00000000..bb5b8a6d --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/java/io/spring/javaformat/gradle/testkit/GradleBuildExtension.java @@ -0,0 +1,54 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.gradle.testkit; + +import java.lang.reflect.Field; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * An {@link Extension} for managing the lifecycle of a {@link GradleBuild} stored in a + * field named {@code gradleBuild}. + * + * @author Andy Wilkinson + * @author Scott Frederick + * @author Phillip Webb + */ +public class GradleBuildExtension implements BeforeEachCallback, AfterEachCallback { + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + extractGradleBuild(context).before(); + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + extractGradleBuild(context).after(); + } + + private GradleBuild extractGradleBuild(ExtensionContext context) throws Exception { + Object testInstance = context.getRequiredTestInstance(); + Field gradleBuildField = testInstance.getClass().getDeclaredField("gradleBuild"); + gradleBuildField.setAccessible(true); + GradleBuild gradleBuild = (GradleBuild) gradleBuildField.get(testInstance); + return gradleBuild; + } + +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-ok/src/main/java/simple/package-info.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-ok/src/main/java/simple/package-info.java new file mode 100644 index 00000000..35b32be0 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-ok/src/main/java/simple/package-info.java @@ -0,0 +1 @@ +package simple; \ No newline at end of file diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-spaces/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-spaces/build.gradle new file mode 100644 index 00000000..d6ca2f32 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-spaces/build.gradle @@ -0,0 +1,10 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'io.spring.javaformat' + +sourceCompatibility = 1.8 diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-spaces/src/main/java/simple/Simple.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-spaces/src/main/java/simple/Simple.java new file mode 100644 index 00000000..cd5523a6 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/check-spaces/src/main/java/simple/Simple.java @@ -0,0 +1,15 @@ +package simple; + +/** + * Simple indented with spaces. + * + * @author Andy Wilkinson + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-apply-default-config/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-apply-default-config/build.gradle new file mode 100644 index 00000000..302352be --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-apply-default-config/build.gradle @@ -0,0 +1,27 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'checkstyle' +apply plugin: 'java' +apply plugin: 'io.spring.javaformat' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +springJavaFormat { + checkstyle { + applyDefaultConfig() + } +} + +tasks.register("checkstyleConfig") { + doFirst { + println checkstyle.config.asString() + } +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-configure-with-custom-tool-version/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-configure-with-custom-tool-version/build.gradle new file mode 100644 index 00000000..cc42d068 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-configure-with-custom-tool-version/build.gradle @@ -0,0 +1,25 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'checkstyle' +apply plugin: 'java' +apply plugin: 'io.spring.javaformat' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +checkstyle { + toolVersion = "10.26.1" +} + +tasks.register("checkstyleDependencies") { + doFirst { + configurations.checkstyle.dependencies.each { println "${it.group}:${it.name}:${it.version}" } + } +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-configure/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-configure/build.gradle new file mode 100644 index 00000000..08207b88 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-configure/build.gradle @@ -0,0 +1,21 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'checkstyle' +apply plugin: 'java' +apply plugin: 'io.spring.javaformat' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +tasks.register("checkstyleDependencies") { + doFirst { + configurations.checkstyle.dependencies.each { println "${it.group}:${it.name}:${it.version}" } + } +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-do-not-configure/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-do-not-configure/build.gradle new file mode 100644 index 00000000..561ffa61 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/checkstyle-do-not-configure/build.gradle @@ -0,0 +1,23 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'checkstyle' +apply plugin: 'java' +apply plugin: 'io.spring.javaformat' + +sourceCompatibility = 1.8 + +springJavaFormat { + checkstyle { + configureDependencies = false + } +} + +tasks.register("checkstyleDependencies") { + doFirst { + configurations.checkstyle.dependencies.each { println "${it.group}:${it.name}:${it.version}" } + } +} diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/.springjavaformatconfig b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/.springjavaformatconfig new file mode 100644 index 00000000..881903b2 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/.springjavaformatconfig @@ -0,0 +1 @@ +indentation-style=spaces diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/build.gradle b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/build.gradle new file mode 100644 index 00000000..d6ca2f32 --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/build.gradle @@ -0,0 +1,10 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'io.spring.javaformat' + +sourceCompatibility = 1.8 diff --git a/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/src/main/java/simple/Simple.java b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/src/main/java/simple/Simple.java new file mode 100644 index 00000000..83b618ce --- /dev/null +++ b/spring-javaformat-gradle/spring-javaformat-gradle-plugin/src/test/resources/format-spaces/src/main/java/simple/Simple.java @@ -0,0 +1,15 @@ +package simple; + +/** + * Simple. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-intellij/pom.xml b/spring-javaformat-intellij-idea/pom.xml similarity index 76% rename from spring-javaformat-intellij/pom.xml rename to spring-javaformat-intellij-idea/pom.xml index f9b8c755..9de7cec6 100644 --- a/spring-javaformat-intellij/pom.xml +++ b/spring-javaformat-intellij-idea/pom.xml @@ -5,11 +5,11 @@ io.spring.javaformat spring-javaformat-build - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT - spring-javaformat-intellij + spring-javaformat-intellij-idea pom - Spring JavaFormat IntelliJ + Spring JavaFormat IntelliJ IDEA ${basedir}/.. @@ -30,7 +30,7 @@ - spring-javaformat-intellij-runtime - spring-javaformat-intellij-plugin + spring-javaformat-intellij-idea-runtime + spring-javaformat-intellij-idea-plugin diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/pom.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml similarity index 59% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/pom.xml rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml index 150e1088..7915af9f 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/pom.xml +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/pom.xml @@ -1,24 +1,21 @@ - 4.0.0 io.spring.javaformat - spring-javaformat-intellij - 0.0.21-SNAPSHOT + spring-javaformat-intellij-idea + 0.0.48-SNAPSHOT - spring-javaformat-intellij-plugin - Spring JavaFormat IntelliJ Plugin + spring-javaformat-intellij-idea-plugin + Spring JavaFormat IntelliJ IDEA Plugin ${basedir}/../.. + 17 - - io.spring.javaformat - spring-javaformat-formatter - ${project.version} - io.spring.javaformat spring-javaformat-formatter-eclipse-runtime @@ -30,82 +27,75 @@ - io.spring.javaformat - spring-javaformat-intellij-runtime - ${project.version} - pom - provided - - - io.spring.javaformat.intellij - extensions + spring-javaformat-formatter ${project.version} - provided + - io.spring.javaformat.intellij - platform-api + io.spring.javaformat + spring-javaformat-intellij-idea-runtime ${project.version} + pom provided - io.spring.javaformat.intellij - platform-impl - ${project.version} + org.jetbrains + annotations + 13.0 provided - io.spring.javaformat.intellij - platform-util-ui + io.spring.javaformat.intellij.idea + app ${project.version} provided - io.spring.javaformat.intellij - platform-service-container + io.spring.javaformat.intellij.idea + jps-model ${project.version} provided - io.spring.javaformat.intellij + io.spring.javaformat.intellij.idea util ${project.version} provided - io.spring.javaformat.intellij - idea + io.spring.javaformat.intellij.idea + util_rt ${project.version} provided - io.spring.javaformat.intellij + io.spring.javaformat.intellij.idea maven ${project.version} provided - io.spring.javaformat.intellij - maven-server-api + io.spring.javaformat.intellij.idea + maven-server ${project.version} provided - io.spring.javaformat.intellij + io.spring.javaformat.intellij.idea gradle ${project.version} provided - io.spring.javaformat.intellij + io.spring.javaformat.intellij.idea gradle-tooling-extension-api ${project.version} provided - io.spring.javaformat.intellij + io.spring.javaformat.intellij.idea gradle-tooling-extension-impl ${project.version} provided @@ -120,9 +110,45 @@ picocontainer provided + + org.jetbrains.kotlinx + kotlinx-coroutines-core + 1.6.4 + provided + + + it.unimi.dsi + fastutil + 8.5.11 + provided + + + + ${basedir}/src/main/resources + true + + META-INF/plugin.xml + + + + ${basedir}/src/main/resources + + META-INF/plugin.xml + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + 11 + false + -Xdoclint:none + + org.apache.maven.plugins maven-shade-plugin diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/EclipseDocumentAdapter.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/EclipseDocumentAdapter.java similarity index 92% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/EclipseDocumentAdapter.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/EclipseDocumentAdapter.java index 5d3e94a6..255a72f1 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/EclipseDocumentAdapter.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/EclipseDocumentAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle; +package io.spring.format.formatter.intellij.formatting; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/EclipseRegionAdapter.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/EclipseRegionAdapter.java similarity index 79% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/EclipseRegionAdapter.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/EclipseRegionAdapter.java index 68db5119..1b1fdc9e 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/EclipseRegionAdapter.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/EclipseRegionAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,9 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle; +package io.spring.format.formatter.intellij.formatting; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import com.intellij.openapi.util.TextRange; @@ -29,15 +28,15 @@ * * @author Phillip Webb */ -public class EclipseRegionAdapter extends Region { +class EclipseRegionAdapter extends Region { private static final IRegion[] NO_REGIONS = {}; - public EclipseRegionAdapter(TextRange range) { + EclipseRegionAdapter(TextRange range) { super(range.getStartOffset(), range.getLength()); } - public static IRegion[] asArray(Collection ranges) { + static IRegion[] asArray(List ranges) { if (ranges == null) { return NO_REGIONS; } diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/SpringJavaFormatFormattingService.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/SpringJavaFormatFormattingService.java new file mode 100644 index 00000000..70bb51e9 --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/formatting/SpringJavaFormatFormattingService.java @@ -0,0 +1,103 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.format.formatter.intellij.formatting; + +import java.nio.file.Path; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; + +import com.intellij.formatting.FormattingContext; +import com.intellij.formatting.service.AbstractDocumentFormattingService; +import com.intellij.formatting.service.FormattingService; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.text.edits.TextEdit; +import org.jetbrains.annotations.NotNull; + +import io.spring.format.formatter.intellij.state.State; +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.formatter.Formatter; + +/** + * {@link FormattingService} to apply Spring formatting conventions. + * + * @author Phillip Webb + */ +public class SpringJavaFormatFormattingService extends AbstractDocumentFormattingService { + + private static final String NORMALIZED_LINE_SEPARATOR = "\n"; + + private static final Set FEATURES = Set.of(Feature.FORMAT_FRAGMENTS); + + private static final FileType JAVA_FILE_TYPE = FileTypeManager.getInstance().getStdFileType("JAVA"); + + private final BiConsumer runAction; + + public SpringJavaFormatFormattingService() { + this(WriteCommandAction::runWriteCommandAction); + } + + SpringJavaFormatFormattingService(BiConsumer runAction) { + this.runAction = runAction; + } + + @Override + public @NotNull Set getFeatures() { + return FEATURES; + } + + @Override + public boolean canFormat(@NotNull PsiFile file) { + return JAVA_FILE_TYPE.equals(file.getFileType()) && State.get(file.getProject()) == State.ACTIVE; + } + + @Override + public void formatDocument(@NotNull Document document, @NotNull List formattingRanges, + @NotNull FormattingContext formattingContext, boolean canChangeWhiteSpaceOnly, boolean quickFormat) { + VirtualFile file = formattingContext.getVirtualFile(); + Path path = (file != null) ? file.getFileSystem().getNioPath(file) : null; + JavaFormatConfig config = JavaFormatConfig.findFrom(path); + Formatter formatter = new Formatter(config); + String source = document.getText(); + formattingRanges = (!formattingRanges.isEmpty()) ? formattingRanges : List.of(TextRange.allOf(source)); + IRegion[] regions = EclipseRegionAdapter.asArray(formattingRanges); + TextEdit edit = formatter.format(source, regions, NORMALIZED_LINE_SEPARATOR); + applyEdit(formattingContext.getProject(), document, edit); + } + + private void applyEdit(Project project, Document document, TextEdit textEdit) { + this.runAction.accept(project, () -> { + try { + IDocument adapted = new EclipseDocumentAdapter(document); + textEdit.apply(adapted); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + }); + } + +} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/FileMonitor.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/FileMonitor.java similarity index 88% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/FileMonitor.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/FileMonitor.java index fc1674d0..84128c15 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/FileMonitor.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/FileMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle.monitor; +package io.spring.format.formatter.intellij.monitor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -24,16 +24,16 @@ import com.intellij.openapi.vfs.VirtualFileMoveEvent; import com.intellij.openapi.vfs.VirtualFilePropertyEvent; -import io.spring.format.formatter.intellij.codestyle.monitor.Trigger.State; +import io.spring.format.formatter.intellij.state.State; /** - * {@link Monitor} that looks for a {@literal .springformat} file. + * {@link Monitor} that looks for a {@literal .springjavaformatconfig} file. * * @author Phillip Webb */ public class FileMonitor extends Monitor { - private static final String TRIGGER_FILE = ".springformat"; + private static final String TRIGGER_FILE = ".springjavaformatconfig"; private final VirtualFileManager fileManager; diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/GradleMonitor.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/GradleMonitor.java similarity index 77% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/GradleMonitor.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/GradleMonitor.java index fc1b35d0..8a41e441 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/GradleMonitor.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/GradleMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,11 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle.monitor; +package io.spring.format.formatter.intellij.monitor; import java.util.Collection; -import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.ExternalProjectInfo; import com.intellij.openapi.externalSystem.model.task.TaskData; @@ -26,9 +26,10 @@ import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener; import com.intellij.openapi.project.Project; import com.intellij.util.messages.MessageBusConnection; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.util.GradleConstants; -import io.spring.format.formatter.intellij.codestyle.monitor.Trigger.State; +import io.spring.format.formatter.intellij.state.State; /** * {@link Monitor} that looks for a {@code spring-javaformat-gradle-plugin} declaration in @@ -38,16 +39,26 @@ */ public class GradleMonitor extends Monitor { - private static final String FORMAT_TASK = "io.spring.javaformat.gradle.FormatTask"; + private static final Logger logger = Logger.getInstance(GradleMonitor.class); + + private static final String FORMAT_TASK = "io.spring.javaformat.gradle.tasks.Format"; public GradleMonitor(Project project, Trigger trigger) { super(project, trigger); MessageBusConnection messageBus = project.getMessageBus().connect(); - messageBus.subscribe(ProjectDataImportListener.TOPIC, (path) -> check()); + messageBus.subscribe(ProjectDataImportListener.TOPIC, new ProjectDataImportListener() { + + @Override + public void onImportFinished(@Nullable String projectPath) { + check(); + } + + }); } private void check() { - ProjectDataManager projectDataManager = ServiceManager.getService(ProjectDataManager.class); + logger.info("Checking " + getProject().getName() + " for use of Spring Java Format"); + ProjectDataManager projectDataManager = ProjectDataManager.getInstance(); boolean hasFormatPlugin = hasFormatPlugin( projectDataManager.getExternalProjectsData(getProject(), GradleConstants.SYSTEM_ID)); getTrigger().updateState(hasFormatPlugin ? State.ACTIVE : State.NOT_ACTIVE); @@ -56,6 +67,7 @@ private void check() { private boolean hasFormatPlugin(Collection projectInfos) { for (ExternalProjectInfo projectInfo : projectInfos) { if (hasFormatPlugin(projectInfo.getExternalProjectStructure())) { + logger.info(projectInfo + " uses Spring Java Format"); return true; } } diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/MavenMonitor.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/MavenMonitor.java similarity index 93% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/MavenMonitor.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/MavenMonitor.java index cb04d5a3..6ddb20e8 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/MavenMonitor.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/MavenMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle.monitor; +package io.spring.format.formatter.intellij.monitor; import java.util.List; @@ -26,7 +26,7 @@ import org.jetbrains.idea.maven.project.MavenProjectsTree.Listener; import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; -import io.spring.format.formatter.intellij.codestyle.monitor.Trigger.State; +import io.spring.format.formatter.intellij.state.State; /** * {@link Monitor} that looks for a {@code spring-javaformat-maven-plugin} declaration in diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Monitor.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Monitor.java similarity index 93% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Monitor.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Monitor.java index 46fe2881..d0663c86 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Monitor.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Monitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle.monitor; +package io.spring.format.formatter.intellij.monitor; import com.intellij.openapi.project.Project; diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Monitors.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Monitors.java similarity index 94% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Monitors.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Monitors.java index 3adc4dcf..cfe8dc4a 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Monitors.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Monitors.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle.monitor; +package io.spring.format.formatter.intellij.monitor; import java.util.ArrayList; import java.util.Arrays; @@ -24,7 +24,7 @@ import com.intellij.openapi.project.Project; -import io.spring.format.formatter.intellij.codestyle.monitor.Trigger.State; +import io.spring.format.formatter.intellij.state.State; /** * Utility class used to manage a collection of {@link Monitors}. Creates and manages diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Trigger.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Trigger.java similarity index 73% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Trigger.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Trigger.java index ebcf1a7a..f1c7d223 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/monitor/Trigger.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/monitor/Trigger.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,9 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle.monitor; +package io.spring.format.formatter.intellij.monitor; + +import io.spring.format.formatter.intellij.state.State; /** * Trigger used to to update the state for this monitor. Triggers are thread safe and can @@ -30,21 +32,4 @@ public interface Trigger { */ void updateState(State state); - /** - * The desired state of the plugin for this monitor. - */ - enum State { - - /** - * The plugin should be active. - */ - ACTIVE, - - /** - * The plugin need not be active. - */ - NOT_ACTIVE - - } - } diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/startup/ManagedSpringJavaFormatProject.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/startup/ManagedSpringJavaFormatProject.java new file mode 100644 index 00000000..2b87dd56 --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/startup/ManagedSpringJavaFormatProject.java @@ -0,0 +1,89 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.format.formatter.intellij.startup; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; + +import io.spring.format.formatter.intellij.monitor.FileMonitor; +import io.spring.format.formatter.intellij.monitor.GradleMonitor; +import io.spring.format.formatter.intellij.monitor.MavenMonitor; +import io.spring.format.formatter.intellij.monitor.Monitors; +import io.spring.format.formatter.intellij.state.State; +import io.spring.format.formatter.intellij.ui.StatusIndicator; + +/** + * Spring Java Format IntelliJ support added to a {@link Project}. + * + * @author Phillip Webb + */ +class ManagedSpringJavaFormatProject { + + private static final String ACTIVE_PROPERTY = ManagedSpringJavaFormatProject.class.getName() + ".ACTIVE"; + + private static final Logger logger = Logger.getInstance(ManagedSpringJavaFormatProject.class); + + private final Project project; + + private final StatusIndicator statusIndicator; + + private final Lock lock = new ReentrantLock(); + + private Monitors monitors; + + private PropertiesComponent properties; + + protected ManagedSpringJavaFormatProject(Project project) { + logger.info("Initializing Spring Format for project " + project.getName()); + this.project = project; + this.statusIndicator = new StatusIndicator(project); + this.properties = PropertiesComponent.getInstance(project); + if (this.properties.getBoolean(ACTIVE_PROPERTY, false)) { + update(State.ACTIVE); + } + this.monitors = new Monitors(this.project, this::update, FileMonitor.factory(), MavenMonitor.factory(), + GradleMonitor.factory()); + Disposer.register(project, this::dispose); + } + + private void dispose() { + if (this.monitors != null) { + logger.info("Stopping monitors for " + this.project.getName()); + this.monitors.stop(); + this.monitors = null; + } + } + + private void update(State state) { + logger.info("Updating state of " + this.project.getName() + " to " + state); + this.lock.lock(); + try { + state.put(this.project); + ApplicationManager.getApplication().invokeLater(() -> this.statusIndicator.update(state)); + } + finally { + this.lock.unlock(); + } + } + +} diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/startup/SpringJavaFormatStartupActivity.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/startup/SpringJavaFormatStartupActivity.java new file mode 100644 index 00000000..f11e345c --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/startup/SpringJavaFormatStartupActivity.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.format.formatter.intellij.startup; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupActivity; + +/** + * {@link StartupActivity} hook for {@link ManagedSpringJavaFormatProject}. + * + * @author Phillip Webb + */ +public class SpringJavaFormatStartupActivity implements StartupActivity { + + @Override + public void runActivity(Project project) { + new ManagedSpringJavaFormatProject(project); + } + +} diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/state/State.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/state/State.java new file mode 100644 index 00000000..6d8fe7c1 --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/state/State.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.format.formatter.intellij.state; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; + +/** + * The state of the plugin. + * + * @author Phillip Webb + */ +public enum State { + + /** + * The plugin is active. + */ + ACTIVE, + + /** + * The plugin is not active. + */ + NOT_ACTIVE; + + private static final Key KEY = Key.create(State.class.getName()); + + /** + * Put this state to the given project. + * @param project the project that should save the state + */ + public void put(Project project) { + project.putUserData(KEY, this); + } + + /** + * Return the state from the given project. + * @param project the project to check + * @return the state of the project + */ + public static State get(Project project) { + State state = (project != null) ? project.getUserData(KEY) : null; + return (state != null) ? state : NOT_ACTIVE; + } + +} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/StatusIndicator.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/ui/StatusIndicator.java similarity index 70% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/StatusIndicator.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/ui/StatusIndicator.java index a0da6c4a..935b738e 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/StatusIndicator.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/java/io/spring/format/formatter/intellij/ui/StatusIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,44 +14,44 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij; +package io.spring.format.formatter.intellij.ui; import java.awt.event.MouseEvent; +import java.util.concurrent.TimeUnit; import javax.swing.Icon; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.StatusBarWidget; import com.intellij.openapi.wm.WindowManager; -import com.intellij.openapi.wm.WindowManagerListener; import com.intellij.util.Consumer; +import com.intellij.util.concurrency.AppExecutorUtil; -import io.spring.format.formatter.intellij.codestyle.monitor.Trigger.State; +import io.spring.format.formatter.intellij.state.State; /** * Indicator used to show when Spring Formatting is active. * * @author Phillip Webb */ -class StatusIndicator { +public class StatusIndicator { private final Project project; private Widget widget; - StatusIndicator(Project project) { + public StatusIndicator(Project project) { this.project = project; } public void update(State state) { WindowManager windowManager = WindowManager.getInstance(); - final StatusBar statusBar = windowManager.getStatusBar(this.project); + StatusBar statusBar = windowManager.getStatusBar(this.project); if (statusBar == null) { - windowManager.addListener(new UpdateOnFrameCreateListener(state)); + AppExecutorUtil.getAppScheduledExecutorService().schedule(() -> retryUpdate(state), 1, TimeUnit.SECONDS); return; } if (state == State.ACTIVE) { @@ -62,6 +62,10 @@ public void update(State state) { } } + private void retryUpdate(State state) { + ApplicationManager.getApplication().invokeLater(() -> update(state)); + } + private void show(StatusBar statusBar) { if (this.widget == null) { this.widget = new Widget(); @@ -76,30 +80,6 @@ private void hide(final StatusBar statusBar) { } } - /** - * {@link WindowManagerListener} used to defer setting the status if the IDE frame - * isn't available. - */ - private class UpdateOnFrameCreateListener implements WindowManagerListener { - - private final State state; - - UpdateOnFrameCreateListener(State state) { - this.state = state; - } - - @Override - public void frameCreated(IdeFrame frame) { - WindowManager.getInstance().removeListener(this); - ApplicationManager.getApplication().invokeLater(() -> update(this.state)); - } - - @Override - public void beforeFrameReleased(IdeFrame frame) { - } - - } - /** * The {@link StatusBarWidget} component for the status. */ diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources/META-INF/plugin.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources/META-INF/plugin.xml new file mode 100644 index 00000000..21c74b0f --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,15 @@ + + spring-javaformat + Spring Javaformat + A source formatter that applies wrapping and whitespace conventions to + provide a consistent “Spring” style. + + ${project.version} + Spring Team + org.jetbrains.idea.maven + org.jetbrains.plugins.gradle + + + + + diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/resources/spring-javaformat/formatOn.png b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources/spring-javaformat/formatOn.png similarity index 100% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/resources/spring-javaformat/formatOn.png rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/main/resources/spring-javaformat/formatOn.png diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/EclipseDocumentAdapterTests.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/EclipseDocumentAdapterTests.java similarity index 82% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/EclipseDocumentAdapterTests.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/EclipseDocumentAdapterTests.java index a56c7be4..4fe90665 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/EclipseDocumentAdapterTests.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/EclipseDocumentAdapterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,10 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle; +package io.spring.format.formatter.intellij.formatting; import com.intellij.openapi.editor.Document; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -29,10 +29,10 @@ * * @author Phillip Webb */ -public class EclipseDocumentAdapterTests { +class EclipseDocumentAdapterTests { @Test - public void createShouldUseDocumentText() throws Exception { + void createUsesDocumentText() throws Exception { Document intellijDocument = mock(Document.class); given(intellijDocument.getText()).willReturn("hello"); EclipseDocumentAdapter adapter = new EclipseDocumentAdapter(intellijDocument); @@ -40,7 +40,7 @@ public void createShouldUseDocumentText() throws Exception { } @Test - public void replaceShouldApplyToIntellijDocument() throws Exception { + void replaceAppliesToIntellijDocument() throws Exception { Document intellijDocument = mock(Document.class); given(intellijDocument.getText()).willReturn("hello"); EclipseDocumentAdapter adapter = new EclipseDocumentAdapter(intellijDocument); diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/EclipseRegionAdapterTests.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/EclipseRegionAdapterTests.java similarity index 80% rename from spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/EclipseRegionAdapterTests.java rename to spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/EclipseRegionAdapterTests.java index 6dc60435..f4c2d2a4 100644 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/EclipseRegionAdapterTests.java +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/EclipseRegionAdapterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.spring.format.formatter.intellij.codestyle; +package io.spring.format.formatter.intellij.formatting; import java.util.Arrays; import java.util.List; import com.intellij.openapi.util.TextRange; import org.eclipse.jface.text.IRegion; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -33,25 +33,25 @@ public class EclipseRegionAdapterTests { @Test - public void getOffsetShouldReturnStartOffset() throws Exception { + void getOffsetReturnsStartOffset() throws Exception { IRegion region = new EclipseRegionAdapter(new TextRange(10, 20)); assertThat(region.getOffset()).isEqualTo(10); } @Test - public void getLengthShouldReturnLength() throws Exception { + void getLengthReturnsLength() throws Exception { IRegion region = new EclipseRegionAdapter(new TextRange(10, 20)); assertThat(region.getLength()).isEqualTo(10); } @Test - public void asArrayWhenCollectionIsNullShouldReturnEmptyArray() throws Exception { + void asArrayWhenCollectionIsNullReturnsEmptyArray() throws Exception { IRegion[] regions = EclipseRegionAdapter.asArray(null); assertThat(regions).isNotNull().isEmpty(); } @Test - public void asArrayShouldReturnArray() throws Exception { + void asArrayReturnsArray() throws Exception { List ranges = Arrays.asList(new TextRange(10, 20), new TextRange(30, 35)); IRegion[] regions = EclipseRegionAdapter.asArray(ranges); assertThat(regions).hasSize(2); diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/SpringJavaFormatFormattingServiceTests.java b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/SpringJavaFormatFormattingServiceTests.java new file mode 100644 index 00000000..6524e10d --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-plugin/src/test/java/io/spring/format/formatter/intellij/formatting/SpringJavaFormatFormattingServiceTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.format.formatter.intellij.formatting; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; + +import com.intellij.formatting.FormattingContext; +import com.intellij.formatting.service.FormattingService.Feature; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.fileTypes.PlainTextFileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.local.CoreLocalFileSystem; +import com.intellij.openapi.vfs.local.CoreLocalVirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.testFramework.LightVirtualFile; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import io.spring.format.formatter.intellij.state.State; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link SpringJavaFormatFormattingService}. + * + * @author Phillip Webb + */ +class SpringJavaFormatFormattingServiceTests { + + private SpringJavaFormatFormattingService service = new SpringJavaFormatFormattingService( + (project, runnable) -> runnable.run()); + + @Test + void getFeaturesReturnsFormatFragments() { + assertThat(this.service.getFeatures()).containsExactly(Feature.FORMAT_FRAGMENTS); + } + + @Test + void canFormatWhenNotJavaReturnsFalse() { + FileType fileType = PlainTextFileType.INSTANCE; + PsiFile file = mockFile(fileType, State.ACTIVE); + assertThat(this.service.canFormat(file)).isFalse(); + } + + @Test + void canFormatWhenJavaFileAndNotActiveReturnsFalse() { + FileType fileType = FileTypeManager.getInstance().getStdFileType("JAVA"); + PsiFile file = mockFile(fileType, State.NOT_ACTIVE); + assertThat(this.service.canFormat(file)).isFalse(); + } + + @Test + void canFormatWhenJavaFileAndActiveReturnsTrue() { + FileType fileType = FileTypeManager.getInstance().getStdFileType("JAVA"); + PsiFile file = mockFile(fileType, State.ACTIVE); + assertThat(this.service.canFormat(file)).isTrue(); + } + + @Test + void formatDocumentAppliesFormatting(@TempDir Path projectDir) throws Exception { + Files.writeString(projectDir.resolve(".springjavaformatconfig"), "indentation-style=spaces"); + Document document = mockDocument("public class Hello{" + + "\tpublic void hello() {" + + "\tString value =\t\"Hello World\";}}"); + FormattingContext formattingContext = mock(FormattingContext.class); + VirtualFile virtualFile = new CoreLocalVirtualFile(new CoreLocalFileSystem(), projectDir.resolve("Hello.java")); + given(formattingContext.getVirtualFile()).willReturn(virtualFile); + this.service.formatDocument(document, Collections.emptyList(), formattingContext, false, false); + assertThat(document.getText()).isEqualTo("public class Hello {\n\n" + + " public void hello() {\n" + + " String value = \"Hello World\";\n" + + " }\n\n" + + "}"); + } + + @Test + void formatDocumentAppliesFormatting() { + Document document = mockDocument("public class Hello{" + + "\tpublic void hello() {" + + "\tString value =\t\"Hello World\";}}"); + FormattingContext formattingContext = mock(FormattingContext.class); + VirtualFile virtualFile = new LightVirtualFile("Hello.java", document.getText()); + given(formattingContext.getVirtualFile()).willReturn(virtualFile); + this.service.formatDocument(document, Collections.emptyList(), formattingContext, false, false); + assertThat(document.getText()).isEqualTo("public class Hello {\n\n" + + "\tpublic void hello() {\n" + + "\t\tString value = \"Hello World\";\n" + + "\t}\n\n" + + "}"); + } + + + private Document mockDocument(String text) { + Document document = mock(Document.class); + StringBuilder documentText = new StringBuilder(text); + willAnswer((invocation) -> { + documentText.replace(invocation.getArgument(0), invocation.getArgument(1), invocation.getArgument(2)); + return null; + }).given(document).replaceString(any(Integer.class), any(Integer.class), any(CharSequence.class)); + given(document.getText()).willAnswer((invocation) -> documentText.toString()); + return document; + } + + private PsiFile mockFile(FileType fileType, State state) { + PsiFile file = mock(PsiFile.class); + given(file.getFileType()).willReturn(fileType); + Project project = mock(Project.class); + given(project.getUserData(any())).willReturn(state); + given(file.getProject()).willReturn(project); + return file; + } + +} diff --git a/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml new file mode 100644 index 00000000..b6202b0d --- /dev/null +++ b/spring-javaformat-intellij-idea/spring-javaformat-intellij-idea-runtime/pom.xml @@ -0,0 +1,301 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat-intellij-idea + 0.0.48-SNAPSHOT + + spring-javaformat-intellij-idea-runtime + pom + Spring JavaFormat IntelliJ IDEA Runtime + + ${basedir}/../.. + https://download.jetbrains.com/idea/ideaIC-2022.3.2.tar.gz + https://github.com/JetBrains/intellij-community/archive/idea/223.8617.56.zip + ${project.build.directory}/intellij-source + idea-IC-223.8617.56 + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + com.googlecode.maven-download-plugin + download-maven-plugin + + + download-intellij-binary + validate + + wget + + + ${intellij.binary} + intellij.tar.gz + + + + download-intellij-source + install + + wget + + + ${intellij.source} + intellij-source.zip + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + prepare-intellij + install + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-install-plugin + + + install-intellij-util + install + false + + install-file + + + ${project.build.directory}/intellij/util.jar + ${intellij.source.directory}/util-sources.zip + io.spring.javaformat.intellij.idea + util + ${project.version} + jar + true + + + + install-intellij-util_rt + install + false + + install-file + + + ${project.build.directory}/intellij/util_rt.jar + ${intellij.source.directory}/util_rt-sources.zip + io.spring.javaformat.intellij.idea + util_rt + ${project.version} + jar + true + + + + install-intellij-app + install + false + + install-file + + + ${project.build.directory}/intellij/app.jar + ${intellij.source.directory}/app-sources.zip + io.spring.javaformat.intellij.idea + app + ${project.version} + jar + true + + + + install-intellij-maven + install + false + + install-file + + + ${project.build.directory}/intellij/maven.jar + ${intellij.source.directory}/maven-sources.zip + io.spring.javaformat.intellij.idea + maven + ${project.version} + jar + true + + + + install-intellij-maven-server + install + false + + install-file + + + ${project.build.directory}/intellij/maven-server.jar + ${intellij.source.directory}/maven-server-sources.zip + io.spring.javaformat.intellij.idea + maven-server + ${project.version} + jar + true + + + + install-intellij-gradle + install + false + + install-file + + + ${project.build.directory}/intellij/gradle.jar + ${intellij.source.directory}/gradle-sources.zip + io.spring.javaformat.intellij.idea + gradle + ${project.version} + jar + true + + + + install-intellij-gradle-tooling-extension-api + install + false + + install-file + + + ${project.build.directory}/intellij/gradle-tooling-extension-api.jar + ${intellij.source.directory}/gradle-tooling-extension-api-sources.zip + io.spring.javaformat.intellij.idea + gradle-tooling-extension-api + ${project.version} + jar + true + + + + install-intellij-jps-model + install + false + + install-file + + + ${project.build.directory}/intellij/jps-model.jar + ${intellij.source.directory}/jps-model-sources.zip + io.spring.javaformat.intellij.idea + jps-model + ${project.version} + jar + true + + + + install-intellij-gradle-tooling-extension-impl + install + false + + install-file + + + ${project.build.directory}/intellij/gradle-tooling-extension-impl.jar + ${intellij.source.directory}/gradle-tooling-extension-impl-sources.zip + io.spring.javaformat.intellij.idea + gradle-tooling-extension-impl + ${project.version} + jar + true + + + + + + + diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/SpringFormatComponent.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/SpringFormatComponent.java deleted file mode 100644 index fc9952ab..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/SpringFormatComponent.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2017-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij; - -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import com.intellij.ide.plugins.IdeaPluginDescriptor; -import com.intellij.ide.plugins.PluginManagerCore; -import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.application.ApplicationInfo; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.ProjectComponent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.PluginId; -import com.intellij.openapi.project.Project; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.serviceContainer.PlatformComponentManagerImpl; -import org.picocontainer.MutablePicoContainer; - -import io.spring.format.formatter.intellij.codestyle.SpringCodeStyleManager; -import io.spring.format.formatter.intellij.codestyle.monitor.FileMonitor; -import io.spring.format.formatter.intellij.codestyle.monitor.GradleMonitor; -import io.spring.format.formatter.intellij.codestyle.monitor.MavenMonitor; -import io.spring.format.formatter.intellij.codestyle.monitor.Monitors; -import io.spring.format.formatter.intellij.codestyle.monitor.Trigger.State; - -/** - * {@link ProjectComponent} to add Spring Java Format IntelliJ support. - * - * @author Phillip Webb - */ -public class SpringFormatComponent implements ProjectComponent { - - private static final String CODE_STYLE_MANAGER_KEY = CodeStyleManager.class.getName(); - - private static final String ACTIVE_PROPERTY = SpringFormatComponent.class.getName() + ".ACTIVE"; - - private final Project project; - - private final StatusIndicator statusIndicator; - - private final Lock lock = new ReentrantLock(); - - private Monitors monitors; - - private static final Logger logger = Logger.getInstance(SpringFormatComponent.class); - - private PropertiesComponent properties; - - protected SpringFormatComponent(Project project) { - this.project = project; - this.statusIndicator = new StatusIndicator(project); - this.properties = PropertiesComponent.getInstance(project); - } - - @Override - public void initComponent() { - if (this.properties.getBoolean(ACTIVE_PROPERTY, false)) { - update(State.ACTIVE); - } - this.monitors = new Monitors(this.project, this::update, FileMonitor.factory(), MavenMonitor.factory(), - GradleMonitor.factory()); - } - - @Override - public void disposeComponent() { - if (this.monitors != null) { - this.monitors.stop(); - this.monitors = null; - } - } - - private void update(State state) { - this.lock.lock(); - try { - CodeStyleManager manager = CodeStyleManager.getInstance(this.project); - if (manager == null) { - logger.warn("Unable to find exiting CodeStyleManager"); - return; - } - if (state == State.ACTIVE && !(manager instanceof SpringCodeStyleManager)) { - logger.debug("Enabling SpringCodeStyleManager"); - registerCodeStyleManager(new SpringCodeStyleManager(manager)); - this.properties.setValue(ACTIVE_PROPERTY, true); - } - if (state == State.NOT_ACTIVE && (manager instanceof SpringCodeStyleManager)) { - logger.debug("Disabling SpringCodeStyleManager"); - registerCodeStyleManager(((SpringCodeStyleManager) manager).getDelegate()); - this.properties.setValue(ACTIVE_PROPERTY, false); - } - ApplicationManager.getApplication().invokeLater(() -> this.statusIndicator.update(state)); - } - finally { - this.lock.unlock(); - } - } - - private void registerCodeStyleManager(CodeStyleManager manager) { - if (ApplicationInfo.getInstance().getBuild().getBaselineVersion() >= 193) { - PlatformComponentManagerImpl platformComponentManager = (PlatformComponentManagerImpl) this.project; - IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(PluginId.getId("spring-javaformat")); - platformComponentManager.registerServiceInstance(CodeStyleManager.class, manager, plugin); - } - else { - MutablePicoContainer container = (MutablePicoContainer) this.project.getPicoContainer(); - container.unregisterComponent(CODE_STYLE_MANAGER_KEY); - container.registerComponentInstance(CODE_STYLE_MANAGER_KEY, manager); - } - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/DelegatingCodeStyleManager.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/DelegatingCodeStyleManager.java deleted file mode 100644 index 20117fd1..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/DelegatingCodeStyleManager.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij.codestyle; - -import java.util.Collection; - -import com.intellij.formatting.FormattingMode; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.ChangedRangesInfo; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.DocCommentSettings; -import com.intellij.psi.codeStyle.FormattingModeAwareIndentAdjuster; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ThrowableRunnable; - -/** - * {@link CodeStyleManager} implementation that delegates all calls. - * - * @author Phillip Webb - */ -public class DelegatingCodeStyleManager extends CodeStyleManager implements FormattingModeAwareIndentAdjuster { - - private final CodeStyleManager delegate; - - public DelegatingCodeStyleManager(CodeStyleManager delegate) { - this.delegate = delegate; - } - - public CodeStyleManager getDelegate() { - return this.delegate; - } - - @Override - public int getSpacing(PsiFile file, int offset) { - return this.delegate.getSpacing(file, offset); - } - - @Override - public int getMinLineFeeds(PsiFile file, int offset) { - return this.delegate.getMinLineFeeds(file, offset); - } - - @Override - public void runWithDocCommentFormattingDisabled(PsiFile file, Runnable runnable) { - this.delegate.runWithDocCommentFormattingDisabled(file, runnable); - } - - @Override - public DocCommentSettings getDocCommentSettings(PsiFile file) { - return this.delegate.getDocCommentSettings(file); - } - - @Override - public Project getProject() { - return this.delegate.getProject(); - } - - @Override - public PsiElement reformat(PsiElement element) throws IncorrectOperationException { - return this.delegate.reformat(element); - } - - @Override - public PsiElement reformat(PsiElement element, boolean canChangeWhiteSpacesOnly) - throws IncorrectOperationException { - return this.delegate.reformat(element, canChangeWhiteSpacesOnly); - } - - @Override - public PsiElement reformatRange(PsiElement element, int startOffset, int endOffset) - throws IncorrectOperationException { - return this.delegate.reformatRange(element, startOffset, endOffset); - } - - @Override - public PsiElement reformatRange(PsiElement element, int startOffset, int endOffset, - boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException { - return this.delegate.reformatRange(element, startOffset, endOffset, canChangeWhiteSpacesOnly); - } - - @Override - public void reformatText(PsiFile file, int startOffset, int endOffset) throws IncorrectOperationException { - this.delegate.reformatText(file, startOffset, endOffset); - } - - @Override - public void reformatText(PsiFile file, Collection ranges) throws IncorrectOperationException { - this.delegate.reformatText(file, ranges); - } - - @Override - public void reformatTextWithContext(PsiFile file, Collection ranges) throws IncorrectOperationException { - this.delegate.reformatTextWithContext(file, ranges); - } - - @Override - public void reformatTextWithContext(PsiFile file, ChangedRangesInfo info) throws IncorrectOperationException { - this.delegate.reformatTextWithContext(file, info); - } - - @Override - public void adjustLineIndent(PsiFile file, TextRange rangeToAdjust) throws IncorrectOperationException { - this.delegate.adjustLineIndent(file, rangeToAdjust); - } - - @Override - public int adjustLineIndent(PsiFile file, int offset) throws IncorrectOperationException { - return this.delegate.adjustLineIndent(file, offset); - } - - @Override - public int adjustLineIndent(Document document, int offset) { - return this.delegate.adjustLineIndent(document, offset); - } - - @Override - @Deprecated - public boolean isLineToBeIndented(PsiFile file, int offset) { - return this.delegate.isLineToBeIndented(file, offset); - } - - @Override - public String getLineIndent(PsiFile file, int offset) { - return this.delegate.getLineIndent(file, offset); - } - - @Override - public String getLineIndent(Document document, int offset) { - return this.delegate.getLineIndent(document, offset); - } - - @Override - @Deprecated - public com.intellij.psi.codeStyle.Indent getIndent(String text, FileType fileType) { - return this.delegate.getIndent(text, fileType); - } - - @Override - @Deprecated - public String fillIndent(com.intellij.psi.codeStyle.Indent indent, FileType fileType) { - return this.delegate.fillIndent(indent, fileType); - } - - @Override - @Deprecated - public com.intellij.psi.codeStyle.Indent zeroIndent() { - return this.delegate.zeroIndent(); - } - - @Override - public void reformatNewlyAddedElement(ASTNode block, ASTNode addedElement) throws IncorrectOperationException { - this.delegate.reformatNewlyAddedElement(block, addedElement); - } - - @Override - public boolean isSequentialProcessingAllowed() { - return this.delegate.isSequentialProcessingAllowed(); - } - - @Override - public void performActionWithFormatterDisabled(Runnable r) { - this.delegate.performActionWithFormatterDisabled(r); - } - - @Override - public void performActionWithFormatterDisabled(ThrowableRunnable r) throws T { - this.delegate.performActionWithFormatterDisabled(r); - } - - @Override - public T performActionWithFormatterDisabled(Computable r) { - return this.delegate.performActionWithFormatterDisabled(r); - } - - @Override - public int adjustLineIndent(Document document, int offset, FormattingMode mode) { - if (this.delegate instanceof FormattingModeAwareIndentAdjuster) { - return ((FormattingModeAwareIndentAdjuster) this.delegate).adjustLineIndent(document, offset, mode); - } - return offset; - } - - @Override - public FormattingMode getCurrentFormattingMode() { - if (this.delegate instanceof FormattingModeAwareIndentAdjuster) { - return ((FormattingModeAwareIndentAdjuster) this.delegate).getCurrentFormattingMode(); - } - return FormattingMode.REFORMAT; - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/SpringCodeStyleManager.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/SpringCodeStyleManager.java deleted file mode 100644 index 9b4719f9..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/SpringCodeStyleManager.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij.codestyle; - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Supplier; - -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; - -/** - * {@link CodeStyleManager} to apply Spring Formatting conventions. - * - * @author Phillip Webb - */ -public class SpringCodeStyleManager extends DelegatingCodeStyleManager { - - private final SpringReformatter springReformatter; - - public SpringCodeStyleManager(CodeStyleManager delegate) { - super(delegate); - this.springReformatter = new SpringReformatter(() -> getProject()); - } - - SpringCodeStyleManager(CodeStyleManager delegate, SpringReformatter springReformatter) { - super(delegate); - this.springReformatter = springReformatter; - } - - @Override - public void reformatText(PsiFile file, int startOffset, int endOffset) throws IncorrectOperationException { - reformat(file, () -> Collections.singleton(new TextRange(startOffset, endOffset)), - () -> super.reformatText(file, startOffset, endOffset)); - } - - @Override - public void reformatText(PsiFile file, Collection ranges) throws IncorrectOperationException { - reformat(file, () -> ranges, () -> super.reformatText(file, ranges)); - } - - @Override - public void reformatTextWithContext(PsiFile file, Collection ranges) throws IncorrectOperationException { - reformat(file, () -> ranges, () -> super.reformatTextWithContext(file, ranges)); - } - - private void reformat(PsiFile file, Supplier> ranges, Runnable delegate) { - if (this.springReformatter.canReformat(file)) { - this.springReformatter.reformat(file, ranges.get()); - } - else { - delegate.run(); - } - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/SpringReformatter.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/SpringReformatter.java deleted file mode 100644 index c74cc3e8..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/java/io/spring/format/formatter/intellij/codestyle/SpringReformatter.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij.codestyle; - -import java.util.Collection; -import java.util.function.Supplier; - -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiBundle; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.util.IncorrectOperationException; -import org.eclipse.jface.text.IRegion; -import org.eclipse.text.edits.TextEdit; - -import io.spring.javaformat.formatter.Formatter; - -/** - * Reformatter used by {@link SpringCodeStyleManager} to determine when formatting can - * apply and to perform the actual formatting. - * - * @author Phillip Webb - */ -class SpringReformatter { - - private static final String NORMALIZED_LINE_SEPARATOR = "\n"; - - private final Supplier project; - - private final Supplier application; - - private final Supplier documentManager; - - SpringReformatter(Supplier project) { - this.project = project; - this.application = () -> ApplicationManager.getApplication(); - this.documentManager = () -> PsiDocumentManager.getInstance(project.get()); - } - - SpringReformatter(Supplier project, Supplier application, - Supplier documentManager) { - this.project = project; - this.application = application; - this.documentManager = documentManager; - } - - public boolean canReformat(PsiFile file) { - return StdFileTypes.JAVA.equals(file.getFileType()); - } - - public void reformat(PsiFile file, Collection ranges) { - this.application.get().assertWriteAccessAllowed(); - this.documentManager.get().commitAllDocuments(); - if (!file.isWritable()) { - throwNotWritableException(file); - } - reformat(file, ranges, this.documentManager.get().getDocument(file)); - } - - private void throwNotWritableException(PsiElement element) throws IncorrectOperationException { - if (element instanceof PsiDirectory) { - String url = ((PsiDirectory) element).getVirtualFile().getPresentableUrl(); - throw new IncorrectOperationException(PsiBundle.message("cannot.modify.a.read.only.directory", url)); - } - PsiFile file = element.getContainingFile(); - if (file == null) { - throw new IncorrectOperationException(); - } - VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null) { - throw new IncorrectOperationException(); - } - throw new IncorrectOperationException( - PsiBundle.message("cannot.modify.a.read.only.file", virtualFile.getPresentableUrl())); - } - - private void reformat(PsiFile file, Collection ranges, Document document) { - if (document != null) { - Formatter formatter = new Formatter(); - String source = document.getText(); - IRegion[] regions = EclipseRegionAdapter.asArray(ranges); - TextEdit edit = formatter.format(source, regions, NORMALIZED_LINE_SEPARATOR); - applyEdit(document, edit); - } - } - - private void applyEdit(Document document, TextEdit textEdit) { - runWriteCommandAction(() -> { - try { - EclipseDocumentAdapter adapter = new EclipseDocumentAdapter(document); - textEdit.apply(adapter); - this.documentManager.get().commitDocument(document); - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - }); - } - - protected void runWriteCommandAction(Runnable runnable) { - WriteCommandAction.runWriteCommandAction(this.project.get(), runnable); - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/resources/META-INF/plugin.xml b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/resources/META-INF/plugin.xml deleted file mode 100644 index 5f8225c8..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/main/resources/META-INF/plugin.xml +++ /dev/null @@ -1,16 +0,0 @@ - - spring-javaformat - spring-javaformat - 1.0 - Spring - - - org.jetbrains.idea.maven - org.jetbrains.plugins.gradle - - - io.spring.format.formatter.intellij.SpringFormatComponent - - - - diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/DelegatingCodeStyleManagerTests.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/DelegatingCodeStyleManagerTests.java deleted file mode 100644 index 8845bf3d..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/DelegatingCodeStyleManagerTests.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij.codestyle; - -import java.util.Collection; -import java.util.Collections; - -import com.intellij.lang.ASTNode; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.ChangedRangesInfo; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.ThrowableRunnable; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -/** - * Tests for {@link DelegatingCodeStyleManager}. - * - * @author Phillip Webb - */ -public class DelegatingCodeStyleManagerTests { - - @Mock - private CodeStyleManager delegate; - - private DelegatingCodeStyleManager delegating; - - @Mock - private PsiElement element; - - @Mock - private PsiFile file; - - @Mock - private TextRange range; - - private Collection ranges; - - @Mock - private Document document; - - @Mock - private FileType fileType; - - @Mock - private ASTNode block; - - @Mock - private ASTNode node; - - @Mock - private ChangedRangesInfo changedRangesInfo; - - @Before - @Test - public void setup() { - MockitoAnnotations.initMocks(this); - this.delegating = new DelegatingCodeStyleManager(this.delegate); - this.ranges = Collections.singleton(mock(TextRange.class)); - } - - @Test - public void getDelegateShouldGetDelegate() throws Exception { - assertThat(this.delegating.getDelegate()).isEqualTo(this.delegate); - } - - @Test - public void getProjectShouldCallDelegate() throws Exception { - this.delegating.getProject(); - verify(this.delegate).getProject(); - } - - @Test - public void reformatShouldCallDelegate() throws Exception { - this.delegating.reformat(this.element); - verify(this.delegate).reformat(this.element); - } - - @Test - public void reformatWithCanChangeWhiteSpacesOnlyShouldCallDelegate() throws Exception { - this.delegating.reformat(this.element, true); - verify(this.delegate).reformat(this.element, true); - } - - @Test - public void reformatRangeShouldCallDelegate() throws Exception { - this.delegating.reformatRange(this.element, 12, 34); - verify(this.delegate).reformatRange(this.element, 12, 34); - } - - @Test - public void reformatRangeWithCanChangeWhiteSpacesOnlyShouldCallDelegate() throws Exception { - this.delegating.reformatRange(this.element, 12, 34, true); - verify(this.delegate).reformatRange(this.element, 12, 34, true); - } - - @Test - public void reformatTextShouldCallDelegate() throws Exception { - this.delegating.reformatText(this.file, 12, 34); - verify(this.delegate).reformatText(this.file, 12, 34); - } - - @Test - public void reformatTextWithRangeCollectionShouldCallDelegate() throws Exception { - this.delegating.reformatText(this.file, this.ranges); - verify(this.delegate).reformatText(this.file, this.ranges); - } - - @Test - public void reformatTextWithContextShouldCallDelegate() throws Exception { - this.delegating.reformatTextWithContext(this.file, this.ranges); - verify(this.delegate).reformatTextWithContext(this.file, this.ranges); - } - - @Test - public void reformatTextWithContextInfoShouldCallDelegate() throws Exception { - this.delegating.reformatTextWithContext(this.file, this.changedRangesInfo); - verify(this.delegate).reformatTextWithContext(this.file, this.changedRangesInfo); - } - - @Test - public void adjustLineIndentForFileWithRangeShouldCallDelegate() throws Exception { - this.delegating.adjustLineIndent(this.file, this.range); - verify(this.delegate).adjustLineIndent(this.file, this.range); - } - - @Test - public void adjustLineIndentForFileShouldCallDelegate() throws Exception { - this.delegating.adjustLineIndent(this.file, 123); - verify(this.delegate).adjustLineIndent(this.file, 123); - } - - @Test - public void adjustLineIndentForDocumentShouldCallDelegate() throws Exception { - this.delegating.adjustLineIndent(this.document, 123); - verify(this.delegate).adjustLineIndent(this.document, 123); - } - - @Test - @Deprecated - public void isLineToBeIndentedShouldCallDelegate() throws Exception { - this.delegating.isLineToBeIndented(this.file, 123); - verify(this.delegate).isLineToBeIndented(this.file, 123); - } - - @Test - public void getLineIndentForFileShouldCallDelegate() throws Exception { - this.delegating.getLineIndent(this.file, 123); - verify(this.delegate).getLineIndent(this.file, 123); - } - - @Test - public void getLineIndentForDocumentShouldCallDelegate() throws Exception { - this.delegating.getLineIndent(this.document, 123); - verify(this.delegate).getLineIndent(this.document, 123); - } - - @Test - @Deprecated - public void getIndentShouldCallDelegate() throws Exception { - this.delegating.getIndent("hello", this.fileType); - verify(this.delegate).getIndent("hello", this.fileType); - } - - @Test - @Deprecated - public void fillIndentShouldCallDelegate() throws Exception { - com.intellij.psi.codeStyle.Indent indent = mock(com.intellij.psi.codeStyle.Indent.class); - this.delegating.fillIndent(indent, this.fileType); - verify(this.delegate).fillIndent(indent, this.fileType); - } - - @Test - @Deprecated - public void zeroIndentShouldCallDelegate() throws Exception { - this.delegating.zeroIndent(); - verify(this.delegate).zeroIndent(); - } - - @Test - public void reformatNewlyAddedElementShouldCallDelegate() throws Exception { - this.delegating.reformatNewlyAddedElement(this.block, this.node); - verify(this.delegate).reformatNewlyAddedElement(this.block, this.node); - } - - @Test - public void isSequentialProcessingAllowedShouldCallDelegate() throws Exception { - this.delegating.isSequentialProcessingAllowed(); - verify(this.delegate).isSequentialProcessingAllowed(); - } - - @Test - public void performActionWithFormatterDisabledWithRunnableShouldCallDelegate() throws Exception { - Runnable runnable = mock(Runnable.class); - this.delegating.performActionWithFormatterDisabled(runnable); - verify(this.delegate).performActionWithFormatterDisabled(runnable); - } - - @Test - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void performActionWithFormatterDisabledWithThrowableRunnableShouldCallDelegate() throws Throwable { - ThrowableRunnable runnable = mock(ThrowableRunnable.class); - this.delegating.performActionWithFormatterDisabled(runnable); - verify(this.delegate).performActionWithFormatterDisabled(runnable); - } - - @Test - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void performActionWithFormatterDisabledWithComputableShouldCallDelegate() throws Exception { - Computable computable = mock(Computable.class); - this.delegating.performActionWithFormatterDisabled(computable); - verify(this.delegate).performActionWithFormatterDisabled(computable); - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/SpringCodeStyleManagerTests.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/SpringCodeStyleManagerTests.java deleted file mode 100644 index f3d3616e..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/SpringCodeStyleManagerTests.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij.codestyle; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleManager; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -/** - * Tests for {@link SpringCodeStyleManager}. - * - * @author Phillip Webb - */ -public class SpringCodeStyleManagerTests { - - @Mock - private CodeStyleManager delegate; - - @Mock - private SpringReformatter springReformatter; - - private SpringCodeStyleManager styleManager; - - @Mock - private PsiFile file; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - this.styleManager = new SpringCodeStyleManager(this.delegate, this.springReformatter); - } - - @Test - public void reformatTextWithOffsetWhenCantFormatShouldCallDelegate() { - given(this.springReformatter.canReformat(any())).willReturn(false); - this.styleManager.reformatText(this.file, 10, 20); - verify(this.delegate).reformatText(this.file, 10, 20); - } - - @Test - public void reformatTextWithOffsetWhenCanFormatShouldCallFormatter() { - given(this.springReformatter.canReformat(any())).willReturn(true); - Set ranges = new HashSet<>(Arrays.asList(new TextRange(10, 20))); - this.styleManager.reformatText(this.file, 10, 20); - verify(this.springReformatter).reformat(this.file, ranges); - verifyZeroInteractions(this.delegate); - } - - @Test - public void reformatTextWithRangeWhenCantFormatShouldCallDelegate() { - given(this.springReformatter.canReformat(any())).willReturn(false); - Collection ranges = Arrays.asList(new TextRange(10, 20)); - this.styleManager.reformatText(this.file, ranges); - verify(this.delegate).reformatText(this.file, ranges); - } - - @Test - public void reformatTextWithRangeWhenCanFormatShouldCallFormatter() { - given(this.springReformatter.canReformat(any())).willReturn(true); - Collection ranges = Arrays.asList(new TextRange(10, 20)); - this.styleManager.reformatText(this.file, ranges); - verify(this.springReformatter).reformat(this.file, ranges); - verifyZeroInteractions(this.delegate); - } - - @Test - public void reformatTextWithContextWhenCantFormatShouldCallDelegate() { - given(this.springReformatter.canReformat(any())).willReturn(false); - Collection ranges = Arrays.asList(new TextRange(10, 20)); - this.styleManager.reformatTextWithContext(this.file, ranges); - verify(this.delegate).reformatTextWithContext(this.file, ranges); - } - - @Test - public void reformatTextWithContextWhenCanFormatShouldCallFormatter() { - given(this.springReformatter.canReformat(any())).willReturn(true); - Collection ranges = Arrays.asList(new TextRange(10, 20)); - this.styleManager.reformatTextWithContext(this.file, ranges); - verify(this.springReformatter).reformat(this.file, ranges); - verifyZeroInteractions(this.delegate); - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/SpringReformatterTests.java b/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/SpringReformatterTests.java deleted file mode 100644 index 1609bdf3..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-plugin/src/test/java/io/spring/format/formatter/intellij/codestyle/SpringReformatterTests.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.format.formatter.intellij.codestyle; - -import java.util.Arrays; -import java.util.Collection; -import java.util.function.Supplier; - -import com.intellij.openapi.application.Application; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.util.IncorrectOperationException; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -/** - * Tests for {@link SpringReformatter}. - * - * @author Phillip Webb - */ -public class SpringReformatterTests { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Mock - private Project project; - - @Mock - private Application application; - - @Mock - private PsiDocumentManager documentManager; - - private SpringReformatter reformatter; - - @Mock - private PsiFile file; - - private Collection ranges = Arrays.asList(new TextRange(10, 20)); - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - this.reformatter = new TestSpringReformatter(() -> this.project, () -> this.application, - () -> this.documentManager); - } - - @Test - public void reformatShouldAssertWriteAccess() throws Exception { - given(this.file.isWritable()).willReturn(true); - this.reformatter.reformat(this.file, this.ranges); - verify(this.application).assertWriteAccessAllowed(); - } - - @Test - public void reformatShouldCommitAllDocuments() throws Exception { - given(this.file.isWritable()).willReturn(true); - this.reformatter.reformat(this.file, this.ranges); - verify(this.documentManager).commitAllDocuments(); - } - - @Test - public void reformatWhenFileIsNotWriteableShouldThrow() throws Exception { - this.thrown.expect(IncorrectOperationException.class); - this.reformatter.reformat(this.file, this.ranges); - } - - @Test - public void reformatShouldReformatDocument() throws Exception { - given(this.file.isWritable()).willReturn(true); - Document document = mock(Document.class); - String text = "public class Hello {}"; - given(document.getText()).willReturn(text); - given(this.documentManager.getDocument(this.file)).willReturn(document); - this.reformatter.reformat(this.file, Arrays.asList(new TextRange(0, text.length()))); - verify(document).replaceString(20, 20, "\n\n"); - verify(this.documentManager).commitDocument(document); - } - - static class TestSpringReformatter extends SpringReformatter { - - TestSpringReformatter(Supplier project, Supplier application, - Supplier documentManager) { - super(project, application, documentManager); - } - - @Override - protected void runWriteCommandAction(Runnable runnable) { - runnable.run(); - } - - } - -} diff --git a/spring-javaformat-intellij/spring-javaformat-intellij-runtime/pom.xml b/spring-javaformat-intellij/spring-javaformat-intellij-runtime/pom.xml deleted file mode 100644 index f82ab1c4..00000000 --- a/spring-javaformat-intellij/spring-javaformat-intellij-runtime/pom.xml +++ /dev/null @@ -1,351 +0,0 @@ - - - 4.0.0 - - io.spring.javaformat - spring-javaformat-intellij - 0.0.21-SNAPSHOT - - spring-javaformat-intellij-runtime - pom - Spring JavaFormat IntelliJ Runtime - - ${basedir}/../.. - https://download.jetbrains.com/idea/ideaIC-2019.3.1.tar.gz - https://github.com/JetBrains/intellij-community/archive/idea/193.5662.53.zip - idea-IC-193.5662.53 - - - - - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - com.googlecode.maven-download-plugin - download-maven-plugin - - - download-intellij-binary - validate - - wget - - - ${intellij.binary} - intellij.tar.gz - - - - download-intellij-source - install - - wget - - - ${intellij.source} - intellij-source.zip - - - - - - org.apache.maven.plugins - maven-antrun-plugin - - - prepare-intellij - install - - run - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.apache.maven.plugins - maven-install-plugin - - - install-intellij-platform-api - install - false - - install-file - - - ${project.build.directory}/intellij/platform-api.jar - ${project.build.directory}/intellij-source/platform-api-sources.zip - io.spring.javaformat.intellij - platform-api - ${project.version} - jar - true - - - - install-intellij-platform-impl - install - false - - install-file - - - ${project.build.directory}/intellij/platform-impl.jar - ${project.build.directory}/intellij-source/platform-impl-sources.zip - io.spring.javaformat.intellij - platform-impl - ${project.version} - jar - true - - - - install-intellij-util - install - false - - install-file - - - ${project.build.directory}/intellij/util.jar - ${project.build.directory}/intellij-source/util-sources.zip - io.spring.javaformat.intellij - util - ${project.version} - jar - true - - - - install-intellij-platform-util-ui - install - false - - install-file - - - ${project.build.directory}/intellij/platform-util-ui.jar - ${project.build.directory}/intellij-source/platform-util-ui-sources.zip - io.spring.javaformat.intellij - platform-util-ui - ${project.version} - jar - true - - - - install-intellij-extensions - install - false - - install-file - - - ${project.build.directory}/intellij/extensions.jar - ${project.build.directory}/intellij-source/extensions-sources.zip - io.spring.javaformat.intellij - extensions - ${project.version} - jar - true - - - - install-intellij-platform-service-container - install - false - - install-file - - - ${project.build.directory}/intellij/platform-serviceContainer.jar - ${project.build.directory}/intellij-source/platform-service-container-sources.zip - io.spring.javaformat.intellij - platform-service-container - ${project.version} - jar - true - - - - install-intellij-idea - install - false - - install-file - - - ${project.build.directory}/intellij/idea.jar - io.spring.javaformat.intellij - idea - ${project.version} - jar - true - - - - install-intellij-maven - install - false - - install-file - - - ${project.build.directory}/intellij/maven.jar - ${project.build.directory}/intellij-source/maven-sources.zip - io.spring.javaformat.intellij - maven - ${project.version} - jar - true - - - - install-intellij-maven-server-api - install - false - - install-file - - - ${project.build.directory}/intellij/maven-server-api.jar - io.spring.javaformat.intellij - maven-server-api - ${project.version} - jar - true - - - - install-intellij-gradle - install - false - - install-file - - - ${project.build.directory}/intellij/gradle-common.jar - ${project.build.directory}/intellij-source/gradle-sources.zip - io.spring.javaformat.intellij - gradle - ${project.version} - jar - true - - - - install-intellij-gradle-tooling-extension-api - install - false - - install-file - - - ${project.build.directory}/intellij/gradle-tooling-extension-api.jar - ${project.build.directory}/intellij-source/gradle-tooling-extension-api-sources.zip - io.spring.javaformat.intellij - gradle-tooling-extension-api - ${project.version} - jar - true - - - - install-intellij-gradle-tooling-extension-impl - install - false - - install-file - - - ${project.build.directory}/intellij/gradle-tooling-extension-impl.jar - ${project.build.directory}/intellij-source/gradle-tooling-extension-impl-sources.zip - io.spring.javaformat.intellij - gradle-tooling-extension-impl - ${project.version} - jar - true - - - - - - - diff --git a/spring-javaformat-maven/pom.xml b/spring-javaformat-maven/pom.xml index 6e772188..61cb5d27 100644 --- a/spring-javaformat-maven/pom.xml +++ b/spring-javaformat-maven/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-maven pom diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml index 32101aa1..af8474d3 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat-maven - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-maven-plugin maven-plugin @@ -15,6 +15,16 @@ + + maven-clean-plugin + + + + out + + + + org.apache.maven.plugins maven-invoker-plugin @@ -91,15 +101,21 @@ + + org.codehaus.plexus + plexus-utils + + org.apache.maven maven-core + provided org.apache.maven maven-plugin-api + provided - org.apache.maven.plugin-tools maven-plugin-annotations diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/pom.xml new file mode 100644 index 00000000..b71be82c --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + io.spring.javaformat + apply-line-separator + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + 1.8 + 1.8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + apply + + + CR + + + + + + + diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/src/main/java/simple/Simple.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/src/main/java/simple/Simple.java new file mode 100644 index 00000000..10016e5d --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/src/main/java/simple/Simple.java @@ -0,0 +1,14 @@ +package simple; + +/** + * Simple. + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/verify.groovy b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/verify.groovy new file mode 100644 index 00000000..21927be4 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-line-separator/verify.groovy @@ -0,0 +1 @@ +new io.spring.format.maven.VerifyApply().verify(basedir, "\r") diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/pom.xml new file mode 100644 index 00000000..213305b9 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + io.spring.javaformat + apply-skip + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + 1.8 + 1.8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + apply + + + true + + + + + + + diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/src/main/java/simple/Simple.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/src/main/java/simple/Simple.java new file mode 100644 index 00000000..10016e5d --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/src/main/java/simple/Simple.java @@ -0,0 +1,14 @@ +package simple; + +/** + * Simple. + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/verify.groovy b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/verify.groovy new file mode 100644 index 00000000..5ffd403d --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-skip/verify.groovy @@ -0,0 +1 @@ +new io.spring.format.maven.VerifyApply().verifyNoApply(basedir) diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/.springjavaformatconfig b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/.springjavaformatconfig new file mode 100644 index 00000000..881903b2 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/.springjavaformatconfig @@ -0,0 +1 @@ +indentation-style=spaces diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/pom.xml new file mode 100644 index 00000000..252e99b8 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + io.spring.javaformat + apply + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + 1.8 + 1.8 + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + apply + + + + + + + diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/src/main/java/simple/Simple.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/src/main/java/simple/Simple.java new file mode 100644 index 00000000..10016e5d --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/src/main/java/simple/Simple.java @@ -0,0 +1,14 @@ +package simple; + +/** + * Simple. + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/verify.groovy b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/verify.groovy new file mode 100644 index 00000000..644be98b --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply-spaces/verify.groovy @@ -0,0 +1 @@ +new io.spring.format.maven.VerifyApply().verify(basedir, true) diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply/pom.xml index 35a6dbe5..252e99b8 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/apply/pom.xml @@ -7,6 +7,8 @@ 0.0.1.BUILD-SNAPSHOT UTF-8 + 1.8 + 1.8 diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-bad/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-bad/pom.xml index d0672160..7c23eaf4 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-bad/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-bad/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 io.spring.javaformat @@ -7,6 +8,8 @@ 0.0.1.BUILD-SNAPSHOT UTF-8 + 1.8 + 1.8 diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-exclude/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-exclude/pom.xml index 9e61971f..d213bc7b 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-exclude/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-exclude/pom.xml @@ -8,6 +8,8 @@ 0.0.1.BUILD-SNAPSHOT UTF-8 + 1.8 + 1.8 diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-include/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-include/pom.xml index 9c522c95..820f2c24 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-include/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-gensource-include/pom.xml @@ -8,6 +8,8 @@ 0.0.1.BUILD-SNAPSHOT UTF-8 + 1.8 + 1.8 diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-ok/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-ok/pom.xml index 0641c178..61fde7ba 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-ok/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-ok/pom.xml @@ -7,6 +7,8 @@ 0.0.1.BUILD-SNAPSHOT UTF-8 + 1.8 + 1.8 diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-global-property/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-global-property/pom.xml new file mode 100644 index 00000000..d05c8e80 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-global-property/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + io.spring.javaformat + validate-skip-global-property + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + 1.8 + 1.8 + true + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + validate + + + + + + + diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-global-property/src/main/java/simple/Simple.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-global-property/src/main/java/simple/Simple.java new file mode 100644 index 00000000..14f14516 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-global-property/src/main/java/simple/Simple.java @@ -0,0 +1,15 @@ +package simple; + +/** + * Simple. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-property/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-property/pom.xml new file mode 100644 index 00000000..e0319c25 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-property/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + io.spring.javaformat + validate-skip-property + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + 1.8 + 1.8 + true + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + validate + + + + + + + diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-property/src/main/java/simple/Simple.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-property/src/main/java/simple/Simple.java new file mode 100644 index 00000000..14f14516 --- /dev/null +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip-property/src/main/java/simple/Simple.java @@ -0,0 +1,15 @@ +package simple; + +/** + * Simple. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // Main method + } + +} diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip/pom.xml b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip/pom.xml index 7977c4fb..84c27feb 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip/pom.xml +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/it/validate-skip/pom.xml @@ -7,6 +7,8 @@ 0.0.1.BUILD-SNAPSHOT UTF-8 + 1.8 + 1.8 diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ApplyMojo.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ApplyMojo.java index 56d4b3b5..3d8bdc6d 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ApplyMojo.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ApplyMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,9 @@ import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; import io.spring.javaformat.formatter.FileEdit; -import io.spring.javaformat.formatter.FileFormatter; import io.spring.javaformat.formatter.FileFormatterException; /** @@ -37,11 +37,21 @@ @Mojo(name = "apply", defaultPhase = LifecyclePhase.PROCESS_SOURCES, threadSafe = true) public class ApplyMojo extends FormatMojo { + /** + * Skip the execution. + */ + @Parameter(property = "spring-javaformat.apply.skip", defaultValue = "false") + private boolean skip; + @Override - protected void execute(List files, Charset encoding) throws MojoExecutionException, MojoFailureException { + protected void execute(List files, Charset encoding, String lineSeparator) + throws MojoExecutionException, MojoFailureException { + if (this.skip || skipGlobally()) { + getLog().info("skipping format apply as per configuration."); + return; + } try { - FileFormatter formatter = new FileFormatter(); - formatter.formatFiles(files, encoding).filter(FileEdit::hasEdits).forEach(this::save); + getFormatter().formatFiles(files, encoding, lineSeparator).filter(FileEdit::hasEdits).forEach(this::save); } catch (FileFormatterException ex) { throw new MojoExecutionException("Unable to format file " + ex.getFile(), ex); diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/FormatMojo.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/FormatMojo.java index ea2de337..6270b549 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/FormatMojo.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/FormatMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,15 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -34,6 +39,9 @@ import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.FileUtils; +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.formatter.FileFormatter; + /** * Base class for formatter Mojo. * @@ -43,7 +51,18 @@ public abstract class FormatMojo extends AbstractMojo { private static final String[] DEFAULT_INCLUDES = new String[] { "**/*.java" }; - private static final String GENERATED_SOURCE = File.separator + "generated-sources" + File.separator; + private static final String GENERATED_SOURCES = File.separator + "generated-sources" + File.separator; + + private static final String GENERATED_TEST_SOURCES = File.separator + "generated-test-sources" + File.separator; + + private static final Map LINE_SEPARATOR; + static { + Map lineSeparator = new LinkedHashMap<>(); + lineSeparator.put("cr", "\r"); + lineSeparator.put("lf", "\n"); + lineSeparator.put("crlf", "\r\n"); + LINE_SEPARATOR = Collections.unmodifiableMap(lineSeparator); + } /** * The Maven Project Object. @@ -51,6 +70,12 @@ public abstract class FormatMojo extends AbstractMojo { @Parameter(defaultValue = "${project}", readonly = true, required = true) protected MavenProject project; + /** + * The Maven Session Object. + */ + @Parameter(defaultValue = "${session}", readonly = true, required = true) + protected MavenSession session; + /** * Specifies the location of the source directories to use. */ @@ -86,6 +111,12 @@ public abstract class FormatMojo extends AbstractMojo { @Parameter(property = "spring-javaformat.includeGeneratedSource", defaultValue = "false") private boolean includeGeneratedSource; + /** + * Specifies the line separator to use when formatting. + */ + @Parameter(property = "spring-javaformat.lineSeparator") + private String lineSeparator; + @Override public final void execute() throws MojoExecutionException, MojoFailureException { List directories = new ArrayList<>(); @@ -96,12 +127,20 @@ public final void execute() throws MojoExecutionException, MojoFailureException files.addAll(scan(directory)); } Charset encoding = (this.encoding == null ? StandardCharsets.UTF_8 : Charset.forName(this.encoding)); - execute(files, encoding); + String lineSeparator = null; + if (this.lineSeparator != null) { + lineSeparator = LINE_SEPARATOR.get(this.lineSeparator.toLowerCase()); + if (lineSeparator == null) { + throw new MojoExecutionException("Unknown lineSeparator " + this.lineSeparator); + } + } + execute(files, encoding, this.lineSeparator != null ? lineSeparator : null); } private Stream resolve(List directories) { - return directories.stream().map(directory -> FileUtils.resolveFile(this.project.getBasedir(), directory)) - .filter(this::include); + return directories.stream() + .map(directory -> FileUtils.resolveFile(this.project.getBasedir(), directory)) + .filter(this::include); } private boolean include(File file) { @@ -121,7 +160,8 @@ private boolean isGeneratedSource(File file) { try { String path = file.getCanonicalPath() + File.separator; String projectPath = this.project.getBasedir().getCanonicalPath(); - return path.startsWith(projectPath) && path.contains(GENERATED_SOURCE); + return path.startsWith(projectPath) + && (path.contains(GENERATED_SOURCES) || path.contains(GENERATED_TEST_SOURCES)); } catch (IOException ex) { return false; @@ -137,8 +177,10 @@ private List scan(File directory) { scanner.setCaseSensitive(false); scanner.setFollowSymlinks(false); scanner.scan(); - return Arrays.asList(scanner.getIncludedFiles()).stream().map(name -> new File(directory, name)) - .collect(Collectors.toList()); + return Arrays.asList(scanner.getIncludedFiles()) + .stream() + .map(name -> new File(directory, name)) + .collect(Collectors.toList()); } private boolean hasLength(Object[] array) { @@ -149,10 +191,28 @@ private boolean hasLength(Object[] array) { * Perform the formatting build-process behavior this {@code Mojo} implements. * @param files the files to process * @param encoding the encoding + * @param lineSeparator the line separator * @throws MojoExecutionException on execution error * @throws MojoFailureException on failure */ - protected abstract void execute(List files, Charset encoding) + protected abstract void execute(List files, Charset encoding, String lineSeparator) throws MojoExecutionException, MojoFailureException; + protected final FileFormatter getFormatter() { + JavaFormatConfig javaFormatConfig = JavaFormatConfig.findFrom(this.project.getBasedir()); + return new FileFormatter(javaFormatConfig); + } + + protected boolean skipGlobally() { + boolean result = false; + result = result || skipGlobally(this.session.getUserProperties()); + result = result || skipGlobally(this.session.getSystemProperties()); + result = result || skipGlobally(this.project.getProperties()); + return result; + } + + private boolean skipGlobally(Properties properties) { + return Boolean.valueOf(properties.getProperty("spring-javaformat.skip")); + } + } diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ValidateMojo.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ValidateMojo.java index 23edcaba..c9a77b81 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ValidateMojo.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/main/java/io/spring/format/maven/ValidateMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import org.apache.maven.plugins.annotations.Parameter; import io.spring.javaformat.formatter.FileEdit; -import io.spring.javaformat.formatter.FileFormatter; /** * Validates that source formatting matches the required style. @@ -41,18 +40,20 @@ public class ValidateMojo extends FormatMojo { /** * Skip the execution. */ - @Parameter(property = "spring-javaformat.skip", defaultValue = "false") + @Parameter(property = "spring-javaformat.validate.skip", defaultValue = "false") private boolean skip; @Override - protected void execute(List files, Charset encoding) throws MojoExecutionException, MojoFailureException { - if (this.skip) { - getLog().debug("skipping validation as per configuration."); + protected void execute(List files, Charset encoding, String lineSeparator) + throws MojoExecutionException, MojoFailureException { + if (this.skip || skipGlobally()) { + getLog().info("skipping format validate as per configuration."); return; } - FileFormatter formatter = new FileFormatter(); - List problems = formatter.formatFiles(files, encoding).filter(FileEdit::hasEdits).map(FileEdit::getFile) - .collect(Collectors.toList()); + List problems = getFormatter().formatFiles(files, encoding, lineSeparator) + .filter(FileEdit::hasEdits) + .map(FileEdit::getFile) + .collect(Collectors.toList()); if (!problems.isEmpty()) { StringBuilder message = new StringBuilder("Formatting violations found in the following files:\n"); problems.stream().forEach((f) -> message.append(" * " + f + "\n")); diff --git a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java index 2f501df2..4338b633 100644 --- a/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java +++ b/spring-javaformat-maven/spring-javaformat-maven-plugin/src/test/java/io/spring/format/maven/VerifyApply.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,13 +30,36 @@ */ public class VerifyApply { - private static final String LF = System.lineSeparator(); - private static final String JAVA_FILE = "src/main/java/simple/Simple.java"; public void verify(File base) throws IOException { + verify(base, null); + } + + public void verify(File base, boolean spaces) throws IOException { + verify(base, null, spaces); + } + + public void verify(File base, String lineSeparator) throws IOException { + verify(base, lineSeparator, false); + } + + public void verify(File base, String lineSeparator, boolean spaces) throws IOException { + String formated = new String(Files.readAllBytes(base.toPath().resolve(JAVA_FILE)), StandardCharsets.UTF_8); + if (lineSeparator == null) { + formated = formated.replace("\r\n", "\n").replace('\r', '\n'); + lineSeparator = "\n"; + } + String indent = (!spaces) ? " " : " "; + assertThat(formated).contains("Simple." + lineSeparator + " *" + lineSeparator + " * @author") + .contains("public class Simple {") + .contains(indent + "public static void main"); + } + + public void verifyNoApply(File base) throws IOException { String formated = new String(Files.readAllBytes(base.toPath().resolve(JAVA_FILE)), StandardCharsets.UTF_8); - assertThat(formated).contains("Simple." + LF + " *" + LF + " * @author").contains("public class Simple {"); + formated = formated.replace("\r\n", "\n").replace('\r', '\n'); + assertThat(formated).contains("Simple {"); } } diff --git a/spring-javaformat-vscode/README.md b/spring-javaformat-vscode/README.md new file mode 100644 index 00000000..e6dea6c9 --- /dev/null +++ b/spring-javaformat-vscode/README.md @@ -0,0 +1,19 @@ +# spring-javaformat-vscode + +`spring-javaformat` extension for visual studio code. + +![](./format.gif) + +## Prerequisites + +* Install [node.js](https://nodejs.org/en/download/) +* Install [yarn](https://yarnpkg.com/en/docs/install) +* Install [vsce](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#vsce) + +## Generate extension + +Just `mvn clean package` + + +> `spring-javaformat-1.0.0.vsix` will be generated there + diff --git a/spring-javaformat-vscode/format.gif b/spring-javaformat-vscode/format.gif new file mode 100644 index 00000000..fd1fdacd Binary files /dev/null and b/spring-javaformat-vscode/format.gif differ diff --git a/spring-javaformat-vscode/pom.xml b/spring-javaformat-vscode/pom.xml new file mode 100644 index 00000000..f42bc4bb --- /dev/null +++ b/spring-javaformat-vscode/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat-build + 0.0.48-SNAPSHOT + + spring-javaformat-vscode + pom + Spring JavaFormat Visual Studio Code + + ${basedir}/.. + + + spring-javaformat-vscode-extension + + diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.gitignore b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.gitignore new file mode 100644 index 00000000..2c32c547 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.gitignore @@ -0,0 +1,7 @@ +out +runtime +dist +node +node_modules +.vscode-test/ +*.vsix diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.prettierignore b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.prettierignore new file mode 100644 index 00000000..717380fe --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.prettierignore @@ -0,0 +1,5 @@ +out +target +node +.vscode +.vscode-test diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.prettierrc b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.prettierrc new file mode 100644 index 00000000..995d5360 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.prettierrc @@ -0,0 +1,6 @@ +{ + "tabWidth": 2, + "semi": false, + "singleQuote": true, + "printWidth": 120 +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/extensions.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/extensions.json new file mode 100644 index 00000000..c0a2258b --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": ["dbaeumer.vscode-eslint"] +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/launch.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/launch.json new file mode 100644 index 00000000..3baae646 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/launch.json @@ -0,0 +1,31 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"], + "preLaunchTask": "build" + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" + ], + "outFiles": ["${workspaceFolder}/out/test/**/*.js"], + "preLaunchTask": "build" + } + ] +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/settings.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/settings.json new file mode 100644 index 00000000..5c3ffd3c --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/settings.json @@ -0,0 +1,12 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "out": false // set this to true to hide the "out" folder with the compiled JS files + }, + "search.exclude": { + "out": true // set this to false to include "out" folder in search results + }, + // Turn off tsc task auto detection since we have the necessary tasks as npm scripts + "typescript.tsc.autoDetect": "off", + "java.configuration.updateBuildConfiguration": "interactive" +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/tasks.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/tasks.json new file mode 100644 index 00000000..0a101bd2 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscode/tasks.json @@ -0,0 +1,21 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "npm", + "script": "watch", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscodeignore b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscodeignore new file mode 100644 index 00000000..4b30b77f --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/.vscodeignore @@ -0,0 +1,17 @@ +.gitignore +.prettierrc +.project +.classpath +.vscode/** +.vscode-test/** +.settings/** +out/test/** +**/tsconfig.json +**/tslint.json +**/*.map +**/*.ts +target/** +node/** +src/** +README.md +**pom.xml \ No newline at end of file diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/LICENSE.txt b/spring-javaformat-vscode/spring-javaformat-vscode-extension/LICENSE.txt new file mode 100644 index 00000000..ff773796 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json new file mode 100644 index 00000000..5da1cec7 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package-lock.json @@ -0,0 +1,3756 @@ +{ + "name": "spring-javaformat-vscode-extension", + "version": "0.0.48-SNAPSHOT", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "spring-javaformat-vscode-extension", + "version": "0.0.48-SNAPSHOT", + "devDependencies": { + "@types/glob": "^8.0.1", + "@types/mocha": "^10.0.1", + "@types/node": "16.x", + "@types/vscode": "^1.75.0", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@vscode/test-electron": "^2.2.2", + "@vscode/vsce": "^2.19.0", + "eslint": "^8.33.0", + "glob": "8.1.0", + "mocha": "10.2.0", + "prettier": "3.0.3", + "typescript": "^4.9.4" + }, + "engines": { + "vscode": "^1.75.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/glob": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.1.tgz", + "integrity": "sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.12.tgz", + "integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/vscode": { + "version": "1.75.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz", + "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", + "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vscode/test-electron": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.2.3.tgz", + "integrity": "sha512-7DmdGYQTqRNaLHKG3j56buc9DkstriY4aV0S3Zj32u0U9/T0L8vwWAC9QGCh1meu1VXDEla1ze27TkqysHGP0Q==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@vscode/vsce": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", + "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/vsce/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/azure-devops-node-api": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", + "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "dev": true, + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "optional": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "optional": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "optional": true + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "optional": true + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true, + "optional": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.33.0.tgz", + "integrity": "sha512-7GGVawqyHF4pfd0YFybhv/eM9JwTtPqx0mAanQ146O3FlSh3pA24zf9IRQTOsfTSqXTNzPSP5iagAJ94jjuVog==", + "dev": true, + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "optional": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", + "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "dev": true, + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json new file mode 100644 index 00000000..c10d286e --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/package.json @@ -0,0 +1,43 @@ +{ + "name": "spring-javaformat-vscode-extension", + "description": "Spring JavaFormat Visual Studio Code Extension", + "displayName": "Spring JavaFormat", + "version": "0.0.48-SNAPSHOT", + "publisher": "io.spring.javaformat", + "engines": { + "vscode": "^1.75.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/spring-io/spring-javaformat.git" + }, + "categories": [ + "Formatters" + ], + "activationEvents": [ + "onLanguage:java" + ], + "main": "./out/extension.js", + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -b ./", + "watch": "tsc -b ./ -watch", + "pretest": "npm run compile", + "test": "node ./out/test/runTest.js", + "package": "vsce package --out ./target/spring-javaformat.vsix" + }, + "devDependencies": { + "@types/glob": "^8.0.1", + "@types/mocha": "^10.0.1", + "@types/node": "16.x", + "@types/vscode": "^1.75.0", + "@typescript-eslint/eslint-plugin": "^5.52.0", + "@vscode/test-electron": "^2.2.2", + "@vscode/vsce": "^2.19.0", + "eslint": "^8.33.0", + "glob": "8.1.0", + "mocha": "10.2.0", + "prettier": "3.0.3", + "typescript": "^4.9.4" + } +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml b/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml new file mode 100644 index 00000000..7891d15d --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/pom.xml @@ -0,0 +1,177 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat-vscode + 0.0.48-SNAPSHOT + + spring-javaformat-vscode-extension + Spring JavaFormat Visual Studio Code Extension + + ${basedir}/../.. + + + + + maven-clean-plugin + + + + out + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + ${basedir}/runtime/spring-java-format.jar + false + + + *:* + + META-INF/MANIFEST.MF + + + + + + io.spring.format.vscode.VisualStudioCodeFormatter + + + + + + + + com.github.eirslett + frontend-maven-plugin + + + install-node-and-npm + initialize + + install-node-and-npm + + + + npm-install + initialize + + npm + + + + prettier-check + compile + + npx + + + prettier --check . + + + + vsce-package + package + + npm + + + run package + + + + update-package-lock + + npm + + + install --package-lock-only + + + + + v19.6.0 + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + attach-artifact + + + + + ${project.build.directory}/spring-javaformat.vsix + vsix + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + update-version + + run + + + + + + + + + + + + + + formatter-dependencies + + true + + + + io.spring.javaformat + spring-javaformat-formatter-shaded + ${project.version} + + + + + diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/java/io/spring/format/vscode/VisualStudioCodeFormatter.java b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/java/io/spring/format/vscode/VisualStudioCodeFormatter.java new file mode 100644 index 00000000..1c4178f5 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/java/io/spring/format/vscode/VisualStudioCodeFormatter.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.format.vscode; + +import java.io.File; + +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.formatter.StreamsFormatter; + +/** + * Called from the Visual Studio Code extension to format source code. + * + * @author Howard Zuo + * @author Phillip Webb + */ +public final class VisualStudioCodeFormatter { + + private VisualStudioCodeFormatter() { + } + + private void run(String[] args) throws Exception { + File location = new File(".").getAbsoluteFile(); + log(String.format("Loading formatter from location '%s'", location)); + JavaFormatConfig config = JavaFormatConfig.findFrom(location); + StreamsFormatter formatter = new StreamsFormatter(config); + formatter.format(System.in).writeTo((Appendable) System.out); + } + + private void log(String message) { + System.err.println(message); + } + + public static void main(String[] args) { + try { + new VisualStudioCodeFormatter().run(args); + } + catch (Exception ex) { + ex.printStackTrace(); + System.exit(1); + } + } + +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/SpringDocumentFormattingEditProvider.ts b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/SpringDocumentFormattingEditProvider.ts new file mode 100644 index 00000000..cd26b056 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/SpringDocumentFormattingEditProvider.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path = require('path') +import vscode = require('vscode') +import childprocess = require('child_process') + +const JAR_PATH = path.resolve(__dirname, '..', 'runtime', 'spring-java-format.jar') + +export default class SpringDocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider { + provideDocumentFormattingEdits( + document: vscode.TextDocument, + options: vscode.FormattingOptions, + token: vscode.CancellationToken, + ): vscode.ProviderResult { + if (vscode.window.visibleTextEditors.every((editor) => editor.document.fileName !== document.fileName)) { + return [] + } + return this.runFormatter(document, token).then( + (edits) => edits, + (err) => { + if (err) { + console.log(err) + return Promise.reject(`Check the console in dev tools to find errors when formatting spring-javaformat`) + } + }, + ) + } + + private runFormatter(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { + return new Promise((resolve, reject) => { + console.log(`formatting ${document.uri} using spring-javaformat`) + let stdout = '' + let stderr = '' + const cwd = path.dirname(document.fileName) + const args = ['-jar', JAR_PATH] + const process = childprocess.spawn('java', args, { cwd }) + token.onCancellationRequested(() => !process.killed && process.kill()) + process.stdout.setEncoding('utf8') + process.stdout.on('data', (data) => (stdout += data)) + process.stderr.on('data', (data) => (stderr += data)) + process.on('error', (err) => { + console.log(`spring-javaformat returned error ${err}`) + if (err && (err).code === 'ENOENT') { + return reject(`failed to find run spring-javaformat due to missing 'java' executable`) + } + }) + process.on('close', (code) => { + if (code !== 0) { + console.log(`spring-javaformat returned error code ${code}`) + return reject(stderr) + } + console.log('spring-javaformat returned without error') + const fileStart = new vscode.Position(0, 0) + const fileEnd = document.lineAt(document.lineCount - 1).range.end + const textEdits: vscode.TextEdit[] = [new vscode.TextEdit(new vscode.Range(fileStart, fileEnd), stdout)] + return resolve(textEdits) + }) + if (process.pid) { + console.log('sending document data to spring-javaformat') + process.stdin.end(document.getText()) + } + }) + } +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/extension.ts b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/extension.ts new file mode 100644 index 00000000..3b4fb826 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/extension.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as vscode from 'vscode' +import SpringDocumentFormattingEditProvider from './SpringDocumentFormattingEditProvider' + +export function activate(context: vscode.ExtensionContext) { + console.log('Activated spring-javaformat extension') + context.subscriptions.push( + vscode.languages.registerDocumentFormattingEditProvider( + [ + { + language: 'java', + scheme: 'file', + }, + ], + new SpringDocumentFormattingEditProvider(), + ), + ) +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/tsconfig.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/tsconfig.json new file mode 100644 index 00000000..431716b1 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/main/typescript/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig-base.json", + "compilerOptions": { + "outDir": "../../../out", + "rootDir": "." + } +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/runTest.ts b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/runTest.ts new file mode 100644 index 00000000..19b689c6 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/runTest.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path' + +import { runTests } from '@vscode/test-electron' + +async function main() { + try { + const extensionDevelopmentPath = path.resolve(__dirname, '../../../../') + const extensionTestsPath = path.resolve(__dirname, './suite/index') + await runTests({ extensionDevelopmentPath, extensionTestsPath, launchArgs: ['--disable-extensions'] }) + } catch (err) { + console.error('Failed to run tests') + process.exit(1) + } +} + +main() diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/suite/extension.test.ts b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/suite/extension.test.ts new file mode 100644 index 00000000..e73b4c89 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/suite/extension.test.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert' +import * as vscode from 'vscode' +import * as path from 'path' +import * as fs from 'fs' + +export const WORKSPACE_PATH = path.resolve(__dirname, '..', '..', '..', 'test-workspace') +export const FILE_PATH = path.resolve(WORKSPACE_PATH, 'Test.java') + +suite('Extension Test Suite', () => { + test('Format file', async () => { + const initial = 'public static class Test {public static void main(String[] args){}}\n' + const expected = 'public static class Test {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n' + if (!fs.existsSync(WORKSPACE_PATH)) { + fs.mkdirSync(WORKSPACE_PATH) + } + fs.closeSync(fs.openSync(FILE_PATH, 'w')) + const document = await vscode.workspace.openTextDocument(vscode.Uri.file(FILE_PATH)) + const editor = await vscode.window.showTextDocument(document) + await editor.edit((builder) => { + builder.delete(new vscode.Range(new vscode.Position(0, 0), document.positionAt(document.getText().length))) + builder.insert(new vscode.Position(0, 0), initial) + }) + editor.selection = new vscode.Selection(0, 0, 0, 0) + await vscode.commands.executeCommand('editor.action.formatDocument') + const actual = document.getText() + assert.deepEqual(actual, expected) + }) +}) diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/suite/index.ts b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/suite/index.ts new file mode 100644 index 00000000..3301b793 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/suite/index.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path' +import * as Mocha from 'mocha' +import * as glob from 'glob' + +export function run(): Promise { + const mocha = new Mocha({ + ui: 'tdd', + }) + const testsRoot = path.resolve(__dirname, '..') + return new Promise((resolve, reject) => { + glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { + console.log(files) + if (err) { + return reject(err) + } + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))) + try { + mocha.run((failures) => { + if (failures > 0) { + reject(new Error(`${failures} tests failed.`)) + } else { + resolve() + } + }) + } catch (err) { + console.error(err) + reject(err) + } + }) + }) +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/tsconfig.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/tsconfig.json new file mode 100644 index 00000000..7412944e --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/src/test/typescript/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig-base.json", + "compilerOptions": { + "outDir": "../../../out/test", + "rootDirs": ["../../main/typescript", "."] + } +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/test-workspace/Test.java b/spring-javaformat-vscode/spring-javaformat-vscode-extension/test-workspace/Test.java new file mode 100644 index 00000000..e69de29b diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/tsconfig-base.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/tsconfig-base.json new file mode 100644 index 00000000..7c273362 --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/tsconfig-base.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "lib": ["ES2020"], + "sourceMap": true, + "strict": true + } +} diff --git a/spring-javaformat-vscode/spring-javaformat-vscode-extension/tsconfig.json b/spring-javaformat-vscode/spring-javaformat-vscode-extension/tsconfig.json new file mode 100644 index 00000000..a6df75bd --- /dev/null +++ b/spring-javaformat-vscode/spring-javaformat-vscode-extension/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], // this root tsconfig just exists to compose sub-projects + "references": [ + { + "path": "./src/main/typescript" + }, + { + "path": "./src/test/typescript" + } + ] +} diff --git a/spring-javaformat/pom.xml b/spring-javaformat/pom.xml index 11244a0e..849cefc1 100644 --- a/spring-javaformat/pom.xml +++ b/spring-javaformat/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat-build - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat pom @@ -31,11 +31,17 @@ + spring-javaformat-config spring-javaformat-checkstyle + spring-javaformat-formatter + spring-javaformat-formatter-test-support + spring-javaformat-formatter-tests spring-javaformat-formatter-eclipse-rewriter + spring-javaformat-formatter-eclipse-jdk8 + spring-javaformat-formatter-eclipse-jdk17 + spring-javaformat-formatter-eclipse-jdt-jdk8 + spring-javaformat-formatter-eclipse-jdt-jdk17 spring-javaformat-formatter-eclipse-runtime - spring-javaformat-formatter-eclipse - spring-javaformat-formatter spring-javaformat-formatter-shader spring-javaformat-formatter-shaded diff --git a/spring-javaformat/spring-javaformat-checkstyle/pom.xml b/spring-javaformat/spring-javaformat-checkstyle/pom.xml index a0ef508e..5605577e 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/pom.xml +++ b/spring-javaformat/spring-javaformat-checkstyle/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-checkstyle Spring JavaFormat CheckStyle @@ -14,6 +14,11 @@ + + io.spring.javaformat + spring-javaformat-config + ${project.version} + com.puppycrawl.tools checkstyle diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/FilteredModuleFactory.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/FilteredModuleFactory.java new file mode 100644 index 00000000..e595863f --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/FilteredModuleFactory.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle; + +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.ModuleFactory; +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.Configuration; + +class FilteredModuleFactory implements ModuleFactory { + + static final TreeWalkerFilter FILTERED = new TreeWalkerFilter() { + + @Override + public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { + return true; + } + + }; + + private final ModuleFactory moduleFactory; + + private final Set excludes; + + FilteredModuleFactory(ModuleFactory moduleFactory, Set excludes) { + this.moduleFactory = moduleFactory; + this.excludes = excludes; + } + + @Override + public Object createModule(String name) throws CheckstyleException { + Object module = this.moduleFactory.createModule(name); + if (isFiltered(module)) { + if (module instanceof AbstractCheck) { + return FILTERED; + } + throw new IllegalStateException("Unable to filter module " + module.getClass().getName()); + } + return module; + } + + boolean nonFiltered(Configuration configuration) { + return !isFiltered(configuration.getName()); + } + + private boolean isFiltered(Object module) { + return isFiltered(module.getClass().getName()); + } + + private boolean isFiltered(String name) { + return this.excludes != null && this.excludes.contains(name); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringChecks.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringChecks.java index 9de210a5..244b7edf 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringChecks.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringChecks.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,16 @@ package io.spring.javaformat.checkstyle; import java.io.File; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Properties; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.stream.Collectors; import com.puppycrawl.tools.checkstyle.Checker; import com.puppycrawl.tools.checkstyle.DefaultContext; @@ -34,7 +38,7 @@ import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; import com.puppycrawl.tools.checkstyle.api.FileSetCheck; import com.puppycrawl.tools.checkstyle.api.FileText; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.Violation; import com.puppycrawl.tools.checkstyle.filters.SuppressFilterElement; import io.spring.javaformat.checkstyle.check.SpringHeaderCheck; @@ -59,8 +63,12 @@ public class SpringChecks extends AbstractFileSetCheck implements ExternalResour private String headerFile; + private Set avoidStaticImportExcludes = Collections.emptySet(); + private String projectRootPackage = SpringImportOrderCheck.DEFAULT_PROJECT_ROOT_PACKAGE; + private Set excludes; + /** * Sets classLoader to load class. * @param classLoader class loader to resolve classes with. @@ -79,18 +87,20 @@ public void setModuleFactory(ModuleFactory moduleFactory) { @Override public void finishLocalSetup() { + FilteredModuleFactory moduleFactory = new FilteredModuleFactory(this.moduleFactory, this.excludes); DefaultContext context = new DefaultContext(); context.add("classLoader", this.classLoader); context.add("severity", getSeverity()); context.add("tabWidth", String.valueOf(getTabWidth())); - context.add("moduleFactory", this.moduleFactory); + context.add("moduleFactory", moduleFactory); Properties properties = new Properties(); put(properties, "headerType", this.headerType); put(properties, "headerCopyrightPattern", this.headerCopyrightPattern); put(properties, "headerFile", this.headerFile); put(properties, "projectRootPackage", this.projectRootPackage); - this.checks = new SpringConfigurationLoader(context, this.moduleFactory) - .load(new PropertiesExpander(properties)); + put(properties, "avoidStaticImportExcludes", + this.avoidStaticImportExcludes.stream().collect(Collectors.joining(","))); + this.checks = new SpringConfigurationLoader(context, moduleFactory).load(new PropertiesExpander(properties)); } private void put(Properties properties, String name, Object value) { @@ -125,11 +135,11 @@ public void beginProcessing(String charset) { @Override protected void processFiltered(File file, FileText fileText) throws CheckstyleException { - SortedSet messages = new TreeSet<>(); + SortedSet violations = new TreeSet<>(); for (FileSetCheck check : this.checks) { - messages.addAll(check.process(file, fileText)); + violations.addAll(check.process(file, fileText)); } - addMessages(messages); + addViolations(violations); } @Override @@ -149,8 +159,16 @@ public void setHeaderFile(String headerFile) { this.headerFile = headerFile; } + public void setAvoidStaticImportExcludes(String[] avoidStaticImportExcludes) { + this.avoidStaticImportExcludes = new LinkedHashSet<>(Arrays.asList(avoidStaticImportExcludes)); + } + public void setProjectRootPackage(String projectRootPackage) { this.projectRootPackage = projectRootPackage; } + public void setExcludes(String... excludes) { + this.excludes = new HashSet<>(Arrays.asList(excludes)); + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java index ac1b1069..0be1ecc6 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,26 @@ package io.spring.javaformat.checkstyle; +import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.stream.Collectors; import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import com.puppycrawl.tools.checkstyle.ConfigurationLoader.IgnoredModulesOptions; -import com.puppycrawl.tools.checkstyle.ModuleFactory; import com.puppycrawl.tools.checkstyle.PropertyResolver; -import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.Configurable; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.Context; +import com.puppycrawl.tools.checkstyle.api.Contextualizable; import com.puppycrawl.tools.checkstyle.api.FileSetCheck; +import com.puppycrawl.tools.checkstyle.api.Scope; +import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck; import org.xml.sax.InputSource; /** @@ -42,22 +48,53 @@ class SpringConfigurationLoader { private final Context context; - private final ModuleFactory moduleFactory; + private final FilteredModuleFactory moduleFactory; - SpringConfigurationLoader(Context context, ModuleFactory moduleFactory) { + SpringConfigurationLoader(Context context, FilteredModuleFactory moduleFactory) { this.context = context; this.moduleFactory = moduleFactory; } public Collection load(PropertyResolver propertyResolver) { - Configuration config = loadConfiguration(getClass().getResourceAsStream("spring-checkstyle.xml"), - propertyResolver); - return Arrays.stream(config.getChildren()).map(this::load).collect(Collectors.toList()); + Configuration config = loadConfiguration(loadConfigurationSource(), propertyResolver); + return Arrays.stream(config.getChildren()) + .filter(this.moduleFactory::nonFiltered) + .map(this::load) + .collect(Collectors.toList()); } - private Configuration loadConfiguration(InputStream inputStream, PropertyResolver propertyResolver) { + private String loadConfigurationSource() { + try (InputStream stream = getClass().getResourceAsStream("spring-checkstyle.xml")) { + StringBuilder builder = new StringBuilder(); + byte[] buffer = new byte[4096]; + int read; + while ((read = stream.read(buffer)) > 0) { + builder.append(new String(buffer, 0, read, StandardCharsets.UTF_8)); + } + return preprocessConfigurationSource(builder.toString()); + } + catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private String preprocessConfigurationSource(String source) { + return source.replace("{{javadocVariableCheckScopeProperty}}", javadocVariableCheckScopeProperty()); + } + + private String javadocVariableCheckScopeProperty() { try { - InputSource inputSource = new InputSource(inputStream); + JavadocVariableCheck.class.getMethod("setScope", Scope.class); + return "scope"; + } + catch (NoSuchMethodException ex) { + return "accessModifiers"; + } + } + + private Configuration loadConfiguration(String source, PropertyResolver propertyResolver) { + try { + InputSource inputSource = new InputSource(new StringReader(source)); return ConfigurationLoader.loadConfiguration(inputSource, propertyResolver, IgnoredModulesOptions.EXECUTE); } catch (CheckstyleException ex) { @@ -77,9 +114,7 @@ private Object createModule(Configuration configuration) { String name = configuration.getName(); try { Object module = this.moduleFactory.createModule(name); - if (module instanceof AutomaticBean) { - initialize(configuration, (AutomaticBean) module); - } + initialize(configuration, module); return module; } catch (CheckstyleException ex) { @@ -87,9 +122,13 @@ private Object createModule(Configuration configuration) { } } - private void initialize(Configuration configuration, AutomaticBean bean) throws CheckstyleException { - bean.contextualize(this.context); - bean.configure(configuration); + private void initialize(Configuration configuration, Object module) throws CheckstyleException { + if (module instanceof Contextualizable) { + ((Contextualizable) module).contextualize(this.context); + } + if (module instanceof Configurable) { + ((Configurable) module).configure(configuration); + } } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/AbstractSpringCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/AbstractSpringCheck.java index 347f1ed1..af4511d2 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/AbstractSpringCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/AbstractSpringCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationAttributeConciseValueCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationAttributeConciseValueCheck.java new file mode 100644 index 00000000..b8b0ad81 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationAttributeConciseValueCheck.java @@ -0,0 +1,157 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + * Spring-specific check of the concision of an annotation's attribute values. + * + * @author Andy Wilkinson + */ +public class SpringAnnotationAttributeConciseValueCheck extends AbstractCheck { + + private final List imports = new ArrayList<>(); + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return new int[] { TokenTypes.ANNOTATION, TokenTypes.IMPORT }; + } + + @Override + public void init() { + this.imports.clear(); + } + + @Override + public void visitToken(DetailAST ast) { + if (ast.getType() == TokenTypes.IMPORT) { + visitImport(ast); + } + else if (ast.getType() == TokenTypes.ANNOTATION) { + visitAnnotation(ast); + } + } + + private void visitImport(DetailAST importNode) { + List components = dotSeparatedComponents(importNode.getFirstChild()); + if (components != null) { + this.imports.add(new ImportStatement(components)); + } + } + + private void visitAnnotation(DetailAST annotation) { + int valuePairCount = annotation.getChildCount(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); + if (valuePairCount == 0) { + DetailAST valueExpression = annotation.findFirstToken(TokenTypes.EXPR); + visitValueExpression(valueExpression, annotation, "value"); + } + else { + DetailAST candidate = annotation.getFirstChild(); + while (candidate != null) { + if (candidate.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { + visitMemberValuePair(candidate); + } + candidate = candidate.getNextSibling(); + } + } + } + + private void visitMemberValuePair(DetailAST annotationValue) { + DetailAST annotation = annotationValue.getParent(); + DetailAST attribute = annotationValue.findFirstToken(TokenTypes.IDENT); + DetailAST valueExpression = annotationValue.findFirstToken(TokenTypes.EXPR); + visitValueExpression(valueExpression, annotation, attribute.getText()); + } + + private void visitValueExpression(DetailAST valueExpression, DetailAST annotation, String attributeName) { + if (valueExpression == null || valueExpression.getChildCount() != 1) { + return; + } + List expressionComponents = dotSeparatedComponents(valueExpression.getFirstChild()); + if (expressionComponents == null || expressionComponents.size() <= 2) { + return; + } + String outerTypeName = expressionComponents.get(0); + DetailAST annotationIdent = annotation.findFirstToken(TokenTypes.IDENT); + if (annotationIdent == null) { + return; + } + String annotationName = annotationIdent.getText(); + if (outerTypeName.equals(annotationName)) { + String innerTypeName = expressionComponents.get(1); + if (!existingClashingImport(outerTypeName, innerTypeName)) { + String toImport = outerTypeName + "." + innerTypeName; + String replacement = String.join(".", expressionComponents.subList(1, expressionComponents.size())); + log(valueExpression.getLineNo(), valueExpression.getColumnNo(), + "annotation.attribute.overlyVerboseValue", attributeName, toImport, replacement); + } + } + } + + private List dotSeparatedComponents(DetailAST ast) { + if (ast.getType() == TokenTypes.IDENT) { + return Collections.singletonList(ast.getText()); + } + if (ast.getType() == TokenTypes.DOT) { + List left = dotSeparatedComponents(ast.getFirstChild()); + List right = dotSeparatedComponents(ast.getLastChild()); + if (left != null && right != null) { + List components = new ArrayList<>(); + components.addAll(left); + components.addAll(right); + return components; + } + } + return null; + } + + private boolean existingClashingImport(String outer, String inner) { + return this.imports.stream().filter((imported) -> imported.clashesWith(outer, inner)).findFirst().isPresent(); + } + + static class ImportStatement { + + private final String imported; + + ImportStatement(List components) { + this.imported = String.join(".", components); + } + + boolean clashesWith(String outer, String inner) { + return this.imported.endsWith("." + inner) && !this.imported.endsWith("." + outer + "." + inner); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java new file mode 100644 index 00000000..c697521f --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAnnotationLocationCheck.java @@ -0,0 +1,124 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtil; + +/** + * Spring variant of {@link AnnotationLocationCheck}. + * + * @author Phillip Webb + */ +public class SpringAnnotationLocationCheck extends AbstractCheck { + + private static final Set JSPECIFY_ANNOTATION_NAMES = new HashSet<>( + Arrays.asList("NonNull", "Nullable", "NullMarked", "NullUnmarked")); + + @Override + public int[] getDefaultTokens() { + return new int[] { TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.PACKAGE_DEF, + TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, + TokenTypes.VARIABLE_DEF, TokenTypes.RECORD_DEF, TokenTypes.COMPACT_CTOR_DEF, }; + } + + @Override + public int[] getAcceptableTokens() { + return new int[] { TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.PACKAGE_DEF, + TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, + TokenTypes.VARIABLE_DEF, TokenTypes.ANNOTATION_DEF, TokenTypes.ANNOTATION_FIELD_DEF, + TokenTypes.RECORD_DEF, TokenTypes.COMPACT_CTOR_DEF, }; + } + + @Override + public int[] getRequiredTokens() { + return CommonUtil.EMPTY_INT_ARRAY; + } + + @Override + public void visitToken(DetailAST ast) { + if (ast.getType() != TokenTypes.VARIABLE_DEF || ast.getParent().getType() == TokenTypes.OBJBLOCK) { + DetailAST node = ast.findFirstToken(TokenTypes.MODIFIERS); + node = (node != null) ? node : ast.findFirstToken(TokenTypes.ANNOTATIONS); + checkAnnotations(node, getExpectedAnnotationIndentation(node)); + } + } + + private int getExpectedAnnotationIndentation(DetailAST node) { + return node.getColumnNo(); + } + + private void checkAnnotations(DetailAST node, int correctIndentation) { + DetailAST annotation = node.getFirstChild(); + while (annotation != null && annotation.getType() == TokenTypes.ANNOTATION) { + checkAnnotation(correctIndentation, annotation); + annotation = annotation.getNextSibling(); + } + } + + private void checkAnnotation(int correctIndentation, DetailAST annotation) { + String annotationName = getAnnotationName(annotation); + if (!isCorrectLocation(annotation) && !isJSpecifyAnnotation(annotationName)) { + log(annotation, AnnotationLocationCheck.MSG_KEY_ANNOTATION_LOCATION_ALONE, annotationName); + } + else if (annotation.getColumnNo() != correctIndentation && !hasNodeBefore(annotation)) { + log(annotation, AnnotationLocationCheck.MSG_KEY_ANNOTATION_LOCATION, annotationName, + annotation.getColumnNo(), correctIndentation); + } + } + + private String getAnnotationName(DetailAST annotation) { + DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT); + if (identNode == null) { + identNode = annotation.findFirstToken(TokenTypes.DOT).findFirstToken(TokenTypes.IDENT); + } + return identNode.getText(); + } + + private boolean isCorrectLocation(DetailAST annotation) { + return !hasNodeBeside(annotation); + } + + private boolean hasNodeBeside(DetailAST annotation) { + return hasNodeBefore(annotation) || hasNodeAfter(annotation); + } + + private boolean hasNodeBefore(DetailAST annotation) { + int annotationLineNo = annotation.getLineNo(); + DetailAST previousNode = annotation.getPreviousSibling(); + return (previousNode != null) && (annotationLineNo == previousNode.getLineNo()); + } + + private boolean hasNodeAfter(DetailAST annotation) { + int annotationLineNo = annotation.getLineNo(); + DetailAST nextNode = annotation.getNextSibling(); + nextNode = (nextNode != null) ? nextNode : annotation.getParent().getNextSibling(); + return annotationLineNo == nextNode.getLineNo(); + } + + private boolean isJSpecifyAnnotation(String annotationName) { + return JSPECIFY_ANNOTATION_NAMES.contains(annotationName); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java new file mode 100644 index 00000000..b9b3c3e4 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringAvoidStaticImportCheck.java @@ -0,0 +1,106 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck; +import com.puppycrawl.tools.checkstyle.checks.imports.AvoidStaticImportCheck; + +/** + * Spring variant of {@link AvoidStarImportCheck}. + * + * @author Phillip Webb + */ +public class SpringAvoidStaticImportCheck extends AvoidStaticImportCheck { + + private static final Set ALWAYS_EXCLUDED; + static { + Set excludes = new LinkedHashSet<>(); + excludes.add("io.restassured.RestAssured.*"); + excludes.add("org.assertj.core.api.Assertions.*"); + excludes.add("org.assertj.core.api.Assumptions.*"); + excludes.add("org.assertj.core.api.BDDAssertions.*"); + excludes.add("org.assertj.core.api.HamcrestCondition.*"); + excludes.add("org.awaitility.Awaitility.*"); + excludes.add("org.hamcrest.CoreMatchers.*"); + excludes.add("org.hamcrest.Matchers.*"); + excludes.add("org.junit.Assert.*"); + excludes.add("org.junit.Assume.*"); + excludes.add("org.junit.internal.matchers.ThrowableMessageMatcher.*"); + excludes.add("org.junit.jupiter.api.Assertions.*"); + excludes.add("org.junit.jupiter.api.Assumptions.*"); + excludes.add("org.mockito.AdditionalMatchers.*"); + excludes.add("org.mockito.ArgumentMatchers.*"); + excludes.add("org.mockito.BDDMockito.*"); + excludes.add("org.mockito.Matchers.*"); + excludes.add("org.mockito.Mockito.*"); + excludes.add("org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*"); + excludes.add("org.springframework.boot.configurationprocessor.TestCompiler.*"); + excludes.add("org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*"); + excludes.add("org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*"); + excludes.add("org.springframework.restdocs.headers.HeaderDocumentation.*"); + excludes.add("org.springframework.restdocs.hypermedia.HypermediaDocumentation.*"); + excludes.add("org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*"); + excludes.add("org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*"); + excludes.add("org.springframework.restdocs.operation.preprocess.Preprocessors.*"); + excludes.add("org.springframework.restdocs.payload.PayloadDocumentation.*"); + excludes.add("org.springframework.restdocs.request.RequestDocumentation.*"); + excludes.add("org.springframework.restdocs.restassured.operation.preprocess.RestAssuredPreprocessors.*"); + excludes.add("org.springframework.restdocs.restassured.RestAssuredRestDocumentation.*"); + excludes.add("org.springframework.restdocs.restassured3.operation.preprocess.RestAssuredPreprocessors.*"); + excludes.add("org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.*"); + excludes.add("org.springframework.restdocs.snippet.Attributes.*"); + excludes.add("org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.*"); + excludes.add("org.springframework.security.config.Customizer.*"); + excludes.add("org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.*"); + excludes.add("org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*"); + excludes.add("org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*"); + excludes.add("org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*"); + excludes.add("org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*"); + excludes.add("org.springframework.test.web.client.ExpectedCount.*"); + excludes.add("org.springframework.test.web.client.match.MockRestRequestMatchers.*"); + excludes.add("org.springframework.test.web.client.response.MockRestResponseCreators.*"); + excludes.add("org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*"); + excludes.add("org.springframework.test.web.servlet.result.MockMvcResultHandlers.*"); + excludes.add("org.springframework.test.web.servlet.result.MockMvcResultMatchers.*"); + excludes.add("org.springframework.test.web.servlet.setup.MockMvcBuilders.*"); + excludes.add("org.springframework.web.reactive.function.BodyInserters.*"); + excludes.add("org.springframework.web.reactive.function.server.RequestPredicates.*"); + excludes.add("org.springframework.web.reactive.function.server.RouterFunctions.*"); + excludes.add("org.springframework.web.servlet.function.RequestPredicates.*"); + excludes.add("org.springframework.web.servlet.function.RouterFunctions.*"); + excludes.add("org.springframework.ws.test.client.RequestMatchers.*"); + excludes.add("org.springframework.ws.test.client.ResponseCreators.*"); + ALWAYS_EXCLUDED = Collections.unmodifiableSet(excludes); + } + + public SpringAvoidStaticImportCheck() { + setExcludes(ALWAYS_EXCLUDED.toArray(new String[0])); + } + + @Override + public void setExcludes(String... excludes) { + Set merged = new LinkedHashSet<>(ALWAYS_EXCLUDED); + merged.addAll(Arrays.asList(excludes)); + super.setExcludes(merged.toArray(new String[0])); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringCatchCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringCatchCheck.java index e1b1e9a6..81d2144b 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringCatchCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringCatchCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,9 @@ private void checkIdent(DetailAST ast) { if (text.length() == 1) { log(ast.getLineNo(), ast.getColumnNo(), "catch.singleLetter"); } + if (text.toLowerCase().equals("o_o")) { + log(ast.getLineNo(), ast.getColumnNo(), "catch.wideEye"); + } } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringDeprecatedCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringDeprecatedCheck.java new file mode 100644 index 00000000..42bf0f4b --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringDeprecatedCheck.java @@ -0,0 +1,78 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + * Checks that {@link Deprecated @Deprecated} annotations follow Spring conventions. + * + * @author Andy Wilkinson + * @since 0.0.35 + */ +public class SpringDeprecatedCheck extends AbstractSpringCheck { + + @Override + public int[] getAcceptableTokens() { + return new int[] { TokenTypes.ANNOTATION }; + } + + @Override + public void visitToken(DetailAST ast) { + if (ast.getType() == TokenTypes.ANNOTATION) { + visitAnnotation(ast); + } + } + + private void visitAnnotation(DetailAST annotation) { + String text = FullIdent.createFullIdent(annotation.findFirstToken(TokenTypes.AT).getNextSibling()).getText(); + if ("Deprecated".equals(text) || "java.lang.Deprecated".equals(text)) { + visitDeprecated(annotation); + } + } + + private void visitDeprecated(DetailAST deprecated) { + DetailAST sinceAttribute = findSinceAttribute(deprecated); + if (sinceAttribute == null) { + log(deprecated.getLineNo(), deprecated.getColumnNo(), "deprecated.missingSince"); + } + else { + DetailAST expr = sinceAttribute.findFirstToken(TokenTypes.EXPR); + DetailAST sinceLiteral = expr.findFirstToken(TokenTypes.STRING_LITERAL); + if ("\"\"".equals(sinceLiteral.getText())) { + log(deprecated.getLineNo(), deprecated.getColumnNo(), "deprecated.emptySince"); + } + } + } + + private DetailAST findSinceAttribute(DetailAST deprecated) { + DetailAST child = deprecated.getFirstChild(); + while (child != null) { + if (child.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { + DetailAST attributeIdent = child.findFirstToken(TokenTypes.IDENT); + if (attributeIdent != null && ("since".equals(attributeIdent.getText()))) { + return child; + } + } + child = child.getNextSibling(); + } + return null; + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHeaderCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHeaderCheck.java index cb2f4e0f..c58e74c4 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHeaderCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHeaderCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ public class SpringHeaderCheck extends AbstractFileSetCheck { /** * The default header copyright pattern. */ - public static final String DEFAULT_HEADER_COPYRIGHT_PATTERN = "20\\d\\d(-20\\d\\d)?"; + public static final String DEFAULT_HEADER_COPYRIGHT_PATTERN = "20\\d\\d(-20\\d\\d|-present)?"; private static final String DEFAULT_CHARSET = System.getProperty("file.encoding", StandardCharsets.UTF_8.name()); @@ -77,6 +77,8 @@ public class SpringHeaderCheck extends AbstractFileSetCheck { private URI packageInfoHeaderFile; + private boolean blankLineAfter = true; + private HeaderCheck check; private HeaderCheck packageInfoCheck; @@ -108,7 +110,7 @@ private HeaderCheck createCheck(String headerType, URI headerFile) throws IOExce @Override protected void processFiltered(File file, FileText fileText) throws CheckstyleException { - getCheck(file).run(fileText); + getCheck(file).run(fileText, this.blankLineAfter); } private HeaderCheck getCheck(File file) { @@ -145,6 +147,10 @@ public void setPackageInfoHeaderFile(URI packageInfoHeaderFile) { this.packageInfoHeaderFile = packageInfoHeaderFile; } + public void setBlankLineAfter(boolean blankLineAfter) { + this.blankLineAfter = blankLineAfter; + } + /** * Interface used to check for a header. */ @@ -153,14 +159,15 @@ private interface HeaderCheck { /** * Don't run any checks. */ - HeaderCheck NONE = (fileText) -> true; + HeaderCheck NONE = (fileText, blankLineAfter) -> true; /** * Run the check. * @param fileText the text to check + * @param blankLineAfter if a blank line should be after the header * @return {@code true} if the header is valid */ - boolean run(FileText fileText); + boolean run(FileText fileText, boolean blankLineAfter); } @@ -209,7 +216,7 @@ private Pattern loadLine(String line, String copyrightPattern) { } @Override - public boolean run(FileText fileText) { + public boolean run(FileText fileText, boolean blankLineAfter) { if (this.lines.size() > fileText.size()) { log(1, RegexpHeaderCheck.MSG_HEADER_MISSING); return false; @@ -222,6 +229,11 @@ public boolean run(FileText fileText) { return false; } } + if (blankLineAfter) { + if (fileText.size() <= this.lines.size() || !"".equals(fileText.get(this.lines.size()))) { + log(this.lines.size() + 1, "header.blankLine"); + } + } return true; } @@ -233,7 +245,7 @@ public boolean run(FileText fileText) { private class NoHeaderCheck implements HeaderCheck { @Override - public boolean run(FileText fileText) { + public boolean run(FileText fileText, boolean blankLineAfter) { for (int i = 0; i < fileText.size(); i++) { String fileLine = fileText.get(i); if (fileLine.trim().isEmpty()) { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHideUtilityClassConstructor.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHideUtilityClassConstructor.java index c7dcaab1..882b9b9a 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHideUtilityClassConstructor.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringHideUtilityClassConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,8 +39,9 @@ public class SpringHideUtilityClassConstructor extends HideUtilityClassConstruct annotations.add("org.springframework.context.annotation.Configuration"); annotations.add("org.springframework.boot.autoconfigure.SpringBootApplication"); annotations.add("org.springframework.boot.autoconfigure.EnableAutoConfiguration"); - Set shortNames = annotations.stream().map((name) -> name.substring(name.lastIndexOf(".") + 1)) - .collect(Collectors.toSet()); + Set shortNames = annotations.stream() + .map((name) -> name.substring(name.lastIndexOf(".") + 1)) + .collect(Collectors.toSet()); annotations.addAll(shortNames); BYPASS_ANNOTATIONS = Collections.unmodifiableSet(annotations); } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringImportOrderCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringImportOrderCheck.java index 5c80479d..69f8bf31 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringImportOrderCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringImportOrderCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java index 75a2f186..722c8868 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; @@ -38,34 +40,35 @@ */ public class SpringJUnit5Check extends AbstractSpringCheck { - private static final String JUNIT4_TEST_ANNOTATION = "org.junit.Test"; + private static final String JUNIT4_TEST_ANNOTATION_NAME = "org.junit.Test"; - private static final List TEST_ANNOTATIONS; + private static final List TEST_ANNOTATIONS; static { - Set annotations = new LinkedHashSet<>(); - addAnnotation(annotations, JUNIT4_TEST_ANNOTATION); - addAnnotation(annotations, "org.junit.jupiter.api.RepeatedTest"); - addAnnotation(annotations, "org.junit.jupiter.api.Test"); - addAnnotation(annotations, "org.junit.jupiter.api.TestFactory"); - addAnnotation(annotations, "org.junit.jupiter.api.TestTemplate"); - addAnnotation(annotations, "org.junit.jupiter.params.ParameterizedTest"); + Set annotations = new LinkedHashSet<>(); + annotations.add(new Annotation("org.junit.jupiter.api", "RepeatedTest")); + annotations.add(new Annotation("org.junit.jupiter.api", "Test")); + annotations.add(new Annotation("org.junit.jupiter.api", "TestFactory")); + annotations.add(new Annotation("org.junit.jupiter.api", "TestTemplate")); + annotations.add(new Annotation("org.junit.jupiter.api", "ParameterizedTest")); TEST_ANNOTATIONS = Collections.unmodifiableList(new ArrayList<>(annotations)); } - private static final List LIFECYCLE_ANNOTATIONS; + private static final List LIFECYCLE_ANNOTATIONS; static { - Set annotations = new LinkedHashSet<>(); - addAnnotation(annotations, "org.junit.jupiter.api.BeforeAll"); - addAnnotation(annotations, "org.junit.jupiter.api.BeforeEach"); - addAnnotation(annotations, "org.junit.jupiter.api.AfterAll"); - addAnnotation(annotations, "org.junit.jupiter.api.AfterEach"); + Set annotations = new LinkedHashSet<>(); + annotations.add(new Annotation("org.junit.jupiter.api", "BeforeAll")); + annotations.add(new Annotation("org.junit.jupiter.api", "BeforeEach")); + annotations.add(new Annotation("org.junit.jupiter.api", "AfterAll")); + annotations.add(new Annotation("org.junit.jupiter.api", "AfterEach")); LIFECYCLE_ANNOTATIONS = Collections.unmodifiableList(new ArrayList<>(annotations)); } + private static final Annotation NESTED_ANNOTATION = new Annotation("org.junit.jupiter.api", "Nested"); + private static final Set BANNED_IMPORTS; static { Set bannedImports = new LinkedHashSet<>(); - bannedImports.add(JUNIT4_TEST_ANNOTATION); + bannedImports.add(JUNIT4_TEST_ANNOTATION_NAME); bannedImports.add("org.junit.After"); bannedImports.add("org.junit.AfterClass"); bannedImports.add("org.junit.Before"); @@ -75,14 +78,6 @@ public class SpringJUnit5Check extends AbstractSpringCheck { BANNED_IMPORTS = Collections.unmodifiableSet(bannedImports); } - private static void addAnnotation(Set annotations, String annotation) { - annotations.add(annotation); - int lastDot = annotation.lastIndexOf("."); - if (lastDot != -1) { - annotations.add(annotation.substring(lastDot + 1)); - } - } - private List unlessImports = new ArrayList<>(); private final List testMethods = new ArrayList<>(); @@ -91,43 +86,84 @@ private static void addAnnotation(Set annotations, String annotation) { private final List lifecycleMethods = new ArrayList<>(); + private final List nestedTestClasses = new ArrayList<>(); + + private DetailAST testClass; + @Override public int[] getAcceptableTokens() { - return new int[] { TokenTypes.METHOD_DEF, TokenTypes.IMPORT }; + return new int[] { TokenTypes.METHOD_DEF, TokenTypes.IMPORT, TokenTypes.CLASS_DEF }; } @Override public void beginTree(DetailAST rootAST) { + this.testClass = null; this.imports.clear(); this.testMethods.clear(); this.lifecycleMethods.clear(); + this.nestedTestClasses.clear(); } @Override public void visitToken(DetailAST ast) { switch (ast.getType()) { - case TokenTypes.METHOD_DEF: - visitMethodDef(ast); - case TokenTypes.IMPORT: - visitImport(ast); - break; + case TokenTypes.METHOD_DEF: + visitMethodDef(ast); + break; + case TokenTypes.IMPORT: + visitImport(ast); + break; + case TokenTypes.CLASS_DEF: + visitClassDefinition(ast); + break; } } private void visitMethodDef(DetailAST ast) { - if (AnnotationUtil.containsAnnotation(ast, TEST_ANNOTATIONS)) { + if (containsAnnotation(ast, TEST_ANNOTATIONS)) { this.testMethods.add(ast); } - if (AnnotationUtil.containsAnnotation(ast, LIFECYCLE_ANNOTATIONS)) { + if (containsAnnotation(ast, LIFECYCLE_ANNOTATIONS)) { this.lifecycleMethods.add(ast); } } + private boolean containsAnnotation(DetailAST ast, List annotations) { + List annotationNames = annotations.stream() + .flatMap((annotation) -> Stream.of(annotation.simpleName, annotation.fullyQualifiedName())) + .collect(Collectors.toList()); + try { + return AnnotationUtil.containsAnnotation(ast, annotationNames); + } + catch (NoSuchMethodError ex) { + // Checkstyle >= 10.3 (https://github.com/checkstyle/checkstyle/issues/14134) + Set annotationNamesSet = new HashSet<>(annotationNames); + try { + return (boolean) AnnotationUtil.class.getMethod("containsAnnotation", DetailAST.class, Set.class) + .invoke(null, ast, annotationNamesSet); + } + catch (Exception ex2) { + throw new RuntimeException("containsAnnotation failed", ex2); + } + } + } + private void visitImport(DetailAST ast) { FullIdent ident = FullIdent.createFullIdentBelow(ast); this.imports.put(ident.getText(), ident); } + private void visitClassDefinition(DetailAST ast) { + if (ast.getParent().getType() == TokenTypes.COMPILATION_UNIT) { + this.testClass = ast; + } + else { + if (containsAnnotation(ast, Arrays.asList(NESTED_ANNOTATION))) { + this.nestedTestClasses.add(ast); + } + } + } + @Override public void finishTree(DetailAST rootAST) { if (shouldCheck()) { @@ -136,7 +172,7 @@ public void finishTree(DetailAST rootAST) { } private boolean shouldCheck() { - if (this.testMethods.isEmpty() && this.lifecycleMethods.isEmpty()) { + if (this.testMethods.isEmpty() && this.lifecycleMethods.isEmpty() && this.nestedTestClasses.isEmpty()) { return false; } for (String unlessImport : this.unlessImports) { @@ -148,6 +184,10 @@ private boolean shouldCheck() { } private void check() { + if (this.testClass != null && !isAbstract(this.testClass)) { + checkVisibility(Arrays.asList(this.testClass), "junit5.publicClass", null); + } + checkVisibility(this.nestedTestClasses, "junit5.publicNestedClass", "junit5.privateNestedClass"); for (String bannedImport : BANNED_IMPORTS) { FullIdent ident = this.imports.get(bannedImport); if (ident != null) { @@ -155,34 +195,56 @@ private void check() { } } for (DetailAST testMethod : this.testMethods) { - if (AnnotationUtil.containsAnnotation(testMethod, JUNIT4_TEST_ANNOTATION)) { + if (AnnotationUtil.containsAnnotation(testMethod, JUNIT4_TEST_ANNOTATION_NAME)) { log(testMethod, "junit5.bannedTestAnnotation"); } } - checkMethodVisibility(this.testMethods, "junit5.testPublicMethod", "junit5.testPrivateMethod"); - checkMethodVisibility(this.lifecycleMethods, "junit5.lifecyclePublicMethod", "junit5.lifecyclePrivateMethod"); + checkVisibility(this.testMethods, "junit5.testPublicMethod", "junit5.testPrivateMethod"); + checkVisibility(this.lifecycleMethods, "junit5.lifecyclePublicMethod", "junit5.lifecyclePrivateMethod"); } - private void checkMethodVisibility(List methods, String publicMessageKey, String privateMessageKey) { - for (DetailAST method : methods) { - DetailAST modifiers = method.findFirstToken(TokenTypes.MODIFIERS); + private boolean isAbstract(DetailAST ast) { + DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); + return modifiers.findFirstToken(TokenTypes.ABSTRACT) != null; + } + + private void checkVisibility(List asts, String publicMessageKey, String privateMessageKey) { + for (DetailAST ast : asts) { + DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); if (modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null) { - log(method, publicMessageKey); + log(ast, publicMessageKey); } - if (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null) { - log(method, privateMessageKey); + if ((privateMessageKey != null) && (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null)) { + log(ast, privateMessageKey); } } } - private void log(DetailAST method, String key) { - String name = method.findFirstToken(TokenTypes.IDENT).getText(); - log(method.getLineNo(), method.getColumnNo(), key, name); + private void log(DetailAST ast, String key) { + String name = ast.findFirstToken(TokenTypes.IDENT).getText(); + log(ast.getLineNo(), ast.getColumnNo(), key, name); } public void setUnlessImports(String unlessImports) { - this.unlessImports = Collections.unmodifiableList( - Arrays.stream(unlessImports.split(",")).map(String::trim).collect(Collectors.toList())); + this.unlessImports = Collections + .unmodifiableList(Arrays.stream(unlessImports.split(",")).map(String::trim).collect(Collectors.toList())); + } + + private static final class Annotation { + + private final String packageName; + + private final String simpleName; + + private Annotation(String packageName, String simpleName) { + this.packageName = packageName; + this.simpleName = simpleName; + } + + private String fullyQualifiedName() { + return this.packageName + "." + this.simpleName; + } + } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJavadocCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJavadocCheck.java index ed24cc47..56f7ea63 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJavadocCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJavadocCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,18 @@ package io.spring.javaformat.checkstyle.check; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -33,11 +38,28 @@ */ public class SpringJavadocCheck extends AbstractSpringCheck { - private static final Pattern[] CASE_CHECKED_TAG_PATTERNS = { Pattern.compile("@param\\s+\\S+\\s+(.*)"), - Pattern.compile("@throws\\s+\\S+\\s+(.*)"), Pattern.compile("@return\\s+(.*)") }; + private static final List CASE_CHECKED_TAG_PATTERNS; + static { + List patterns = new ArrayList<>(); + patterns.add(Pattern.compile("@param\\s+\\S+\\s+(.*)")); + patterns.add(Pattern.compile("@throws\\s+\\S+\\s+(.*)")); + patterns.add(Pattern.compile("@return\\s+(.*)")); + CASE_CHECKED_TAG_PATTERNS = Collections.unmodifiableList(patterns); + } + + private static final List BANNED_TAGS; + static { + List patterns = new ArrayList<>(); + patterns.add(Pattern.compile("(@soundtrack)\\s+.*")); + BANNED_TAGS = Collections.unmodifiableList(patterns); + } private static final Pattern SINCE_TAG_PATTERN = Pattern.compile("@since\\s+(.*)"); + private static final Pattern AT_TAG_PATTERN = Pattern.compile("[^{]@\\w+\\s+.*"); + + private static final Pattern NON_JAVADOC_COMMENT = Pattern.compile("\\(non-Javadoc\\)", Pattern.CASE_INSENSITIVE); + private static final Set TOP_LEVEL_TYPES; static { Set topLevelTypes = new HashSet(); @@ -52,10 +74,14 @@ public class SpringJavadocCheck extends AbstractSpringCheck { private boolean publicOnlySinceTags; + private boolean allowNonJavadocComments; + + private Map blockComments; + @Override public int[] getDefaultTokens() { return new int[] { TokenTypes.INTERFACE_DEF, TokenTypes.CLASS_DEF, TokenTypes.ENUM_DEF, - TokenTypes.ANNOTATION_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF }; + TokenTypes.ANNOTATION_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, TokenTypes.ANNOTATION_FIELD_DEF }; } @Override @@ -65,13 +91,58 @@ public int[] getAcceptableTokens() { TokenTypes.ANNOTATION_FIELD_DEF }; } + @Override + public void beginTree(DetailAST rootAST) { + super.beginTree(rootAST); + this.blockComments = new HashMap<>(); + FileContents contents = getFileContents(); + for (List blockComments : contents.getBlockComments().values()) { + for (TextBlock blockComment : blockComments) { + this.blockComments.put(blockComment.getEndLineNo(), blockComment); + } + } + } + @Override public void visitToken(DetailAST ast) { int lineNumber = ast.getLineNo(); TextBlock javadoc = getFileContents().getJavadocBefore(lineNumber); if (javadoc != null) { - checkTagCase(ast, javadoc); - checkSinceTag(ast, javadoc); + checkJavadoc(ast, javadoc); + } + if (!this.allowNonJavadocComments) { + checkForNonJavadocComments(javadoc); + checkForNonJavadocComments(getBlockCommentBefore(lineNumber)); + } + } + + public TextBlock getBlockCommentBefore(int lineNoBefore) { + FileContents contents = getFileContents(); + int lineNo = lineNoBefore - 1; + while (lineNo > 0 && (contents.lineIsBlank(lineNo) || contents.lineIsComment(lineNo))) { + lineNo--; + } + return this.blockComments.get(lineNo); + } + + private void checkJavadoc(DetailAST ast, TextBlock javadoc) { + checkBannedTags(ast, javadoc); + checkTagCase(ast, javadoc); + checkSinceTag(ast, javadoc); + checkMethodJavaDoc(ast, javadoc); + checkAnnotationFieldJavaDoc(ast, javadoc); + } + + private void checkBannedTags(DetailAST ast, TextBlock javadoc) { + String[] text = javadoc.getText(); + for (int i = 0; i < text.length; i++) { + for (Pattern pattern : BANNED_TAGS) { + Matcher matcher = pattern.matcher(text[i]); + if (matcher.find()) { + String tagName = matcher.group(1).trim(); + log(javadoc.getStartLineNo() + i, tagName.length(), "javadoc.bannedTag", tagName); + } + } } } @@ -94,23 +165,82 @@ private void checkSinceTag(DetailAST ast, TextBlock javadoc) { if (!TOP_LEVEL_TYPES.contains(ast.getType())) { return; } + DetailAST interfaceOrAnnotationDef = getInterfaceOrAnnotationDef(ast); + boolean privateType = !isPublicOrProtected(ast) + && (interfaceOrAnnotationDef == null || !isPublicOrProtected(interfaceOrAnnotationDef)); + SinceTag sinceTag = SinceTag.find(ast, javadoc); + if (sinceTag != null) { + if (this.publicOnlySinceTags && privateType) { + log(sinceTag.lineNumber, sinceTag.columnNumber, "javadoc.publicSince"); + } + else { + checkContainingSince(ast, sinceTag); + } + } + else { + boolean innerType = ast.getParent() != null && ast.getParent().getType() != TokenTypes.COMPILATION_UNIT; + if (this.requireSinceTag && !innerType && sinceTag == null && !(this.publicOnlySinceTags && privateType)) { + log(javadoc.getStartLineNo(), 0, "javadoc.missingSince"); + } + } + } + + private void checkContainingSince(DetailAST ast, SinceTag currentTag) { + SinceTag containingSince = findContainingSince(ast); + if (containingSince != null) { + SinceVersion current = currentTag.version; + SinceVersion container = containingSince.version; + if (current != SinceVersion.UNKNOWN && container != SinceVersion.UNKNOWN) { + int comparison = current.compareTo(container); + if (comparison < 0) { + log(currentTag.lineNumber, currentTag.columnNumber, "javadoc.earlierSince", current, container, containingSince.lineNumber, containingSince.columnNumber); + } + else if (comparison == 0) { + log(currentTag.lineNumber, currentTag.columnNumber, "javadoc.sameSince", current, containingSince.lineNumber, containingSince.columnNumber); + } + } + } + } + + private SinceTag findContainingSince(DetailAST ast) { + DetailAST parent = ast.getParent(); + while (parent != null && parent.getType() != TokenTypes.COMPILATION_UNIT) { + TextBlock javadoc = getFileContents().getJavadocBefore(parent.getLineNo()); + if (javadoc != null) { + SinceTag sinceTag = SinceTag.find(ast, javadoc); + if (sinceTag != null) { + return sinceTag; + } + } + parent = parent.getParent(); + } + return null; + } + + private void checkMethodJavaDoc(DetailAST ast, TextBlock javadoc) { + if (TokenTypes.METHOD_DEF != ast.getType()) { + return; + } String[] text = javadoc.getText(); - DetailAST interfaceDef = getInterfaceDef(ast); - boolean privateType = !isPublicOrProtected(ast) && (interfaceDef == null || !isPublicOrProtected(interfaceDef)); - boolean innerType = ast.getParent() != null; - boolean found = false; for (int i = 0; i < text.length; i++) { - Matcher matcher = SINCE_TAG_PATTERN.matcher(text[i]); - if (matcher.find()) { - found = true; - String description = matcher.group(1).trim(); - if (this.publicOnlySinceTags && privateType) { - log(javadoc.getStartLineNo() + i, text[i].length() - description.length(), "javadoc.publicSince"); - } + Matcher matcher = AT_TAG_PATTERN.matcher(text[i]); + if (matcher.find() && i > 0 && text[i - 1].trim().equals("*")) { + log(javadoc.getStartLineNo() + i - 1, 0, "javadoc.emptyLineBeforeTag"); } } - if (this.requireSinceTag && !innerType && !found && !(this.publicOnlySinceTags && privateType)) { - log(javadoc.getStartLineNo(), 0, "javadoc.missingSince"); + SinceTag sinceTag = SinceTag.find(ast, javadoc); + if (sinceTag != null) { + checkContainingSince(ast, sinceTag); + } + } + + private void checkAnnotationFieldJavaDoc(DetailAST ast, TextBlock javadoc) { + if (TokenTypes.ANNOTATION_FIELD_DEF != ast.getType()) { + return; + } + SinceTag sinceTag = SinceTag.find(ast, javadoc); + if (sinceTag != null) { + checkContainingSince(ast, sinceTag); } } @@ -118,6 +248,18 @@ private boolean startsWithUppercase(String description) { return description.length() > 0 && Character.isUpperCase(description.charAt(0)); } + private void checkForNonJavadocComments(TextBlock block) { + if (block == null) { + return; + } + String[] text = block.getText(); + for (int i = 0; i < text.length; i++) { + if (NON_JAVADOC_COMMENT.matcher(text[i]).find()) { + log(block.getStartLineNo() + i - 1, 0, "javadoc.nonJavadocComment"); + } + } + } + public void setRequireSinceTag(boolean requireSinceTag) { this.requireSinceTag = requireSinceTag; } @@ -126,14 +268,20 @@ public void setPublicOnlySinceTags(boolean publicOnlySinceTags) { this.publicOnlySinceTags = publicOnlySinceTags; } - private DetailAST getInterfaceDef(DetailAST ast) { - return findParent(ast, TokenTypes.INTERFACE_DEF); + public void setAllowNonJavadocComments(boolean allowNonJavadocComments) { + this.allowNonJavadocComments = allowNonJavadocComments; } - private DetailAST findParent(DetailAST ast, int classDef) { + private DetailAST getInterfaceOrAnnotationDef(DetailAST ast) { + return findParent(ast, TokenTypes.INTERFACE_DEF, TokenTypes.ANNOTATION_DEF); + } + + private DetailAST findParent(DetailAST ast, int... classDefs) { while (ast != null) { - if (ast.getType() == classDef) { - return ast; + for (int classDef : classDefs) { + if (ast.getType() == classDef) { + return ast; + } } ast = ast.getParent(); } @@ -149,4 +297,86 @@ private boolean isPublicOrProtected(DetailAST ast) { || modifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) != null; } + private static final class SinceTag { + + private final int lineNumber; + + private final int columnNumber; + + private final SinceVersion version; + + private SinceTag(int lineNumber, int columnNumber, SinceVersion version) { + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.version = version; + } + + private static SinceTag find(DetailAST ast, TextBlock javadoc) { + String[] text = javadoc.getText(); + for (int i = 0; i < text.length; i++) { + Matcher matcher = SINCE_TAG_PATTERN.matcher(text[i]); + if (matcher.find()) { + String description = matcher.group(1).trim(); + return new SinceTag(javadoc.getStartLineNo() + i, text[i].length() - description.length(), SinceVersion.of(description)); + } + } + return null; + } + } + + private static final class SinceVersion implements Comparable { + + private static final SinceVersion UNKNOWN = new SinceVersion(-1, -1, -1, "unknown"); + + private static final Pattern DATE_PATTERN = Pattern.compile("[0-3][0-9]\\.[0-1][0-9]\\.20[0-2][0-9]"); + + private final int major; + + private final int minor; + + private final int patch; + + private final String text; + + private SinceVersion(int major, int minor, int patch, String text) { + this.major = major; + this.minor = minor; + this.patch = patch; + this.text = text; + } + + private static SinceVersion of(String text) { + if (DATE_PATTERN.matcher(text).matches()) { + return UNKNOWN; + } + try { + String[] components = text.split("\\."); + int major = (components.length > 0) ? Integer.parseInt(components[0]) : 0; + int minor = (components.length > 1) ? Integer.parseInt(components[1]) : 0; + int patch = (components.length > 2) ? Integer.parseInt(components[2]) : 0; + return new SinceVersion(major, minor, patch, text); + } + catch (NumberFormatException ex) { + return UNKNOWN; + } + } + + public String toString() { + return this.text; + } + + @Override + public int compareTo(SinceVersion other) { + int diff = this.major - other.major; + if (diff == 0) { + diff = this.minor - other.minor; + if (diff == 0) { + diff = this.patch - other.patch; + } + } + return diff; + } + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLambdaCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLambdaCheck.java index 4d452ea7..c0f45f07 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLambdaCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLambdaCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,8 @@ public int[] getAcceptableTokens() { @Override public void visitToken(DetailAST ast) { - if (ast.getType() == TokenTypes.LAMBDA) { + if (ast.getType() == TokenTypes.LAMBDA && ast.getParent() != null + && ast.getParent().getType() != TokenTypes.SWITCH_RULE) { visitLambda(ast); } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java new file mode 100644 index 00000000..abeba9de --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringLeadingWhitespaceCheck.java @@ -0,0 +1,137 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.io.File; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FileContents; +import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Checks that leading whitespace matches the expected indentation style. + * + * @author Phillip Webb + */ +public class SpringLeadingWhitespaceCheck extends AbstractSpringCheck { + + private static final Pattern PATTERN = Pattern.compile("^([\\ \\t]+)\\S"); + + private static final Map INDENTATION_STYLE_PATTERN; + static { + Map indentationStylePatterns = new HashMap<>(); + indentationStylePatterns.put(IndentationStyle.TABS, Pattern.compile("\\t*")); + indentationStylePatterns.put(IndentationStyle.SPACES, Pattern.compile("\\ *")); + INDENTATION_STYLE_PATTERN = Collections.unmodifiableMap(indentationStylePatterns); + } + + private IndentationStyle indentationStyle; + + private final Deque textBlockPairs = new ArrayDeque<>(); + + @Override + public int[] getAcceptableTokens() { + return new int[] { TokenTypes.TEXT_BLOCK_LITERAL_BEGIN, TokenTypes.TEXT_BLOCK_LITERAL_END }; + } + + @Override + public void visitToken(DetailAST ast) { + super.visitToken(ast); + if (ast.getType() == TokenTypes.TEXT_BLOCK_LITERAL_BEGIN) { + this.textBlockPairs.add(new TextBlockPair(ast)); + } + else if (ast.getType() == TokenTypes.TEXT_BLOCK_LITERAL_END) { + this.textBlockPairs.getLast().end(ast); + } + } + + @Override + public void beginTree(DetailAST rootAST) { + super.beginTree(rootAST); + this.textBlockPairs.clear(); + } + + @Override + public void finishTree(DetailAST rootAST) { + FileContents fileContents = getFileContents(); + FileText fileText = fileContents.getText(); + File file = fileText.getFile(); + if (file == null) { + return; + } + IndentationStyle indentationStyle = (this.indentationStyle != null) ? this.indentationStyle + : JavaFormatConfig.findFrom(file.getParentFile()).getIndentationStyle(); + for (int i = 0; i < fileText.size(); i++) { + int lineNo = i + 1; + if (isInTextBlock(lineNo)) { + continue; + } + String line = fileText.get(i); + Matcher matcher = PATTERN.matcher(line); + boolean found = matcher.find(0); + while (found + && fileContents.hasIntersectionWithComment(lineNo, matcher.start(0), lineNo, matcher.end(0) - 1)) { + found = matcher.find(matcher.end(0)); + } + if (found && !INDENTATION_STYLE_PATTERN.get(indentationStyle).matcher(matcher.group(1)).matches()) { + log(lineNo, "leadingwhitespace.incorrect", indentationStyle.toString().toLowerCase()); + } + } + super.finishTree(rootAST); + } + + private boolean isInTextBlock(int lineNo) { + return this.textBlockPairs.stream().anyMatch((textBlockPair) -> textBlockPair.contains(lineNo)); + } + + public void setIndentationStyle(String indentationStyle) { + this.indentationStyle = (indentationStyle != null && !"".equals(indentationStyle)) + ? IndentationStyle.valueOf(indentationStyle.toUpperCase()) : null; + } + + private static class TextBlockPair { + + private final DetailAST begin; + + private DetailAST end; + + TextBlockPair(DetailAST begin) { + this.begin = begin; + } + + public boolean contains(int lineNo) { + return (lineNo > this.begin.getLineNo()) && (lineNo <= this.end.getLineNo()); + } + + void end(DetailAST end) { + this.end = end; + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodOrderCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodOrderCheck.java index c486888f..bbb088bc 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodOrderCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodOrderCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ public class SpringMethodOrderCheck extends AbstractSpringCheck { private static final List EXPECTED_ORDER = Collections - .unmodifiableList(Arrays.asList("equals", "hashCode", "toString")); + .unmodifiableList(Arrays.asList("equals", "hashCode", "toString")); @Override public int[] getAcceptableTokens() { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodVisibilityCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodVisibilityCheck.java index ab431020..ca5bd3ef 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodVisibilityCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringMethodVisibilityCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,17 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes; /** - * Checks that protected, package-private and private classes to not have public methods - * unless they are also annotated with {@link Override @Override}. + * Check for compliance with Spring-style method visibility. Checks that: + * + *
    + *
  • package-private and private classes do not have public methods + * unless they are also annotated with {@link Override @Override} + *
  • final classes do not have protected methods unless that are also + * annotated with {@link Override @Override} + *
* * @author Phillip Webb + * @author Andy Wilkinson */ public class SpringMethodVisibilityCheck extends AbstractSpringCheck { @@ -38,6 +45,9 @@ public void visitToken(DetailAST ast) { if (modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null) { visitPublicMethod(modifiers, ast); } + else if (modifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) != null) { + visitProtectedMethod(modifiers, ast); + } } private void visitPublicMethod(DetailAST modifiers, DetailAST method) { @@ -56,6 +66,18 @@ private void visitPublicMethod(DetailAST modifiers, DetailAST method) { log(ident.getLineNo(), ident.getColumnNo(), "methodvisibility.publicMethod", ident.getText()); } + private void visitProtectedMethod(DetailAST modifiers, DetailAST method) { + if (hasOverrideAnnotation(modifiers)) { + return; + } + DetailAST classDef = getClassDef(method.getParent()); + if (classDef == null || !isFinal(classDef)) { + return; + } + DetailAST ident = method.findFirstToken(TokenTypes.IDENT); + log(ident.getLineNo(), ident.getColumnNo(), "methodvisibility.protectedMethodInFinalClass", ident.getText()); + } + private boolean hasOverrideAnnotation(DetailAST modifiers) { DetailAST candidate = modifiers.getFirstChild(); while (candidate != null) { @@ -98,4 +120,12 @@ private boolean isPublicOrProtected(DetailAST ast) { || modifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) != null; } + private boolean isFinal(DetailAST ast) { + DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); + if (modifiers == null) { + return false; + } + return modifiers.findFirstToken(TokenTypes.FINAL) != null; + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoThisCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoThisCheck.java index ffeda211..1a4ee466 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoThisCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoThisCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoWhitespaceBeforeCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoWhitespaceBeforeCheck.java new file mode 100644 index 00000000..f06a88c5 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNoWhitespaceBeforeCheck.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCheck; + +/** + * Spring-specific customization of {@link NoWhitespaceBeforeCheck} that permits + * whitespace before {@code ...} when it is a separator after an annotation, for + * example {@code int @Nullable ...}. + * + * @author Andy Wilkinson + */ +public class SpringNoWhitespaceBeforeCheck extends NoWhitespaceBeforeCheck { + + @Override + public void visitToken(DetailAST ast) { + if (ast.getType() != TokenTypes.ELLIPSIS) { + super.visitToken(ast); + } + else { + visitEllipsis(ast); + } + } + + private void visitEllipsis(DetailAST ellipsis) { + DetailAST previousSibling = ellipsis.getPreviousSibling(); + if (previousSibling.getType() == TokenTypes.TYPE && + previousSibling.getChildCount() == 2 && + previousSibling.getLastChild().getType() == TokenTypes.ANNOTATIONS) { + return; + } + super.visitToken(ellipsis); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNullabilityCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNullabilityCheck.java new file mode 100644 index 00000000..4c48c381 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringNullabilityCheck.java @@ -0,0 +1,140 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + * Checks compliance with Spring team's nullability conventions. JSpecify annotations + * should be used to express nullability and type-use annotations ({@code @Nullable} + * and {@code @NonNull}) should appear immediately before a type. + * + * @author Andy Wilkinson + */ +public class SpringNullabilityCheck extends AbstractSpringCheck { + + private final Set unwantedNullabilityImports = new HashSet<>(); + + private final List modifiers = new ArrayList<>(); + + @Override + public int[] getAcceptableTokens() { + return new int[] { TokenTypes.IMPORT, TokenTypes.MODIFIERS }; + } + + @Override + public void beginTree(DetailAST rootAST) { + this.modifiers.clear(); + this.unwantedNullabilityImports.clear(); + } + + @Override + public void finishTree(DetailAST rootAST) { + this.modifiers.forEach(this::visitModifiers); + } + + @Override + public void visitToken(DetailAST ast) { + switch (ast.getType()) { + case TokenTypes.IMPORT: + visitImport(ast); + break; + case TokenTypes.MODIFIERS: + this.modifiers.add(ast); + break; + } + } + + private void visitImport(DetailAST ast) { + FullIdent ident = FullIdent.createFullIdentBelow(ast); + if (!isFullyQualifiedJSpecifyAnnotation(ident)) { + String simpleName = simpleNameOf(ident); + for (JSpecifyAnnotation annotation: JSpecifyAnnotation.values()) { + if (annotation.replaces.contains(simpleName)) { + log(ident.getLineNo(), ident.getColumnNo(), "nullability.bannedImport", ident.getText(), annotation.name); + this.unwantedNullabilityImports.add(simpleName); + } + } + } + } + + private boolean isFullyQualifiedJSpecifyAnnotation(FullIdent ident) { + for (JSpecifyAnnotation annotation: JSpecifyAnnotation.values()) { + if (ident.getText().equals(annotation.name)) { + return true; + } + } + return false; + } + + private String simpleNameOf(FullIdent ident) { + String identText = ident.getText(); + return identText.substring(identText.lastIndexOf(".") + 1); + } + + private void visitModifiers(DetailAST ast) { + DetailAST annotation = ast.findFirstToken(TokenTypes.ANNOTATION); + if (annotation != null) { + DetailAST ident = annotation.findFirstToken(TokenTypes.IDENT); + if (ident != null) { + String identText = ident.getText(); + DetailAST lastChild = ast.getLastChild(); + if (isJSpecifyAnnotation(ident) && !annotation.equals(lastChild)) { + log(annotation.getLineNo(), annotation.getColumnNo(), "nullability.annotationLocation", identText); + } + } + } + } + + private boolean isJSpecifyAnnotation(DetailAST ident) { + for (JSpecifyAnnotation annotation: JSpecifyAnnotation.values()) { + if (ident.getText().equals(annotation.simpleName) && !this.unwantedNullabilityImports.contains(ident.getText())) { + return true; + } + } + return false; + } + + private enum JSpecifyAnnotation { + + NULLABLE("Nullable", "Nullable"), + + NON_NULL("NonNull", "NonNull", "Nonnull"); + + private final String simpleName; + + private final String name; + + private Set replaces; + + JSpecifyAnnotation(String simpleName, String... replaces) { + this.simpleName = simpleName; + this.name = "org.jspecify.annotations." + simpleName; + this.replaces = new HashSet<>(Arrays.asList(replaces)); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringParenPadCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringParenPadCheck.java new file mode 100644 index 00000000..a49789b0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringParenPadCheck.java @@ -0,0 +1,77 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.util.Locale; + +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.checks.whitespace.PadOption; +import com.puppycrawl.tools.checkstyle.checks.whitespace.ParenPadCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtil; + +/** + * {@link ParenPadCheck} variant that allows whitespace after {@code (} if before + * {@code //}. + * + * @author Phillip Webb + */ +public class SpringParenPadCheck extends ParenPadCheck { + + private static final char OPEN_PARENTHESIS = '('; + + private static final char CLOSE_PARENTHESIS = ')'; + + private PadOption option = PadOption.NOSPACE; + + @Override + public void setOption(String optionStr) { + this.option = PadOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); + } + + @Override + protected void processLeft(DetailAST ast) { + String line = getLines()[ast.getLineNo() - 1]; + int[] codePoints = line.codePoints().toArray(); + int after = ast.getColumnNo() + 1; + if (after < codePoints.length) { + boolean hasWhitespaceAfter = isConsideredWhitespace(codePoints, after); + if (this.option == PadOption.NOSPACE && hasWhitespaceAfter) { + log(ast, MSG_WS_FOLLOWED, OPEN_PARENTHESIS); + } + else if (this.option == PadOption.SPACE && !hasWhitespaceAfter && line.charAt(after) != CLOSE_PARENTHESIS) { + log(ast, MSG_WS_NOT_FOLLOWED, OPEN_PARENTHESIS); + } + } + } + + private boolean isConsideredWhitespace(int[] codePoints, int after) { + if (CommonUtil.isCodePointWhitespace(codePoints, after)) { + return !isSlashSlash(codePoints, after + 1); + } + return false; + } + + private boolean isSlashSlash(int[] codePoints, int index) { + if (index + 1 < codePoints.length) { + char c1 = Character.toChars(codePoints[index])[0]; + char c2 = Character.toChars(codePoints[index + 1])[0]; + return c1 == '/' && c2 == '/'; + } + return false; + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTernaryCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTernaryCheck.java index 0bf7a2e9..caf82d1e 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTernaryCheck.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTernaryCheck.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,9 +61,9 @@ private void visitQuestion(DetailAST ast) { private boolean requiresParens(DetailAST expression) { if (expression != null && expression.getChildCount() > 1) { switch (expression.getType()) { - case TokenTypes.METHOD_CALL: - case TokenTypes.DOT: - return false; + case TokenTypes.METHOD_CALL: + case TokenTypes.DOT: + return false; } return true; } @@ -86,13 +86,13 @@ private boolean isSimpleEqualsExpression(DetailAST expression) { private boolean isEqualsTestAllowed(DetailAST ast) { switch (this.equalsTest) { - case ANY: - return true; - case NEVER: - return false; - case NEVER_FOR_NULLS: - DetailAST equal = ast.findFirstToken(TokenTypes.EQUAL); - return equal.findFirstToken(TokenTypes.LITERAL_NULL) == null; + case ANY: + return true; + case NEVER: + return false; + case NEVER_FOR_NULLS: + DetailAST equal = ast.findFirstToken(TokenTypes.EQUAL); + return equal.findFirstToken(TokenTypes.LITERAL_NULL) == null; } throw new IllegalStateException("Unsupported equals test " + this.equalsTest); } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java new file mode 100644 index 00000000..31dda6a0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringTestFileNameCheck.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.checkstyle.check; + +import java.io.File; + +import com.puppycrawl.tools.checkstyle.JavaParser; +import com.puppycrawl.tools.checkstyle.JavaParser.Options; +import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + * Checks that test class filenames end {@literal Tests.java} and not + * {@literal Test.java}. + * + * @author Phillip Webb + * @author Andy Wilkinson + */ +public class SpringTestFileNameCheck extends AbstractFileSetCheck { + + @Override + protected void processFiltered(File file, FileText fileText) throws CheckstyleException { + String path = file.getPath().replace('\\', '/'); + if (path.contains("src/test/java") && file.getName().endsWith("Test.java")) { + visitCompilationUnit(JavaParser.parseFileText(fileText, Options.WITHOUT_COMMENTS)); + } + } + + private void visitCompilationUnit(DetailAST ast) { + DetailAST child = ast.getFirstChild(); + while (child != null) { + if (child.getType() == TokenTypes.CLASS_DEF) { + log(1, "testfilename.wrongName"); + return; + } + child = child.getNextSibling(); + } + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/CheckFilter.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/CheckFilter.java index bdfac6fa..5388e5bd 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/CheckFilter.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/CheckFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.Context; import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.Violation; /** * Base class for {@link AbstractCheck checks} that act as a filter for a single child. @@ -100,14 +100,14 @@ public boolean isCommentNodesRequired() { } @Override - public SortedSet getMessages() { - return this.check.getMessages(); + public SortedSet getViolations() { + return this.check.getViolations(); } @Override public void beginTree(DetailAST rootAST) { this.check.setFileContents(getFileContents()); - this.check.clearMessages(); + this.check.clearViolations(); this.check.beginTree(rootAST); } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/IdentCheckFilter.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/IdentCheckFilter.java index d8950d5e..6e434bcc 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/IdentCheckFilter.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/IdentCheckFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/RequiresOuterThisFilter.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/RequiresOuterThisFilter.java index 949bb599..080bf8ec 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/RequiresOuterThisFilter.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/filter/RequiresOuterThisFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.Violation; /** * {@link TreeWalkerFilter} that can used to relax the {@code 'this.'} requirement when @@ -35,9 +35,9 @@ public class RequiresOuterThisFilter implements TreeWalkerFilter { @Override public boolean accept(TreeWalkerAuditEvent event) { - LocalizedMessage message = event.getLocalizedMessage(); - if ("require.this.variable".equals(message.getKey())) { - Object[] args = getArgs(message); + Violation violation = event.getViolation(); + if ("require.this.variable".equals(violation.getKey())) { + Object[] args = getArgs(violation); String prefex = (args.length > 1 ? Objects.toString(args[1]) : null); if (prefex != null && prefex.length() > 0) { return false; @@ -46,12 +46,12 @@ public boolean accept(TreeWalkerAuditEvent event) { return true; } - private Object[] getArgs(LocalizedMessage message) { + private Object[] getArgs(Violation violation) { if (ARGS_FIELD == null) { throw new IllegalStateException("Unable to extract message args"); } try { - return (Object[]) ARGS_FIELD.get(message); + return (Object[]) ARGS_FIELD.get(violation); } catch (Exception ex) { return null; @@ -60,7 +60,7 @@ private Object[] getArgs(LocalizedMessage message) { private static Field getArgsField() { try { - Field field = LocalizedMessage.class.getDeclaredField("args"); + Field field = Violation.class.getDeclaredField("args"); field.setAccessible(true); return field; } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties index 540aca17..eaaec1f1 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/check/messages.properties @@ -1,13 +1,29 @@ +annotation.attribute.overlyVerboseValue=Value of ''{0}'' attribute is overly verbose. Import ''{1}'' and use ''{2}'' instead. +annotation.location=Annotation ''{0}'' have incorrect indentation level {1}, expected level should be {2}. +annotation.location.alone=Annotation ''{0}'' should be alone on line. catch.singleLetter=Single letter catch variable (use "ex" instead). +catch.wideEye=''o_O'' catch variable (use "ex" instead). header.unexpected=Unexpected header. header.mismatch=Line does not match expected header line of ''{0}''. +header.blankLine=Blank line expected after header. +hide.utility.class=Utility classes should not have a public or default constructor. +import.avoidStatic=Using a static member import should be avoided - {0}. +import.ordering=Wrong order for ''{0}'' import. javadoc.badCase=Javadoc element descriptions should not start with an uppercase letter. +javadoc.bannedTag=Javadoc tag ''{0}'' should not be used. +javadoc.earlierSince=Javadoc @since version ''{0}'' is earlier than @since version ''{1}'' at {2}:{3}. javadoc.missingSince=Missing Javadoc @since tag. +javadoc.sameSince=Javadoc @since version ''{0}'' is unnecessary as it is the same as the @since version at {1}:{2}. javadoc.publicSince=Javadoc @since tag should not be used on private classes. +javadoc.emptyLineBeforeTag=Method Javadoc should not have empty line before tag. +javadoc.nonJavadocComment=Comments should not include \"(non-Javadoc)\". junit5.bannedImport=Import ''{0}'' should not be used in a JUnit 5 test. junit5.bannedTestAnnotation=JUnit 4 @Test annotation should not be used in a JUnit 5 test. junit5.lifecyclePrivateMethod=Lifecycle method ''{0}'' should not be private. junit5.lifecyclePublicMethod=Lifecycle method ''{0}'' should not be public. +junit5.publicClass=Test class ''{0}'' should not be public. +junit5.publicNestedClass=Nested test class ''{0}'' should not be public. +junit5.privateNestedClass=Nested test class ''{0}'' should not be private. junit5.testPrivateMethod=Test method ''{0}'' should not be private. junit5.testPublicMethod=Test method ''{0}'' should not be public. lambda.missingParen=Lambda argument missing parentheses. @@ -15,6 +31,19 @@ lambda.unnecessaryBlock=Lambda block is unnecessary. lambda.unnecessaryParen=Lambda argument has unnecessary parentheses. methodorder.outOfOrder=Method ''{0}'' is out of order, expected {1}. methodvisibility.publicMethod=Method ''{0}'' in private class should not be public. +methodvisibility.protectedMethodInFinalClass=Method ''{0}'' in final class should be package-private rather than protected. nothis.unexpected=Reference to instance variable ''{0}'' should not use \"this.\". +nullability.bannedImport=Nullability should be expressed using JSpecify. Replace ''{0}'' with ''{1}''. +nullability.annotationLocation=''{0}'' should only be used immediately before a type. ternary.equalOperator=Ternary operation should use != when testing. -ternary.missingParen=Ternary operation missing parentheses. Use the form \"(a != b) ? y : n\" +ternary.missingParen=Ternary operation missing parentheses. Use the form \"(a != b) ? y : n\". +testfilename.wrongName=Test classes should have a name ending with 'Tests.java'. +leadingwhitespace.incorrect=Indentation should be performed with {0} only. +deprecated.missingSince=@Deprecated has no since attribute. +deprecated.emptySince=@Deprecated has an empty since attribute. +ws.followed=''{0}'' is followed by whitespace. +ws.illegalFollow=''{0}'' is followed by an illegal character. +ws.notFollowed=''{0}'' is not followed by whitespace. +ws.notPreceded=''{0}'' is not preceded with whitespace. +ws.preceded=''{0}'' is preceded with whitespace. +ws.typeCast=''typecast'' is not followed by whitespace. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml index 65820e80..829e6959 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/resources/io/spring/javaformat/checkstyle/spring-checkstyle.xml @@ -7,13 +7,13 @@ - - - - - - + + + + + + @@ -22,11 +22,10 @@ + - - - + + @@ -70,55 +69,10 @@ + - - - @@ -134,7 +88,7 @@ - + @@ -145,11 +99,11 @@ - + - + - + @@ -165,22 +119,16 @@ - - + + + + value="Please use BDD-style (given, when, then) using BDDMockito imports." /> - - - - - - - - - + + + @@ -197,18 +145,23 @@ - - + + + + + - + + + diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/AssertionsAuditListener.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/AssertionsAuditListener.java index 92105e06..6b36f545 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/AssertionsAuditListener.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/AssertionsAuditListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ import com.puppycrawl.tools.checkstyle.Definitions; import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.AuditListener; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; +import com.puppycrawl.tools.checkstyle.api.Violation; import static org.assertj.core.api.Assertions.assertThat; @@ -110,8 +110,8 @@ private void recordLevel(AuditEvent event) { } private void recordLocalizedMessage(String message, String... args) { - recordMessage(new LocalizedMessage(0, Definitions.CHECKSTYLE_BUNDLE, message, args, null, - LocalizedMessage.class, null).getMessage()); + recordMessage(new Violation(0, Definitions.CHECKSTYLE_BUNDLE, message, args, null, Violation.class, null) + .getViolation()); } private void recordMessage(String message) { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTestParameter.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTestParameter.java index 2cad6835..62e4a959 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTestParameter.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTestParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java index 692d2134..0be6bdb9 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringChecksTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -40,10 +42,9 @@ import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.RootModule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.xml.sax.InputSource; /** @@ -51,7 +52,6 @@ * * @author Phillip Webb */ -@RunWith(Parameterized.class) public class SpringChecksTests { private static final boolean RUNNING_ON_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win"); @@ -64,20 +64,18 @@ public class SpringChecksTests { private static final File DEFAULT_CONFIG = new File(CONFIGS_DIR, "default-checkstyle-configuration.xml"); - private final Parameter parameter; + @TempDir + public Path temp; - public SpringChecksTests(Parameter parameter) throws Exception { - this.parameter = parameter; - } - - @Test - public void processHasExpectedResults() throws Exception { + @ParameterizedTest + @MethodSource("paramaters") + public void processHasExpectedResults(Parameter parameter) throws Exception { Locale previousLocale = Locale.getDefault(); Locale.setDefault(Locale.ENGLISH); - Configuration configuration = loadConfiguration(); + Configuration configuration = loadConfiguration(parameter); RootModule rootModule = createRootModule(configuration); try { - processAndCheckResults(rootModule); + processAndCheckResults(parameter, rootModule); } finally { rootModule.destroy(); @@ -85,8 +83,8 @@ public void processHasExpectedResults() throws Exception { } } - private Configuration loadConfiguration() throws Exception { - try (InputStream inputStream = new FileInputStream(this.parameter.getConfigFile())) { + private Configuration loadConfiguration(Parameter parameter) throws Exception { + try (InputStream inputStream = new FileInputStream(parameter.getConfigFile())) { Configuration configuration = ConfigurationLoader.loadConfiguration(new InputSource(inputStream), new PropertiesExpander(new Properties()), IgnoredModulesOptions.EXECUTE, ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); @@ -103,12 +101,12 @@ private RootModule createRootModule(Configuration configuration) throws Checksty return rootModule; } - private void processAndCheckResults(RootModule rootModule) throws CheckstyleException { - rootModule.addListener(this.parameter.getAssertionsListener()); + private void processAndCheckResults(Parameter parameter, RootModule rootModule) throws CheckstyleException { + rootModule.addListener(parameter.getAssertionsListener()); if (!RUNNING_ON_WINDOWS) { - printDebugInfo(this.parameter.getSourceFile()); + printDebugInfo(parameter.getSourceFile()); } - rootModule.process(Arrays.asList(this.parameter.getSourceFile())); + rootModule.process(Arrays.asList(parameter.getSourceFile())); } private void printDebugInfo(File file) throws CheckstyleException { @@ -119,10 +117,21 @@ private void printDebugInfo(File file) throws CheckstyleException { } } - @Parameters(name = "{0}") - public static Collection files() throws IOException { - return Arrays.stream(SOURCES_DIR.list((dir, name) -> !name.startsWith("."))).sorted().map(Parameter::new) - .collect(Collectors.toList()); + public static Collection paramaters() throws IOException { + ArrayList parameters = Arrays.stream(SOURCES_DIR.listFiles(SpringChecksTests::sourceFile)) + .sorted() + .map(Parameter::new) + .collect(Collectors.toCollection(ArrayList::new)); + parameters.add(new Parameter(new File(SOURCES_DIR, "nopackageinfo/NoPackageInfo.java"))); + Arrays.stream(new File(SOURCES_DIR, "src/test/java").listFiles(SpringChecksTests::sourceFile)) + .sorted() + .map(Parameter::new) + .forEach(parameters::add); + return parameters; + } + + private static boolean sourceFile(File file) { + return file.isFile() && !file.getName().startsWith(".") && !file.getName().equals("package-info.java"); } private static class Parameter { @@ -135,7 +144,8 @@ private static class Parameter { private final File configFile; - Parameter(String sourceName) { + Parameter(File sourceFile) { + String sourceName = sourceFile.getAbsolutePath().substring(SOURCES_DIR.getAbsolutePath().length() + 1); this.name = sourceName.replace(".java", ""); this.sourceFile = new File(SOURCES_DIR, sourceName); File configFile = new File(CONFIGS_DIR, this.name + ".xml"); diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java index c4f8d323..2c81cdd4 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/java/io/spring/javaformat/checkstyle/SpringConfigurationLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,21 @@ package io.spring.javaformat.checkstyle; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Properties; +import java.util.Set; import com.puppycrawl.tools.checkstyle.DefaultContext; -import com.puppycrawl.tools.checkstyle.ModuleFactory; import com.puppycrawl.tools.checkstyle.PackageObjectFactory; import com.puppycrawl.tools.checkstyle.PropertiesExpander; import com.puppycrawl.tools.checkstyle.PropertyResolver; +import com.puppycrawl.tools.checkstyle.TreeWalker; import com.puppycrawl.tools.checkstyle.api.FileSetCheck; -import org.junit.Test; +import org.assertj.core.extractor.Extractors; +import org.junit.jupiter.api.Test; import io.spring.javaformat.checkstyle.check.SpringHeaderCheck; import io.spring.javaformat.checkstyle.check.SpringImportOrderCheck; @@ -41,14 +46,44 @@ public class SpringConfigurationLoaderTests { @Test public void loadShouldLoadChecks() { + Collection checks = load(null); + assertThat(checks).hasSize(5); + TreeWalker treeWalker = (TreeWalker) checks.toArray()[4]; + Set ordinaryChecks = (Set) Extractors.byName("ordinaryChecks").extract(treeWalker); + assertThat(ordinaryChecks).hasSize(63); + Set commentChecks = (Set) Extractors.byName("commentChecks").extract(treeWalker); + assertThat(commentChecks).hasSize(6); + } + + @Test + public void loadWithExcludeShouldExcludeChecks() { + Set excludes = new HashSet( + Arrays.asList("com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck", + "com.puppycrawl.tools.checkstyle.checks.annotation.MissingDeprecatedCheck")); + Collection checks = load(excludes); + assertThat(checks).hasSize(5); + TreeWalker treeWalker = (TreeWalker) checks.toArray()[4]; + Set ordinaryChecks = (Set) Extractors.byName("ordinaryChecks").extract(treeWalker); + assertThat(ordinaryChecks).hasSize(62); + Set commentChecks = (Set) Extractors.byName("commentChecks").extract(treeWalker); + assertThat(commentChecks).hasSize(5); + } + + @Test + public void loadWithExcludeHeaderShouldExcludeChecks() { + Set excludes = Collections.singleton("io.spring.javaformat.checkstyle.check.SpringHeaderCheck"); + Object[] checks = load(excludes).stream().toArray(); + assertThat(checks).hasSize(4); + } + + private Collection load(Set excludes) { DefaultContext context = new DefaultContext(); - context.add("moduleFactory", - new PackageObjectFactory(getClass().getPackage().getName(), getClass().getClassLoader())); - ModuleFactory moduleFactory = new PackageObjectFactory(getClass().getPackage().getName(), - getClass().getClassLoader()); - Collection checks = new SpringConfigurationLoader(context, moduleFactory) - .load(getPropertyResolver()); - assertThat(checks).hasSize(3); + FilteredModuleFactory filteredModuleFactory = new FilteredModuleFactory( + new PackageObjectFactory(getClass().getPackage().getName(), getClass().getClassLoader()), excludes); + context.add("moduleFactory", filteredModuleFactory); + Collection checks = new SpringConfigurationLoader(context, filteredModuleFactory) + .load(getPropertyResolver()); + return checks; } private PropertyResolver getPropertyResolver() { @@ -57,6 +92,7 @@ private PropertyResolver getPropertyResolver() { properties.put("headerFile", ""); properties.put("headerCopyrightPattern", SpringHeaderCheck.DEFAULT_HEADER_COPYRIGHT_PATTERN); properties.put("projectRootPackage", SpringImportOrderCheck.DEFAULT_PROJECT_ROOT_PACKAGE); + properties.put("avoidStaticImportExcludes", ""); return new PropertiesExpander(properties); } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasReferenceToContainedConstant.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasReferenceToContainedConstant.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasReferenceToContainedConstant.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.txt new file mode 100644 index 00000000..17a91c25 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.txt @@ -0,0 +1,2 @@ ++AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java:17:84: Value of 'value' attribute is overly verbose. Import 'ConditionalOnWebApplicationType.WebApplicationType' and use 'WebApplicationType.SERVLET' instead. [SpringAnnotationAttributeConciseValue] ++1 error \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.txt new file mode 100644 index 00000000..2c02256f --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.txt @@ -0,0 +1,2 @@ ++AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java:17:91: Value of 'type' attribute is overly verbose. Import 'ConditionalOnWebApplicationType.WebApplicationType' and use 'WebApplicationType.SERVLET' instead. [SpringAnnotationAttributeConciseValue] ++1 error \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationOnNewLine.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AsciidoctorCallout.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AsciidoctorCallout.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AsciidoctorCallout.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AssertJBadAssertImport.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AssertJBadAssertImport.txt new file mode 100644 index 00000000..05108d50 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AssertJBadAssertImport.txt @@ -0,0 +1,2 @@ ++Please use AssertJ imports. ++3 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AssertJBadAssertionsImport.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AssertJBadAssertionsImport.txt new file mode 100644 index 00000000..05108d50 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/AssertJBadAssertionsImport.txt @@ -0,0 +1,2 @@ ++Please use AssertJ imports. ++3 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/CatchOo.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/CatchOo.txt new file mode 100644 index 00000000..dba33895 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/CatchOo.txt @@ -0,0 +1 @@ ++'o_O' catch variable (use "ex" instead) diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/DeprecatedBadCase.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/DeprecatedBadCase.txt new file mode 100644 index 00000000..96f86d18 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/DeprecatedBadCase.txt @@ -0,0 +1,6 @@ ++DeprecatedBadCase.java:22:1: @Deprecated has no since attribute. [SpringDeprecated] ++DeprecatedBadCase.java:25:9: @Deprecated has no since attribute. [SpringDeprecated] ++DeprecatedBadCase.java:28:9: @Deprecated has an empty since attribute. [SpringDeprecated] ++DeprecatedBadCase.java:33:9: @Deprecated has no since attribute. [SpringDeprecated] ++DeprecatedBadCase.java:36:17: @Deprecated has an empty since attribute. [SpringDeprecated] ++5 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/DeprecatedValid.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/DeprecatedValid.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/DeprecatedValid.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HeaderMissingBlankLine.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HeaderMissingBlankLine.txt new file mode 100644 index 00000000..7ffa25dc --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HeaderMissingBlankLine.txt @@ -0,0 +1,2 @@ ++Blank line expected after header ++1 error \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HeaderWithDateToPresent.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HeaderWithDateToPresent.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HeaderWithDateToPresent.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HideUtilityClassConstructorInvalid.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HideUtilityClassConstructorInvalid.txt index 84638146..dc14dcd3 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HideUtilityClassConstructorInvalid.txt +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/HideUtilityClassConstructorInvalid.txt @@ -1 +1 @@ -+HideUtilityClassConstructorInvalid.java:22:1: hide.utility.class [SpringHideUtilityClassConstructor] ++HideUtilityClassConstructorInvalid.java:22:1: Utility classes should not have a public or default constructor. [SpringHideUtilityClassConstructor] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/ImportOrderCustomPackageInvalid.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/ImportOrderCustomPackageInvalid.txt index 3304f9d6..37a1d385 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/ImportOrderCustomPackageInvalid.txt +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/ImportOrderCustomPackageInvalid.txt @@ -1 +1 @@ -+ImportOrderCustomPackageInvalid.java:21: import.ordering [SpringImportOrder] ++ImportOrderCustomPackageInvalid.java:21:1: Wrong order for 'java.util.Objects' import. [SpringImportOrder] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt index 376aa13c..7ec1d4de 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5BadModifier.txt @@ -1,7 +1,11 @@ ++Test class 'JUnit5BadModifier' should not be public ++Nested test class 'PublicNestedTests' should not be public ++Nested test class 'PrivateNestedTests' should not be private +Test method 'doSomethingWorks' should not be public +Test method 'doSomethingElseWorks' should not be private +Test method 'doSomethingWithTemplateWorks' should not be public +Test method 'doSomethingElseWithTemplateWorks' should not be private ++Test method 'nestedPublicTest' should not be public +Lifecycle method 'publicBeforeAll' should not be public +Lifecycle method 'publicBeforeEach' should not be public +Lifecycle method 'publicAfterAll' should not be public diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5PublicAbstractIsValid.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5PublicAbstractIsValid.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JUnit5PublicAbstractIsValid.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocAnnotationFieldHasEarlierSince.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocAnnotationFieldHasEarlierSince.txt new file mode 100644 index 00000000..e5c19bf9 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocAnnotationFieldHasEarlierSince.txt @@ -0,0 +1,2 @@ ++28:19: Javadoc @since version '1.1.0' is earlier than @since version '1.2.0' at 21:10. ++1 error diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocInnerClassHasEarlierSince.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocInnerClassHasEarlierSince.txt new file mode 100644 index 00000000..73737acb --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocInnerClassHasEarlierSince.txt @@ -0,0 +1,2 @@ ++28:19: Javadoc @since version '1.2.3' is earlier than @since version '2.0.0' at 21:10. ++1 error diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodEmptyLineBeforeTag.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodEmptyLineBeforeTag.txt new file mode 100644 index 00000000..efa9ef2f --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodEmptyLineBeforeTag.txt @@ -0,0 +1,2 @@ ++Method Javadoc should not have empty line before tag. ++1 error \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodEmptyLineBeforeTagWithStarAtEnd.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodEmptyLineBeforeTagWithStarAtEnd.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodEmptyLineBeforeTagWithStarAtEnd.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodHasEarlierSince.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodHasEarlierSince.txt new file mode 100644 index 00000000..7d3a7148 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocMethodHasEarlierSince.txt @@ -0,0 +1,2 @@ ++27:19: Javadoc @since version '1.2.3' is earlier than @since version '2.0.0' at 21:10. ++1 error diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocNonJavadocComment.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocNonJavadocComment.txt new file mode 100644 index 00000000..7ba1b19a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocNonJavadocComment.txt @@ -0,0 +1,3 @@ ++23:1: Comments should not include "(non-Javadoc)" ++30:1: Comments should not include "(non-Javadoc)" ++2 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocNonPublicSinceInsideAnnotation.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocNonPublicSinceInsideAnnotation.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocNonPublicSinceInsideAnnotation.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocSoundtrack.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocSoundtrack.txt new file mode 100644 index 00000000..20ea9833 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/JavadocSoundtrack.txt @@ -0,0 +1 @@ ++Javadoc tag '@soundtrack' should not be used. [SpringJavadoc] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LambdaSwitch.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LambdaSwitch.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LambdaSwitch.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceSpaces.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceSpaces.txt new file mode 100644 index 00000000..23d7767e --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceSpaces.txt @@ -0,0 +1,2 @@ ++Indentation should be performed with spaces only. [SpringLeadingWhitespace] ++1 error diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabs.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabs.txt new file mode 100644 index 00000000..3a32b527 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabs.txt @@ -0,0 +1,2 @@ ++Indentation should be performed with tabs only. [SpringLeadingWhitespace] ++1 error diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/LeadingWhitespaceTabsAndTextBlock.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityFinalClassWithOverride.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityFinalClassWithOverride.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityFinalClassWithOverride.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityFinalClassWithProtectedMethod.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityFinalClassWithProtectedMethod.txt new file mode 100644 index 00000000..20293abd --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityFinalClassWithProtectedMethod.txt @@ -0,0 +1,2 @@ ++Method 'bad' in final class should be package-private rather than protected. ++Method 'badStatic' in final class should be package-private rather than protected. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityProtectedWithPublicMethod.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityProtectedWithPublicMethod.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/MethodVisibilityProtectedWithPublicMethod.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityBannedNonNull.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityBannedNonNull.txt new file mode 100644 index 00000000..2565624c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityBannedNonNull.txt @@ -0,0 +1,3 @@ ++NullabilityBannedNonNull.java:17:8: Nullability should be expressed using JSpecify. Replace 'javax.annotation.Nonnull' with 'org.jspecify.annotations.NonNull'. [SpringNullability] ++NullabilityBannedNonNull.java:19:8: Nullability should be expressed using JSpecify. Replace 'org.checkerframework.checker.nullness.qual.NonNull' with 'org.jspecify.annotations.NonNull'. [SpringNullability] ++2 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityBannedNullable.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityBannedNullable.txt new file mode 100644 index 00000000..f3829412 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityBannedNullable.txt @@ -0,0 +1 @@ ++Nullability should be expressed using JSpecify. Replace 'javax.annotation.Nullable' with 'org.jspecify.annotations.Nullable'. [SpringNullability] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingFieldType.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingFieldType.txt new file mode 100644 index 00000000..de4383d2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingFieldType.txt @@ -0,0 +1 @@ ++NullabilityNullableNotPrecedingFieldType.java:26:17: 'Nullable' should only be used immediately before a type. [SpringNullability] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingParameterType.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingParameterType.txt new file mode 100644 index 00000000..7b47421a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingParameterType.txt @@ -0,0 +1 @@ +NullabilityNullableNotPrecedingParameterType.java:26:30: 'Nullable' should only be used immediately before a type. [SpringNullability] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingReturnType.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingReturnType.txt new file mode 100644 index 00000000..fe62aa47 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableNotPrecedingReturnType.txt @@ -0,0 +1 @@ ++NullabilityNullableNotPrecedingReturnType.java:26:9: 'Nullable' should only be used immediately before a type. [SpringNullability] diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableOnSeparateLine.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityNullableOnSeparateLine.txt new file mode 100644 index 00000000..e69de29b diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityValid.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityValid.txt new file mode 100644 index 00000000..23435c7a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/NullabilityValid.txt @@ -0,0 +1 @@ ++0 errors diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/TryWithResources.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/TryWithResources.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/TryWithResources.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableArray.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableArray.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableArray.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableArrayElements.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableArrayElements.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableArrayElements.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableVarargs.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableVarargs.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceNullableVarargs.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceVarargs.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceVarargs.txt new file mode 100644 index 00000000..1ec0d7e2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/WhitespaceVarargs.txt @@ -0,0 +1,2 @@ ++WhitespaceVarargs.java:24:24: '...' is preceded with whitespace. [SpringNoWhitespaceBefore] ++1 error \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/nopackageinfo/NoPackageInfo.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/nopackageinfo/NoPackageInfo.txt new file mode 100644 index 00000000..a19759c0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/nopackageinfo/NoPackageInfo.txt @@ -0,0 +1 @@ ++Missing package-info.java file \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/AnnotationEndingInTest.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/AnnotationEndingInTest.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/AnnotationEndingInTest.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/InterfaceEndingInTest.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/InterfaceEndingInTest.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/InterfaceEndingInTest.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/NamedTest.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/NamedTest.txt new file mode 100644 index 00000000..38fff433 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/NamedTest.txt @@ -0,0 +1 @@ ++Test classes should have a name ending with Tests.java diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/NamedTests.txt b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/NamedTests.txt new file mode 100644 index 00000000..69174e4c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/check/src/test/java/NamedTests.txt @@ -0,0 +1 @@ ++0 errors \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/DeprecatedBadCase.xml b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/DeprecatedBadCase.xml new file mode 100644 index 00000000..0a4b92ee --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/DeprecatedBadCase.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/DeprecatedValid.xml b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/DeprecatedValid.xml new file mode 100644 index 00000000..0a4b92ee --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/DeprecatedValid.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/HeaderMissingBlankLine.xml b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/HeaderMissingBlankLine.xml new file mode 100644 index 00000000..1f3c7efa --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/HeaderMissingBlankLine.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/JavadocNonPublicSinceInsideAnnotation.xml b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/JavadocNonPublicSinceInsideAnnotation.xml new file mode 100644 index 00000000..c2b98905 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/JavadocNonPublicSinceInsideAnnotation.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/LeadingWhitespaceSpaces.xml b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/LeadingWhitespaceSpaces.xml new file mode 100644 index 00000000..0070d582 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/config/LeadingWhitespaceSpaces.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java new file mode 100644 index 00000000..d7ea8e09 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@ConditionalOnWebApplicationType(WebApplicationType.A.B.C.D.SERVLET) +public class AnnotationAttributeWithValueThatHasConciseReferenceToContainedEnumValue { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasReferenceToContainedConstant.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasReferenceToContainedConstant.java new file mode 100644 index 00000000..edc98fb7 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasReferenceToContainedConstant.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@ConditionalOnSomething(ConditionalOnSomething.TYPE_ONE) +public class AnnotationAttributeWithValueThatHasReferenceToContainedConstant { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java new file mode 100644 index 00000000..8594fc9b --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@ConditionalOnWebApplicationType(ConditionalOnWebApplicationType.WebApplicationType.SERVLET) +public class AnnotationAttributeWithValueThatHasVerboseReferenceToContainedEnumValue { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java new file mode 100644 index 00000000..ea1a39cd --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@ConditionalOnWebApplicationType(type = WebApplicationType.A.B.C.D.SERVLET) +public class AnnotationNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue.java new file mode 100644 index 00000000..12557326 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.example.some.other.WebApplicationType; + +@ConditionalOnWebApplicationType(type = ConditionalOnWebApplicationType.WebApplicationType.SERVLET) +public class AnnotationNamedAttributeWithValueThatHasNecessarilyVerboseReferenceToContainedEnumValue { + + WebApplicationType type; + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant.java new file mode 100644 index 00000000..44d6eb5a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@ConditionalOnSomething(type = ConditionalOnSomething.TYPE_ONE) +public class AnnotationNamedAttributeWithValueThatHasReferenceToContainedConstant { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java new file mode 100644 index 00000000..c652976e --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@ConditionalOnWebApplicationType(type = ConditionalOnWebApplicationType.WebApplicationType.SERVLET) +public class AnnotationNamedAttributeWithValueThatHasVerboseReferenceToContainedEnumValue { + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/Preparators.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java similarity index 56% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/Preparators.java rename to spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java index 20f795a1..f4893731 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/Preparators.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationOnNewLine.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,32 @@ * limitations under the License. */ -package io.spring.javaformat.formatter.preparator; - -import java.util.function.Consumer; - -import io.spring.javaformat.formatter.eclipse.Preparator; +import org.jspecify.annotations.Nullable; /** - * {@link Preparator} instances that can be added. + * This is a valid example. * * @author Phillip Webb */ -public final class Preparators { +public class AnnotationOnNewLine { + + @Override + public String toString() { + return ""; + } + + @Nullable String test1() { + return ""; + } - private Preparators() { + @Override + @Nullable String test2() { + return ""; } - public static void forEach(Consumer consumer) { - consumer.accept(new JavadocLineBreakPreparator()); - consumer.accept(new CodeLineBreakPreparator()); + @Override + public @Nullable String test3() { + return ""; } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java new file mode 100644 index 00000000..614e11c0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@com.example.web.condition.ConditionalOnWebApplicationType(type = WebApplicationType.A.B.C.D.SERVLET) +public class AnnotationWithFullyQualifiedNameAndNamedAttributeWithValueThatHasConciseReferenceToContainedEnumValue { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AsciidoctorCallout.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AsciidoctorCallout.java new file mode 100644 index 00000000..4f8a00ef --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AsciidoctorCallout.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a valid example. + * + * @author Phillip Webb + */ +public class AsciidoctorCallout { + + public void example() { + RestAssured.given(this.spec).filter(document("headers", requestHeaders( // <1> + ))); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AssertJBadAssertImport.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AssertJBadAssertImport.java new file mode 100644 index 00000000..7646caff --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AssertJBadAssertImport.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Import of banned org.junit.Assert. + * + * @author Andy Wilkinson + */ +public class AssertJBadAssertImport { + + @Test + void useTheImports() { + assertTrue(true); + Assert.assertFalse(false); + fail("oops"); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AssertJBadAssertionsImport.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AssertJBadAssertionsImport.java new file mode 100644 index 00000000..5d877c52 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/AssertJBadAssertionsImport.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Import of banned org.junit.jupiter.api.Assertions. + * + * @author Andy Wilkinson + */ +public class AssertJBadAssertionsImport { + + @Test + void useTheImports() { + assertTrue(true); + Assertions.assertFalse(false); + fail("oops"); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchE.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchE.java index aedce6b2..c1e81c66 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchE.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchE.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchEx.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchEx.java index 68bb8c00..e9739ae0 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchEx.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchEx.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchOo.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchOo.java new file mode 100644 index 00000000..1d21cda5 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchOo.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A invalid catch with o_O as the variable. + * + * @author Phillip Webb + */ +public class CatchOo { + + public void test() { + try { + new String("foo"); + } + catch (IllegalStateException o_O) { + // Ignore + } + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchWord.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchWord.java index 50bc7af6..3c7d230b 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchWord.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/CatchWord.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/DeprecatedBadCase.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/DeprecatedBadCase.java new file mode 100644 index 00000000..b806639d --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/DeprecatedBadCase.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Bad cases for use of {@link Deprecated @Deprecated}. + * + * @author Andy Wilkinson + */ +@Deprecated +public class DeprecatedBadCase { + + @java.lang.Deprecated + public static final String SOME_CONSTANT; + + @Deprecated(since = "") + public void someMethod() { + + } + + @Deprecated + private class InnerClass { + + @Deprecated(since = "") + private void someInnerMethod() { + + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/DeprecatedValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/DeprecatedValid.java new file mode 100644 index 00000000..e52e3ae1 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/DeprecatedValid.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Valid cases for use of {@link Deprecated @Deprecated}. + * + * @author Andy Wilkinson + */ +@Deprecated(since = "2.0.0") +public class DeprecatedValid { + + @Deprecated(since = "1.2.0") + public static final String SOME_CONSTANT; + + @Deprecated(since = "1.3.0") + public void someMethod() { + + } + + @Deprecated(since = "1.2.0") + private class InnerClass { + + @Deprecated(since = "1.1.0") + private void someInnerMethod() { + + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/FiltersToSkipThis.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/FiltersToSkipThis.java index 82c0a957..e25b5cf8 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/FiltersToSkipThis.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/FiltersToSkipThis.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderDate.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderDate.java index ecf31c47..2f23d85c 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderDate.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderDate.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMismatch.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMismatch.java index d410278e..48e94313 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMismatch.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMismatch.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this foil except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMissingBlankLine.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMissingBlankLine.java new file mode 100644 index 00000000..a12b1152 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderMissingBlankLine.java @@ -0,0 +1,9 @@ +// (c) Somebody 2017-2019 +/** + * A custom header file. + * + * @author Phillip Webb + */ +public class HeaderMissingBlankLine { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooLong.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooLong.java index cdf92b18..8b8a0b85 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooLong.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooLong.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooShort.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooShort.java index 467a2381..0325be9e 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooShort.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderTooShort.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithDateToPresent.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithDateToPresent.java new file mode 100644 index 00000000..5f6957b3 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithDateToPresent.java @@ -0,0 +1,24 @@ +/* + * Copyright 2019-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The header uses NNNN-present. + * + * @author Phillip Webb + */ +public class HeaderWithDateToPresent { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithSingleDate.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithSingleDate.java index a3045e8e..11600fcd 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithSingleDate.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HeaderWithSingleDate.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2019 the original author or authors. + * Copyright 2019-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorInvalid.java index 414731c4..5a6b3543 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorInvalid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorInvalid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringApplication.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringApplication.java index 23ee070d..ece74108 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringApplication.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringConfiguration.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringConfiguration.java index 080feb69..cafe6164 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringConfiguration.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/HideUtilityClassConstructorSpringConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageInvalid.java index 796175c7..7aa089cf 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageInvalid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageInvalid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageValid.java index 129348fb..427075e6 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageValid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/ImportOrderCustomPackageValid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadAnnotation.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadAnnotation.java index e157a8fa..e9c41790 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadAnnotation.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImport.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImport.java index 92d8f1ab..2870f5fb 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImport.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImport.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImportWithOptOut.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImportWithOptOut.java index 668ca7c8..4b471be5 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImportWithOptOut.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadImportWithOptOut.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java index 22befdfa..0e665db0 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5BadModifier.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,12 @@ * limitations under the License. */ +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; /** * Test with bad modifiers. @@ -38,7 +43,7 @@ public static void publicAfterAll() { } - @BeforeEach + @AfterEach public void publicAfterEach() { } @@ -58,7 +63,7 @@ private static void privateAfterAll() { } - @BeforeEach + @AfterEach private void privateAfterEach() { } @@ -83,4 +88,19 @@ private void doSomethingElseWithTemplateWorks() { // test here } + @Nested + public static class PublicNestedTests { + + @Test + public void nestedPublicTest() { + + } + + } + + @Nested + private static class PrivateNestedTests { + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5PublicAbstractIsValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5PublicAbstractIsValid.java new file mode 100644 index 00000000..dee91ee2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5PublicAbstractIsValid.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.junit.jupiter.api.Test; + +/** + * This is a valid example. We allow abstract test classes to be + * public so that classes in other packages can extend them. + * + * @author Andy Wilkinson + */ +public abstract class JUnit5PublicAbstractIsValid { + + @Test + void doSomethingWorks() { + // test here + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java index cc7b4cd0..df921319 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JUnit5Valid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ * * @author Phillip Webb */ -public class JUnit5Valid { +class JUnit5Valid { @Test void doSomethingWorks() { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAnnotationFieldHasEarlierSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAnnotationFieldHasEarlierSince.java new file mode 100644 index 00000000..2ecaf03c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAnnotationFieldHasEarlierSince.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Javadoc with a good since tag. + * + * @author Andy Wilkinson + * @since 1.2.0 + */ +public @interface JavadocAnnotationFieldHasEarlierSince { + + /** + * An attribute. + * @return the value + * @since 1.1.0 + */ + boolean attribute() default true; + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAuthorWithoutSpace.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAuthorWithoutSpace.java index d96d4e66..8a421b44 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAuthorWithoutSpace.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocAuthorWithoutSpace.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocBadCase.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocBadCase.java index 8bdca2a1..4a5df596 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocBadCase.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocBadCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocInnerClassHasEarlierSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocInnerClassHasEarlierSince.java new file mode 100644 index 00000000..2ad74700 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocInnerClassHasEarlierSince.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Javadoc with an earlier since tag on an inner class. + * + * @author Phillip Webb + * @since 2.0.0 + */ +class JavadocInnerClassHasEarlierSince { + + /** + * Inner class. + * + * @since 1.2.3 + */ + private static class Inner { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodEmptyLineBeforeTag.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodEmptyLineBeforeTag.java new file mode 100644 index 00000000..dcb778a8 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodEmptyLineBeforeTag.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Javadoc with white space. + * @param this is a valid param + * @author Sushant Kumar Singh + */ +public class JavadocMethodEmptyLineBeforeTag { + + /** + * Do something. + * + * @param something a lovely thing + */ + public void test(String something) { + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodEmptyLineBeforeTagWithStarAtEnd.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodEmptyLineBeforeTagWithStarAtEnd.java new file mode 100644 index 00000000..2d92f513 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodEmptyLineBeforeTagWithStarAtEnd.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Javadoc with white space. + * @param this is a valid param + * @author Sushant Kumar Singh + */ +public class JavadocMethodEmptyLineBeforeTagWithStarAtEnd { + + /** + * First paragraph. + * + *

Second paragraph contains an asterisk in a code element: {@code *}. + * @since 1.0 + */ + public void test() { + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodHasEarlierSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodHasEarlierSince.java new file mode 100644 index 00000000..d23d74ee --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMethodHasEarlierSince.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Javadoc with an earlier since tag on a method. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class JavadocMethodHasEarlierSince { + + /** + * Some method. + * @since 1.2.3 + */ + public void someMethod() { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java index 9f22ace8..c9afd407 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocMissingSince.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonJavadocComment.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonJavadocComment.java new file mode 100644 index 00000000..047b2a05 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonJavadocComment.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Example with non javadoc comments. + * + * @author Phillip Webb + */ +public class JavadocNonJavadocComment { + + /* (non-Javadoc) + * Example. + */ + public void one() { + } + + /** + * (non-Javadoc). + */ + public void two() { + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java index 58e914d3..4f0f2fde 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSince.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ class JavadocNonPublicSince { /** * Inner class. * - * @since 1.2.3 + * @since 1.2.4 */ private static class Inner { diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FormatterOption.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideAnnotation.java similarity index 72% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FormatterOption.java rename to spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideAnnotation.java index 5b2504ef..b79a5a85 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FormatterOption.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,23 @@ * limitations under the License. */ -package io.spring.javaformat.formatter; - /** - * Options that can be used to configure a {@link Formatter}. + * Javadoc with a good since tag. * * @author Phillip Webb + * @since 1.2.3 */ -public enum FormatterOption { +public @interface JavadocNonPublicSinceInsideAnnotation { /** - * Show Eclipse NLS warnings. + * Inner enum. + * + * @since 1.2.4 */ - SHOW_NLS_WARNINGS + enum Inner { + + FOO + + } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java index a8fa5f47..c0e4b412 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocNonPublicSinceInsideInterface.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ public interface JavadocNonPublicSinceInsideInterface { /** * Inner enum. * - * @since 1.2.3 + * @since 1.2.4 */ enum Inner { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocSoundtrack.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocSoundtrack.java new file mode 100644 index 00000000..846bf48d --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocSoundtrack.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Valid Javadoc. + * + * @param this is a valid param + * @author Phillip Webb + * @soundtrack Gina G - Ooh Aah Just A Little Bit + */ +public class JavadocSoundtrack { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java index 21d30add..6584ef36 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/JavadocValid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,4 +46,34 @@ public void test2(String something) { public String test3(String something) throws RuntimeException { } + /** + * Class with a numeric date since. + * @since 28.12.2003 + */ + public class NumericDateSince { + + /** + * Method with version-based since. + * @since 1.3.0 + */ + public void versionSince() { + } + + } + + /** + * Class with an alphanumeric date since. + * @since 16 April 2001 + */ + public class AlphanumericDateSince { + + /** + * Method with version-based since. + * @since 1.3.0 + */ + public void versionSince() { + } + + } + } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java index c4f17b30..5e82a117 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaExtraParens.java @@ -1,6 +1,6 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java index 4e621d28..9ab33a37 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaMissingParens.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java index 86807333..cfb42294 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java index d1f83089..b8246fee 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryEmptyBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java index 4208b212..5468bb48 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java index 059bb564..473fa096 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryIfElseBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java index 24f4da47..61350fe8 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryThrowBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java index d2f5cde9..2c874d0d 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryTryBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java index c9cab5fa..54864d72 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaNecessaryVoidCallable.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaSwitch.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaSwitch.java new file mode 100644 index 00000000..55640621 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaSwitch.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.function.Function; + +/** + * Lambda in a switch statement. + * + * @author Josef Reichardt + */ +public class LambdaSwitch { + + private void sayHello(String[] args) { + Function getText = (cnt) -> "Number of args: " + cnt; + String message = switch (args.length) { + case 0 -> "No arg"; + case 1 -> "One arg"; + default -> getText.apply(args.length); + }; + System.out.println(message); + } +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java index b5f9b616..df215545 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaUnnecessaryBlock.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java index 465f92c0..768488e7 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LambdaValid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceSpaces.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceSpaces.java new file mode 100644 index 00000000..0e69080a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceSpaces.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Leading whitepace expects only tabs. + * + * @author Phillip Webb + */ +public class LeadingWhitespaceSpaces { + + /** + * Comments are ignored. + */ + public void hello() { + System.out.println("World"); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabs.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabs.java new file mode 100644 index 00000000..53d64c19 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabs.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Leading whitepace expects only tabs. + * + * @author Phillip Webb + */ +public class LeadingWhitespaceTabs { + + /** + * Comments are ignored. + */ + public void hello() { + System.out.println("World"); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java new file mode 100644 index 00000000..21a2311a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/LeadingWhitespaceTabsAndTextBlock.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Leading whitepace with a text block. + * + * @author Phillip Webb + */ +public class LeadingWhitespaceTabsAndTextBlock { + + /** + * Comments are ignored. + */ + public void hello() { + System.out.println("""" + Hello + World!"""); + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java index 9271ba92..0db3e04c 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderInvalid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java index 2bffbcae..b44ad87b 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodOrderValid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithOverride.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithOverride.java new file mode 100644 index 00000000..6a74b3b7 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithOverride.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Good visibility because, while class is final, protected methods are + * annotated with {@code @Override}. + * + * @author Andy Wilkinson + */ +public final class MethodVisibilityFinalClassWithOverride { + + @Override + protected void good() { + } + + @Override + protected static void goodStatic() { + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithProtectedMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithProtectedMethod.java new file mode 100644 index 00000000..7452e21f --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityFinalClassWithProtectedMethod.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Bad visibility because class is final. + * + * @author Andy Wilkinson + */ +public final class MethodVisibilityFinalClassWithProtectedMethod { + + protected void bad() { + } + + protected static void badStatic() { + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java index cf10eb76..262a258f 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityInnerClassesWithPublicMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java index 75d5b080..c6377f3d 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityPackagePrivateWithPublicMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityProtectedWithPublicMethod.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityProtectedWithPublicMethod.java new file mode 100644 index 00000000..fe36ec8c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityProtectedWithPublicMethod.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Good visibility because class is protected. + * + * @author Phillip Webb + */ +protected class MethodVisibilityProtectedWithPublicMethod { + + MethodVisibilityPackagePrivateWithPublicMethod() { + } + + public void bad() { + } + + public static void badStatic() { + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java index 2be96a19..c4b8d3b3 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/MethodVisibilityWithOverride.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /** - * Bad visibility because of public method. + * Good visibility because of {@code @Override} annotation. * * @author Phillip Webb */ diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java index d41dbaee..8f9bb820 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NestedInterfaceItems.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java index 2e80c229..436c72a4 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NewlineAtEndOfFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java index aa8fe05d..556214ab 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NoThis.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNonNull.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNonNull.java new file mode 100644 index 00000000..870a40e9 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNonNull.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import javax.annotation.Nonnull; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * JSpecify's NonNull annotation should be used. + * + * @author Andy Wilkinson + */ +public class NullabilityBannedNonNull { + + public void method(@Nonnull String one, @NonNull String two) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNullable.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNullable.java new file mode 100644 index 00000000..61d918d1 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityBannedNullable.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import javax.annotation.Nullable; + +/** + * JSpecify's Nullable annotation should be used. + * + * @author Andy Wilkinson + */ +public class NullabilityBannedNullable { + + public void method(@Nullable String one) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingFieldType.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingFieldType.java new file mode 100644 index 00000000..a54069ef --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingFieldType.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jspecify.annotations.Nullable; + +/** + * {@code @Nullable} should appear immediately before the parameter type. + * + * @author Andy Wilkinson + */ +public class NullabilityNullableNotPrecedingFieldType { + + private @Nullable static String field = null; + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingParameterType.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingParameterType.java new file mode 100644 index 00000000..bd55d9d2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingParameterType.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jspecify.annotations.Nullable; + +/** + * {@code @Nullable} should appear immediately before the parameter type. + * + * @author Andy Wilkinson + */ +public class NullabilityNullableNotPrecedingParameterType { + + public String method(@Nullable final String arg) { + return "result"; + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingReturnType.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingReturnType.java new file mode 100644 index 00000000..9b9b8a4e --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableNotPrecedingReturnType.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jspecify.annotations.Nullable; + +/** + * {@code @Nullable} should appear immediately before the return type. + * + * @author Andy Wilkinson + */ +public class NullabilityNullableNotPrecedingReturnType { + + @Nullable public String method() { + return "result"; + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableOnSeparateLine.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableOnSeparateLine.java new file mode 100644 index 00000000..b18ee10a --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityNullableOnSeparateLine.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jspecify.annotations.Nullable; + +/** + * {@code @Nullable} should appear immediately before the return type. + * + * @author Andy Wilkinson + */ +public class NullabilityNullableOnSeparateLine { + + @Nullable + public String method() { + return "result"; + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityValid.java new file mode 100644 index 00000000..e0ea5cca --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/NullabilityValid.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Collections; +import java.util.Map; + +import org.jspecify.annotations.Nullable; + +/** + * Valid use of nullability annotations. + * + * @author Andy Wilkinson + */ +public class NullabilityValid { + + private @Nullable String field; + + public NullabilityValid(@Nullable String arg, final @Nullable String anotherArg) { + + } + + public @Nullable String publicMethod() { + return "result"; + } + + @Nullable String packagePrivateMethod() { + return "result"; + } + + public Map genericReturnType() { + return Collections.emptyMap(); + } + + void genericParameter(Map<@Nullable ? extends String, @Nullable String> arg) { + + } + + void parameter(@Nullable String arg) { + + } + + void finalParameter(final @Nullable String arg) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java index 0c2f80ad..59f7dc88 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameInvalid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java index c9ee62bc..6814ed2f 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/OuterTypeFilenameValid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java index d64f298e..d72c300b 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/SpringApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -935,8 +935,8 @@ public void setMainApplicationClass(Class mainApplicationClass) { /** * Returns whether this {@link SpringApplication} is running within a web environment. * @return {@code true} if running within a web environment, otherwise {@code false}. - * @see #setWebEnvironment(boolean) * @deprecated since 2.0.0 in favor of {@link #getWebApplicationType()} + * @see #setWebEnvironment(boolean) */ @Deprecated public boolean isWebEnvironment() { diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java index 355cfad5..afd0926d 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEquals.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java index bc73a067..9eb48eb9 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsAny.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java index 8371a02e..3a30c31a 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryEqualsEqualsNever.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java index 1fedecbe..99c43de5 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInArray.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java index 61a4ab20..6414b748 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInIf.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,9 @@ public class TernaryInIf { public void test() { boolean a = true; boolean b = false; - if ((a != b) ? true : false) { + int c = 1; + int d = 2; + if ((a != b) ? d < c : c >= d) { System.out.println("OK"); } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java index 46641514..1bef3bee 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryInWhile.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,9 @@ public class TernaryInWhile { public void test() { boolean a = true; boolean b = false; - while ((a != b) ? true : false) { + int c = 1; + int d = 2; + while ((a != b) ? d < c : c >= d) { System.out.println("OK"); } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java index 942b1bce..36e22af3 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensAndPlus.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java index 69fc4218..cbd7ce9e 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensInvalid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java index 42f842c3..f9f490ee 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TernaryParensValid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TryWithResources.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TryWithResources.java new file mode 100644 index 00000000..c68396dc --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/TryWithResources.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a valid example. + * + * @author Phillip Webb + */ +public class TryWithResources { + + public void test() { + try (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) { + System.out.println(session); + } + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java index da4f0436..e14319f1 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/Valid.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArray.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArray.java new file mode 100644 index 00000000..2d25cfa7 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArray.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Whitespace is expected before {@code []} when @Nullable. + * + * @author Andy Wilkinson + */ +public class WhitespaceNullableArray { + + void bytes(int @Nullable [] elements) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArrayElements.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArrayElements.java new file mode 100644 index 00000000..6e23b7fb --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableArrayElements.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Whitespace is expected before {@code type[]} when @Nullable. + * + * @author Andy Wilkinson + */ +public class WhitespaceNullableArrayElements { + + void bytes(@Nullable int[] elements) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableVarargs.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableVarargs.java new file mode 100644 index 00000000..1b4eaeae --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceNullableVarargs.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Whitespace is expected before ... when @Nullable. + * + * @author Andy Wilkinson + */ +public class WhitespaceNullableVarargs { + + void bytes(int @Nullable ... elements) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceVarargs.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceVarargs.java new file mode 100644 index 00000000..2a962abe --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/WhitespaceVarargs.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Whitespace is not expected before {@code ...}. + * + * @author Andy Wilkinson + */ +public class WhitespaceVarargs { + + void bytes(int ... elements) { + + } + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/nopackageinfo/NoPackageInfo.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/nopackageinfo/NoPackageInfo.java new file mode 100644 index 00000000..5ae26280 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/nopackageinfo/NoPackageInfo.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package nopackageinfo; + +/** + * A class in a package with no {@code package-info.java} file. + * + * @author Andy Wilkinson + */ +class NoPackageInfo { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java index b426e3ba..039f3f05 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info-header-must-be-missing.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this foil except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/package-info.java new file mode 100644 index 00000000..e69de29b diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java new file mode 100644 index 00000000..cdc31f8c --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/AnnotationEndingInTest.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is an annotation with a legal name. Only test classes must + * have a name that ends with {@code Tests}. + * + * @author Andy Wilkinson + */ +public @interface AnnotationEndingInTest { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java new file mode 100644 index 00000000..d79b6453 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/InterfaceEndingInTest.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is an interface with a legal name. Only test classes must + * have a name that ends with {@code Tests}. + * + * @author Andy Wilkinson + */ +public interface InterfaceEndingInTest { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTest.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTest.java new file mode 100644 index 00000000..a042f613 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTest.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a test with the wrong name. + * + * @author Phillip Webb + */ +public class NamedTest { + +} diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTests.java b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTests.java new file mode 100644 index 00000000..423428e5 --- /dev/null +++ b/spring-javaformat/spring-javaformat-checkstyle/src/test/resources/source/src/test/java/NamedTests.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is a test with the correct name. + * + * @author Phillip Webb + */ +public class NamedTests { + +} diff --git a/spring-javaformat/spring-javaformat-config/pom.xml b/spring-javaformat/spring-javaformat-config/pom.xml new file mode 100644 index 00000000..e984a073 --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat + 0.0.48-SNAPSHOT + + spring-javaformat-config + Spring JavaFormat Config + + ${basedir}/../.. + + diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/DefaultJavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/DefaultJavaFormatConfig.java new file mode 100644 index 00000000..d2b5ee8c --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/DefaultJavaFormatConfig.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.config; + +/** + * Default {@link JavaFormatConfig} implementation used when no config file is found. + * + * @author Phillip Webb + */ +class DefaultJavaFormatConfig implements JavaFormatConfig { + + private final JavaBaseline javaBaseline; + + private final IndentationStyle indentationStyle; + + DefaultJavaFormatConfig(JavaBaseline javaBaseline, IndentationStyle indentationStyle) { + this.javaBaseline = javaBaseline; + this.indentationStyle = indentationStyle; + } + + @Override + public JavaBaseline getJavaBaseline() { + return this.javaBaseline; + } + + @Override + public IndentationStyle getIndentationStyle() { + return this.indentationStyle; + } + +} diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/IndentationStyle.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/IndentationStyle.java new file mode 100644 index 00000000..f6e2144d --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/IndentationStyle.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.config; + +/** + * Indentation styles that can be used. + * + * @author Phillip Webb + */ +public enum IndentationStyle { + + /** + * Indent with tabs. + */ + TABS, + + /** + * Indent with spaces. + */ + SPACES + +} diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java new file mode 100644 index 00000000..a27c3df0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaBaseline.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.config; + +/** + * Java JDK baseline version expected be used when formatting. + * + * @author Phillip Webb + */ +public enum JavaBaseline { + + /** + * Use JDK 8+ compatible formatter. + */ + V8, + + /** + * Use JDK 17+ or higher compatible formatter. + */ + V17 + +} diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java new file mode 100644 index 00000000..23bf45c8 --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/JavaFormatConfig.java @@ -0,0 +1,121 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.config; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; + +/** + * Support for the {@code .springjavaformatconfig} file that can be used to apply settings + * on a per-project basis. + * + * @author Phillip Webb + */ +public interface JavaFormatConfig { + + /** + * The default {@link JavaFormatConfig}. + */ + JavaFormatConfig DEFAULT = of(JavaBaseline.V17, IndentationStyle.TABS); + + /** + * Java JDK baseline version expected be used when formatting. + * @return the JDK version + */ + JavaBaseline getJavaBaseline(); + + /** + * Return the indentation style that should be used with the project. + * @return the indentation style + */ + IndentationStyle getIndentationStyle(); + + /** + * Find and load a {@code .springjavaformatconfig} by searching from the given file. + * @param path the file or directory to search from + * @return a loaded {@link JavaFormatConfig} or {@link #DEFAULT} if no + * {@code .springjavaformatconfig} file is found + */ + static JavaFormatConfig findFrom(Path path) { + return findFrom((path != null) ? path.toFile() : (File) null); + } + + /** + * Find and load a {@code .springjavaformatconfig} by searching from the given file. + * @param file the file or directory to search from + * @return a loaded {@link JavaFormatConfig} or {@link #DEFAULT} if no + * {@code .springjavaformatconfig} file is found + */ + static JavaFormatConfig findFrom(File file) { + if (file != null && file.isFile()) { + return findFrom(file.getParentFile()); + } + try { + while (file != null) { + File candidate = new File(file, ".springjavaformatconfig"); + if (candidate.exists() && candidate.isFile()) { + return load(candidate); + } + file = file.getParentFile(); + } + } + catch (Exception ex) { + } + return DEFAULT; + } + + /** + * Load a {@link JavaFormatConfig} from the given file. + * @param file the file to load + * @return the loaded config + */ + static JavaFormatConfig load(File file) { + try { + return PropertiesJavaFormatConfig.load(file); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + /** + * Load a {@link JavaFormatConfig} from the given input stream. + * @param inputStream the input stream to load + * @return the loaded config + */ + static JavaFormatConfig load(InputStream inputStream) { + try { + return PropertiesJavaFormatConfig.load(inputStream); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + /** + * Factory method to create a {@link JavaFormatConfig} with specific settings. + * @param javaBaseline The baseline JDK version + * @param indentationStyle the indentation style + * @return a {@link JavaFormatConfig} instance + */ + static JavaFormatConfig of(JavaBaseline javaBaseline, IndentationStyle indentationStyle) { + return new DefaultJavaFormatConfig(javaBaseline, indentationStyle); + } + +} diff --git a/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/PropertiesJavaFormatConfig.java b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/PropertiesJavaFormatConfig.java new file mode 100644 index 00000000..d631312d --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/src/main/java/io/spring/javaformat/config/PropertiesJavaFormatConfig.java @@ -0,0 +1,64 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * {@link JavaFormatConfig} backed by a properties file. + * + * @author Phillip Webb + */ +class PropertiesJavaFormatConfig implements JavaFormatConfig { + + private final Properties properties; + + PropertiesJavaFormatConfig(Properties properties) { + this.properties = properties; + } + + @Override + public JavaBaseline getJavaBaseline() { + Object value = this.properties.get("java-baseline"); + return (value != null) ? JavaBaseline.valueOf("V" + value.toString().toUpperCase().trim()) + : DEFAULT.getJavaBaseline(); + } + + @Override + public IndentationStyle getIndentationStyle() { + Object value = this.properties.get("indentation-style"); + return (value != null) ? IndentationStyle.valueOf(value.toString().toUpperCase().trim()) + : DEFAULT.getIndentationStyle(); + } + + static JavaFormatConfig load(File file) throws IOException { + try (InputStream inputStream = new FileInputStream(file)) { + return load(inputStream); + } + } + + static JavaFormatConfig load(InputStream inputStream) throws IOException { + Properties properties = new Properties(); + properties.load(inputStream); + return new PropertiesJavaFormatConfig(properties); + } + +} diff --git a/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java b/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java new file mode 100644 index 00000000..2c702617 --- /dev/null +++ b/spring-javaformat/spring-javaformat-config/src/test/java/io/spring/javaformat/config/PropertiesJavaFormatConfigTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.config; + +import java.util.Properties; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link PropertiesJavaFormatConfig}. + * + * @author Phillip Webb + */ +class PropertiesJavaFormatConfigTests { + + @Test + void getJavaBaselineWhenNoPropertyReturnsJava11() { + Properties properties = new Properties(); + PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties); + assertThat(config.getJavaBaseline()).isEqualTo(JavaBaseline.V17); + } + + @Test + void getJavaBaselineWhenPropertyReturnsPropertyValue() { + Properties properties = new Properties(); + properties.setProperty("java-baseline", "8"); + PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties); + assertThat(config.getJavaBaseline()).isEqualTo(JavaBaseline.V8); + } + + @Test + void getIndentationStyleWhenNoPropertyReturnsJava11() { + Properties properties = new Properties(); + PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties); + assertThat(config.getIndentationStyle()).isEqualTo(IndentationStyle.TABS); + } + + @Test + void getIndentationStyleWhenPropertyReturnsPropertyValue() { + Properties properties = new Properties(); + properties.setProperty("indentation-style", "spaces"); + PropertiesJavaFormatConfig config = new PropertiesJavaFormatConfig(properties); + assertThat(config.getIndentationStyle()).isEqualTo(IndentationStyle.SPACES); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5e2e9099 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Spring Formatter Eclipse Runtime JDK17 +Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk17 +Bundle-Version: 0.0.48.qualifier +Require-Bundle: org.eclipse.jdt.core;bundle-version="[1.0.0,10.0.0)", + org.eclipse.jface;bundle-version="[1.0.0,10.0.0)", + org.eclipse.jdt.core.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, + org.eclipse.jface.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, + org.eclipse.jface.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, + org.eclipse.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional +Bundle-RequiredExecutionEnvironment: JavaSE-11 diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/build.properties b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/build.properties similarity index 100% rename from spring-javaformat/spring-javaformat-formatter-eclipse-runtime/build.properties rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/build.properties diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml new file mode 100644 index 00000000..0e73c0e4 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk17/pom.xml @@ -0,0 +1,213 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat + 0.0.48-SNAPSHOT + + spring-javaformat-formatter-eclipse-jdk17 + eclipse-plugin + Spring JavaFormat Eclipse JDK-17 + + ${basedir}/../.. + org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source + + + + Eclipse Public License, Version 1.0 + https://www.eclipse.org/legal/epl-v10.html + + + + + eclipse-jdk17 + p2 + ${eclipse.jdk17.repository} + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + empty-javadoc-jar + package + + jar + + + javadoc + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-rewriter + ${project.version} + + + ant-contrib + ant-contrib + ${ant-contrib.version} + + + ant + ant + + + + + org.apache.ant + ant-nodeps + ${ant.version} + + + + + rewrite-bytecode + package + + run + + + + + + + + + + + + repackage-source + package + + run + + + + + + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + + false + + + + org.eclipse.tycho + tycho-maven-plugin + + + org.eclipse.tycho + target-platform-configuration + + + org.eclipse.tycho + tycho-versions-plugin + + + update-eclipse-version + initialize + + update-eclipse-metadata + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack-dependencies + + unpack-dependencies + + prepare-package + + ${project.build.outputDirectory} + META-INF/*,**.dll,**.so,**.java + ${sourceartifacts} + + + + unpack-source-dependencies + + unpack-dependencies + + prepare-package + + ${project.build.directory}/sources + ${sourceartifacts} + + + + + + com.github.wvengen + proguard-maven-plugin + + + reduce-eclipse-runtime + package + + proguard + + + false + + ${java.home}/jmods + + + + + + + + + + + + + + + + + + + + + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-rewriter + ${project.version} + provided + + + diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/META-INF/MANIFEST.MF b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF similarity index 72% rename from spring-javaformat/spring-javaformat-formatter-eclipse-runtime/META-INF/MANIFEST.MF rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF index b6666bd7..3c5dbb8b 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/META-INF/MANIFEST.MF +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/META-INF/MANIFEST.MF @@ -1,12 +1,12 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Spring Formatter Eclipse Runtime -Bundle-SymbolicName: spring-javaformat-formatter-eclipse-runtime -Bundle-Version: 0.0.21.qualifier +Bundle-Name: Spring Formatter Eclipse JDK8 +Bundle-SymbolicName: spring-javaformat-formatter-eclipse-jdk8 +Bundle-Version: 0.0.48.qualifier Require-Bundle: org.eclipse.jdt.core;bundle-version="[1.0.0,10.0.0)", org.eclipse.jface;bundle-version="[1.0.0,10.0.0)", org.eclipse.jdt.core.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, org.eclipse.jface.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, org.eclipse.jface.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional, org.eclipse.text.source;bundle-version="[1.0.0,10.0.0)";resolution:=optional -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-RequiredExecutionEnvironment: JavaSE-11 diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/build.properties b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/build.properties new file mode 100755 index 00000000..45d47043 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = target/classes +bin.includes = META-INF/,\ + .,\ diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml new file mode 100644 index 00000000..0e52bf06 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdk8/pom.xml @@ -0,0 +1,213 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat + 0.0.48-SNAPSHOT + + spring-javaformat-formatter-eclipse-jdk8 + eclipse-plugin + Spring JavaFormat Eclipse JDK-8 + + ${basedir}/../.. + org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source + + + + Eclipse Public License, Version 1.0 + https://www.eclipse.org/legal/epl-v10.html + + + + + eclipse-jdk8 + p2 + ${eclipse.jdk8.repository} + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + empty-javadoc-jar + package + + jar + + + javadoc + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-rewriter + ${project.version} + + + ant-contrib + ant-contrib + ${ant-contrib.version} + + + ant + ant + + + + + org.apache.ant + ant-nodeps + ${ant.version} + + + + + rewrite-bytecode + package + + run + + + + + + + + + + + + repackage-source + package + + run + + + + + + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + + false + + + + org.eclipse.tycho + tycho-maven-plugin + + + org.eclipse.tycho + target-platform-configuration + + + org.eclipse.tycho + tycho-versions-plugin + + + update-eclipse-version + initialize + + update-eclipse-metadata + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack-dependencies + + unpack-dependencies + + prepare-package + + ${project.build.outputDirectory} + META-INF/*,**.dll,**.so,**.java + ${sourceartifacts} + + + + unpack-source-dependencies + + unpack-dependencies + + prepare-package + + ${project.build.directory}/sources + ${sourceartifacts} + + + + + + com.github.wvengen + proguard-maven-plugin + + + reduce-eclipse-runtime + package + + proguard + + + false + + ${java.home}/jmods + + + + + + + + + + + + + + + + + + + + + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-rewriter + ${project.version} + provided + + + diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml similarity index 78% rename from spring-javaformat/spring-javaformat-formatter-eclipse/pom.xml rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml index f298f7e4..9aef9a9a 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/pom.xml @@ -6,18 +6,18 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT - spring-javaformat-formatter-eclipse - Spring JavaFormat Eclipse + spring-javaformat-formatter-eclipse-jdt-jdk17 + Spring JavaFormat Eclipse JDT JDK-17 ${basedir}/../.. io.spring.javaformat - spring-javaformat-formatter-eclipse-runtime - 0.0.21-SNAPSHOT + spring-javaformat-formatter-eclipse-jdk17 + ${project.version} true @@ -48,16 +48,16 @@ - io.spring.javaformat:spring-javaformat-formatter-eclipse-runtime + io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk17 - org/eclipse/jdt/internal/formatter/** + org/eclipse/jdt/** - org.eclipse.jdt.internal.formatter - io.spring.javaformat.formatter.eclipse + org.eclipse.jdt + io.spring.javaformat.eclipse.jdt.jdk17 false diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java similarity index 94% rename from spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java index ad16d3f2..a2664b72 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -107,8 +107,9 @@ protected void prepareWraps(int kind) { } private void applyPreparators(Phase preWrapping, int kind, ASTNode astRoot, TokenManager tokenManager) { - this.preparators.stream().filter((preparator) -> preparator.getPhase() == preWrapping) - .forEach((preparator) -> preparator.apply(kind, tokenManager, astRoot)); + this.preparators.stream() + .filter((preparator) -> preparator.getPhase() == preWrapping) + .forEach((preparator) -> preparator.apply(kind, tokenManager, astRoot)); } @SuppressWarnings("unchecked") diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java similarity index 95% rename from spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java rename to spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java index 23b52527..bfd16b37 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk17/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ enum Phase { /** * Apply the preparator after wrapping. */ - POST_WRAPPING; + POST_WRAPPING } diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml new file mode 100644 index 00000000..30a2af39 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat + 0.0.48-SNAPSHOT + + spring-javaformat-formatter-eclipse-jdt-jdk8 + Spring JavaFormat Eclipse JDT JDK-8 + + ${basedir}/../.. + + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-jdk8 + ${project.version} + true + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-source + package + + jar + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk8 + + org/eclipse/jdt/** + + + + + + org.eclipse.jdt + io.spring.javaformat.eclipse.jdt.jdk8 + + + false + true + true + + + + + + + diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java new file mode 100644 index 00000000..a2664b72 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/ExtendedCodeFormatter.java @@ -0,0 +1,127 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.eclipse.jdt.internal.formatter; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.jdt.internal.formatter.Preparator.Phase; + +/** + * Extended version of {@link DefaultCodeFormatter} that allows additional + * {@link Preparator preparators} to be used. + * + * @author Phillip Webb + */ +public class ExtendedCodeFormatter extends DefaultCodeFormatter { + + private static boolean useLegacyTokenize = false; + + private final List preparators = new ArrayList<>(); + + public ExtendedCodeFormatter() { + super(); + } + + public ExtendedCodeFormatter(DefaultCodeFormatterOptions defaultCodeFormatterOptions, Map options) { + super(defaultCodeFormatterOptions, options); + } + + public ExtendedCodeFormatter(DefaultCodeFormatterOptions options) { + super(options); + } + + public ExtendedCodeFormatter(Map options) { + super(options); + } + + protected void addPreparator(Preparator preparator) { + this.preparators.add(preparator); + } + + @Override + protected void tokenizeSource(int kind) { + if (useLegacyTokenize) { + legacyTokenizeSource(kind); + return; + } + try { + super.tokenizeSource(kind); + } + catch (NoSuchMethodError ex) { + useLegacyTokenize = true; + legacyTokenizeSource(kind); + } + } + + private void legacyTokenizeSource(int kind) { + this.tokens.clear(); + long sourceLevel = CompilerOptions.versionToJdkLevel(this.sourceLevel); + Scanner scanner = new Scanner(true, false, false, sourceLevel, null, null, false); + scanner.setSource(this.sourceArray); + scanner.fakeInModule = (kind & K_MODULE_INFO) != 0; + while (true) { + try { + int tokenType = scanner.getNextToken(); + if (tokenType == TerminalTokens.TokenNameEOF) { + break; + } + Token token = Token.fromCurrent(scanner, tokenType); + this.tokens.add(token); + } + catch (InvalidInputException ex) { + Token token = Token.fromCurrent(scanner, TerminalTokens.TokenNameNotAToken); + this.tokens.add(token); + } + } + } + + @Override + protected void prepareWraps(int kind) { + ASTNode astRoot = getField("astRoot", ASTNode.class); + TokenManager tokenManager = getField("tokenManager", TokenManager.class); + applyPreparators(Phase.PRE_WRAPPING, kind, astRoot, tokenManager); + super.prepareWraps(kind); + applyPreparators(Phase.POST_WRAPPING, kind, astRoot, tokenManager); + } + + private void applyPreparators(Phase preWrapping, int kind, ASTNode astRoot, TokenManager tokenManager) { + this.preparators.stream() + .filter((preparator) -> preparator.getPhase() == preWrapping) + .forEach((preparator) -> preparator.apply(kind, tokenManager, astRoot)); + } + + @SuppressWarnings("unchecked") + private T getField(String name, Class type) { + try { + Field field = DefaultCodeFormatter.class.getDeclaredField(name); + field.setAccessible(true); + return (T) field.get(this); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java new file mode 100644 index 00000000..bfd16b37 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/Preparator.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.eclipse.jdt.internal.formatter; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.formatter.CodeFormatter; + +/** + * Strategy interface used by {@link ExtendedCodeFormatter} to allow additional code + * formatting before wrapping. + * + * @author Phillip Webb + */ +public interface Preparator { + + default Phase getPhase() { + return Phase.POST_WRAPPING; + } + + /** + * Apply the preparator. + * @param kind the format kind (see + * {@link CodeFormatter#format(int, String, org.eclipse.jface.text.IRegion[], int, String)} + * for details) + * @param tokenManager the token manager + * @param astRoot the AST root node + */ + void apply(int kind, TokenManager tokenManager, ASTNode astRoot); + + /** + * The phase where the {@link Preparator} should be applied. + */ + enum Phase { + + /** + * Apply the preparator before wrapping. + */ + PRE_WRAPPING, + + /** + * Apply the preparator after wrapping. + */ + POST_WRAPPING + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java new file mode 100644 index 00000000..6878ca6f --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-jdt-jdk8/src/main/java/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java @@ -0,0 +1,1688 @@ +/******************************************************************************* + * Copyright (c) 2014, 2020 Mateusz Matela and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Mateusz Matela - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519 + * Mateusz Matela - [formatter] follow up bug for comments - https://bugs.eclipse.org/458208 + *******************************************************************************/ +package org.eclipse.jdt.internal.formatter.linewrap; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.ToIntFunction; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.AssertStatement; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.ConditionalExpression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.CreationReference; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.EnumConstantDeclaration; +import org.eclipse.jdt.core.dom.EnumDeclaration; +import org.eclipse.jdt.core.dom.ExportsDirective; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionMethodReference; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IExtendedModifier; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.InfixExpression.Operator; +import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.OpensDirective; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.ProvidesDirective; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.RecordDeclaration; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SuperMethodReference; +import org.eclipse.jdt.core.dom.SwitchExpression; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.ThisExpression; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeMethodReference; +import org.eclipse.jdt.core.dom.TypeParameter; +import org.eclipse.jdt.core.dom.UnionType; +import org.eclipse.jdt.core.dom.VariableDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.core.formatter.CodeFormatter; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions; +import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment; +import org.eclipse.jdt.internal.formatter.Token; +import org.eclipse.jdt.internal.formatter.Token.WrapMode; +import org.eclipse.jdt.internal.formatter.Token.WrapPolicy; +import org.eclipse.jdt.internal.formatter.TokenManager; +import org.eclipse.jdt.internal.formatter.TokenTraverser; +import org.eclipse.jface.text.IRegion; + +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOLON; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMA; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameDOT; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEQUAL; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameIdentifier; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLBRACE; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLESS; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLPAREN; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameOR; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameQUESTION; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameRBRACE; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameRPAREN; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameSEMICOLON; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameStringLiteral; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameenum; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameextends; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameimplements; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamenew; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamesuper; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamethis; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamethrows; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameto; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamewhile; +import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamewith; + +public class WrapPreparator extends ASTVisitor { + + // @formatter:off + + /** + * Helper for common handling of all expressions that should be treated the same as + * {@link FieldAccess} + */ + private static class FieldAccessAdapter { + final Expression accessExpression; + + public FieldAccessAdapter(Expression expression) { + this.accessExpression = expression; + } + + public static boolean isFieldAccess(ASTNode expr) { + return expr instanceof FieldAccess || expr instanceof QualifiedName || expr instanceof ThisExpression + || expr instanceof SuperFieldAccess; + } + + public Expression getExpression() { + if (this.accessExpression instanceof FieldAccess) { + return ((FieldAccess) this.accessExpression).getExpression(); + } + if (this.accessExpression instanceof QualifiedName) { + return ((QualifiedName) this.accessExpression).getQualifier(); + } + if (this.accessExpression instanceof ThisExpression) { + return ((ThisExpression) this.accessExpression).getQualifier(); + } + if (this.accessExpression instanceof SuperFieldAccess) { + return ((SuperFieldAccess) this.accessExpression).getQualifier(); + } + throw new AssertionError(); + } + + public int getIdentifierIndex(TokenManager tm) { + if (this.accessExpression instanceof FieldAccess) { + return tm.firstIndexIn(((FieldAccess) this.accessExpression).getName(), TokenNameIdentifier); + } + if (this.accessExpression instanceof QualifiedName) { + return tm.firstIndexIn(((QualifiedName) this.accessExpression).getName(), TokenNameIdentifier); + } + if (this.accessExpression instanceof ThisExpression) { + return tm.lastIndexIn(this.accessExpression, TokenNamethis); + } + if (this.accessExpression instanceof SuperFieldAccess) { + return tm.lastIndexIn(this.accessExpression, TokenNamesuper); + } + throw new AssertionError(); + } + } + + private static final Map OPERATOR_PRECEDENCE; + private static final Map> OPERATOR_WRAPPING_OPTION; + private static final Map> OPERATOR_WRAP_BEFORE_OPTION; + static { + HashMap precedence = new HashMap<>(); + HashMap> wrappingOption = new HashMap<>(); + HashMap> wrapBeforeOption = new HashMap<>(); + for (Operator op : Arrays.asList(Operator.TIMES, Operator.DIVIDE, Operator.REMAINDER)) { + precedence.put(op, 1); + wrappingOption.put(op, o -> o.alignment_for_multiplicative_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_multiplicative_operator); + } + for (Operator op : Arrays.asList(Operator.PLUS, Operator.MINUS)) { + precedence.put(op, 2); + wrappingOption.put(op, o -> o.alignment_for_additive_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_additive_operator); + } + for (Operator op : Arrays.asList(Operator.LEFT_SHIFT, Operator.RIGHT_SHIFT_SIGNED, + Operator.RIGHT_SHIFT_UNSIGNED)) { + precedence.put(op, 3); + wrappingOption.put(op, o -> o.alignment_for_shift_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_shift_operator); + } + for (Operator op : Arrays.asList(Operator.LESS, Operator.GREATER, Operator.LESS_EQUALS, + Operator.GREATER_EQUALS)) { + precedence.put(op, 4); + wrappingOption.put(op, o -> o.alignment_for_relational_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_relational_operator); + } + for (Operator op : Arrays.asList(Operator.EQUALS, Operator.NOT_EQUALS)) { + precedence.put(op, 5); + wrappingOption.put(op, o -> o.alignment_for_relational_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_relational_operator); + } + + precedence.put(Operator.AND, 6); + precedence.put(Operator.XOR, 7); + precedence.put(Operator.OR, 8); + for (Operator op : Arrays.asList(Operator.AND, Operator.XOR, Operator.OR)) { + wrappingOption.put(op, o -> o.alignment_for_bitwise_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_bitwise_operator); + } + + precedence.put(Operator.CONDITIONAL_AND, 9); + precedence.put(Operator.CONDITIONAL_OR, 10); + for (Operator op : Arrays.asList(Operator.CONDITIONAL_AND, Operator.CONDITIONAL_OR)) { + wrappingOption.put(op, o -> o.alignment_for_logical_operator); + wrapBeforeOption.put(op, o -> o.wrap_before_logical_operator); + } + // ternary and assignment operators not relevant to infix expressions + + OPERATOR_PRECEDENCE = Collections.unmodifiableMap(precedence); + OPERATOR_WRAPPING_OPTION = Collections.unmodifiableMap(wrappingOption); + OPERATOR_WRAP_BEFORE_OPTION = Collections.unmodifiableMap(wrapBeforeOption); + } + + /** Penalty multiplier for wraps that are preferred */ + private final static float PREFERRED = 7f / 8; + + final TokenManager tm; + final DefaultCodeFormatterOptions options; + final int kind; + + final Aligner aligner; + + /* + * temporary values used when calling {@link #handleWrap(int)} to avoid ArrayList + * initialization and long lists of parameters + */ + private List wrapIndexes = new ArrayList<>(); + /** + * Indexes for wraps that shouldn't happen but should be indented if cannot be removed + */ + private List secondaryWrapIndexes = new ArrayList<>(); + private List wrapPenalties = new ArrayList<>(); + private int wrapParentIndex = -1; + private int wrapGroupEnd = -1; + + private int currentDepth = 0; + + public WrapPreparator(TokenManager tokenManager, DefaultCodeFormatterOptions options, int kind) { + this.tm = tokenManager; + this.options = options; + this.kind = kind; + + this.aligner = new Aligner(this.tm, this.options); + } + + @Override + public boolean preVisit2(ASTNode node) { + this.currentDepth++; + + assert this.wrapIndexes.isEmpty() && this.secondaryWrapIndexes.isEmpty() && this.wrapPenalties.isEmpty(); + assert this.wrapParentIndex == -1 && this.wrapGroupEnd == -1; + + boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0; + if (isMalformed) { + this.tm.addDisableFormatTokenPair(this.tm.firstTokenIn(node, -1), this.tm.lastTokenIn(node, -1)); + } + return !isMalformed; + } + + @Override + public void postVisit(ASTNode node) { + this.currentDepth--; + } + + @Override + public boolean visit(PackageDeclaration node) { + handleAnnotations(node.annotations(), this.options.alignment_for_annotations_on_package); + return true; + } + + @Override + public boolean visit(NormalAnnotation node) { + int lParen = this.tm.firstIndexAfter(node.getTypeName(), TokenNameLPAREN); + int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_annotation); + + handleArguments(node.values(), this.options.alignment_for_arguments_in_annotation); + return true; + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + int lParen = this.tm.firstIndexAfter(node.getTypeName(), TokenNameLPAREN); + int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_annotation); + return true; + } + + @Override + public boolean visit(TypeDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type); + + Type superclassType = node.getSuperclassType(); + if (superclassType != null) { + this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1); + this.wrapGroupEnd = this.tm.lastIndexIn(superclassType, -1); + this.wrapIndexes.add(this.tm.firstIndexBefore(superclassType, TokenNameextends)); + this.wrapIndexes.add(this.tm.firstIndexIn(superclassType, -1)); + handleWrap(this.options.alignment_for_superclass_in_type_declaration, PREFERRED); + } + + List superInterfaceTypes = node.superInterfaceTypes(); + if (!superInterfaceTypes.isEmpty()) { + int implementsToken = node.isInterface() ? TokenNameextends : TokenNameimplements; + this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1); + this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), implementsToken)); + prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1); + handleWrap(this.options.alignment_for_superinterfaces_in_type_declaration, PREFERRED); + } + + prepareElementsList(node.typeParameters(), TokenNameCOMMA, TokenNameLESS); + handleWrap(this.options.alignment_for_type_parameters); + + this.aligner.handleAlign(node.bodyDeclarations()); + + return true; + } + + @Override + public boolean visit(AnnotationTypeDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type); + this.aligner.handleAlign(node.bodyDeclarations()); + return true; + } + + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_method); + return true; + } + + @Override + public boolean visit(AnonymousClassDeclaration node) { + this.aligner.handleAlign(node.bodyDeclarations()); + return true; + } + + @Override + public boolean visit(RecordDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type); + + int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN); + List components = node.recordComponents(); + int rParen = this.tm.firstIndexAfter( + components.isEmpty() ? node.getName() : components.get(components.size() - 1), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_record_declaration); + + if (!components.isEmpty()) { + int wrappingOption = this.options.alignment_for_record_components; + this.wrapGroupEnd = this.tm.lastIndexIn(components.get(components.size() - 1), -1); + handleArguments(components, wrappingOption); + } + + List superInterfaceTypes = node.superInterfaceTypes(); + if (!superInterfaceTypes.isEmpty()) { + this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1); + this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), TokenNameimplements)); + prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1); + handleWrap(this.options.alignment_for_superinterfaces_in_record_declaration, PREFERRED); + } + return true; + } + + @Override + public boolean visit(MethodDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_method); + + if (!node.isCompactConstructor()) { + int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN); + int rParen = node.getBody() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN) + : this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_declaration); + } + + List parameters = node.parameters(); + Type receiverType = node.getReceiverType(); + if (!parameters.isEmpty() || receiverType != null) { + if (receiverType != null) { + this.wrapIndexes.add(this.tm.firstIndexIn(receiverType, -1)); + } + int wrappingOption = node.isConstructor() ? this.options.alignment_for_parameters_in_constructor_declaration + : this.options.alignment_for_parameters_in_method_declaration; + this.wrapGroupEnd = this.tm + .lastIndexIn(parameters.isEmpty() ? receiverType : parameters.get(parameters.size() - 1), -1); + handleArguments(parameters, wrappingOption); + } + + List exceptionTypes = node.thrownExceptionTypes(); + if (!exceptionTypes.isEmpty()) { + int wrappingOption = node.isConstructor() + ? this.options.alignment_for_throws_clause_in_constructor_declaration + : this.options.alignment_for_throws_clause_in_method_declaration; + if ((wrappingOption & Alignment.M_INDENT_ON_COLUMN) == 0) { + this.wrapParentIndex = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN); + } + prepareElementsList(exceptionTypes, TokenNameCOMMA, TokenNameRPAREN); + // instead of the first exception type, wrap the "throws" token + this.wrapIndexes.set(0, this.tm.firstIndexBefore(exceptionTypes.get(0), TokenNamethrows)); + handleWrap(wrappingOption, 0.5f); + } + + if (!node.isConstructor()) { + this.wrapParentIndex = this.tm.findFirstTokenInLine(this.tm.firstIndexIn(node.getName(), -1)); + while (this.tm.get(this.wrapParentIndex).isComment()) { + this.wrapParentIndex++; + } + List typeParameters = node.typeParameters(); + if (!typeParameters.isEmpty()) { + this.wrapIndexes.add(this.tm.firstIndexIn(typeParameters.get(0), -1)); + } + if (node.getReturnType2() != null) { + int returTypeIndex = this.tm.firstIndexIn(node.getReturnType2(), -1); + if (returTypeIndex != this.wrapParentIndex) { + this.wrapIndexes.add(returTypeIndex); + } + } + this.wrapIndexes.add(this.tm.firstIndexIn(node.getName(), -1)); + this.wrapGroupEnd = this.tm.lastIndexIn(node.getName(), -1); + handleWrap(this.options.alignment_for_method_declaration); + } + + prepareElementsList(node.typeParameters(), TokenNameCOMMA, TokenNameLESS); + handleWrap(this.options.alignment_for_type_parameters); + + return true; + } + + @Override + public boolean visit(EnumDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_type); + + List enumConstants = node.enumConstants(); + int constantsEnd = -1; + if (!enumConstants.isEmpty()) { + for (EnumConstantDeclaration constant : enumConstants) { + this.wrapIndexes.add(this.tm.firstIndexIn(constant, -1)); + } + this.wrapParentIndex = (this.options.alignment_for_enum_constants & Alignment.M_INDENT_ON_COLUMN) > 0 + ? this.tm.firstIndexBefore(enumConstants.get(0), TokenNameLBRACE) + : this.tm.firstIndexIn(node, TokenNameenum); + this.wrapGroupEnd = constantsEnd = this.tm.lastIndexIn(enumConstants.get(enumConstants.size() - 1), -1); + handleWrap(this.options.alignment_for_enum_constants, node); + } + + if (!this.options.join_wrapped_lines) { + // preserve a line break between the last comma and semicolon + int commaIndex = -1; + int i = constantsEnd > 0 ? constantsEnd : this.tm.firstIndexAfter(node.getName(), TokenNameLBRACE); + while (++i < this.tm.size()) { + Token t = this.tm.get(i); + if (t.isComment()) { + continue; + } + if (t.tokenType == TokenNameCOMMA) { + commaIndex = i; + continue; + } + if (t.tokenType == TokenNameSEMICOLON && commaIndex >= 0 + && this.tm.countLineBreaksBetween(this.tm.get(commaIndex), t) == 1) { + t.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, commaIndex, 0)); + } + break; + } + } + + List superInterfaceTypes = node.superInterfaceTypes(); + if (!superInterfaceTypes.isEmpty()) { + this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1); + this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), TokenNameimplements)); + prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1); + handleWrap(this.options.alignment_for_superinterfaces_in_enum_declaration, PREFERRED); + } + + this.aligner.handleAlign(node.bodyDeclarations()); + + return true; + } + + @Override + public boolean visit(EnumConstantDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_enum_constant); + + int lParen = this.tm.firstIndexAfter(node.getName(), -1); + while (this.tm.get(lParen).isComment()) { + lParen++; + } + if (this.tm.get(lParen).tokenType == TokenNameLPAREN) { + int rParen = node.getAnonymousClassDeclaration() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN) + : this.tm.firstIndexBefore(node.getAnonymousClassDeclaration(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_enum_constant_declaration); + } + + handleArguments(node.arguments(), this.options.alignment_for_arguments_in_enum_constant); + AnonymousClassDeclaration anonymousClass = node.getAnonymousClassDeclaration(); + if (anonymousClass != null) { + forceContinuousWrapping(anonymousClass, this.tm.firstIndexIn(node.getName(), -1)); + } + return true; + } + + @Override + public boolean visit(Block node) { + this.aligner.handleAlign(node); + return true; + } + + @Override + public boolean visit(MethodInvocation node) { + // Method patched based on + // https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/189391/4/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java + int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN); + int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation); + + handleArguments(node.arguments(), this.options.alignment_for_arguments_in_method_invocation); + handleTypeArguments(node.typeArguments()); + + boolean isInvocationChainRoot = !(node.getParent() instanceof MethodInvocation) + || node.getLocationInParent() != MethodInvocation.EXPRESSION_PROPERTY; + if (isInvocationChainRoot) { + Expression expression = node; + MethodInvocation invocation = node; + while (expression instanceof MethodInvocation) { + invocation = (MethodInvocation) expression; + expression = invocation.getExpression(); + if (expression != null) { + this.wrapIndexes.add(this.tm.firstIndexBefore(invocation.getName(), TokenNameDOT)); + this.secondaryWrapIndexes.add(this.tm.firstIndexIn(invocation.getName(), TokenNameIdentifier)); + } + } + Collections.reverse(this.wrapIndexes); + expression = (expression != null) ? expression : invocation; + this.wrapParentIndex = this.tm.lastIndexIn(expression, -1); + if ((this.options.alignment_for_selector_in_method_invocation & Alignment.M_INDENT_ON_COLUMN) == 0) { + this.wrapParentIndex = this.tm.firstIndexIn(expression, -1); + } + this.wrapGroupEnd = this.tm.lastIndexIn(node, -1); + handleWrap(this.options.alignment_for_selector_in_method_invocation); + } + return true; + } + + @Override + public boolean visit(SuperMethodInvocation node) { + int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN); + int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation); + + handleArguments(node.arguments(), this.options.alignment_for_arguments_in_method_invocation); + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(ClassInstanceCreation node) { + int lParen = this.tm.firstIndexAfter(node.getType(), TokenNameLPAREN); + int rParen = node.getAnonymousClassDeclaration() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN) + : this.tm.firstIndexBefore(node.getAnonymousClassDeclaration(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation); + + AnonymousClassDeclaration anonymousClass = node.getAnonymousClassDeclaration(); + if (anonymousClass != null) { + forceContinuousWrapping(anonymousClass, this.tm.firstIndexIn(node, TokenNamenew)); + } + + int wrappingOption = node.getExpression() != null + ? this.options.alignment_for_arguments_in_qualified_allocation_expression + : this.options.alignment_for_arguments_in_allocation_expression; + handleArguments(node.arguments(), wrappingOption); + + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(ConstructorInvocation node) { + int lParen = node.arguments().isEmpty() ? this.tm.lastIndexIn(node, TokenNameLPAREN) + : this.tm.firstIndexBefore((ASTNode) node.arguments().get(0), TokenNameLPAREN); + int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation); + + handleArguments(node.arguments(), this.options.alignment_for_arguments_in_explicit_constructor_call); + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(SuperConstructorInvocation node) { + int lParen = node.arguments().isEmpty() ? this.tm.lastIndexIn(node, TokenNameLPAREN) + : this.tm.firstIndexBefore((ASTNode) node.arguments().get(0), TokenNameLPAREN); + int rParen = this.tm.lastIndexIn(node, TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_invocation); + + handleArguments(node.arguments(), this.options.alignment_for_arguments_in_explicit_constructor_call); + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(FieldAccess node) { + handleFieldAccess(node); + return true; + } + + @Override + public boolean visit(QualifiedName node) { + handleFieldAccess(node); + return true; + } + + @Override + public boolean visit(ThisExpression node) { + handleFieldAccess(node); + return true; + } + + @Override + public boolean visit(SuperFieldAccess node) { + handleFieldAccess(node); + return true; + } + + private void handleFieldAccess(Expression node) { + boolean isAccessChainRoot = !FieldAccessAdapter.isFieldAccess(node.getParent()); + if (!isAccessChainRoot) { + return; + } + + Expression expression = node; + FieldAccessAdapter access = null; + while (FieldAccessAdapter.isFieldAccess(expression)) { + access = new FieldAccessAdapter(expression); + int nameIndex = access.getIdentifierIndex(this.tm); + // find a dot preceding the name, may not be there + for (int i = nameIndex - 1; i > this.tm.firstIndexIn(node, -1); i--) { + Token t = this.tm.get(i); + if (t.tokenType == TokenNameDOT) { + this.wrapIndexes.add(i); + this.secondaryWrapIndexes.add(nameIndex); + } + if (!t.isComment() && t.tokenType != TokenNamesuper) { + break; + } + } + expression = access.getExpression(); + } + Collections.reverse(this.wrapIndexes); + this.wrapParentIndex = this.tm.lastIndexIn(expression != null ? expression : access.accessExpression, -1); + boolean isFollowedByInvocation = node.getParent() instanceof MethodInvocation + && node.getLocationInParent() == MethodInvocation.EXPRESSION_PROPERTY; + this.wrapGroupEnd = isFollowedByInvocation ? this.tm.lastIndexIn(node.getParent(), -1) + : new FieldAccessAdapter(node).getIdentifierIndex(this.tm); + // TODO need configuration for this, now only handles line breaks that cannot be + // removed + handleWrap(Alignment.M_NO_ALIGNMENT); + } + + @Override + public boolean visit(InfixExpression node) { + Integer operatorPrecedence = OPERATOR_PRECEDENCE.get(node.getOperator()); + if (operatorPrecedence == null) { + return true; + } + ASTNode parent = node.getParent(); + if ((parent instanceof InfixExpression) && samePrecedence(node, (InfixExpression) parent)) { + return true; // this node has been handled higher in the AST + } + + int wrappingOption = OPERATOR_WRAPPING_OPTION.get(node.getOperator()).applyAsInt(this.options); + boolean wrapBeforeOperator = OPERATOR_WRAP_BEFORE_OPTION.get(node.getOperator()).test(this.options); + if (this.tm.isStringConcatenation(node)) { + wrappingOption = this.options.alignment_for_string_concatenation; + wrapBeforeOperator = this.options.wrap_before_string_concatenation; + } + + findTokensToWrap(node, wrapBeforeOperator, 0); + this.wrapParentIndex = this.wrapIndexes.remove(0); + this.wrapGroupEnd = this.tm.lastIndexIn(node, -1); + if ((wrappingOption & Alignment.M_INDENT_ON_COLUMN) != 0 && this.wrapParentIndex > 0) { + this.wrapParentIndex--; + } + for (int i = this.wrapParentIndex; i >= 0; i--) { + if (!this.tm.get(i).isComment()) { + this.wrapParentIndex = i; + break; + } + } + handleWrap(wrappingOption, !wrapBeforeOperator, node); + return true; + } + + private void findTokensToWrap(InfixExpression node, boolean wrapBeforeOperator, int depth) { + Expression left = node.getLeftOperand(); + if (left instanceof InfixExpression && samePrecedence(node, (InfixExpression) left)) { + findTokensToWrap((InfixExpression) left, wrapBeforeOperator, depth + 1); + } + else if (this.wrapIndexes.isEmpty() // always add first operand, it will be taken + // as wrap parent + || !wrapBeforeOperator) { + this.wrapIndexes.add(this.tm.firstIndexIn(left, -1)); + } + + Expression right = node.getRightOperand(); + List extended = node.extendedOperands(); + for (int i = -1; i < extended.size(); i++) { + Expression operand = (i == -1) ? right : extended.get(i); + if (operand instanceof InfixExpression && samePrecedence(node, (InfixExpression) operand)) { + findTokensToWrap((InfixExpression) operand, wrapBeforeOperator, depth + 1); + } + int indexBefore = this.tm.firstIndexBefore(operand, -1); + while (this.tm.get(indexBefore).isComment()) { + indexBefore--; + } + assert node.getOperator().toString().equals(this.tm.toString(indexBefore)); + int indexAfter = this.tm.firstIndexIn(operand, -1); + this.wrapIndexes.add(wrapBeforeOperator ? indexBefore : indexAfter); + this.secondaryWrapIndexes.add(wrapBeforeOperator ? indexAfter : indexBefore); + + if (!this.options.join_wrapped_lines) { + // TODO there should be an option for never joining wraps on opposite side + // of the operator + if (wrapBeforeOperator) { + if (this.tm.countLineBreaksBetween(this.tm.get(indexAfter - 1), this.tm.get(indexAfter)) > 0) { + this.wrapIndexes.add(indexAfter); + } + } + else { + if (this.tm.countLineBreaksBetween(this.tm.get(indexBefore), this.tm.get(indexBefore - 1)) > 0) { + this.wrapIndexes.add(indexBefore); + } + } + } + } + } + + private boolean samePrecedence(InfixExpression expression1, InfixExpression expression2) { + Integer precedence1 = OPERATOR_PRECEDENCE.get(expression1.getOperator()); + Integer precedence2 = OPERATOR_PRECEDENCE.get(expression2.getOperator()); + if (precedence1 == null || precedence2 == null) { + return false; + } + return precedence1.equals(precedence2); + } + + @Override + public boolean visit(ConditionalExpression node) { + boolean chainsMatter = (this.options.alignment_for_conditional_expression_chain + & Alignment.SPLIT_MASK) != Alignment.M_NO_ALIGNMENT; + boolean isNextInChain = node.getParent() instanceof ConditionalExpression + && node == ((ConditionalExpression) node.getParent()).getElseExpression(); + boolean isFirstInChain = node.getElseExpression() instanceof ConditionalExpression && !isNextInChain; + boolean wrapBefore = this.options.wrap_before_conditional_operator; + List before = wrapBefore ? this.wrapIndexes : this.secondaryWrapIndexes; + List after = wrapBefore ? this.secondaryWrapIndexes : this.wrapIndexes; + if (!chainsMatter || (!isFirstInChain && !isNextInChain)) { + before.add(this.tm.firstIndexAfter(node.getExpression(), TokenNameQUESTION)); + before.add(this.tm.firstIndexAfter(node.getThenExpression(), TokenNameCOLON)); + after.add(this.tm.firstIndexIn(node.getThenExpression(), -1)); + after.add(this.tm.firstIndexIn(node.getElseExpression(), -1)); + this.wrapParentIndex = this.tm.lastIndexIn(node.getExpression(), -1); + this.wrapGroupEnd = this.tm.lastIndexIn(node, -1); + handleWrap(this.options.alignment_for_conditional_expression); + + } + else if (isFirstInChain) { + List chain = new ArrayList<>(); + chain.add(node); + ConditionalExpression next = node; + while (next.getElseExpression() instanceof ConditionalExpression) { + next = (ConditionalExpression) next.getElseExpression(); + chain.add(next); + } + + for (ConditionalExpression conditional : chain) { + before.add(this.tm.firstIndexAfter(conditional.getThenExpression(), TokenNameCOLON)); + after.add(this.tm.firstIndexIn(conditional.getElseExpression(), -1)); + } + this.wrapParentIndex = this.tm.firstIndexIn(node.getExpression(), -1); + this.wrapGroupEnd = this.tm.lastIndexIn(node, -1); + handleWrap(this.options.alignment_for_conditional_expression_chain); + + this.currentDepth++; + for (ConditionalExpression conditional : chain) { + before.add(this.tm.firstIndexAfter(conditional.getExpression(), TokenNameQUESTION)); + after.add(this.tm.firstIndexIn(conditional.getThenExpression(), -1)); + this.wrapParentIndex = this.tm.firstIndexIn(conditional.getExpression(), -1); + this.wrapGroupEnd = this.tm.lastIndexIn(conditional.getThenExpression(), -1); + handleWrap(this.options.alignment_for_conditional_expression); + } + this.currentDepth--; + } + return true; + } + + @Override + public boolean visit(ArrayInitializer node) { + List expressions = node.expressions(); + if (!expressions.isEmpty()) { + prepareElementsList(expressions, TokenNameCOMMA, TokenNameLBRACE); + handleWrap(this.options.alignment_for_expressions_in_array_initializer, node); + } + int openingBraceIndex = this.tm.firstIndexIn(node, TokenNameLBRACE); + Token openingBrace = this.tm.get(openingBraceIndex); + if (openingBrace.isNextLineOnWrap() && openingBrace.getWrapPolicy() == null && openingBraceIndex > 0) { + // add fake wrap policy to make sure the brace indentation is right + openingBrace.setWrapPolicy(new WrapPolicy(WrapMode.DISABLED, openingBraceIndex - 1, 0)); + } + if (!this.options.join_wrapped_lines + && !this.options.insert_new_line_before_closing_brace_in_array_initializer) { + // if there is a line break before the closing brace, formatter should treat + // it as a valid wrap to preserve + int closingBraceIndex = this.tm.lastIndexIn(node, TokenNameRBRACE); + Token closingBrace = this.tm.get(closingBraceIndex); + if (this.tm.countLineBreaksBetween(this.tm.get(closingBraceIndex - 1), closingBrace) == 1) { + closingBrace.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, openingBraceIndex, + closingBraceIndex, 0, this.currentDepth, 1, true, false)); + } + } + if (this.options.brace_position_for_array_initializer.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED) + && openingBrace.getWrapPolicy() == null && (node.getParent() instanceof SingleMemberAnnotation + || node.getParent() instanceof MemberValuePair)) { + int parentIndex = this.tm.firstIndexIn(node.getParent(), -1); + int indent = this.options.indentation_size; + openingBrace.setWrapPolicy(new WrapPolicy(WrapMode.BLOCK_INDENT, parentIndex, indent)); + } + return true; + } + + @Override + public boolean visit(Assignment node) { + int rightSideIndex = this.tm.firstIndexIn(node.getRightHandSide(), -1); + if (this.tm.get(rightSideIndex).getLineBreaksBefore() > 0) { + return true; // must be an array initializer in new line because of + // brace_position_for_array_initializer + } + + int operatorIndex = this.tm.firstIndexBefore(node.getRightHandSide(), -1); + while (this.tm.get(operatorIndex).isComment()) { + operatorIndex--; + } + assert node.getOperator().toString().equals(this.tm.toString(operatorIndex)); + + this.wrapIndexes.add(this.options.wrap_before_assignment_operator ? operatorIndex : rightSideIndex); + this.secondaryWrapIndexes.add(this.options.wrap_before_assignment_operator ? rightSideIndex : operatorIndex); + this.wrapParentIndex = operatorIndex - 1; + this.wrapGroupEnd = this.tm.lastIndexIn(node.getRightHandSide(), -1); + handleWrap(this.options.alignment_for_assignment); + return true; + } + + @Override + public boolean visit(VariableDeclarationFragment node) { + if (node.getInitializer() == null) { + return true; + } + int rightSideIndex = this.tm.firstIndexIn(node.getInitializer(), -1); + if (this.tm.get(rightSideIndex).getLineBreaksBefore() > 0) { + return true; // must be an array initializer in new line because of + // brace_position_for_array_initializer + } + int equalIndex = this.tm.firstIndexBefore(node.getInitializer(), TokenNameEQUAL); + + this.wrapIndexes.add(this.options.wrap_before_assignment_operator ? equalIndex : rightSideIndex); + this.secondaryWrapIndexes.add(this.options.wrap_before_assignment_operator ? rightSideIndex : equalIndex); + this.wrapParentIndex = equalIndex - 1; + this.wrapGroupEnd = this.tm.lastIndexIn(node.getInitializer(), -1); + handleWrap(this.options.alignment_for_assignment); + return true; + } + + @Override + public boolean visit(IfStatement node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_if_while_statement); + + Statement elseStatement = node.getElseStatement(); + boolean keepThenOnSameLine = this.options.keep_then_statement_on_same_line + || (this.options.keep_simple_if_on_one_line && elseStatement == null); + if (keepThenOnSameLine) { + handleSimpleLoop(node.getThenStatement(), this.options.alignment_for_compact_if); + } + + if (this.options.keep_else_statement_on_same_line && elseStatement != null) { + handleSimpleLoop(elseStatement, this.options.alignment_for_compact_if); + } + return true; + } + + @Override + public boolean visit(ForStatement node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_for_statement); + + List initializers = node.initializers(); + if (!initializers.isEmpty()) { + this.wrapIndexes.add(this.tm.firstIndexIn(initializers.get(0), -1)); + } + if (node.getExpression() != null) { + this.wrapIndexes.add(this.tm.firstIndexIn(node.getExpression(), -1)); + } + List updaters = node.updaters(); + if (!updaters.isEmpty()) { + this.wrapIndexes.add(this.tm.firstIndexIn(updaters.get(0), -1)); + } + if (!this.wrapIndexes.isEmpty()) { + this.wrapParentIndex = lParen; + this.wrapGroupEnd = rParen; + handleWrap(this.options.alignment_for_expressions_in_for_loop_header); + } + if (this.options.keep_simple_for_body_on_same_line) { + handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop); + } + return true; + } + + @Override + public boolean visit(EnhancedForStatement node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_for_statement); + + if (this.options.keep_simple_for_body_on_same_line) { + handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop); + } + return true; + } + + @Override + public boolean visit(WhileStatement node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_if_while_statement); + + if (this.options.keep_simple_while_body_on_same_line) { + handleSimpleLoop(node.getBody(), this.options.alignment_for_compact_loop); + } + return true; + } + + private void handleSimpleLoop(Statement body, int wrappingOption) { + if (!(body instanceof Block)) { + this.wrapIndexes.add(this.tm.firstIndexIn(body, -1)); + this.wrapParentIndex = this.tm.firstIndexBefore(body, TokenNameRPAREN); + this.wrapGroupEnd = this.tm.lastIndexIn(body, -1); + handleWrap(wrappingOption, body.getParent()); + + body.accept(new ASTVisitor() { + @Override + public boolean visit(Block node) { + forceContinuousWrapping(node, WrapPreparator.this.tm.firstIndexIn(node, -1)); + return false; + } + }); + } + } + + @Override + public void endVisit(DoStatement node) { + if (this.options.keep_simple_do_while_body_on_same_line && !(node.getBody() instanceof Block)) { + int whileIndex = this.tm.firstIndexAfter(node.getBody(), TokenNamewhile); + this.wrapIndexes.add(whileIndex); + this.wrapParentIndex = this.tm.lastIndexIn(node.getBody(), -1); + this.wrapGroupEnd = this.tm.lastIndexIn(node, -1); + + int alignment = this.options.alignment_for_compact_loop; + for (int i = this.tm.firstIndexIn(node, -1) + 1; i < whileIndex; i++) { + Token token = this.tm.get(i); + if (token.getLineBreaksBefore() > 0 || token.getLineBreaksAfter() > 0) { + alignment |= Alignment.M_FORCE; + } + } + handleWrap(alignment, node); + } + } + + @Override + public boolean visit(TryStatement node) { + if (!node.resources().isEmpty()) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_try_clause); + } + prepareElementsList(node.resources(), TokenNameSEMICOLON, TokenNameLPAREN); + handleWrap(this.options.alignment_for_resources_in_try); + return true; + } + + @Override + public boolean visit(UnionType node) { + List types = node.types(); + if (types.isEmpty()) { + return true; + } + if (this.options.wrap_before_or_operator_multicatch) { + for (Type type : types) { + if (this.wrapIndexes.isEmpty()) { + this.wrapIndexes.add(this.tm.firstIndexIn(type, -1)); + } + else { + this.wrapIndexes.add(this.tm.firstIndexBefore(type, TokenNameOR)); + this.secondaryWrapIndexes.add(this.tm.firstIndexIn(type, -1)); + } + } + this.wrapParentIndex = this.tm.firstIndexBefore(node, -1); + while (this.tm.get(this.wrapParentIndex).isComment()) { + this.wrapParentIndex--; + } + this.wrapGroupEnd = this.tm.lastIndexIn(types.get(types.size() - 1), -1); + handleWrap(this.options.alignment_for_union_type_in_multicatch); + } + else { + prepareElementsList(types, TokenNameOR, TokenNameLPAREN); + handleWrap(this.options.alignment_for_union_type_in_multicatch); + } + return true; + } + + @Override + public boolean visit(LambdaExpression node) { + int lParen = this.tm.firstIndexIn(node, -1); + if (this.tm.get(lParen).tokenType == TokenNameLPAREN) { + int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_lambda_declaration); + } + if (node.getBody() instanceof Block) { + forceContinuousWrapping(node.getBody(), this.tm.firstIndexIn(node, -1)); + + List statements = ((Block) node.getBody()).statements(); + if (!statements.isEmpty()) { + int openBraceIndex = this.tm.firstIndexBefore(statements.get(0), TokenNameLBRACE); + int closeBraceIndex = this.tm.firstIndexAfter(statements.get(statements.size() - 1), TokenNameRBRACE); + boolean areKeptOnOneLine = this.tm.stream().skip(openBraceIndex + 1) + .limit(closeBraceIndex - openBraceIndex - 1) + .allMatch(t -> t.getLineBreaksBefore() == 0 && t.getLineBreaksAfter() == 0); + if (areKeptOnOneLine) { + for (Statement statement : statements) { + this.wrapIndexes.add(this.tm.firstIndexIn(statement, -1)); + } + this.wrapParentIndex = openBraceIndex; + this.wrapGroupEnd = closeBraceIndex; + handleWrap(Alignment.M_ONE_PER_LINE_SPLIT, node); + this.tm.get(closeBraceIndex).setWrapPolicy(new WrapPolicy(WrapMode.TOP_PRIORITY, openBraceIndex, + closeBraceIndex, 0, this.currentDepth, 1, false, false)); + } + } + } + if (node.hasParentheses()) { + List parameters = node.parameters(); + // the legacy formatter didn't like wrapping lambda parameters, so neither do + // we + this.currentDepth++; + handleArguments(parameters, this.options.alignment_for_parameters_in_method_declaration); + this.currentDepth--; + } + return true; + } + + @Override + public boolean visit(FieldDeclaration node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_field); + handleVariableDeclarations(node.fragments()); + return true; + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_local_variable); + handleVariableDeclarations(node.fragments()); + return true; + } + + @Override + public boolean visit(VariableDeclarationExpression node) { + handleAnnotations(node.modifiers(), this.options.alignment_for_annotations_on_local_variable); + handleVariableDeclarations(node.fragments()); + return true; + } + + @Override + public boolean visit(SingleVariableDeclaration node) { + handleAnnotations(node.modifiers(), + node.getParent() instanceof EnhancedForStatement + ? this.options.alignment_for_annotations_on_local_variable + : this.options.alignment_for_annotations_on_parameter); + return true; + } + + @Override + public boolean visit(ParameterizedType node) { + prepareElementsList(node.typeArguments(), TokenNameCOMMA, TokenNameLESS); + handleWrap(this.options.alignment_for_parameterized_type_references); + return true; + } + + @Override + public boolean visit(TypeMethodReference node) { + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(ExpressionMethodReference node) { + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(SuperMethodReference node) { + handleTypeArguments(node.typeArguments()); + return true; + } + + @Override + public boolean visit(CreationReference node) { + handleTypeArguments(node.typeArguments()); + return true; + } + + private void handleTypeArguments(List typeArguments) { + if (typeArguments.isEmpty()) { + return; + } + prepareElementsList(typeArguments, TokenNameCOMMA, TokenNameLESS); + handleWrap(this.options.alignment_for_type_arguments); + } + + @Override + public boolean visit(ExportsDirective node) { + handleModuleStatement(node.modules(), TokenNameto); + return true; + } + + @Override + public boolean visit(OpensDirective node) { + handleModuleStatement(node.modules(), TokenNameto); + return true; + } + + @Override + public boolean visit(ProvidesDirective node) { + handleModuleStatement(node.implementations(), TokenNamewith); + return true; + } + + private void handleModuleStatement(List names, int joiningTokenType) { + if (names.isEmpty()) { + return; + } + int joiningTokenIndex = this.tm.firstIndexBefore(names.get(0), joiningTokenType); + this.wrapParentIndex = this.tm.firstIndexBefore(names.get(0), TokenNameIdentifier); + this.wrapIndexes.add(joiningTokenIndex); + prepareElementsList(names, TokenNameCOMMA, -1); + handleWrap(this.options.alignment_for_module_statements, PREFERRED); + } + + @Override + public boolean visit(CatchClause node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_catch_clause); + return true; + } + + @Override + public boolean visit(SwitchStatement node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_switch_statement); + return true; + } + + @Override + public boolean visit(SwitchExpression node) { + int lParen = this.tm.firstIndexIn(node, TokenNameLPAREN); + int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_switch_statement); + return true; + } + + @Override + public boolean visit(DoStatement node) { + int lParen = this.tm.firstIndexBefore(node.getExpression(), TokenNameLPAREN); + int rParen = this.tm.firstIndexAfter(node.getExpression(), TokenNameRPAREN); + handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_if_while_statement); + return true; + } + + @Override + public boolean visit(AssertStatement node) { + Expression message = node.getMessage(); + if (message != null) { + int atColon = this.tm.firstIndexBefore(message, TokenNameCOLON); + int afterColon = this.tm.firstIndexIn(message, -1); + if (this.options.wrap_before_assertion_message_operator) { + this.wrapIndexes.add(atColon); + this.secondaryWrapIndexes.add(afterColon); + } + else { + this.wrapIndexes.add(afterColon); + this.secondaryWrapIndexes.add(atColon); + } + this.wrapParentIndex = this.tm.firstIndexIn(node, -1); + this.wrapGroupEnd = this.tm.lastIndexIn(node, -1); + handleWrap(this.options.alignment_for_assertion_message); + } + return true; + } + + /** + * Makes sure all new lines within given node will have wrap policy so that wrap + * executor will fix their indentation if necessary. + */ + void forceContinuousWrapping(ASTNode node, int parentIndex) { + int parentIndent = this.tm.get(parentIndex).getIndent(); + int indentChange = -parentIndent; + int lineStart = this.tm.findFirstTokenInLine(parentIndex); + for (int i = parentIndex; i >= lineStart; i--) { + int align = this.tm.get(i).getAlign(); + if (align > 0) { + indentChange = -2 * parentIndent + align; + break; + } + } + + Token previous = null; + int from = this.tm.firstIndexIn(node, -1); + int to = this.tm.lastIndexIn(node, -1); + for (int i = from; i <= to; i++) { + Token token = this.tm.get(i); + if ((token.getLineBreaksBefore() > 0 || (previous != null && previous.getLineBreaksAfter() > 0)) + && (token.getWrapPolicy() == null || token.getWrapPolicy().wrapMode == WrapMode.BLOCK_INDENT)) { + int extraIndent = token.getIndent() + indentChange; + token.setWrapPolicy(new WrapPolicy(WrapMode.BLOCK_INDENT, parentIndex, extraIndent)); + token.setIndent(parentIndent + extraIndent); + } + previous = token; + } + } + + private void handleVariableDeclarations(List fragments) { + if (fragments.size() > 1) { + this.wrapParentIndex = this.tm.firstIndexIn(fragments.get(0), -1); + prepareElementsList(fragments, TokenNameCOMMA, -1); + this.wrapIndexes.remove(0); + handleWrap(this.options.alignment_for_multiple_fields); + } + } + + private void handleArguments(List arguments, int wrappingOption) { + this.wrapPenalties.add(1 / PREFERRED); + prepareElementsList(arguments, TokenNameCOMMA, TokenNameLPAREN); + handleWrap(wrappingOption); + } + + private void handleAnnotations(List modifiers, int wrappingOption) { + Annotation last = null; + int i; + for (i = 0; i < modifiers.size(); i++) { + if (modifiers.get(i).isModifier()) { + break; + } + Annotation annotation = (Annotation) modifiers.get(i); + if (i == 0) { + this.wrapParentIndex = this.tm.firstIndexIn(annotation, -1); + } + else { + this.wrapIndexes.add(this.tm.firstIndexIn(annotation, -1)); + this.wrapGroupEnd = this.tm.lastIndexIn(annotation, -1); + } + last = annotation; + } + handleWrap(wrappingOption, last); + + if (i < modifiers.size()) { + // any annotations following other modifiers will be associated with + // declaration type + handleAnnotations(modifiers.subList(i + 1, modifiers.size()), this.options.alignment_for_type_annotations); + } + } + + private void prepareElementsList(List elements, int separatorType, int wrapParentType) { + for (int i = 0; i < elements.size(); i++) { + ASTNode element = elements.get(i); + this.wrapIndexes.add(this.tm.firstIndexIn(element, -1)); + if (i > 0) { + this.secondaryWrapIndexes.add(this.tm.firstIndexBefore(element, separatorType)); + } + } + // wrapIndexes may have been filled with additional values even if arguments is + // empty + if (!this.wrapIndexes.isEmpty()) { + Token firstToken = this.tm.get(this.wrapIndexes.get(0)); + if (this.wrapParentIndex < 0) { + this.wrapParentIndex = this.tm.findIndex(firstToken.originalStart - 1, wrapParentType, false); + } + if (!elements.isEmpty() && this.wrapGroupEnd < 0) { + this.wrapGroupEnd = this.tm.lastIndexIn(elements.get(elements.size() - 1), -1); + } + } + } + + private void handleWrap(int wrappingOption) { + handleWrap(wrappingOption, null); + } + + private void handleWrap(int wrappingOption, float firstPenaltyMultiplier) { + this.wrapPenalties.add(firstPenaltyMultiplier); + handleWrap(wrappingOption, null); + } + + private void handleWrap(int wrappingOption, ASTNode parentNode) { + handleWrap(wrappingOption, true, parentNode); + } + + private void handleWrap(int wrappingOption, boolean wrapPreceedingComments, ASTNode parentNode) { + doHandleWrap(wrappingOption, wrapPreceedingComments, parentNode); + this.wrapIndexes.clear(); + this.secondaryWrapIndexes.clear(); + this.wrapPenalties.clear(); + this.wrapParentIndex = this.wrapGroupEnd = -1; + } + + private void doHandleWrap(int wrappingOption, boolean wrapPreceedingComments, ASTNode parentNode) { + if (this.wrapIndexes.isEmpty()) { + return; + } + assert this.wrapParentIndex >= 0 && this.wrapParentIndex < this.wrapIndexes.get(0); + assert this.wrapGroupEnd >= this.wrapIndexes.get(this.wrapIndexes.size() - 1); + + while (this.tm.get(this.wrapParentIndex).isComment() && this.wrapParentIndex > 0) { + this.wrapParentIndex--; + } + + float penalty = this.wrapPenalties.isEmpty() ? 1 : this.wrapPenalties.get(0); + WrapPolicy policy = getWrapPolicy(wrappingOption, penalty, true, parentNode); + + WrapPolicy existing = this.tm.get(this.wrapIndexes.get(0)).getWrapPolicy(); + if (existing != null && existing.wrapMode == WrapMode.TOP_PRIORITY) { + // SEPARATE_LINES_IF_WRAPPED + assert existing.wrapParentIndex == this.wrapParentIndex; + this.wrapGroupEnd = existing.groupEndIndex; + policy = new WrapPolicy(WrapMode.TOP_PRIORITY, policy.wrapParentIndex, this.wrapGroupEnd, + policy.extraIndent, policy.structureDepth, policy.penaltyMultiplier, true, policy.indentOnColumn); + } + + setTokenWrapPolicy(0, policy, true); + + for (int i = 1; i < this.wrapIndexes.size(); i++) { + penalty = this.wrapPenalties.size() > i ? this.wrapPenalties.get(i) : 1; + if (penalty != policy.penaltyMultiplier || i == 1) { + policy = getWrapPolicy(wrappingOption, penalty, false, parentNode); + } + setTokenWrapPolicy(i, policy, wrapPreceedingComments); + } + + if (!this.secondaryWrapIndexes.isEmpty()) { + int optionNoAlignment = (wrappingOption & ~Alignment.SPLIT_MASK) | Alignment.M_NO_ALIGNMENT; + policy = getWrapPolicy(optionNoAlignment, 1, false, parentNode); + for (int index : this.secondaryWrapIndexes) { + Token token = this.tm.get(index); + if (token.getWrapPolicy() == null) { + token.setWrapPolicy(policy); + } + } + } + } + + private void setTokenWrapPolicy(int wrapIndexesIndex, WrapPolicy policy, boolean wrapPreceedingComments) { + int index = this.wrapIndexes.get(wrapIndexesIndex); + if (wrapPreceedingComments) { + for (int i = index - 1; i >= 0; i--) { + Token previous = this.tm.get(i); + if (!previous.isComment()) { + break; + } + if (previous.getWrapPolicy() == WrapPolicy.FORCE_FIRST_COLUMN) { + break; + } + if (previous.getLineBreaksAfter() == 0 && i == index - 1) { + index = i; + } + if (previous.getLineBreaksBefore() > 0) { + previous.setWrapPolicy(policy); + } + } + this.wrapIndexes.set(wrapIndexesIndex, index); + } + + Token token = this.tm.get(index); + if (token.getWrapPolicy() == WrapPolicy.DISABLE_WRAP) { + return; + } + + token.setWrapPolicy(policy); + if (policy.wrapMode == WrapMode.FORCE) { + token.breakBefore(); + } + else if (this.options.join_wrapped_lines && token.tokenType == TokenNameCOMMENT_BLOCK) { + // allow wrap preparator to decide if this comment should be wrapped + token.clearLineBreaksBefore(); + } + } + + private WrapPolicy getWrapPolicy(int wrappingOption, float penaltyMultiplier, boolean isFirst, ASTNode parentNode) { + assert this.wrapParentIndex >= 0 && this.wrapGroupEnd >= 0; + int extraIndent = this.options.continuation_indentation; + boolean indentOnColumn = (wrappingOption & Alignment.M_INDENT_ON_COLUMN) != 0; + boolean isForceWrap = (wrappingOption & Alignment.M_FORCE) != 0; + boolean isAlreadyWrapped = false; + if (indentOnColumn) { + extraIndent = 0; + } + else if (parentNode instanceof Annotation) { + extraIndent = 0; + } + else if (parentNode instanceof EnumDeclaration) { + // special behavior for compatibility with legacy formatter + extraIndent = ((wrappingOption & Alignment.M_INDENT_BY_ONE) != 0) ? 2 : 1; + if (!this.options.indent_body_declarations_compare_to_enum_declaration_header) { + extraIndent--; + } + isAlreadyWrapped = isFirst; + } + else if (parentNode instanceof IfStatement || parentNode instanceof ForStatement + || parentNode instanceof EnhancedForStatement || parentNode instanceof WhileStatement) { + extraIndent = 1; + this.wrapParentIndex = this.tm.firstIndexIn(parentNode, -1); // only if + // !indoentOnColumn + } + else if (parentNode instanceof DoStatement) { + extraIndent = 0; + this.wrapParentIndex = this.tm.firstIndexIn(parentNode, -1); // only if + // !indoentOnColumn + } + else if (parentNode instanceof LambdaExpression) { + extraIndent = 1; + } + else if ((wrappingOption & Alignment.M_INDENT_BY_ONE) != 0) { + extraIndent = 1; + } + else if (parentNode instanceof ArrayInitializer) { + extraIndent = this.options.continuation_indentation_for_array_initializer; + isAlreadyWrapped = isFirst && this.options.insert_new_line_after_opening_brace_in_array_initializer; + } + + WrapMode wrapMode = WrapMode.WHERE_NECESSARY; + boolean isTopPriority = false; + switch (wrappingOption & Alignment.SPLIT_MASK) { + case Alignment.M_NO_ALIGNMENT: + wrapMode = WrapMode.DISABLED; + isForceWrap = false; + break; + case Alignment.M_COMPACT_FIRST_BREAK_SPLIT: + isTopPriority = isFirst; + isForceWrap &= isFirst; + break; + case Alignment.M_ONE_PER_LINE_SPLIT: + isTopPriority = true; + break; + case Alignment.M_NEXT_SHIFTED_SPLIT: + isTopPriority = true; + if (!isFirst) { + extraIndent++; + } + break; + case Alignment.M_NEXT_PER_LINE_SPLIT: + isTopPriority = !isFirst; + isForceWrap &= !isFirst; + break; + } + + if (isForceWrap) { + wrapMode = WrapMode.FORCE; + } + else if (isAlreadyWrapped) { + wrapMode = WrapMode.DISABLED; // to avoid triggering top priority wrapping + } + else if (isTopPriority) { + wrapMode = WrapMode.TOP_PRIORITY; + } + extraIndent *= this.options.indentation_size; + return new WrapPolicy(wrapMode, this.wrapParentIndex, this.wrapGroupEnd, extraIndent, this.currentDepth, + penaltyMultiplier, isFirst, indentOnColumn); + } + + public void finishUp(ASTNode astRoot, List regions) { + preserveExistingLineBreaks(); + applyBreaksOutsideRegions(regions); + new WrapExecutor(this.tm, this.options, regions).executeWraps(); + this.aligner.alignComments(); + wrapComments(); + fixEnumConstantIndents(astRoot); + } + + private void preserveExistingLineBreaks() { + // normally n empty lines = n+1 line breaks, but not at the file start and end + Token first = this.tm.get(0); + int startingBreaks = first.getLineBreaksBefore(); + first.clearLineBreaksBefore(); + first.putLineBreaksBefore(startingBreaks - 1); + + this.tm.traverse(0, new TokenTraverser() { + boolean join_wrapped_lines = WrapPreparator.this.options.join_wrapped_lines; + + @Override + protected boolean token(Token token, int index) { + int lineBreaks = getLineBreaksToPreserve(getPrevious(), token); + if (lineBreaks > 1 || (!this.join_wrapped_lines && token.isWrappable()) || index == 0) { + token.putLineBreaksBefore(lineBreaks); + } + return true; + } + + }); + + Token last = this.tm.get(this.tm.size() - 1); + last.clearLineBreaksAfter(); + int endingBreaks = getLineBreaksToPreserve(last, null); + if (endingBreaks > 0) { + last.putLineBreaksAfter(endingBreaks); + } + else if ((this.kind & (CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.K_MODULE_INFO)) != 0 + && this.options.insert_new_line_at_end_of_file_if_missing) { + last.breakAfter(); + } + } + + int getLineBreaksToPreserve(Token token1, Token token2) { + if ((token1 != null && !token1.isPreserveLineBreaksAfter()) + || (token2 != null && !token2.isPreserveLineBreaksBefore())) { + return 0; + } + if (token1 != null) { + List structure = token1.getInternalStructure(); + if (structure != null && !structure.isEmpty()) { + token1 = structure.get(structure.size() - 1); + } + } + if (token2 != null) { + List structure = token2.getInternalStructure(); + if (structure != null && !structure.isEmpty()) { + token2 = structure.get(0); + } + } + int lineBreaks = WrapPreparator.this.tm.countLineBreaksBetween(token1, token2); + int toPreserve = this.options.number_of_empty_lines_to_preserve; + if (token1 != null && token2 != null) { + toPreserve++; // n empty lines = n+1 line breaks, except for file start and + // end + } + return Math.min(lineBreaks, toPreserve); + } + + private void applyBreaksOutsideRegions(List regions) { + String source = this.tm.getSource(); + int previousRegionEnd = 0; + for (IRegion region : regions) { + int index = this.tm.findIndex(previousRegionEnd, -1, true); + Token token = this.tm.get(index); + if (this.tm.countLineBreaksBetween(source, previousRegionEnd, + Math.min(token.originalStart, region.getOffset())) > 0) { + token.breakBefore(); + } + for (index++; index < this.tm.size(); index++) { + Token next = this.tm.get(index); + if (next.originalStart > region.getOffset()) { + if (this.tm.countLineBreaksBetween(source, token.originalEnd, region.getOffset()) > 0) { + next.breakBefore(); + } + break; + } + if (this.tm.countLineBreaksBetween(token, next) > 0) { + next.breakBefore(); + } + token = next; + } + previousRegionEnd = region.getOffset() + region.getLength() - 1; + } + } + + private void wrapComments() { + CommentWrapExecutor commentWrapper = new CommentWrapExecutor(this.tm, this.options); + boolean isNLSTagInLine = false; + for (int i = 0; i < this.tm.size(); i++) { + Token token = this.tm.get(i); + if (token.getLineBreaksBefore() > 0 || token.getLineBreaksAfter() > 0) { + isNLSTagInLine = false; + } + if (token.hasNLSTag()) { + assert token.tokenType == TokenNameStringLiteral; + isNLSTagInLine = true; + } + List structure = token.getInternalStructure(); + if (token.isComment() && structure != null && !structure.isEmpty() && !isNLSTagInLine) { + int startPosition = this.tm.getPositionInLine(i); + if (token.tokenType == TokenNameCOMMENT_LINE) { + commentWrapper.wrapLineComment(token, startPosition); + } + else { + assert token.tokenType == TokenNameCOMMENT_BLOCK || token.tokenType == TokenNameCOMMENT_JAVADOC; + commentWrapper.wrapMultiLineComment(token, startPosition, false, false); + } + } + } + } + + private void fixEnumConstantIndents(ASTNode astRoot) { + if (this.options.use_tabs_only_for_leading_indentations) { + // enum constants should be indented like other declarations, not like wrapped + // elements + astRoot.accept(new ASTVisitor() { + + @Override + public boolean visit(EnumConstantDeclaration node) { + WrapPreparator.this.tm.firstTokenIn(node, -1).setWrapPolicy(null); + return true; + } + }); + } + } + + private void handleParenthesesPositions(int openingParenIndex, int closingParenIndex, String positionsSetting) { + boolean isEmpty = openingParenIndex + 1 == closingParenIndex; + switch (positionsSetting) { + case DefaultCodeFormatterConstants.COMMON_LINES: + // nothing to do + break; + case DefaultCodeFormatterConstants.SEPARATE_LINES_IF_WRAPPED: + if (isEmpty) { + break; + } + this.tm.get(openingParenIndex + 1).setWrapPolicy(new WrapPolicy(WrapMode.TOP_PRIORITY, openingParenIndex, + closingParenIndex, this.options.indentation_size, this.currentDepth, 1, true, false)); + this.tm.get(closingParenIndex).setWrapPolicy(new WrapPolicy(WrapMode.TOP_PRIORITY, openingParenIndex, + closingParenIndex, 0, this.currentDepth, 1, false, false)); + break; + case DefaultCodeFormatterConstants.SEPARATE_LINES_IF_NOT_EMPTY: + if (isEmpty) { + break; + } + //$FALL-THROUGH$ + case DefaultCodeFormatterConstants.SEPARATE_LINES: + case DefaultCodeFormatterConstants.PRESERVE_POSITIONS: + boolean always = !positionsSetting.equals(DefaultCodeFormatterConstants.PRESERVE_POSITIONS); + Token afterOpening = this.tm.get(openingParenIndex + 1); + if (always || this.tm.countLineBreaksBetween(this.tm.get(openingParenIndex), afterOpening) > 0) { + afterOpening.setWrapPolicy( + new WrapPolicy(WrapMode.WHERE_NECESSARY, openingParenIndex, this.options.indentation_size)); + afterOpening.breakBefore(); + } + Token closingParen = this.tm.get(closingParenIndex); + if (always || this.tm.countLineBreaksBetween(this.tm.get(closingParenIndex - 1), closingParen) > 0) { + closingParen.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, openingParenIndex, 0)); + closingParen.breakBefore(); + } + break; + default: + throw new IllegalArgumentException("Unrecognized parentheses positions setting: " + positionsSetting); //$NON-NLS-1$ + } + } + + // @formatter:on + +} diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml index b58b2ad3..9be11ea0 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/pom.xml @@ -5,7 +5,7 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-formatter-eclipse-rewriter Spring JavaFormat Eclipse Rewriter diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java index 9086d63f..7053dc0c 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-rewriter/src/main/java/io/spring/javaformat/formatter/eclipse/rewrite/EclipseRewriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import java.util.function.Function; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -63,38 +64,59 @@ public final class EclipseRewriter { private EclipseRewriter() { } - public void rewrite(String file) throws IOException { + public void rewrite(JdkVersion jdkVersion, String file) throws IOException { System.out.println("Rewriting classes in " + file); URI uri = URI.create("jar:file:" + Paths.get(file).toUri().getPath()); try (FileSystem zip = FileSystems.newFileSystem(uri, Collections.singletonMap("create", "true"))) { - rewrite(zip); + rewrite(jdkVersion, zip); } } - private void rewrite(FileSystem zip) throws IOException { - Path path = zip.getPath("org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.class"); - ClassWriter writer = new ClassWriter(0); + private void rewrite(JdkVersion jdkVersion, FileSystem zip) throws IOException { + rewrite(zip, "org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.class", + DefaultCodeFormatterManipulator::new); + if (jdkVersion == JdkVersion.V8) { + rewrite(zip, "org/eclipse/osgi/util/NLS$1.class", NlsJdk8Manipulator::new); + deleteWrapPreparator(zip); + } + else { + rewrite(zip, "org/eclipse/osgi/util/NLS.class", NlsJdk17Manipulator::new); + } + } + + private void rewrite(FileSystem zip, String name, Function manipulator) + throws IOException { + ClassWriter classWriter = new ClassWriter(0); + Path path = zip.getPath(name); try (InputStream in = Files.newInputStream(path)) { - DefaultCodeFormatterManipulator manipulator = new DefaultCodeFormatterManipulator(writer); ClassReader reader = new ClassReader(in); - reader.accept(manipulator, 0); + reader.accept(manipulator.apply(classWriter), 0); } - Files.copy(new ByteArrayInputStream(writer.toByteArray()), path, StandardCopyOption.REPLACE_EXISTING); + Files.copy(new ByteArrayInputStream(classWriter.toByteArray()), path, StandardCopyOption.REPLACE_EXISTING); + } + + private void deleteWrapPreparator(FileSystem zip) throws IOException { + Path path = zip.getPath("org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.class"); + Files.delete(path); } public static void main(String[] args) throws Exception { - new EclipseRewriter().rewrite(args[0]); + new EclipseRewriter().rewrite(JdkVersion.valueOf("V" + args[0]), args[1]); } + /** + * {@link ClassVisitor} to make some fields and methods from + * {@code DefaultCodeFormatter} public. + */ private static class DefaultCodeFormatterManipulator extends ClassVisitor { DefaultCodeFormatterManipulator(ClassVisitor visitor) { - super(Opcodes.ASM5, visitor); + super(Opcodes.ASM9, visitor); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - if (access == Opcodes.ACC_PRIVATE && UPDATED_FIELDS.contains(name)) { + if ((access & Opcodes.ACC_PRIVATE) != 0 && UPDATED_FIELDS.contains(name)) { access = Opcodes.ACC_PROTECTED; } return super.visitField(access, name, desc, signature, value); @@ -102,7 +124,7 @@ public FieldVisitor visitField(int access, String name, String desc, String sign @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (access == Opcodes.ACC_PRIVATE && UPDATED_METHODS.contains(name)) { + if ((access & Opcodes.ACC_PRIVATE) != 0 && UPDATED_METHODS.contains(name)) { access = Opcodes.ACC_PROTECTED; } return new DefaultCodeFormatterMethodManipulator( @@ -111,10 +133,14 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si } + /** + * {@link MethodVisitor} to make some fields and methods from + * {@code DefaultCodeFormatter} public. + */ private static class DefaultCodeFormatterMethodManipulator extends MethodVisitor { DefaultCodeFormatterMethodManipulator(MethodVisitor mv) { - super(Opcodes.ASM5, mv); + super(Opcodes.ASM9, mv); } @Override @@ -127,4 +153,109 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, } + /** + * {@link ClassVisitor} to update the {@code NLS} class in the JDK 8 version so it + * doesn't use a System property to disable warning messages. + */ + private static class NlsJdk8Manipulator extends ClassVisitor { + + NlsJdk8Manipulator(ClassVisitor visitor) { + super(Opcodes.ASM9, visitor); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if ("run".equals(name) && desc.contains("Boolean")) { + return new NslJdk8MethodManipulator(super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + /** + * {@link MethodVisitor} to update the {@code NLS} class in the JDK 8 version so it + * doesn't use a System property to disable warning messages. + */ + private static class NslJdk8MethodManipulator extends MethodVisitor { + + private final MethodVisitor methodVisitor; + + NslJdk8MethodManipulator(MethodVisitor mv) { + super(Opcodes.ASM9, null); + this.methodVisitor = mv; + } + + @Override + public void visitEnd() { + MethodVisitor mv = this.methodVisitor; + mv.visitCode(); + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;"); + mv.visitInsn(Opcodes.ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + } + + /** + * {@link ClassVisitor} to update the {@code NLS} class in the JDK 8 version so it + * doesn't use a System property to disable warning messages. + */ + private static class NlsJdk17Manipulator extends ClassVisitor { + + NlsJdk17Manipulator(ClassVisitor visitor) { + super(Opcodes.ASM9, visitor); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if ("".equals(name)) { + return new NslJdk17MethodManipulator(super.visitMethod(access, name, desc, signature, exceptions)); + } + return super.visitMethod(access, name, desc, signature, exceptions); + } + + } + + /** + * {@link MethodVisitor} to update the {@code NLS} class in the JDK 8 version so it + * doesn't use a System property to disable warning messages. + */ + private static class NslJdk17MethodManipulator extends MethodVisitor { + + private final MethodVisitor methodVisitor; + + NslJdk17MethodManipulator(MethodVisitor mv) { + super(Opcodes.ASM9, null); + this.methodVisitor = mv; + } + + @Override + public void visitEnd() { + MethodVisitor mv = this.methodVisitor; + mv.visitCode(); + mv.visitInsn(Opcodes.ICONST_0); + mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); + mv.visitFieldInsn(Opcodes.PUTSTATIC, "org/eclipse/osgi/util/NLS", "EMPTY_ARGS", "[Ljava/lang/Object;"); + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); + mv.visitFieldInsn(Opcodes.PUTSTATIC, "org/eclipse/osgi/util/NLS", "ignoreWarnings", "Z"); + mv.visitTypeInsn(Opcodes.NEW, "java/lang/Object"); + mv.visitInsn(Opcodes.DUP); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitFieldInsn(Opcodes.PUTSTATIC, "org/eclipse/osgi/util/NLS", "ASSIGNED", "Ljava/lang/Object;"); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(2, 0); + mv.visitEnd(); + } + + } + + enum JdkVersion { + + V8, V11 + + } + } diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml index b895cc7e..dab30621 100644 --- a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/pom.xml @@ -6,185 +6,79 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-formatter-eclipse-runtime - eclipse-plugin Spring JavaFormat Eclipse Runtime ${basedir}/../.. - org.eclipse.jdt.core.source,org.eclipse.jface.source,org.eclipse.text.source - - - Eclipse Public License, Version 1.0 - https://www.eclipse.org/legal/epl-v10.html - - + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-jdk8 + ${project.version} + true + + org.apache.maven.plugins - maven-antrun-plugin - - - io.spring.javaformat - spring-javaformat-formatter-eclipse-rewriter - ${project.version} - - - ant-contrib - ant-contrib - ${ant-contrib.version} - - - ant - ant - - - - - org.apache.ant - ant-nodeps - ${ant.version} - - + maven-jar-plugin - rewrite-bytecode - package - - run - - - - - - - - - - - repackage-source + empty-javadoc-jar package - run + jar - - - - + javadoc - - org.eclipse.tycho - tycho-packaging-plugin - - false - - - - org.eclipse.tycho - tycho-maven-plugin - - - org.eclipse.tycho - target-platform-configuration - - - org.eclipse.tycho - tycho-versions-plugin - - - update-eclipse-version - initialize - - update-eclipse-metadata - - - - org.apache.maven.plugins - maven-dependency-plugin + maven-source-plugin - unpack-dependencies - - unpack-dependencies - - prepare-package - - ${project.build.outputDirectory} - META-INF/*,**.dll,**.so,**.java - ${sourceartifacts} - - - - unpack-source-dependencies + attach-source + package - unpack-dependencies + jar - prepare-package - - ${project.build.directory}/sources - ${sourceartifacts} - - com.github.wvengen - proguard-maven-plugin + org.apache.maven.plugins + maven-shade-plugin - reduce-eclipse-runtime package - proguard + shade - false - - ${java.home}/lib/rt.jar - ${java.home}/lib/jsse.jar - - - - - - - - - - - - - - + + + io.spring.javaformat:spring-javaformat-formatter-eclipse-jdk8 + + org/eclipse/jdt/** + META-INF/ECLIPSE_.SF + META-INF/ECLIPSE_.RSA + + + + false + true + true - - - io.spring.javaformat - spring-javaformat-formatter-eclipse-rewriter - ${project.version} - provided - - diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/src/main/java/org/eclipse/core/runtime/content/IContentTypeManager$ContentTypeChangeEvent.java b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/src/main/java/org/eclipse/core/runtime/content/IContentTypeManager$ContentTypeChangeEvent.java new file mode 100644 index 00000000..78e9cd52 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/src/main/java/org/eclipse/core/runtime/content/IContentTypeManager$ContentTypeChangeEvent.java @@ -0,0 +1,21 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.eclipse.core.runtime.content; + +public class IContentTypeManager$ContentTypeChangeEvent { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/src/main/java/org/eclipse/core/runtime/content/IContentTypeManager$IContentTypeChangeListener.java b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/src/main/java/org/eclipse/core/runtime/content/IContentTypeManager$IContentTypeChangeListener.java new file mode 100644 index 00000000..6458ef5a --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-eclipse-runtime/src/main/java/org/eclipse/core/runtime/content/IContentTypeManager$IContentTypeChangeListener.java @@ -0,0 +1,23 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.eclipse.core.runtime.content; + +public interface IContentTypeManager$IContentTypeChangeListener { + + void contentTypeChanged(IContentTypeManager$ContentTypeChangeEvent event); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml b/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml index 3df56f10..330f53c9 100644 --- a/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-shaded/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-formatter-shaded Spring JavaFormat Formatter Shaded @@ -80,6 +80,11 @@ + + + ${project.version} + + @@ -94,6 +99,11 @@ + + io.spring.javaformat + spring-javaformat-config + ${project.version} + io.spring.javaformat spring-javaformat-formatter diff --git a/spring-javaformat/spring-javaformat-formatter-shader/pom.xml b/spring-javaformat/spring-javaformat-formatter-shader/pom.xml index 373b7e86..a07cf239 100644 --- a/spring-javaformat/spring-javaformat-formatter-shader/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter-shader/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-formatter-shader Spring JavaFormat Formatter Shader diff --git a/spring-javaformat/spring-javaformat-formatter-shader/src/main/java/io/spring/javaformat/formatter/shader/PrefsResourceTransformer.java b/spring-javaformat/spring-javaformat-formatter-shader/src/main/java/io/spring/javaformat/formatter/shader/PrefsResourceTransformer.java index 47ba9843..09882163 100644 --- a/spring-javaformat/spring-javaformat-formatter-shader/src/main/java/io/spring/javaformat/formatter/shader/PrefsResourceTransformer.java +++ b/spring-javaformat/spring-javaformat-formatter-shader/src/main/java/io/spring/javaformat/formatter/shader/PrefsResourceTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml b/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml new file mode 100644 index 00000000..1f72a67a --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-test-support/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat + 0.0.48-SNAPSHOT + + spring-javaformat-formatter-test-support + Spring JavaFormat Formatter Test Support + + ${basedir}/../.. + + + + + io.spring.javaformat + spring-javaformat-formatter + ${project.version} + + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-runtime + ${project.version} + provided + + + diff --git a/spring-javaformat/spring-javaformat-formatter-test-support/src/main/java/io/spring/javaformat/formatter/FormatterApp.java b/spring-javaformat/spring-javaformat-formatter-test-support/src/main/java/io/spring/javaformat/formatter/FormatterApp.java new file mode 100644 index 00000000..ca679983 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-test-support/src/main/java/io/spring/javaformat/formatter/FormatterApp.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.text.edits.TextEdit; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Test app used to format something in a test container. + * + * @author Phillip Webb + */ +public final class FormatterApp { + + private FormatterApp() { + } + + public static void main(String[] args) throws Exception, BadLocationException { + JavaBaseline javaBaseline = JavaBaseline.valueOf(args[0]); + Formatter formatter = new Formatter(JavaFormatConfig.of(javaBaseline, IndentationStyle.TABS)); + String source = "public class Test {}"; + TextEdit edit = formatter.format(source); + IDocument document = new Document(source); + edit.apply(document); + String formatted = document.get(); + System.out.println(formatted); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/pom.xml b/spring-javaformat/spring-javaformat-formatter-tests/pom.xml new file mode 100644 index 00000000..30ea6a7e --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + io.spring.javaformat + spring-javaformat + 0.0.48-SNAPSHOT + + spring-javaformat-formatter-tests + Spring JavaFormat Formatter Tests + + ${basedir}/../.. + 17 + + + + + io.spring.javaformat + spring-javaformat-formatter + ${project.version} + + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-runtime + ${project.version} + provided + + + + io.spring.javaformat + spring-javaformat-formatter-test-support + ${project.version} + test + + + org.apache.logging.log4j + log4j-api + test + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.testcontainers + testcontainers + test + + + org.testcontainers + junit-jupiter + test + + + diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java new file mode 100644 index 00000000..1af21b70 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java @@ -0,0 +1,167 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Base class for formatter tests. + * + * @author Phillip Webb + */ +public abstract class AbstractFormatterTests { + + protected final void print(String name, String content) { + System.out.println(name + ":"); + System.out.println(); + System.out.println("----------------------------------------"); + System.out.println(content); + System.out.println("----------------------------------------"); + System.out.println(); + System.out.println(); + } + + protected final String read(File file) throws Exception { + return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + } + + protected static Item[] items(String expectedOverride) { + List items = new ArrayList<>(); + File sourceDir = new File("src/test/resources/source"); + File expectedDir = new File("src/test/resources/expected"); + File configDir = new File("src/test/resources/config"); + File expectedOverrideDir = new File("src/test/resources/" + expectedOverride); + for (File source : sourceDir.listFiles((dir, name) -> !name.startsWith("."))) { + File config = new File(configDir, source.getName()); + for (JavaBaseline javaBaseline : JavaBaseline.values()) { + File expected = getExpected(source, javaBaseline, expectedOverrideDir, expectedDir); + addItem(items, javaBaseline, source, expected, config); + } + } + items.sort(Comparator.comparing(Item::getName)); + return items.toArray(new Item[0]); + } + + private static File getExpected(File source, JavaBaseline javaBaseline, File... expectedDirs) { + for (File expectedDir : expectedDirs) { + File versionSpecificExpectedDir = new File(expectedDir, javaBaseline.toString().toLowerCase()); + File expected = new File(versionSpecificExpectedDir, source.getName()); + expected = (!expected.exists()) ? new File(expectedDir, source.getName()) : expected; + if (expected.exists()) { + return expected; + } + } + throw new IllegalStateException("Unable to find expected file"); + } + + private static void addItem(List items, JavaBaseline javaBaseline, File source, File expected, File config) { + if (source.getName().contains("lineendings")) { + items.add(new Item(javaBaseline, copy(source, LineEnding.CR), copy(expected, LineEnding.CR), config)); + items.add(new Item(javaBaseline, copy(source, LineEnding.LF), copy(expected, LineEnding.LF), config)); + items.add(new Item(javaBaseline, copy(source, LineEnding.CRLF), copy(expected, LineEnding.CRLF), config)); + } + else { + items.add(new Item(javaBaseline, source, expected, config)); + } + } + + private static File copy(File file, LineEnding lineEnding) { + try { + String[] name = file.getName().split("\\."); + File result = File.createTempFile(name[0] + "_" + lineEnding + "_", "." + name[1]); + String content = Files.readString(file.toPath()); + content = content.replace("\r\n", "\n").replace('\r', '\n').replace("\n", lineEnding.ending()); + Files.writeString(result.toPath(), content); + return result; + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + enum LineEnding { + + CR("\r"), LF("\n"), CRLF("\r\n"); + + private final String ending; + + LineEnding(String ending) { + this.ending = ending; + } + + String ending() { + return this.ending; + } + + }; + + static class Item { + + private final JavaBaseline javaBaseline; + + private final File source; + + private final File expected; + + private final JavaFormatConfig config; + + Item(JavaBaseline javaBaseline, File source, File expected, File config) { + this.javaBaseline = javaBaseline; + this.source = source; + this.expected = expected; + this.config = loadConfig(javaBaseline, config); + } + + private JavaFormatConfig loadConfig(JavaBaseline javaBaseline, File configFile) { + JavaFormatConfig config = (!configFile.exists()) ? JavaFormatConfig.DEFAULT + : JavaFormatConfig.load(configFile); + return JavaFormatConfig.of(javaBaseline, config.getIndentationStyle()); + } + + String getName() { + return this.source.getName(); + } + + public File getSource() { + return this.source; + } + + public File getExpected() { + return this.expected; + } + + public JavaFormatConfig getConfig() { + return this.config; + } + + @Override + public String toString() { + return this.javaBaseline + " " + this.source.getName(); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FileEditTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FileEditTests.java similarity index 77% rename from spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FileEditTests.java rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FileEditTests.java index 872af875..015b9eb7 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FileEditTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FileEditTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,10 +24,9 @@ import java.nio.file.StandardCopyOption; import org.eclipse.text.edits.TextEdit; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; @@ -40,8 +39,8 @@ public class FileEditTests { private static final Charset UTF_8 = StandardCharsets.UTF_8; - @Rule - public TemporaryFolder temp = new TemporaryFolder(); + @TempDir + public File temp; private File source; @@ -51,10 +50,10 @@ public class FileEditTests { private FileEdit fileEdit; - @Before - public void setup() throws IOException { - this.source = this.temp.newFile("source.txt"); - this.expected = this.temp.newFile("expected.txt"); + @BeforeEach + void setup() throws IOException { + this.source = new File(this.temp, "source.txt"); + this.expected = new File(this.temp, "expected.txt"); Files.copy(new File("src/test/resources/source/javadoc-top.txt").toPath(), this.source.toPath(), StandardCopyOption.REPLACE_EXISTING); Files.copy(new File("src/test/resources/expected/javadoc-top.txt").toPath(), this.expected.toPath(), @@ -65,17 +64,17 @@ public void setup() throws IOException { } @Test - public void getFileShouldReturnFile() throws Exception { + void getFileReturnsFile() throws Exception { assertThat(this.fileEdit.getFile()).isEqualTo(this.source); } @Test - public void hasEditsWhenHasEditsShouldReturnTrue() throws Exception { + void hasEditsWhenHasEditsReturnsTrue() throws Exception { assertThat(this.fileEdit.hasEdits()).isTrue(); } @Test - public void hasEditsWhenHasNoEditsShouldReturnFalse() throws Exception { + void hasEditsWhenHasNoEditsReturnsFalse() throws Exception { String content = read(this.expected); this.textEdit = new Formatter().format(content); this.fileEdit = new FileEdit(this.source, UTF_8, content, this.textEdit); @@ -83,7 +82,7 @@ public void hasEditsWhenHasNoEditsShouldReturnFalse() throws Exception { } @Test - public void saveShouldSaveContent() throws Exception { + void saveSavesContent() throws Exception { String expected = read(this.expected); assertThat(read(this.source)).isNotEqualTo(expected); this.fileEdit.save(); @@ -91,7 +90,7 @@ public void saveShouldSaveContent() throws Exception { } @Test - public void getFormattedContentShouldReturnFormattedContent() throws Exception { + void getFormattedContentReturnsFormattedContent() throws Exception { String expected = read(this.expected); assertThat(this.fileEdit.getFormattedContent()).isEqualTo(expected); } diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FileFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FileFormatterTests.java similarity index 52% rename from spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FileFormatterTests.java rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FileFormatterTests.java index 21d30df1..f9d14f7c 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FileFormatterTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FileFormatterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,14 @@ import java.io.File; import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.Collection; -import org.junit.Test; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for FileFormatter. + * Tests for {@link FileFormatter}. * * @author Phillip Webb */ @@ -35,30 +34,33 @@ public class FileFormatterTests extends AbstractFormatterTests { private static final boolean RUNNING_ON_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win"); - public FileFormatterTests(File source, File expected) { - super(source, expected); + @ParameterizedTest + @MethodSource("items") + void formatFilesFromIteratorFormatsFile(Item item) throws Exception { + FileEdit edit = new FileFormatter(item.getConfig()) + .formatFiles(Arrays.asList(item.getSource()), StandardCharsets.UTF_8) + .findFirst() + .get(); + assertThat(edit.getFormattedContent()).isEqualTo(read(item.getExpected())); } - @Test - public void formatFilesFromIteratorShouldFormatFile() throws Exception { - FileEdit edit = new FileFormatter().formatFiles(Arrays.asList(getSource()), StandardCharsets.UTF_8).findFirst() - .get(); - assertThat(edit.getFormattedContent()).isEqualTo(read(getExpected())); + @ParameterizedTest + @MethodSource("items") + void formatFilesFromStreamFormatsFile(Item item) throws Exception { + FileEdit edit = new FileFormatter(item.getConfig()) + .formatFiles(Arrays.asList(item.getSource()).stream(), StandardCharsets.UTF_8) + .findFirst() + .get(); + assertThat(edit.getFormattedContent()).isEqualTo(read(item.getExpected())); } - @Test - public void formatFilesFromStreamShouldFormatFile() throws Exception { - FileEdit edit = new FileFormatter().formatFiles(Arrays.asList(getSource()).stream(), StandardCharsets.UTF_8) - .findFirst().get(); - assertThat(edit.getFormattedContent()).isEqualTo(read(getExpected())); - } - - @Test - public void formatFileShouldFormatFile() throws Exception { - File source = getSource(); - FileEdit edit = new FileFormatter().formatFile(source, StandardCharsets.UTF_8); + @ParameterizedTest + @MethodSource("items") + void formatFileFormatsFile(Item item) throws Exception { + File source = item.getSource(); + FileEdit edit = new FileFormatter(item.getConfig()).formatFile(source, StandardCharsets.UTF_8); String formattedContent = edit.getFormattedContent(); - String expected = read(getExpected()); + String expected = read(item.getExpected()); if (!RUNNING_ON_WINDOWS) { System.out.println(source); System.out.println("----- got"); @@ -70,9 +72,8 @@ public void formatFileShouldFormatFile() throws Exception { assertThat(formattedContent).isEqualTo(expected); } - @Parameters(name = "{0}") - public static Collection files() { - return AbstractFormatterTests.files(null); + static Item[] items() { + return items(null); } } diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java new file mode 100644 index 00000000..383b07cd --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterIntegrationTests.java @@ -0,0 +1,130 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.output.ToStringConsumer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.MountableFile; + +import io.spring.javaformat.config.JavaBaseline; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Tests to ensure the formatter can run in different JVM versions. + * + * @author Phillip Webb + */ +@Testcontainers(disabledWithoutDocker = true) +public class FormatterIntegrationTests { + + @ParameterizedTest + @ValueSource(strings = { "8", "11", "17" }) + void formatCodeWithV8BaselineCanFormatOnAllVersions(String version) throws Exception { + runFormatter(JavaBaseline.V8, version); + } + + @ParameterizedTest + @ValueSource(strings = { "17" }) + void formatCodeWithV11BaselineCanFormatOn11OrHigher(String version) throws Exception { + runFormatter(JavaBaseline.V17, version); + } + + @ParameterizedTest + @ValueSource(strings = "8") + void formatCodeWithV11BaselineCannotFormatOn8(String version) throws Exception { + assertThatExceptionOfType(ContainerLaunchException.class) + .isThrownBy(() -> runFormatter(JavaBaseline.V17, version)); + } + + private void runFormatter(JavaBaseline baseline, String version) throws IOException, Exception { + try (JavaContainer container = new JavaContainer(version)) { + ToStringConsumer output = new ToStringConsumer(); + container.withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(5))); + container.withLogConsumer(output); + String classpath = withCopyClasspathToContainer(container); + container.withCommand( + "java -cp " + classpath + " " + "io.spring.javaformat.formatter.FormatterApp" + " " + baseline); + container.start(); + assertThat(output.toUtf8String()).isEqualTo("public class Test {\n\n}\n"); + } + } + + private String withCopyClasspathToContainer(JavaContainer container) throws IOException { + List classpath = new ArrayList<>(); + for (String entry : System.getProperty("java.class.path").split(File.pathSeparator)) { + if (entry.contains("spring-javaformat")) { + String classpathEntry = withCopyClasspathEntryToContainer(container, entry); + if (classpathEntry != null) { + classpath.add(classpathEntry); + } + } + } + return classpath.stream().collect(Collectors.joining(":")); + } + + private String withCopyClasspathEntryToContainer(JavaContainer container, String entry) throws IOException { + if (entry.endsWith(".jar")) { + return withCopyClasspathJarToContainer(container, new File(entry)); + } + return withCopyClasspathFolderToContainer(container, new File(entry)); + } + + private String withCopyClasspathJarToContainer(JavaContainer container, File jarFile) { + container.withCopyFileToContainer(MountableFile.forHostPath(jarFile.toPath()), "/app/" + jarFile.getName()); + return "/app/" + jarFile.getName(); + } + + private String withCopyClasspathFolderToContainer(JavaContainer container, File classesFolder) throws IOException { + String name = classesFolder.getName(); + Path source = classesFolder.toPath(); + if (!Files.exists(source)) { + return null; + } + try (Stream stream = Files.walk(source)) { + stream.forEach((child) -> { + try { + Path relative = source.relativize(child); + if (!child.toFile().isDirectory()) { + String containerPath = "/app/" + name + "/" + relative; + container.withCopyFileToContainer(MountableFile.forHostPath(child), containerPath); + } + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + }); + } + return "/app/" + name; + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterTests.java similarity index 52% rename from spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FormatterTests.java rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterTests.java index 1f64f02c..cc1c8b50 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/FormatterTests.java +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/FormatterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,13 @@ package io.spring.javaformat.formatter; -import java.io.File; -import java.util.Collection; - import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; -import org.junit.Test; -import org.junit.runners.Parameterized.Parameters; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import io.spring.javaformat.config.JavaFormatConfig; import static org.assertj.core.api.Assertions.assertThat; @@ -32,36 +31,32 @@ */ public class FormatterTests extends AbstractFormatterTests { - public FormatterTests(File source, File expected) { - super(source, expected); - } - - @Test - public void format() throws Exception { - String sourceContent = read(getSource()); - String expectedContent = read(getExpected()); - String formattedContent = format(sourceContent); + @ParameterizedTest + @MethodSource("items") + void format(Item item) throws Exception { + String sourceContent = read(item.getSource()); + String expectedContent = read(item.getExpected()); + String formattedContent = format(item.getConfig(), sourceContent); if (!expectedContent.equals(formattedContent)) { - System.out.println("Formatted " + getSource() + " does not match " + getExpected()); - print("Source " + getSource(), sourceContent); - print("Expected +" + getExpected(), expectedContent); + System.out.println("Formatted " + item.getSource() + " does not match " + item.getExpected()); + print("Source " + item.getSource(), sourceContent); + print("Expected +" + item.getExpected(), expectedContent); print("Got", formattedContent); System.out.println("========================================"); - assertThat(expectedContent).isEqualTo(formattedContent) - .describedAs("Formatted content does not match for " + getSource()); + assertThat(formattedContent).isEqualTo(expectedContent) + .describedAs("Formatted content does not match for " + item.getSource()); } } - private String format(String sourceContent) throws Exception { + private String format(JavaFormatConfig config, String sourceContent) throws Exception { IDocument document = new Document(sourceContent); - TextEdit textEdit = new Formatter().format(sourceContent); + TextEdit textEdit = new Formatter(config).format(sourceContent); textEdit.apply(document); return document.get(); } - @Parameters(name = "{0}") - public static Collection files() { - return AbstractFormatterTests.files("FormatterTests-expected"); + static Item[] items() { + return items("FormatterTests-expected"); } } diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/JavaContainer.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/JavaContainer.java new file mode 100644 index 00000000..8f847bbb --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/JavaContainer.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import org.testcontainers.containers.GenericContainer; + +/** + * {@link GenericContainer} for Java. + * + * @author Phillip Webb + */ +public class JavaContainer extends GenericContainer { + + JavaContainer(String version) { + super("bellsoft/liberica-openjdk-debian:" + version); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/StreamsEditTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/StreamsEditTests.java new file mode 100644 index 00000000..b054f57d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/StreamsEditTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +import org.eclipse.text.edits.TextEdit; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link StreamsEdit}. + * + * @author Phillip Webb + */ +public class StreamsEditTests { + + private static final Charset UTF_8 = StandardCharsets.UTF_8; + + @TempDir + public File temp; + + private File source; + + private File expected; + + private TextEdit textEdit; + + private StreamsEdit streamsEdit; + + @BeforeEach + void setup() throws IOException { + this.source = new File(this.temp, "source.txt"); + this.expected = new File(this.temp, "expected.txt"); + Files.copy(new File("src/test/resources/source/javadoc-top.txt").toPath(), this.source.toPath(), + StandardCopyOption.REPLACE_EXISTING); + Files.copy(new File("src/test/resources/expected/javadoc-top.txt").toPath(), this.expected.toPath(), + StandardCopyOption.REPLACE_EXISTING); + String content = read(this.source); + this.textEdit = new Formatter().format(content); + this.streamsEdit = new StreamsEdit(content, this.textEdit); + } + + @Test + void hasEditsWhenHasEditsReturnsTrue() throws Exception { + assertThat(this.streamsEdit.hasEdits()).isTrue(); + } + + @Test + void hasEditsWhenHasNoEditsReturnsFalse() throws Exception { + String content = read(this.expected); + this.textEdit = new Formatter().format(content); + this.streamsEdit = new StreamsEdit(content, this.textEdit); + assertThat(this.streamsEdit.hasEdits()).isFalse(); + } + + @Test + void writeToOutputStreamWritesContent() throws Exception { + String expected = read(this.expected); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + this.streamsEdit.writeTo(outputStream); + assertThat(outputStream.toByteArray()).isEqualTo(expected.getBytes(UTF_8)); + } + + @Test + void writeToOutputStreamWithCharsetWritesContent() throws IOException { + String expected = read(this.expected); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + this.streamsEdit.writeTo(outputStream, UTF_8); + assertThat(outputStream.toByteArray()).isEqualTo(expected.getBytes(UTF_8)); + } + + @Test + void writeToAppendableWritesContent() throws IOException { + String expected = read(this.expected); + StringBuilder output = new StringBuilder(); + this.streamsEdit.writeTo(output); + assertThat(output.toString()).isEqualTo(expected); + } + + @Test + void getFormattedContentReturnsFormattedContent() throws Exception { + String expected = read(this.expected); + assertThat(this.streamsEdit.getFormattedContent()).isEqualTo(expected); + } + + private String read(File file) throws IOException { + return new String(Files.readAllBytes(file.toPath()), UTF_8); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/StreamsFormatterTests.java b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/StreamsFormatterTests.java new file mode 100644 index 00000000..388c123c --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/java/io/spring/javaformat/formatter/StreamsFormatterTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link StreamsFormatter}. + * + * @author Phillip Webb + */ +public class StreamsFormatterTests extends AbstractFormatterTests { + + @ParameterizedTest + @MethodSource("items") + void formatInputStreamFormatsFile(Item item) throws Exception { + try (InputStream inputStream = new FileInputStream(item.getSource())) { + StreamsEdit edit = new StreamsFormatter(item.getConfig()).format(inputStream); + assertThat(edit.getFormattedContent()).isEqualTo(read(item.getExpected())); + } + } + + @ParameterizedTest + @MethodSource("items") + void formatInputStreamWithCharsetFormatsFile(Item item) throws Exception { + try (InputStream inputStream = new FileInputStream(item.getSource())) { + StreamsEdit edit = new StreamsFormatter(item.getConfig()).format(inputStream, StandardCharsets.UTF_8); + assertThat(edit.getFormattedContent()).isEqualTo(read(item.getExpected())); + } + } + + @ParameterizedTest + @MethodSource("items") + void formatReaderFormatsFile(Item item) throws Exception { + try (Reader reader = new InputStreamReader(new FileInputStream(item.getSource()))) { + StreamsEdit edit = new StreamsFormatter(item.getConfig()).format(reader); + assertThat(edit.getFormattedContent()).isEqualTo(read(item.getExpected())); + } + } + + static Item[] items() { + return items(null); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/FormatterTests-expected/javadoc-top-add.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/javadoc-top-add.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/FormatterTests-expected/javadoc-top-add.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/javadoc-top-add.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/record-with-param.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/record-with-param.txt new file mode 100644 index 00000000..57e16f3c --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/record-with-param.txt @@ -0,0 +1,16 @@ +package simple; + +/** + * Settings that can be applied when creating a {@link ClientHttpRequestFactory}. + * + * @param connectTimeout the connect timeout + * @param readTimeout the read timeout + * @param bufferRequestBody if request body buffering is used + * @author Andy Wilkinson + * @author Phillip Webb + * @since 3.0.0 + * @see ClientHttpRequestFactories + */ +public record Simple(String name) { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/simple.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/simple.txt new file mode 100644 index 00000000..63ca9a5c --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/FormatterTests-expected/simple.txt @@ -0,0 +1,15 @@ +package simple; + +/** + * Simple. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public class Simple { + + public static void main(String[] args) throws Exception { + // FIXME + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/config/spaces.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/config/spaces.txt new file mode 100644 index 00000000..2588c596 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/config/spaces.txt @@ -0,0 +1 @@ +indentation-style=spaces \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/annotation-attributes.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/annotation-attributes.txt new file mode 100644 index 00000000..7dc4da2d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/annotation-attributes.txt @@ -0,0 +1,15 @@ +class MyTest { + + @SpringBootTest(properties = "spring.main.web-application-type=reactive", classes = { + WebTestClientSpringBootTestIntegrationTests.TestConfiguration.class, ExampleWebFluxApplication.class }) + static class One { + + } + + @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.jersey.type=filter", + "server.servlet.context-path=/app", "server.servlet.register-default-servlet=true" }) + static class Two { + + } + +} \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex-annotation-gh-78.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex-annotation-gh-78.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex-annotation-gh-78.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex-annotation-gh-78.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex-annotation.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex-annotation.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex-annotation.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex-annotation.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex.txt similarity index 99% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex.txt index d451eb1c..a874b5bd 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/complex.txt +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/complex.txt @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -557,8 +557,8 @@ public class SpringApplication { */ protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.beanNameGenerator != null) { - context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, - this.beanNameGenerator); + context.getBeanFactory() + .registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/enum-constructor.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/enum-constructor.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/enum-constructor.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/enum-constructor.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/enum-with-many-uncommented-values.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/enum-with-many-uncommented-values.txt new file mode 100644 index 00000000..b92ba57c --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/enum-with-many-uncommented-values.txt @@ -0,0 +1,18 @@ +package io.spring.javaformat.formatter; + +public enum EnumWithManyUncommentedValues { + + ONE("Long text value to force formatting of the enum's values across multiple lines"), + TWO("Long text value to force formatting of the enum's values across multiple lines"), + THREE("Long text value to force formatting of the enum's values across multiple lines"), + FOUR("Long text value to force formatting of the enum's values across multiple lines"), + FIVE("Long text value to force formatting of the enum's values across multiple lines"), + SIX("Long text value to force formatting of the enum's values across multiple lines"); + + private String text; + + EnumWithManyUncommentedValues(String text) { + this.text = text; + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/generics.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/generics.txt new file mode 100644 index 00000000..4c3055e0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/generics.txt @@ -0,0 +1,8 @@ +package simple; + +/** + * gh-363. + */ +class SpectatorToDoubleGauge extends AbstractMeter implements Gauge { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/generics2.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/generics2.txt new file mode 100644 index 00000000..da493d53 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/generics2.txt @@ -0,0 +1,8 @@ +package simple; + +/** + * gh-363. + */ +public class UnresolvedGenericProperties extends AbstractGenericProperties { + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-nested.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-nested.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-nested.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-nested.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-param.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-param.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-param.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-param.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-top-add.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-top-add.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-top-add.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-top-add.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-top-empty.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-top-empty.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-top-empty.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-top-empty.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-top.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-top.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/javadoc-top.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-top.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-with-format-off.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-with-format-off.txt new file mode 100644 index 00000000..157ea11b --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/javadoc-with-format-off.txt @@ -0,0 +1,8 @@ +/** + * This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. + * @formatter:off + * @formatter:on + */ +public class Format { + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-classbraces.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-classbraces.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-classbraces.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-classbraces.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-fields-comment-above.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-fields-comment-above.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-fields-comment-above.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-fields-comment-above.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-fields-comments.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-fields-comments.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-fields-comments.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-fields-comments.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-fields.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-fields.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-fields.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-fields.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-interface.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-interface.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-interface.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-interface.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-trailing.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-trailing.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/linebreak-trailing.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/linebreak-trailing.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt new file mode 100644 index 00000000..92ad853f --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/lineendings.txt @@ -0,0 +1,8 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/method-wrap.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/method-wrap.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/method-wrap.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/method-wrap.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/multi-line-statement-indentation.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/multi-line-statement-indentation.txt new file mode 100644 index 00000000..a7946a65 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/multi-line-statement-indentation.txt @@ -0,0 +1,20 @@ +package simple; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class Simple { + + public String someMethod() throws MalformedURLException, IOException { + String settingsXml = new String(Files.readAllBytes(Paths.get("src", "intTest", "projects", "settings.xml")), + StandardCharsets.UTF_8) + .replace("@localCentralUrl@", new File("build/int-test-maven-repository").toURI().toURL().toString()) + .replace("@localRepositoryPath@", new File("build/local-maven-repository").getAbsolutePath()); + return settingsXml; + } + +} \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt new file mode 100644 index 00000000..dbdb1f45 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-not-jspecify.txt @@ -0,0 +1,23 @@ +package example; + +import com.example.Nullable; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override + @Nullable + String myMethod(String param); + + @Override + public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, + @Nullable String @Nullable... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt new file mode 100644 index 00000000..053cbc13 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable-wildcard-import.txt @@ -0,0 +1,22 @@ +package example; + +import org.jspecify.annotations.*; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override + @Nullable String myMethod(String param); + + @Override + public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, + @Nullable String @Nullable ... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt new file mode 100644 index 00000000..aa859a6e --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/nullable.txt @@ -0,0 +1,50 @@ +package example; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override + @Nullable String myMethod(String param); + + @Override + public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, + @Nullable String @Nullable ... varargs); + + default Object inBody() { + @Nullable Object[] args = new Object[length]; + @Nullable List<@Nullable Object> list = new Object[length]; + Object @Nullable [] moreArgs = new Object[length]; + return args; + } + + @NullMarked + void withNullMarked(String str); + + @NullUnmarked + void withNullUnmarked(String str); + + static class Fields { + + @Nullable Object one; + + @NonNull Object two; + + private @Nullable Object three; + + private @NonNull Object four; + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/record-with-param.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/record-with-param.txt new file mode 100644 index 00000000..164c5351 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/record-with-param.txt @@ -0,0 +1,16 @@ +package simple; + +/** + * Settings that can be applied when creating a {@link ClientHttpRequestFactory}. + * + * @param connectTimeout the connect timeout + * @param readTimeout the read timeout + * @param bufferRequestBody if request body buffering is used + * @author Andy Wilkinson + * @author Phillip Webb + * @since 3.0.0 + * @see ClientHttpRequestFactories + */ +public record Simple(String name) { + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/simple.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/simple.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/simple.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/simple.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/spaces.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/spaces.txt new file mode 100644 index 00000000..f2133b38 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/spaces.txt @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.context.TypeExcludeFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.annotation.AliasFor; + +/** + * Indicates a {@link Configuration configuration} class that declares one or more + * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration + * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience + * annotation that is equivalent to declaring {@code @Configuration}, + * {@code @EnableAutoConfiguration} and {@code @ComponentScan}. + * + * @author Phillip Webb + * @author Stephane Nicoll + * @since 1.2.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@SpringBootConfiguration +@EnableAutoConfiguration +@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)) +public @interface SpringBootApplication { + + /** + * Exclude specific auto-configuration classes such that they will never be applied. + * @return the classes to exclude + */ + Class[] exclude() default {}; + + /** + * Exclude specific auto-configuration class names such that they will never be + * applied. + * @return the class names to exclude + * @since 1.3.0 + */ + String[] excludeName() default {}; + + /** + * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses} + * for a type-safe alternative to String-based package names. + * @return base packages to scan + * @since 1.3.0 + */ + @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") + String[] scanBasePackages() default {}; + + /** + * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to + * scan for annotated components. The package of each class specified will be scanned. + *

+ * Consider creating a special no-op marker class or interface in each package that + * serves no purpose other than being referenced by this attribute. + * @return base packages to scan + * @since 1.3.0 + */ + @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") + Class[] scanBasePackageClasses() default {}; + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/static-initializer.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/static-initializer.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/static-initializer.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/static-initializer.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/switch.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/switch.txt new file mode 100644 index 00000000..87ae995d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/switch.txt @@ -0,0 +1,14 @@ +public class SwitchExample { + + protected boolean isIncludeBindingErrors(HttpServletRequest request, MediaType produces) { + switch (getErrorProperties().getIncludeBindingErrors()) { + case ALWAYS: + return true; + case ON_PARAM: + return getErrorsParameter(request); + default: + return false; + } + } + +} \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/typical.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/typical.txt similarity index 98% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/typical.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/typical.txt index b88780c1..e370bf0e 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/resources/expected/typical.txt +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/typical.txt @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v17/record-with-generic.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v17/record-with-generic.txt new file mode 100644 index 00000000..45528043 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v17/record-with-generic.txt @@ -0,0 +1,11 @@ +package simple; + +/** + * Record with generic. + * + * @author Andy Wilkinson + * @since 1.0.0 + */ +public record SomeRecord(T item) { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v8/record-with-generic.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v8/record-with-generic.txt new file mode 100644 index 00000000..d31ccb47 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/expected/v8/record-with-generic.txt @@ -0,0 +1,11 @@ +package simple; + +/** + * Record with generic. + * + * @author Andy Wilkinson + * @since 1.0.0 + */ +public record SomeRecord (T item) { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/annotation-attributes.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/annotation-attributes.txt new file mode 100644 index 00000000..19ae7f4d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/annotation-attributes.txt @@ -0,0 +1,9 @@ +class MyTest { + + @SpringBootTest(properties = "spring.main.web-application-type=reactive", classes = { WebTestClientSpringBootTestIntegrationTests.TestConfiguration.class, ExampleWebFluxApplication.class }) + static class One {} + + @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.jersey.type=filter", "server.servlet.context-path=/app", "server.servlet.register-default-servlet=true" }) + static class Two {} + +} \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex-annotation-gh-78.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex-annotation-gh-78.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex-annotation-gh-78.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex-annotation-gh-78.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex-annotation.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex-annotation.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex-annotation.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex-annotation.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex.txt similarity index 99% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex.txt index b8b50b19..936faa1b 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/complex.txt +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/complex.txt @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/enum-constructor.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/enum-constructor.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/enum-constructor.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/enum-constructor.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/enum-with-many-uncommented-values.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/enum-with-many-uncommented-values.txt new file mode 100644 index 00000000..b92ba57c --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/enum-with-many-uncommented-values.txt @@ -0,0 +1,18 @@ +package io.spring.javaformat.formatter; + +public enum EnumWithManyUncommentedValues { + + ONE("Long text value to force formatting of the enum's values across multiple lines"), + TWO("Long text value to force formatting of the enum's values across multiple lines"), + THREE("Long text value to force formatting of the enum's values across multiple lines"), + FOUR("Long text value to force formatting of the enum's values across multiple lines"), + FIVE("Long text value to force formatting of the enum's values across multiple lines"), + SIX("Long text value to force formatting of the enum's values across multiple lines"); + + private String text; + + EnumWithManyUncommentedValues(String text) { + this.text = text; + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/generics.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/generics.txt new file mode 100644 index 00000000..4c3055e0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/generics.txt @@ -0,0 +1,8 @@ +package simple; + +/** + * gh-363. + */ +class SpectatorToDoubleGauge extends AbstractMeter implements Gauge { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/generics2.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/generics2.txt new file mode 100644 index 00000000..da493d53 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/generics2.txt @@ -0,0 +1,8 @@ +package simple; + +/** + * gh-363. + */ +public class UnresolvedGenericProperties extends AbstractGenericProperties { + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-nested.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-nested.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-nested.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-nested.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-param.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-param.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-param.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-param.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-top-add.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-top-add.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-top-add.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-top-add.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-top-empty.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-top-empty.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-top-empty.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-top-empty.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-top.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-top.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/javadoc-top.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-top.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-with-format-off.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-with-format-off.txt new file mode 100644 index 00000000..dbfef5c0 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/javadoc-with-format-off.txt @@ -0,0 +1,7 @@ +/** + * This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. This is a test. + * @formatter:off + * @formatter:on + */ +public class Format { +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-classbraces.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-classbraces.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-classbraces.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-classbraces.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-fields-comment-above.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-fields-comment-above.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-fields-comment-above.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-fields-comment-above.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-fields-comments.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-fields-comments.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-fields-comments.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-fields-comments.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-fields.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-fields.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-fields.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-fields.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-interface.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-interface.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-interface.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-interface.txt diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-trailing.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-trailing.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/linebreak-trailing.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/linebreak-trailing.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt new file mode 100644 index 00000000..e56b3941 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/lineendings.txt @@ -0,0 +1,7 @@ +package correct; + +public class CorrectLf { + + public static void main(String[] args) throws Exception { } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/method-wrap.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/method-wrap.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/method-wrap.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/method-wrap.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/multi-line-statement-indentation.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/multi-line-statement-indentation.txt new file mode 100644 index 00000000..7c63370c --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/multi-line-statement-indentation.txt @@ -0,0 +1,21 @@ +package simple; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class Simple { + + public String someMethod() throws MalformedURLException, IOException { + String settingsXml = new String(Files.readAllBytes(Paths.get("src", "intTest", "projects", "settings.xml")), + StandardCharsets.UTF_8) + .replace("@localCentralUrl@", + new File("build/int-test-maven-repository").toURI().toURL().toString()) + .replace("@localRepositoryPath@", new File("build/local-maven-repository").getAbsolutePath()); + return settingsXml; + } + +} \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt new file mode 100644 index 00000000..011a2189 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-not-jspecify.txt @@ -0,0 +1,20 @@ +package example; + +import com.example.Nullable; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override @Nullable String myMethod(String param); + + @Override public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable + String @Nullable ... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt new file mode 100644 index 00000000..11c65198 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable-wildcard-import.txt @@ -0,0 +1,20 @@ +package example; + +import org.jspecify.annotations.*; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override @Nullable String myMethod(String param); + + @Override public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable + String @Nullable ... varargs); + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt new file mode 100644 index 00000000..45c9c0da --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/nullable.txt @@ -0,0 +1,48 @@ +package example; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; + +/** + * Nullable. + * + * @author Phillip Webb + * @since 1.0.0 + */ +public interface ExampleNullables { + + @Override @Nullable String myMethod(String param); + + @Override public @Nullable String myPublicMethod(String param); + + Object myArrayMethod(@Nullable String string, @Nullable String @Nullable [] array, @Nullable + String @Nullable ... varargs); + + default Object inBody() { + @Nullable Object[] args = new Object[length]; + @Nullable List<@Nullable Object> list = new Object[length]; + Object @Nullable [] moreArgs = new Object[length]; + return args; + } + + @NullMarked + void withNullMarked(String str); + + @NullUnmarked + void withNullUnmarked(String str); + + static class Fields { + + @Nullable Object one; + + @NonNull Object two; + + private @Nullable Object three; + + private @NonNull Object four; + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/record-with-generic.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/record-with-generic.txt new file mode 100644 index 00000000..5a608dfe --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/record-with-generic.txt @@ -0,0 +1,11 @@ +package simple; + +/** + * Record with generic. + * + * @author Andy Wilkinson + * @since 1.0.0 + */ +public record SomeRecord ( T item) { + +} diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/record-with-param.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/record-with-param.txt new file mode 100644 index 00000000..37149688 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/record-with-param.txt @@ -0,0 +1,15 @@ +package simple; + +/** + * Settings that can be applied when creating a {@link ClientHttpRequestFactory}. + * @param connectTimeout the connect timeout + * @param readTimeout the read timeout + * @param bufferRequestBody if request body buffering is used + * @author Andy Wilkinson + * @author Phillip Webb + * @since 3.0.0 + * @see ClientHttpRequestFactories + */ + public record Simple(String name) { + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/simple.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/simple.txt similarity index 98% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/simple.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/simple.txt index a12ac39e..62d2a493 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/simple.txt +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/simple.txt @@ -2,7 +2,6 @@ package simple; /** * Simple. - * * @author Phillip Webb * @since 1.0.0 */ diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/spaces.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/spaces.txt new file mode 100644 index 00000000..e370bf0e --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/spaces.txt @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.context.TypeExcludeFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.annotation.AliasFor; + +/** + * Indicates a {@link Configuration configuration} class that declares one or more + * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration + * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience + * annotation that is equivalent to declaring {@code @Configuration}, + * {@code @EnableAutoConfiguration} and {@code @ComponentScan}. + * + * @author Phillip Webb + * @author Stephane Nicoll + * @since 1.2.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@SpringBootConfiguration +@EnableAutoConfiguration +@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)) +public @interface SpringBootApplication { + + /** + * Exclude specific auto-configuration classes such that they will never be applied. + * @return the classes to exclude + */ + Class[] exclude() default {}; + + /** + * Exclude specific auto-configuration class names such that they will never be + * applied. + * @return the class names to exclude + * @since 1.3.0 + */ + String[] excludeName() default {}; + + /** + * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses} + * for a type-safe alternative to String-based package names. + * @return base packages to scan + * @since 1.3.0 + */ + @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") + String[] scanBasePackages() default {}; + + /** + * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to + * scan for annotated components. The package of each class specified will be scanned. + *

+ * Consider creating a special no-op marker class or interface in each package that + * serves no purpose other than being referenced by this attribute. + * @return base packages to scan + * @since 1.3.0 + */ + @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") + Class[] scanBasePackageClasses() default {}; + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/static-initializer.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/static-initializer.txt similarity index 100% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/static-initializer.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/static-initializer.txt diff --git a/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/switch.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/switch.txt new file mode 100644 index 00000000..2f58321f --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/switch.txt @@ -0,0 +1,12 @@ +public class SwitchExample { + protected boolean isIncludeBindingErrors(HttpServletRequest request, MediaType produces) { + switch (getErrorProperties().getIncludeBindingErrors()) { + case ALWAYS: + return true; + case ON_PARAM: + return getErrorsParameter(request); + default: + return false; + } + } +} \ No newline at end of file diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/typical.txt b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/typical.txt similarity index 98% rename from spring-javaformat/spring-javaformat-formatter/src/test/resources/source/typical.txt rename to spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/typical.txt index b88780c1..e370bf0e 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/test/resources/source/typical.txt +++ b/spring-javaformat/spring-javaformat-formatter-tests/src/test/resources/source/typical.txt @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-formatter/pom.xml b/spring-javaformat/spring-javaformat-formatter/pom.xml index 4a600dae..d4642459 100644 --- a/spring-javaformat/spring-javaformat-formatter/pom.xml +++ b/spring-javaformat/spring-javaformat-formatter/pom.xml @@ -6,7 +6,7 @@ io.spring.javaformat spring-javaformat - 0.0.21-SNAPSHOT + 0.0.48-SNAPSHOT spring-javaformat-formatter Spring JavaFormat Formatter @@ -17,7 +17,17 @@ io.spring.javaformat - spring-javaformat-formatter-eclipse + spring-javaformat-config + ${project.version} + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-jdt-jdk8 + ${project.version} + + + io.spring.javaformat + spring-javaformat-formatter-eclipse-jdt-jdk17 ${project.version} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Edit.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Edit.java new file mode 100644 index 00000000..8e6a9c4d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Edit.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.util.regex.Pattern; + +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.text.edits.TextEdit; + +/** + * Base class for edits that can be applied to content. + * + * @author Phillip Webb + */ +public abstract class Edit { + + private static final Pattern TRAILING_WHITESPACE = Pattern.compile(" +$", Pattern.MULTILINE); + + private final String originalContent; + + private final TextEdit textEdit; + + protected Edit(String originalContent, TextEdit textEdit) { + super(); + this.originalContent = originalContent; + this.textEdit = textEdit; + } + + public boolean hasEdits() { + return (this.textEdit.hasChildren() || this.textEdit.getLength() > 0); + } + + public String getFormattedContent() throws Exception { + IDocument document = new Document(this.originalContent); + this.textEdit.apply(document); + String formattedContent = document.get(); + return trimTrailingWhitespace(formattedContent); + } + + private String trimTrailingWhitespace(String content) { + return TRAILING_WHITESPACE.matcher(content).replaceAll(""); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileEdit.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileEdit.java index 78604658..457fcc7c 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileEdit.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileEdit.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,44 +20,30 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.StandardOpenOption; -import java.util.regex.Pattern; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; /** - * An Edit that can be applied to a File. + * An {@link Edit} that can be applied to a {@link File}. * * @author Phillip Webb */ -public class FileEdit { - - private static final Pattern TRAILING_WHITESPACE = Pattern.compile(" +$", Pattern.MULTILINE); +public class FileEdit extends Edit { private final File file; private final Charset encoding; - private final String originalContent; - - private final TextEdit edit; - - FileEdit(File file, Charset encoding, String originalContent, TextEdit edit) { + FileEdit(File file, Charset encoding, String originalContent, TextEdit textEdit) { + super(originalContent, textEdit); this.file = file; this.encoding = encoding; - this.originalContent = originalContent; - this.edit = edit; } public File getFile() { return this.file; } - public boolean hasEdits() { - return (this.edit.hasChildren() || this.edit.getLength() > 0); - } - public void save() { try { String formattedContent = getFormattedContent(); @@ -69,20 +55,14 @@ public void save() { } } + @Override public String getFormattedContent() throws Exception { try { - IDocument document = new Document(this.originalContent); - this.edit.apply(document); - String formattedContent = document.get(); - return trimTrailingWhitespace(formattedContent); + return super.getFormattedContent(); } catch (Exception ex) { throw FileFormatterException.wrap(this.file, ex); } } - private String trimTrailingWhitespace(String content) { - return TRAILING_WHITESPACE.matcher(content).replaceAll(""); - } - } diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatter.java index 72ae2b29..49b05234 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,8 @@ import org.eclipse.text.edits.TextEdit; +import io.spring.javaformat.config.JavaFormatConfig; + /** * A code formatter designed to work with {@link File Files}. * @@ -39,8 +41,8 @@ public FileFormatter() { this(new Formatter()); } - public FileFormatter(FormatterOption... options) { - this(new Formatter(options)); + public FileFormatter(JavaFormatConfig javaFormatConfig) { + this(new Formatter(javaFormatConfig)); } public FileFormatter(Formatter formatter) { @@ -53,10 +55,22 @@ public FileFormatter(Formatter formatter) { * instances. * @param files the files to format * @param encoding the source encoding - * @return a stream of formatted files that have edits + * @return a stream of file edits */ public Stream formatFiles(Iterable files, Charset encoding) { - return formatFiles(StreamSupport.stream(files.spliterator(), false), encoding); + return formatFiles(files, encoding, Formatter.DEFAULT_LINE_SEPARATOR); + } + + /** + * Format the given source files and provide a {@link Stream} of {@link FileEdit} + * instances. + * @param files the files to format + * @param encoding the source encoding + * @param lineSeparator the line separator + * @return a stream of file edits + */ + public Stream formatFiles(Iterable files, Charset encoding, String lineSeparator) { + return formatFiles(StreamSupport.stream(files.spliterator(), false), encoding, lineSeparator); } /** @@ -64,22 +78,45 @@ public Stream formatFiles(Iterable files, Charset encoding) { * instances. * @param files the files to format * @param encoding the source encoding - * @return a stream of formatted files that have edits + * @return a stream of file edits */ public Stream formatFiles(Stream files, Charset encoding) { - return files.map((file) -> formatFile(file, encoding)); + return formatFiles(files, encoding, Formatter.DEFAULT_LINE_SEPARATOR); } /** - * Format the the given source file and return a {@link FileEdit} instance. + * Format the given source files and provide a {@link Stream} of {@link FileEdit} + * instances. + * @param files the files to format + * @param encoding the source encoding + * @param lineSeparator the line separator + * @return a stream of file edits + */ + public Stream formatFiles(Stream files, Charset encoding, String lineSeparator) { + return files.map((file) -> formatFile(file, encoding, lineSeparator)); + } + + /** + * Format the given source file and return a {@link FileEdit} instance. * @param file the file to format * @param encoding the source encoding - * @return a formatted file + * @return a file edit */ public FileEdit formatFile(File file, Charset encoding) { + return formatFile(file, encoding, Formatter.DEFAULT_LINE_SEPARATOR); + } + + /** + * Format the given source file and return a {@link FileEdit} instance. + * @param file the file to format + * @param encoding the source encoding + * @param lineSeparator the line separator + * @return a file edit + */ + public FileEdit formatFile(File file, Charset encoding, String lineSeparator) { try { String content = new String(Files.readAllBytes(file.toPath()), encoding); - TextEdit edit = this.formatter.format(content); + TextEdit edit = this.formatter.format(content, lineSeparator); return new FileEdit(file, encoding, content, edit); } catch (Exception ex) { diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatterException.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatterException.java index 09f17a5d..2d054698 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatterException.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/FileFormatterException.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java index 3211b25d..ed6169c4 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,35 +16,40 @@ package io.spring.javaformat.formatter; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.function.Supplier; -import org.eclipse.jdt.core.formatter.CodeFormatter; import org.eclipse.jface.text.IRegion; import org.eclipse.text.edits.TextEdit; -import io.spring.javaformat.formatter.eclipse.ExtendedCodeFormatter; -import io.spring.javaformat.formatter.eclipse.Preparator; -import io.spring.javaformat.formatter.preparator.Preparators; +import io.spring.javaformat.config.JavaBaseline; +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.formatter.eclipse.EclipseCodeFormatter; +import io.spring.javaformat.formatter.jdk17.eclipse.EclipseJdk17CodeFormatter; +import io.spring.javaformat.formatter.jdk8.eclipse.EclipseJdk8CodeFormatter; /** - * A {@link CodeFormatter} that applies Spring formatting conventions. + * A code formatter that applies Spring formatting conventions. * * @author Phillip Webb */ -public class Formatter extends CodeFormatter { +public class Formatter { + + /** + * Kind used to format a compilation unit. See Eclipse {@code CodeFormatter} + * constants. + */ + private static final int K_COMPILATION_UNIT = 0x08; + + /** + * Flag used to include the comments during the formatting of the code snippet. See + * Eclipse {@code CodeFormatter} constants. + */ + private static final int F_INCLUDE_COMMENTS = 0x1000; /** * The components that will be formatted by default. */ - private static final int DEFAULT_COMPONENTS = CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS; + private static final int DEFAULT_COMPONENTS = K_COMPILATION_UNIT | F_INCLUDE_COMMENTS; /** * The default indentation level. @@ -54,25 +59,24 @@ public class Formatter extends CodeFormatter { /** * The default line separator. */ - private static final String DEFAULT_LINE_SEPARATOR = null; - - private final Set options; + public static final String DEFAULT_LINE_SEPARATOR = null; - private CodeFormatter delegate = new DelegateCodeFormatter(); + private final EclipseCodeFormatter delegate; /** * Create a new formatter instance. */ public Formatter() { - this.options = Collections.emptySet(); + this(JavaFormatConfig.DEFAULT); } /** * Create a new formatter instance. - * @param options formatter options + * @param javaFormatConfig the java format config to use */ - public Formatter(FormatterOption... options) { - this.options = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(options))); + public Formatter(JavaFormatConfig javaFormatConfig) { + this.delegate = javaFormatConfig.getJavaBaseline() == JavaBaseline.V8 + ? new EclipseJdk8CodeFormatter(javaFormatConfig) : new EclipseJdk17CodeFormatter(javaFormatConfig); } /** @@ -81,7 +85,17 @@ public Formatter(FormatterOption... options) { * @return the text edit */ public TextEdit format(String source) { - return format(source, 0, source.length()); + return format(source, DEFAULT_LINE_SEPARATOR); + } + + /** + * Format the given source content. + * @param source the source content to format + * @param lineSeparator the line separator + * @return the text edit + */ + public TextEdit format(String source, String lineSeparator) { + return format(source, 0, source.length(), lineSeparator); } /** @@ -92,15 +106,25 @@ public TextEdit format(String source) { * @return the text edit */ public TextEdit format(String source, int offset, int length) { - return format(DEFAULT_COMPONENTS, source, offset, length, DEFAULT_INDENTATION_LEVEL, DEFAULT_LINE_SEPARATOR); + return format(source, offset, length, DEFAULT_LINE_SEPARATOR); + } + + /** + * Format a specific subsection of the given source content. + * @param source the source content to format + * @param offset the offset to start formatting + * @param length the length to format + * @param lineSeparator the line separator + * @return the text edit + */ + public TextEdit format(String source, int offset, int length, String lineSeparator) { + return format(DEFAULT_COMPONENTS, source, offset, length, DEFAULT_INDENTATION_LEVEL, lineSeparator); } - @Override public TextEdit format(int kind, String source, int offset, int length, int indentationLevel, String lineSeparator) { - return nlsSafe(() -> { - return this.delegate.format(kind, source, offset, length, indentationLevel, lineSeparator); - }); + lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source); + return this.delegate.format(kind, source, offset, length, indentationLevel, lineSeparator); } /** @@ -124,70 +148,32 @@ public TextEdit format(String source, IRegion[] regions, String lineSeparator) { return format(DEFAULT_COMPONENTS, source, regions, DEFAULT_INDENTATION_LEVEL, lineSeparator); } - @Override public TextEdit format(int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator) { - return nlsSafe(() -> this.delegate.format(kind, source, regions, indentationLevel, lineSeparator)); + lineSeparator = (lineSeparator != null) ? lineSeparator : detectLineSeparator(source); + return this.delegate.format(kind, source, regions, indentationLevel, lineSeparator); } - @Override public String createIndentationString(int indentationLevel) { return this.delegate.createIndentationString(indentationLevel); } - @Override public void setOptions(Map options) { this.delegate.setOptions(options); } - private T nlsSafe(Supplier formatted) { - if (this.options.contains(FormatterOption.SHOW_NLS_WARNINGS)) { - return formatted.get(); - } - String nlsWarnings = System.getProperty("osgi.nls.warnings"); - try { - System.setProperty("osgi.nls.warnings", "ignore"); - return formatted.get(); - } - finally { - if (nlsWarnings != null) { - System.setProperty("osgi.nls.warnings", nlsWarnings); + private String detectLineSeparator(String contents) { + int length = contents.length(); + for (int i = 0; i < length; i++) { + char ch = contents.charAt(i); + boolean isLastChar = (i + 1) == length; + if (ch == '\r') { + return (isLastChar || contents.charAt(i + 1) != '\n') ? "\r" : "\r\n"; } - } - - } - - /** - * Internal delegate code formatter to apply Spring {@literal formatter.prefs} and add - * {@link Preparator Preparators}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static class DelegateCodeFormatter extends ExtendedCodeFormatter { - - static Map OPTIONS; - - static { - try { - Properties properties = new Properties(); - try (InputStream inputStream = Formatter.class.getResourceAsStream("formatter.prefs")) { - properties.load(inputStream); - OPTIONS = (Map) Collections.unmodifiableMap(properties); - } - } - catch (IOException ex) { - throw new IllegalStateException(ex); + if (ch == '\n') { + return "\n"; } } - - DelegateCodeFormatter() { - super(OPTIONS); - Preparators.forEach(this::addPreparator); - } - - @Override - public void setOptions(Map options) { - super.setOptions(OPTIONS); - } - + return null; } } diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/StreamsEdit.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/StreamsEdit.java new file mode 100644 index 00000000..7263a5e6 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/StreamsEdit.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import org.eclipse.text.edits.TextEdit; + +/** + * An {@link Edit} that can be applied to IO Streams. + * + * @author Phillip Webb + */ +public class StreamsEdit extends Edit { + + StreamsEdit(String originalContent, TextEdit textEdit) { + super(originalContent, textEdit); + } + + /** + * Write the edited content to the given {@link OutputStream}. + * @param outputStream the output stream where formatted content should be written + */ + public void writeTo(OutputStream outputStream) { + writeTo(outputStream, StandardCharsets.UTF_8); + } + + /** + * Write the edited content to the given {@link OutputStream}. + * @param outputStream the output stream where formatted content should be written + * @param encoding the source encoding + */ + public void writeTo(OutputStream outputStream, Charset encoding) { + try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, encoding)) { + writeTo(writer); + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Write the edited content to the given {@link Appendable}. + * @param appendable the appendable where formatted content should be written + */ + public void writeTo(Appendable appendable) { + try { + appendable.append(getFormattedContent()); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/StreamsFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/StreamsFormatter.java new file mode 100644 index 00000000..fb8257d7 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/StreamsFormatter.java @@ -0,0 +1,125 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +import org.eclipse.text.edits.TextEdit; + +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * A code formatter designed to work with IO streams. + * + * @author Phillip Webb + * @see Formatter + */ +public class StreamsFormatter { + + private final Formatter formatter; + + public StreamsFormatter() { + this(new Formatter()); + } + + public StreamsFormatter(JavaFormatConfig javaFormatConfig) { + this(new Formatter(javaFormatConfig)); + } + + public StreamsFormatter(Formatter formatter) { + Optional.ofNullable(formatter).orElseThrow(() -> new IllegalArgumentException("Formatter must not be null")); + this.formatter = formatter; + } + + /** + * Format content from the given source {@link InputStream} and return a + * {@link StreamsEdit} instance. + * @param inputStream the source input stream + * @return a streams edit + */ + public StreamsEdit format(InputStream inputStream) { + return format(inputStream, StandardCharsets.UTF_8); + } + + /** + * Format content from the given source {@link InputStream} and return a + * {@link StreamsEdit} instance. + * @param inputStream the source input stream + * @param encoding the source encoding + * @return a streams edit + */ + public StreamsEdit format(InputStream inputStream, Charset encoding) { + return format(inputStream, encoding, Formatter.DEFAULT_LINE_SEPARATOR); + } + + /** + * Format content from the given source {@link InputStream} and return a + * {@link StreamsEdit} instance. + * @param inputStream the source input stream + * @param encoding the source encoding + * @param lineSeparator the line separator + * @return a streams edit + */ + public StreamsEdit format(InputStream inputStream, Charset encoding, String lineSeparator) { + return format(new InputStreamReader(inputStream, encoding), lineSeparator); + } + + /** + * Format content from the given source {@link Reader} and return a + * {@link StreamsEdit} instance. + * @param reader the source reader + * @return a streams edit + */ + public StreamsEdit format(Reader reader) { + return format(reader, Formatter.DEFAULT_LINE_SEPARATOR); + } + + /** + * Format content from the given source {@link Reader} and return a + * {@link StreamsEdit} instance. + * @param reader the source reader + * @param lineSeparator the line separator + * @return a streams edit + */ + public StreamsEdit format(Reader reader, String lineSeparator) { + try { + String content = readContent(reader); + TextEdit edit = this.formatter.format(content, lineSeparator); + return new StreamsEdit(content, edit); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private String readContent(Reader reader) throws IOException { + StringBuilder result = new StringBuilder(); + char[] buffer = new char[2048]; + int numChars; + while ((numChars = reader.read(buffer)) >= 0) { + result.append(buffer, 0, numChars); + } + return result.toString(); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/eclipse/EclipseCodeFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/eclipse/EclipseCodeFormatter.java new file mode 100644 index 00000000..121ddc4a --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/eclipse/EclipseCodeFormatter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.eclipse; + +import java.util.Map; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.text.edits.TextEdit; + +/** + * Internal interface used to access an Eclipse {@code CodeFormatter} implementation. + * + * @author Phillip Webb + */ +public interface EclipseCodeFormatter { + + TextEdit format(int kind, String source, int offset, int length, int indentationLevel, String lineSeparator); + + TextEdit format(int kind, String source, IRegion[] regions, int indentationLevel, String lineSeparator); + + String createIndentationString(int indentationLevel); + + void setOptions(Map options); + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/eclipse/Options.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/eclipse/Options.java new file mode 100644 index 00000000..b80c0346 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/eclipse/Options.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.eclipse; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import io.spring.javaformat.config.IndentationStyle; +import io.spring.javaformat.config.JavaFormatConfig; + +/** + * Utility class used to load formatter options. + * + * @author Phillip Webb + */ +public class Options { + + private final String prefix; + + public Options(String prefix) { + this.prefix = prefix; + } + + public Map load(JavaFormatConfig javaFormatConfig) { + try { + Map properties = loadProperties(); + applyConfig(properties, javaFormatConfig); + return Collections.unmodifiableMap(properties); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + private Map loadProperties() throws IOException { + Properties properties = new Properties(); + try (InputStream inputStream = getClass().getResourceAsStream("formatter.prefs")) { + properties.load(inputStream); + } + Map prefixedProperties = new LinkedHashMap<>(); + for (Map.Entry entry : properties.entrySet()) { + prefixedProperties.put(this.prefix + "." + entry.getKey(), (String) entry.getValue()); + } + return prefixedProperties; + } + + private void applyConfig(Map properties, JavaFormatConfig javaFormatConfig) { + String coreFormatter = this.prefix + ".core.formatter."; + if (javaFormatConfig.getIndentationStyle() == IndentationStyle.SPACES) { + properties.put(coreFormatter + "tabulation.char", "space"); + } + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/CodeLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/CodeLineBreakPreparator.java new file mode 100644 index 00000000..3f5a7337 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/CodeLineBreakPreparator.java @@ -0,0 +1,121 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk17.eclipse; + +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.AbstractTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.AnnotationTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.EnumDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.FieldDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.SimpleName; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.TypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.compiler.parser.TerminalTokens; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Token; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager; + +/** + * {@link Preparator} to finetune curly-brace line breaks. + * + * @author Phillip Webb + */ +class CodeLineBreakPreparator implements Preparator { + + @Override + public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) { + if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) { + ASTVisitor visitor = new Vistor(tokenManager); + astRoot.accept(visitor); + } + } + + private static class Vistor extends ASTVisitor { + + private final TokenManager tokenManager; + + Vistor(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + @Override + public boolean visit(TypeDeclaration node) { + visitType(node); + return true; + } + + @Override + public boolean visit(AnnotationTypeDeclaration node) { + visitType(node); + return true; + } + + @Override + public boolean visit(EnumDeclaration node) { + visitType(node); + return true; + } + + private void visitType(AbstractTypeDeclaration node) { + SimpleName name = node.getName(); + int openBraceIndex = (name == null ? this.tokenManager.firstIndexIn(node, TerminalTokens.TokenNameLBRACE) + : this.tokenManager.firstIndexAfter(name, TerminalTokens.TokenNameLBRACE)); + Token openBraceToken = this.tokenManager.get(openBraceIndex); + openBraceToken.clearLineBreaksAfter(); + openBraceToken.putLineBreaksAfter(2); + int closeBraceIndex = this.tokenManager.lastIndexIn(node, TerminalTokens.TokenNameRBRACE); + Token closeBraceToken = this.tokenManager.get(closeBraceIndex); + closeBraceToken.clearLineBreaksBefore(); + closeBraceToken.putLineBreaksBefore(2); + } + + @Override + public boolean visit(FieldDeclaration node) { + int index = this.tokenManager.lastIndexIn(node, TerminalTokens.TokenNameSEMICOLON); + while (tokenIsOfType(index + 1, TerminalTokens.TokenNameCOMMENT_LINE, + TerminalTokens.TokenNameCOMMENT_BLOCK)) { + if (this.tokenManager.get(index).getLineBreaksAfter() > 0 + || this.tokenManager.get(index + 1).getLineBreaksBefore() > 0) { + break; + } + index++; + } + Token token = this.tokenManager.get(index); + if (tokenIsOfType(index + 1, TerminalTokens.TokenNamestatic)) { + return true; + } + token.clearLineBreaksAfter(); + token.putLineBreaksAfter(2); + return true; + } + + private boolean tokenIsOfType(int index, int... types) { + if (index < this.tokenManager.size()) { + Token token = this.tokenManager.get(index); + for (int type : types) { + if (token.tokenType == type) { + return true; + } + } + } + return false; + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/EclipseJdk17CodeFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/EclipseJdk17CodeFormatter.java new file mode 100644 index 00000000..a7530156 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/EclipseJdk17CodeFormatter.java @@ -0,0 +1,54 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk17.eclipse; + +import java.util.Map; + +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.ExtendedCodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.formatter.eclipse.EclipseCodeFormatter; +import io.spring.javaformat.formatter.eclipse.Options; + +/** + * Internal delegate JDK 17 baseline {@link EclipseCodeFormatter} to apply Spring + * {@literal formatter.prefs} and add {@link Preparator Preparators}. + * + * @author Phillip Webb + */ +public class EclipseJdk17CodeFormatter extends ExtendedCodeFormatter implements EclipseCodeFormatter { + + private final Map appliedOptions; + + public EclipseJdk17CodeFormatter(JavaFormatConfig javaFormatConfig) { + this(new Options("io.spring.javaformat.eclipse.jdt.jdk17").load(javaFormatConfig)); + } + + EclipseJdk17CodeFormatter(Map options) { + super(options); + this.appliedOptions = options; + addPreparator(new JavadocLineBreakPreparator()); + addPreparator(new CodeLineBreakPreparator()); + addPreparator(new JSpecifyPreparator()); + } + + @Override + public void setOptions(Map options) { + super.setOptions(this.appliedOptions); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java new file mode 100644 index 00000000..2f9b8aeb --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JSpecifyPreparator.java @@ -0,0 +1,146 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk17.eclipse; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Annotation; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.FieldDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.IExtendedModifier; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ImportDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.MethodDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.SingleVariableDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.VariableDeclarationStatement; +import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager; + +public class JSpecifyPreparator implements Preparator { + + private static final String PACKAGE_NAME = "org.jspecify.annotations"; + + private static final Set ANNOTATION_NAMES = new HashSet<>(Arrays.asList("NonNull", "Nullable")); + + private static final Set FULLY_QUALIFIED_ANNOTATION_NAMES = ANNOTATION_NAMES.stream() + .map((annotationName) -> PACKAGE_NAME + "." + annotationName) + .collect(Collectors.toSet()); + + @Override + public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) { + if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) { + ASTVisitor visitor = new Vistor(tokenManager); + astRoot.accept(visitor); + } + } + + private static class Vistor extends ASTVisitor { + + private final TokenManager tokenManager; + + private final Map fullyQualified = new HashMap<>(); + + Vistor(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + @Override + public boolean visit(CompilationUnit node) { + this.fullyQualified.clear(); + return super.visit(node); + } + + @Override + public boolean visit(ImportDeclaration node) { + String name = node.getName().toString(); + if (name.equals(PACKAGE_NAME) || name.startsWith(PACKAGE_NAME)) { + Set annotationNames = (node.isOnDemand()) ? ANNOTATION_NAMES + : Collections.singleton(name.substring(name.lastIndexOf(".") + 1)); + for (String annotationName : annotationNames) { + this.fullyQualified.put(annotationName, PACKAGE_NAME + "." + annotationName); + } + } + return super.visit(node); + } + + @Override + public boolean visit(FieldDeclaration node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return super.visit(node); + } + + @Override + public boolean visit(MethodDeclaration node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + @SuppressWarnings("unchecked") + public void endVisit(SingleVariableDeclaration node) { + if (node.isVarargs()) { + List annotations = node.varargsAnnotations(); + Annotation lastAnnotation = getLastAnnotation(annotations); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).spaceAfter(); + } + } + } + + @SuppressWarnings("unchecked") + private void clearLineBreaksIfHasJSpecifyAnnotation(List modifiers) { + Annotation lastAnnotation = getLastAnnotation((List) modifiers); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter(); + } + } + + private Annotation getLastAnnotation(List modifiers) { + Annotation annotation = null; + for (IExtendedModifier modifier : modifiers) { + if (!modifier.isAnnotation()) { + return annotation; + } + annotation = (Annotation) modifier; + } + return annotation; + } + + private boolean isJSpecifyAnnotation(Annotation annotation) { + String fullyQualifiedName = (annotation != null) + ? this.fullyQualified.get(annotation.getTypeName().toString()) : null; + return (fullyQualifiedName != null) && FULLY_QUALIFIED_ANNOTATION_NAMES.contains(fullyQualifiedName); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JavadocLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JavadocLineBreakPreparator.java new file mode 100644 index 00000000..28b369c7 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk17/eclipse/JavadocLineBreakPreparator.java @@ -0,0 +1,133 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk17.eclipse; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.AbstractTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Comment; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.Javadoc; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.TagElement; +import io.spring.javaformat.eclipse.jdt.jdk17.core.dom.TextElement; +import io.spring.javaformat.eclipse.jdt.jdk17.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.compiler.parser.TerminalTokens; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.Token; +import io.spring.javaformat.eclipse.jdt.jdk17.internal.formatter.TokenManager; + +/** + * {@link Preparator} to finetune Javadoc whitespace. + * + * @author Phillip Webb + */ +class JavadocLineBreakPreparator implements Preparator { + + private final static List PARAM_TAGS; + + static { + List paramTags = new ArrayList(); + paramTags.add(TagElement.TAG_PARAM); + paramTags.add(TagElement.TAG_EXCEPTION); + paramTags.add(TagElement.TAG_SERIALFIELD); + paramTags.add(TagElement.TAG_THROWS); + paramTags.add(TagElement.TAG_RETURN); + paramTags.add(TagElement.TAG_DEPRECATED); + PARAM_TAGS = Collections.unmodifiableList(paramTags); + } + + @Override + public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) { + if ((kind & CodeFormatter.F_INCLUDE_COMMENTS) != 0) { + ASTVisitor visitor = new Vistor(tokenManager); + for (Comment comment : getComments(astRoot)) { + comment.accept(visitor); + } + } + } + + @SuppressWarnings("unchecked") + private List getComments(ASTNode astRoot) { + if (astRoot.getRoot() instanceof CompilationUnit) { + CompilationUnit compilationUnit = (CompilationUnit) astRoot.getRoot(); + return compilationUnit.getCommentList(); + } + return Collections.emptyList(); + } + + private static class Vistor extends ASTVisitor { + + private final TokenManager tokenManager; + + private TokenManager commentTokenManager; + + private ASTNode declaration; + + private boolean firstTagElement; + + private boolean hasText; + + Vistor(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + @Override + public boolean visit(Javadoc node) { + int commentIndex = this.tokenManager.firstIndexIn(node, TerminalTokens.TokenNameCOMMENT_JAVADOC); + Token commentToken = this.tokenManager.get(commentIndex); + this.commentTokenManager = (commentToken.getInternalStructure() != null) + ? new TokenManager(commentToken.getInternalStructure(), this.tokenManager) : null; + this.declaration = node.getParent(); + this.firstTagElement = true; + this.hasText = false; + return true; + } + + @Override + public boolean visit(TextElement node) { + this.hasText = true; + return true; + } + + @Override + public boolean visit(TagElement node) { + if (this.commentTokenManager != null && isSquashRequired(node, this.declaration)) { + int startIndex = this.commentTokenManager.findIndex(node.getStartPosition(), -1, false); + Token token = this.commentTokenManager.get(startIndex); + token.clearLineBreaksBefore(); + boolean isTypeDeclaration = this.declaration instanceof AbstractTypeDeclaration; + token.putLineBreaksBefore(isTypeDeclaration && this.firstTagElement && this.hasText ? 2 : 1); + this.firstTagElement = false; + } + return true; + } + + private boolean isSquashRequired(TagElement node, ASTNode declaration) { + if (declaration instanceof AbstractTypeDeclaration) { + String tagName = node.getTagName(); + return (!node.isNested() && tagName != null && tagName.startsWith("@")); + } + return PARAM_TAGS.contains(node.getTagName()); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/CodeLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/CodeLineBreakPreparator.java similarity index 72% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/CodeLineBreakPreparator.java rename to spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/CodeLineBreakPreparator.java index 07134c56..2cb2ef68 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/CodeLineBreakPreparator.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/CodeLineBreakPreparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,25 +14,24 @@ * limitations under the License. */ -package io.spring.javaformat.formatter.preparator; - -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTVisitor; -import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; -import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; -import org.eclipse.jdt.core.dom.EnumDeclaration; -import org.eclipse.jdt.core.dom.FieldDeclaration; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.formatter.CodeFormatter; -import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; - -import io.spring.javaformat.formatter.eclipse.Preparator; -import io.spring.javaformat.formatter.eclipse.Token; -import io.spring.javaformat.formatter.eclipse.TokenManager; +package io.spring.javaformat.formatter.jdk8.eclipse; + +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.AbstractTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.AnnotationTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.EnumDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.FieldDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.SimpleName; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.TypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.compiler.parser.TerminalTokens; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Token; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.TokenManager; /** - * {@link Preparator} to fine tune curly-brace line breaks. + * {@link Preparator} to finetune curly-brace line breaks. * * @author Phillip Webb */ diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java new file mode 100644 index 00000000..9887ccb2 --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/EclipseJdk8CodeFormatter.java @@ -0,0 +1,54 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk8.eclipse; + +import java.util.Map; + +import io.spring.javaformat.config.JavaFormatConfig; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.ExtendedCodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Preparator; +import io.spring.javaformat.formatter.eclipse.EclipseCodeFormatter; +import io.spring.javaformat.formatter.eclipse.Options; + +/** + * Internal delegate JDK 8 baseline {@link EclipseCodeFormatter} to apply Spring + * {@literal formatter.prefs} and add {@link Preparator Preparators}. + * + * @author Phillip Webb + */ +public class EclipseJdk8CodeFormatter extends ExtendedCodeFormatter implements EclipseCodeFormatter { + + private final Map appliedOptions; + + public EclipseJdk8CodeFormatter(JavaFormatConfig javaFormatConfig) { + this(new Options("io.spring.javaformat.eclipse.jdt.jdk8").load(javaFormatConfig)); + } + + EclipseJdk8CodeFormatter(Map options) { + super(options); + this.appliedOptions = options; + addPreparator(new JavadocLineBreakPreparator()); + addPreparator(new CodeLineBreakPreparator()); + addPreparator(new JSpecifyPreparator()); + } + + @Override + public void setOptions(Map options) { + super.setOptions(this.appliedOptions); + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java new file mode 100644 index 00000000..89397c6d --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JSpecifyPreparator.java @@ -0,0 +1,146 @@ +/* + * Copyright 2017-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.javaformat.formatter.jdk8.eclipse; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.Annotation; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.FieldDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.IExtendedModifier; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ImportDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.MethodDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.SingleVariableDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.VariableDeclarationStatement; +import io.spring.javaformat.eclipse.jdt.jdk8.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.TokenManager; + +public class JSpecifyPreparator implements Preparator { + + private static final String PACKAGE_NAME = "org.jspecify.annotations"; + + private static final Set ANNOTATION_NAMES = new HashSet<>(Arrays.asList("NonNull", "Nullable")); + + private static final Set FULLY_QUALIFIED_ANNOTATION_NAMES = ANNOTATION_NAMES.stream() + .map((annotationName) -> PACKAGE_NAME + "." + annotationName) + .collect(Collectors.toSet()); + + @Override + public void apply(int kind, TokenManager tokenManager, ASTNode astRoot) { + if ((kind & CodeFormatter.K_COMPILATION_UNIT) != 0) { + ASTVisitor visitor = new Vistor(tokenManager); + astRoot.accept(visitor); + } + } + + private static class Vistor extends ASTVisitor { + + private final TokenManager tokenManager; + + private final Map fullyQualified = new HashMap<>(); + + Vistor(TokenManager tokenManager) { + this.tokenManager = tokenManager; + } + + @Override + public boolean visit(CompilationUnit node) { + this.fullyQualified.clear(); + return super.visit(node); + } + + @Override + public boolean visit(ImportDeclaration node) { + String name = node.getName().toString(); + if (name.equals(PACKAGE_NAME) || name.startsWith(PACKAGE_NAME)) { + Set annotationNames = (node.isOnDemand()) ? ANNOTATION_NAMES + : Collections.singleton(name.substring(name.lastIndexOf(".") + 1)); + for (String annotationName : annotationNames) { + this.fullyQualified.put(annotationName, PACKAGE_NAME + "." + annotationName); + } + } + return super.visit(node); + } + + @Override + public boolean visit(FieldDeclaration node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return super.visit(node); + } + + @Override + public boolean visit(MethodDeclaration node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + clearLineBreaksIfHasJSpecifyAnnotation(node.modifiers()); + return true; + } + + @Override + @SuppressWarnings("unchecked") + public void endVisit(SingleVariableDeclaration node) { + if (node.isVarargs()) { + List annotations = node.varargsAnnotations(); + Annotation lastAnnotation = getLastAnnotation(annotations); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).spaceAfter(); + } + } + } + + @SuppressWarnings("unchecked") + private void clearLineBreaksIfHasJSpecifyAnnotation(List modifiers) { + Annotation lastAnnotation = getLastAnnotation((List) modifiers); + if (isJSpecifyAnnotation(lastAnnotation)) { + this.tokenManager.lastTokenIn(lastAnnotation, -1).clearLineBreaksAfter(); + } + } + + private Annotation getLastAnnotation(List modifiers) { + Annotation annotation = null; + for (IExtendedModifier modifier : modifiers) { + if (!modifier.isAnnotation()) { + return annotation; + } + annotation = (Annotation) modifier; + } + return annotation; + } + + private boolean isJSpecifyAnnotation(Annotation annotation) { + String fullyQualifiedName = (annotation != null) + ? this.fullyQualified.get(annotation.getTypeName().toString()) : null; + return (fullyQualifiedName != null) && FULLY_QUALIFIED_ANNOTATION_NAMES.contains(fullyQualifiedName); + } + + } + +} diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/JavadocLineBreakPreparator.java b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java similarity index 65% rename from spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/JavadocLineBreakPreparator.java rename to spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java index 7cf4e50c..a5b8a035 100644 --- a/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/preparator/JavadocLineBreakPreparator.java +++ b/spring-javaformat/spring-javaformat-formatter/src/main/java/io/spring/javaformat/formatter/jdk8/eclipse/JavadocLineBreakPreparator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2017-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,29 +14,28 @@ * limitations under the License. */ -package io.spring.javaformat.formatter.preparator; +package io.spring.javaformat.formatter.jdk8.eclipse; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTVisitor; -import org.eclipse.jdt.core.dom.Comment; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.Javadoc; -import org.eclipse.jdt.core.dom.TagElement; -import org.eclipse.jdt.core.dom.TextElement; -import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.formatter.CodeFormatter; -import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; - -import io.spring.javaformat.formatter.eclipse.Preparator; -import io.spring.javaformat.formatter.eclipse.Token; -import io.spring.javaformat.formatter.eclipse.TokenManager; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTNode; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.ASTVisitor; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.AbstractTypeDeclaration; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.Comment; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.CompilationUnit; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.Javadoc; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.TagElement; +import io.spring.javaformat.eclipse.jdt.jdk8.core.dom.TextElement; +import io.spring.javaformat.eclipse.jdt.jdk8.core.formatter.CodeFormatter; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.compiler.parser.TerminalTokens; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Preparator; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.Token; +import io.spring.javaformat.eclipse.jdt.jdk8.internal.formatter.TokenManager; /** - * {@link Preparator} to fine tune Javadoc whitespace. + * {@link Preparator} to finetune Javadoc whitespace. * * @author Phillip Webb */ @@ -94,7 +93,8 @@ private static class Vistor extends ASTVisitor { public boolean visit(Javadoc node) { int commentIndex = this.tokenManager.firstIndexIn(node, TerminalTokens.TokenNameCOMMENT_JAVADOC); Token commentToken = this.tokenManager.get(commentIndex); - this.commentTokenManager = new TokenManager(commentToken.getInternalStructure(), this.tokenManager); + this.commentTokenManager = (commentToken.getInternalStructure() != null) + ? new TokenManager(commentToken.getInternalStructure(), this.tokenManager) : null; this.declaration = node.getParent(); this.firstTagElement = true; this.hasText = false; @@ -109,19 +109,19 @@ public boolean visit(TextElement node) { @Override public boolean visit(TagElement node) { - if (isSquashRequired(node, this.declaration)) { + if (this.commentTokenManager != null && isSquashRequired(node, this.declaration)) { int startIndex = this.commentTokenManager.findIndex(node.getStartPosition(), -1, false); Token token = this.commentTokenManager.get(startIndex); token.clearLineBreaksBefore(); - token.putLineBreaksBefore( - this.declaration instanceof TypeDeclaration && this.firstTagElement && this.hasText ? 2 : 1); + boolean isTypeDeclaration = this.declaration instanceof AbstractTypeDeclaration; + token.putLineBreaksBefore(isTypeDeclaration && this.firstTagElement && this.hasText ? 2 : 1); this.firstTagElement = false; } return true; } private boolean isSquashRequired(TagElement node, ASTNode declaration) { - if (declaration instanceof TypeDeclaration) { + if (declaration instanceof AbstractTypeDeclaration) { String tagName = node.getTagName(); return (!node.isNested() && tagName != null && tagName.startsWith("@")); } diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/resources/io/spring/javaformat/formatter/eclipse/formatter.prefs b/spring-javaformat/spring-javaformat-formatter/src/main/resources/io/spring/javaformat/formatter/eclipse/formatter.prefs new file mode 100644 index 00000000..46940cbe --- /dev/null +++ b/spring-javaformat/spring-javaformat-formatter/src/main/resources/io/spring/javaformat/formatter/eclipse/formatter.prefs @@ -0,0 +1,355 @@ +core.formatter.align_assignment_statements_on_columns=false +core.formatter.align_fields_grouping_blank_lines=2147483647 +core.formatter.align_type_members_on_columns=false +core.formatter.align_variable_declarations_on_columns=false +core.formatter.align_with_spaces=false +core.formatter.alignment_for_additive_operator=16 +core.formatter.alignment_for_arguments_in_allocation_expression=16 +core.formatter.alignment_for_arguments_in_annotation=16 +core.formatter.alignment_for_arguments_in_enum_constant=16 +core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +core.formatter.alignment_for_arguments_in_method_invocation=16 +core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +core.formatter.alignment_for_assignment=0 +core.formatter.alignment_for_binary_expression=16 +core.formatter.alignment_for_bitwise_operator=16 +core.formatter.alignment_for_compact_if=16 +core.formatter.alignment_for_compact_loops=16 +core.formatter.alignment_for_conditional_expression=16 +core.formatter.alignment_for_conditional_expression_chain=0 +core.formatter.alignment_for_enum_constants=16 +core.formatter.alignment_for_expressions_in_array_initializer=16 +core.formatter.alignment_for_expressions_in_for_loop_header=0 +core.formatter.alignment_for_logical_operator=16 +core.formatter.alignment_for_method_declaration=0 +core.formatter.alignment_for_module_statements=16 +core.formatter.alignment_for_multiple_fields=16 +core.formatter.alignment_for_multiplicative_operator=16 +core.formatter.alignment_for_parameterized_type_references=0 +core.formatter.alignment_for_parameters_in_constructor_declaration=16 +core.formatter.alignment_for_parameters_in_method_declaration=16 +core.formatter.alignment_for_relational_operator=0 +core.formatter.alignment_for_resources_in_try=80 +core.formatter.alignment_for_selector_in_method_invocation=84 +core.formatter.alignment_for_shift_operator=0 +core.formatter.alignment_for_string_concatenation=16 +core.formatter.alignment_for_superclass_in_type_declaration=16 +core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +core.formatter.alignment_for_throws_clause_in_method_declaration=16 +core.formatter.alignment_for_type_arguments=0 +core.formatter.alignment_for_type_parameters=0 +core.formatter.alignment_for_union_type_in_multicatch=16 +core.formatter.align_selector_in_method_invocation_on_expression_first_line=true +core.formatter.blank_lines_after_imports=1 +core.formatter.blank_lines_after_package=1 +core.formatter.blank_lines_before_field=0 +core.formatter.blank_lines_before_first_class_body_declaration=0 +core.formatter.blank_lines_before_imports=1 +core.formatter.blank_lines_before_member_type=1 +core.formatter.blank_lines_before_method=1 +core.formatter.blank_lines_before_new_chunk=1 +core.formatter.blank_lines_before_package=0 +core.formatter.blank_lines_between_import_groups=1 +core.formatter.blank_lines_between_type_declarations=1 +core.formatter.brace_position_for_annotation_type_declaration=end_of_line +core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +core.formatter.brace_position_for_array_initializer=end_of_line +core.formatter.brace_position_for_block=end_of_line +core.formatter.brace_position_for_block_in_case=end_of_line +core.formatter.brace_position_for_constructor_declaration=end_of_line +core.formatter.brace_position_for_enum_constant=end_of_line +core.formatter.brace_position_for_enum_declaration=end_of_line +core.formatter.brace_position_for_lambda_body=end_of_line +core.formatter.brace_position_for_method_declaration=end_of_line +core.formatter.brace_position_for_switch=end_of_line +core.formatter.brace_position_for_type_declaration=end_of_line +core.formatter.comment.align_tags_descriptions_grouped=false +core.formatter.comment.align_tags_names_descriptions=false +core.formatter.comment.clear_blank_lines_in_block_comment=false +core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +core.formatter.comment.count_line_length_from_starting_position=false +core.formatter.comment.format_block_comments=true +core.formatter.comment.format_header=false +core.formatter.comment.format_html=true +core.formatter.comment.format_javadoc_comments=true +core.formatter.comment.format_line_comments=true +core.formatter.comment.format_source_code=false +core.formatter.comment.indent_parameter_description=false +core.formatter.comment.indent_root_tags=false +core.formatter.comment.indent_tag_description=false +core.formatter.comment.insert_new_line_before_root_tags=do not insert +core.formatter.comment.insert_new_line_for_parameter=do not insert +core.formatter.comment.line_length=90 +core.formatter.comment.new_lines_at_block_boundaries=true +core.formatter.comment.new_lines_at_javadoc_boundaries=true +core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +core.formatter.compact_else_if=true +core.formatter.continuation_indentation=2 +core.formatter.continuation_indentation_for_array_initializer=2 +core.formatter.disabling_tag=@formatter\:off +core.formatter.enabling_tag=@formatter\:on +core.formatter.format_guardian_clause_on_one_line=false +core.formatter.format_line_comment_starting_on_first_column=true +core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +core.formatter.indent_body_declarations_compare_to_type_header=true +core.formatter.indent_breaks_compare_to_cases=true +core.formatter.indent_empty_lines=false +core.formatter.indent_statements_compare_to_block=true +core.formatter.indent_statements_compare_to_body=true +core.formatter.indent_switchstatements_compare_to_cases=true +core.formatter.indent_switchstatements_compare_to_switch=true +core.formatter.indentation.size=4 +core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +core.formatter.insert_new_line_after_annotation_on_field=insert +core.formatter.insert_new_line_after_annotation_on_local_variable=insert +core.formatter.insert_new_line_after_annotation_on_method=insert +core.formatter.insert_new_line_after_annotation_on_package=insert +core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +core.formatter.insert_new_line_after_annotation_on_type=insert +core.formatter.insert_new_line_after_label=do not insert +core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +core.formatter.insert_new_line_after_type_annotation=do not insert +core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +core.formatter.insert_new_line_before_catch_in_try_statement=insert +core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +core.formatter.insert_new_line_before_else_in_if_statement=insert +core.formatter.insert_new_line_before_finally_in_try_statement=insert +core.formatter.insert_new_line_before_while_in_do_statement=insert +core.formatter.insert_new_line_in_empty_annotation_declaration=insert +core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +core.formatter.insert_new_line_in_empty_block=insert +core.formatter.insert_new_line_in_empty_enum_constant=insert +core.formatter.insert_new_line_in_empty_enum_declaration=insert +core.formatter.insert_new_line_in_empty_method_body=insert +core.formatter.insert_new_line_in_empty_type_declaration=insert +core.formatter.insert_space_after_additive_operator=insert +core.formatter.insert_space_after_and_in_type_parameter=insert +core.formatter.insert_space_after_assignment_operator=insert +core.formatter.insert_space_after_at_in_annotation=do not insert +core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +core.formatter.insert_space_after_binary_operator=insert +core.formatter.insert_space_after_bitwise_operator=insert +core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert +core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +core.formatter.insert_space_after_closing_brace_in_block=insert +core.formatter.insert_space_after_closing_paren_in_cast=insert +core.formatter.insert_space_after_colon_in_assert=insert +core.formatter.insert_space_after_colon_in_case=insert +core.formatter.insert_space_after_colon_in_conditional=insert +core.formatter.insert_space_after_colon_in_for=insert +core.formatter.insert_space_after_colon_in_labeled_statement=insert +core.formatter.insert_space_after_comma_in_allocation_expression=insert +core.formatter.insert_space_after_comma_in_annotation=insert +core.formatter.insert_space_after_comma_in_array_initializer=insert +core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +core.formatter.insert_space_after_comma_in_enum_declarations=insert +core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +core.formatter.insert_space_after_comma_in_for_increments=insert +core.formatter.insert_space_after_comma_in_for_inits=insert +core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +core.formatter.insert_space_after_comma_in_superinterfaces=insert +core.formatter.insert_space_after_comma_in_type_arguments=insert +core.formatter.insert_space_after_comma_in_type_parameters=insert +core.formatter.insert_space_after_ellipsis=insert +core.formatter.insert_space_after_lambda_arrow=insert +core.formatter.insert_space_after_logical_operator=insert +core.formatter.insert_space_after_multiplicative_operator=insert +core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +core.formatter.insert_space_after_opening_paren_in_cast=do not insert +core.formatter.insert_space_after_opening_paren_in_catch=do not insert +core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +core.formatter.insert_space_after_opening_paren_in_for=do not insert +core.formatter.insert_space_after_opening_paren_in_if=do not insert +core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +core.formatter.insert_space_after_opening_paren_in_switch=do not insert +core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +core.formatter.insert_space_after_opening_paren_in_try=do not insert +core.formatter.insert_space_after_opening_paren_in_while=do not insert +core.formatter.insert_space_after_postfix_operator=do not insert +core.formatter.insert_space_after_prefix_operator=do not insert +core.formatter.insert_space_after_question_in_conditional=insert +core.formatter.insert_space_after_question_in_wildcard=do not insert +core.formatter.insert_space_after_relational_operator=insert +core.formatter.insert_space_after_semicolon_in_for=insert +core.formatter.insert_space_after_semicolon_in_try_resources=insert +core.formatter.insert_space_after_shift_operator=insert +core.formatter.insert_space_after_string_concatenation=insert +core.formatter.insert_space_after_unary_operator=do not insert +core.formatter.insert_space_before_additive_operator=insert +core.formatter.insert_space_before_and_in_type_parameter=insert +core.formatter.insert_space_before_assignment_operator=insert +core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +core.formatter.insert_space_before_binary_operator=insert +core.formatter.insert_space_before_bitwise_operator=insert +core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +core.formatter.insert_space_before_closing_paren_in_cast=do not insert +core.formatter.insert_space_before_closing_paren_in_catch=do not insert +core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +core.formatter.insert_space_before_closing_paren_in_for=do not insert +core.formatter.insert_space_before_closing_paren_in_if=do not insert +core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +core.formatter.insert_space_before_closing_paren_in_switch=do not insert +core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +core.formatter.insert_space_before_closing_paren_in_try=do not insert +core.formatter.insert_space_before_closing_paren_in_while=do not insert +core.formatter.insert_space_before_colon_in_assert=insert +core.formatter.insert_space_before_colon_in_case=do not insert +core.formatter.insert_space_before_colon_in_conditional=insert +core.formatter.insert_space_before_colon_in_default=do not insert +core.formatter.insert_space_before_colon_in_for=insert +core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +core.formatter.insert_space_before_comma_in_annotation=do not insert +core.formatter.insert_space_before_comma_in_array_initializer=do not insert +core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +core.formatter.insert_space_before_comma_in_for_increments=do not insert +core.formatter.insert_space_before_comma_in_for_inits=do not insert +core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +core.formatter.insert_space_before_comma_in_type_arguments=do not insert +core.formatter.insert_space_before_comma_in_type_parameters=do not insert +core.formatter.insert_space_before_ellipsis=do not insert +core.formatter.insert_space_before_lambda_arrow=insert +core.formatter.insert_space_before_logical_operator=insert +core.formatter.insert_space_before_multiplicative_operator=insert +core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +core.formatter.insert_space_before_opening_brace_in_block=insert +core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +core.formatter.insert_space_before_opening_brace_in_switch=insert +core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +core.formatter.insert_space_before_opening_paren_in_catch=insert +core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +core.formatter.insert_space_before_opening_paren_in_for=insert +core.formatter.insert_space_before_opening_paren_in_if=insert +core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +core.formatter.insert_space_before_opening_paren_in_switch=insert +core.formatter.insert_space_before_opening_paren_in_synchronized=insert +core.formatter.insert_space_before_opening_paren_in_try=insert +core.formatter.insert_space_before_opening_paren_in_while=insert +core.formatter.insert_space_before_parenthesized_expression_in_return=insert +core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +core.formatter.insert_space_before_postfix_operator=do not insert +core.formatter.insert_space_before_prefix_operator=do not insert +core.formatter.insert_space_before_question_in_conditional=insert +core.formatter.insert_space_before_question_in_wildcard=do not insert +core.formatter.insert_space_before_relational_operator=insert +core.formatter.insert_space_before_semicolon=do not insert +core.formatter.insert_space_before_semicolon_in_for=do not insert +core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +core.formatter.insert_space_before_shift_operator=insert +core.formatter.insert_space_before_string_concatenation=insert +core.formatter.insert_space_before_unary_operator=do not insert +core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +core.formatter.join_lines_in_comments=true +core.formatter.join_wrapped_lines=true +core.formatter.keep_annotation_declaration_on_one_line=one_line_never +core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +core.formatter.keep_code_block_on_one_line=one_line_never +core.formatter.keep_else_statement_on_same_line=false +core.formatter.keep_empty_array_initializer_on_one_line=false +core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never +core.formatter.keep_enum_declaration_on_one_line=one_line_never +core.formatter.keep_if_then_body_block_on_one_line=one_line_never +core.formatter.keep_imple_if_on_one_line=false +core.formatter.keep_lambda_body_block_on_one_line=one_line_never +core.formatter.keep_loop_body_block_on_one_line=one_line_never +core.formatter.keep_method_body_on_one_line=one_line_never +core.formatter.keep_simple_do_while_body_on_same_line=false +core.formatter.keep_simple_for_body_on_same_line=false +core.formatter.keep_simple_getter_setter_on_one_line=false +core.formatter.keep_simple_while_body_on_same_line=false +core.formatter.keep_then_statement_on_same_line=false +core.formatter.keep_type_declaration_on_one_line=one_line_never +core.formatter.lineSplit=120 +core.formatter.never_indent_block_comments_on_first_column=false +core.formatter.never_indent_line_comments_on_first_column=false +core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +core.formatter.number_of_empty_lines_to_preserve=1 +core.formatter.parentheses_positions_in_annotation=common_lines +core.formatter.parentheses_positions_in_catch_clause=common_lines +core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +core.formatter.parentheses_positions_in_for_statment=common_lines +core.formatter.parentheses_positions_in_if_while_statement=common_lines +core.formatter.parentheses_positions_in_lambda_declaration=common_lines +core.formatter.parentheses_positions_in_method_delcaration=common_lines +core.formatter.parentheses_positions_in_method_invocation=common_lines +core.formatter.parentheses_positions_in_switch_statement=common_lines +core.formatter.parentheses_positions_in_try_clause=common_lines +core.formatter.put_empty_statement_on_new_line=true +core.formatter.tabulation.char=tab +core.formatter.tabulation.size=4 +core.formatter.use_on_off_tags=true +core.formatter.use_tabs_only_for_leading_indentations=false +core.formatter.wrap_before_additive_operator=true +core.formatter.wrap_before_assignment_operator=false +core.formatter.wrap_before_binary_operator=true +core.formatter.wrap_before_bitwise_operator=true +core.formatter.wrap_before_conditional_operator=true +core.formatter.wrap_before_logical_operator=true +core.formatter.wrap_before_multiplicative_operator=true +core.formatter.wrap_before_or_operator_multicatch=true +core.formatter.wrap_before_relational_operator=true +core.formatter.wrap_before_shift_operator=true +core.formatter.wrap_before_string_concatenation=true +core.formatter.wrap_outer_expressions_when_nested=true diff --git a/spring-javaformat/spring-javaformat-formatter/src/main/resources/io/spring/javaformat/formatter/formatter.prefs b/spring-javaformat/spring-javaformat-formatter/src/main/resources/io/spring/javaformat/formatter/formatter.prefs deleted file mode 100644 index 8ca6bd7b..00000000 --- a/spring-javaformat/spring-javaformat-formatter/src/main/resources/io/spring/javaformat/formatter/formatter.prefs +++ /dev/null @@ -1,354 +0,0 @@ -org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false -org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false -org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false -org.eclipse.jdt.core.formatter.align_with_spaces=false -org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 -org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 -org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 -org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 -org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 -org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 -org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=0 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false -org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false -org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false -org.eclipse.jdt.core.formatter.comment.format_block_comments=true -org.eclipse.jdt.core.formatter.comment.format_header=false -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=true -org.eclipse.jdt.core.formatter.comment.format_source_code=false -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false -org.eclipse.jdt.core.formatter.comment.indent_root_tags=false -org.eclipse.jdt.core.formatter.comment.indent_tag_description=false -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert -org.eclipse.jdt.core.formatter.comment.line_length=90 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=2 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 -org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off -org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false -org.eclipse.jdt.core.formatter.indentation.size=4 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert -org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false -org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false -org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false -org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.lineSplit=120 -org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=tab -org.eclipse.jdt.core.formatter.tabulation.size=4 -org.eclipse.jdt.core.formatter.use_on_off_tags=true -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false -org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true -org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true -org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true -org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true -org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true -org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true -org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true -org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true -org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java b/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java deleted file mode 100644 index fc5cf1c5..00000000 --- a/spring-javaformat/spring-javaformat-formatter/src/test/java/io/spring/javaformat/formatter/AbstractFormatterTests.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.javaformat.formatter; - -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collection; - -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -/** - * @author Phillip Webb - */ -@RunWith(Parameterized.class) -public abstract class AbstractFormatterTests { - - private final File source; - - private final File expected; - - public AbstractFormatterTests(File source, File expected) { - this.source = source; - this.expected = expected; - } - - protected final File getSource() { - return this.source; - } - - protected final File getExpected() { - return this.expected; - } - - protected final void print(String name, String content) { - System.out.println(name + ":"); - System.out.println(); - System.out.println("----------------------------------------"); - System.out.println(content); - System.out.println("----------------------------------------"); - System.out.println(); - System.out.println(); - } - - protected final String read(File file) throws Exception { - return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - } - - protected static Collection files(String expectedOverride) { - Collection files = new ArrayList<>(); - File sourceDir = new File("src/test/resources/source"); - File expectedDir = new File("src/test/resources/expected"); - File expectedOverrideDir = new File("src/test/resources/" + expectedOverride); - for (File source : sourceDir.listFiles((dir, name) -> !name.startsWith("."))) { - File expected = new File(expectedOverrideDir, source.getName()); - if (!expected.exists()) { - expected = new File(expectedDir, source.getName()); - } - files.add(new Object[] { source, expected }); - } - return files; - } - -} diff --git a/src/checkstyle/checkstyle-header.txt b/src/checkstyle/checkstyle-header.txt index 39429ee6..7e182ab3 100644 --- a/src/checkstyle/checkstyle-header.txt +++ b/src/checkstyle/checkstyle-header.txt @@ -1,5 +1,5 @@ ^\Q/*\E$ -^\Q * Copyright \E20\d\d\-20\d\d\Q the original author or authors.\E$ +^\Q * Copyright \E20\d\d\-present\Q the original author or authors.\E$ ^\Q *\E$ ^\Q * Licensed under the Apache License, Version 2.0 (the "License");\E$ ^\Q * you may not use this file except in compliance with the License.\E$ diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 75d577f2..b115d317 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -6,4 +6,5 @@ + diff --git a/src/checkstyle/checkstyle.xml b/src/checkstyle/checkstyle.xml index c765c0a0..c13faf85 100644 --- a/src/checkstyle/checkstyle.xml +++ b/src/checkstyle/checkstyle.xml @@ -8,9 +8,7 @@ - - - + @@ -67,6 +65,7 @@ + @@ -105,11 +104,11 @@ - + - + - + @@ -124,21 +123,21 @@ - + - - + + - - + + @@ -161,5 +160,5 @@ - +