001/* 002 * Configurate 003 * Copyright (C) zml and Configurate contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.spongepowered.configurate.util; 018 019import java.util.regex.Matcher; 020import java.util.regex.Pattern; 021 022/** 023 * Standard naming schemes. 024 * 025 * @since 4.0.0 026 */ 027public enum NamingSchemes implements NamingScheme { 028 029 /** 030 * Passes through names unchanged. 031 * 032 * @since 4.0.0 033 */ 034 PASSTHROUGH { 035 @Override 036 public String coerce(final String input) { 037 return input; 038 } 039 }, 040 041 /** 042 * Reformats names to {@code camelCase} style. 043 * 044 * @since 4.0.0 045 */ 046 CAMEL_CASE { 047 @Override 048 @SuppressWarnings("JdkObsolete") // StringBuilder methods not present until JDK 9 049 public String coerce(final String input) { 050 final Matcher match = DASH_UNDERSCORE.matcher(input); 051 if (!match.find()) { 052 return input; 053 } 054 final StringBuffer ret = new StringBuffer(input.length()); 055 do { 056 match.appendReplacement(ret, ""); 057 ret.appendCodePoint(input.codePointAt(match.start())); 058 ret.appendCodePoint(Character.toUpperCase(input.codePointBefore(match.end()))); 059 } while (match.find()); 060 match.appendTail(ret); 061 return ret.toString(); 062 } 063 }, 064 065 /** 066 * Reformats names to {@code snake_case} format. 067 * 068 * @since 4.0.0 069 */ 070 SNAKE_CASE { 071 @Override 072 public String coerce(final String input) { 073 return NamingSchemes.enforceLowerCaseSeparatorChar(input, UNDERSCORE, DASH); 074 } 075 }, 076 077 /** 078 * Reformats names to {@code lower-case-dashed} format. 079 * 080 * @since 4.0.0 081 */ 082 LOWER_CASE_DASHED { 083 @Override 084 public String coerce(final String input) { 085 return NamingSchemes.enforceLowerCaseSeparatorChar(input, DASH, UNDERSCORE); 086 } 087 }; 088 089 private static final Pattern DASH_UNDERSCORE = Pattern.compile(".[-_]."); 090 private static final char UNDERSCORE = '_'; 091 private static final char DASH = '-'; 092 093 // Common logic for snake_case and dash-separated 094 private static String enforceLowerCaseSeparatorChar(final String input, final char preferredDelimiter, final char convertDelimiter) { 095 final StringBuilder build = new StringBuilder(input); 096 for (int i = 0; i < build.length(); i++) { 097 final int ch = build.codePointAt(i); 098 if (ch == convertDelimiter) { 099 if (i != 0 && i != build.length() - 1) { // only convert actual separators 100 build.setCharAt(i, preferredDelimiter); 101 } 102 } else if (Character.isUpperCase(ch)) { 103 build.insert(i++, preferredDelimiter); 104 final int lower = Character.toLowerCase(ch); 105 if (Character.isBmpCodePoint(lower)) { 106 build.setCharAt(i, (char) lower); 107 } else { 108 build.setCharAt(i++, Character.highSurrogate(lower)); 109 build.setCharAt(i, Character.lowSurrogate(lower)); 110 } 111 } 112 } 113 return build.toString(); 114 115 } 116 117}