Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d2a6dc2
improve speed of generator
Picazsoo Mar 16, 2026
d343433
implement suggested fixes from CR. fix some general nitpicks.
Picazsoo Mar 16, 2026
cecf84f
implement suggested fixes from CR. fix some general nitpicks.
Picazsoo Mar 16, 2026
ae35597
implement suggested fixes from CR. fix some general nitpicks.
Picazsoo Mar 16, 2026
3b8e4c2
revert some changes
Picazsoo Mar 17, 2026
607c678
fix
Picazsoo Mar 17, 2026
8297e27
Revert "fix"
Picazsoo Mar 17, 2026
2d00db2
Revert "revert some changes"
Picazsoo Mar 17, 2026
9941a95
fix
Picazsoo Mar 17, 2026
4a5e1d2
fix working with regex patterns
Picazsoo Mar 17, 2026
bbeee7d
fix working with regex patterns
Picazsoo Mar 17, 2026
d74b796
fix working with regex patterns
Picazsoo Mar 17, 2026
5c48182
fix working with regex patterns
Picazsoo Mar 17, 2026
4f76b5b
fix working with regex patterns. Add duration logging to GenerateBatch
Picazsoo Mar 18, 2026
d461793
DRY regex patterns
Picazsoo Mar 23, 2026
55934d7
DRY regex patterns
Picazsoo Mar 23, 2026
848b5fc
DRY regex patterns
Picazsoo Mar 23, 2026
db462a6
DRY regex patterns
Picazsoo Mar 23, 2026
6c4c02e
DRY regex patterns
Picazsoo Mar 24, 2026
798b7d4
Merge branch 'master' into feature/fix-speed-bottlenecks-2
Picazsoo Mar 25, 2026
28e7026
refactor: introduce shared regex patterns for improved code readability
Picazsoo Mar 25, 2026
15fc1f5
refactor: introduce shared regex patterns for improved code readability
Picazsoo Mar 25, 2026
a0172e1
refactor: introduce shared regex patterns for improved code readability
Picazsoo Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ public void execute() {

ExecutorService executor = Executors.newFixedThreadPool(numThreads);

long startTime = System.currentTimeMillis();

// Execute each configurator on a separate pooled thread.
configurators.forEach(configurator -> {
GenerationRunner runner = new GenerationRunner(configurator, rootDir, Boolean.TRUE.equals(failFast), Boolean.TRUE.equals(clean));
Expand All @@ -163,12 +165,18 @@ public void execute() {

executor.awaitTermination(awaitFor, TimeUnit.MINUTES);

long elapsedMs = System.currentTimeMillis() - startTime;
long minutes = TimeUnit.MILLISECONDS.toMinutes(elapsedMs);
long seconds = TimeUnit.MILLISECONDS.toSeconds(elapsedMs) % 60;
long millis = elapsedMs % 1000;
String elapsed = String.format(Locale.ROOT, "%dm %ds %dms", minutes, seconds, millis);

int failCount = failures.intValue();
if (failCount > 0) {
System.err.println(String.format(Locale.ROOT, "[FAIL] Completed with %d failures, %d successes", failCount, successes.intValue()));
System.err.println(String.format(Locale.ROOT, "[FAIL] Completed with %d failures, %d successes in %s", failCount, successes.intValue(), elapsed));
System.exit(1);
} else {
System.out.println(String.format(Locale.ROOT, "[SUCCESS] Batch generation finished %d generators successfully.", successes.intValue()));
System.out.println(String.format(Locale.ROOT, "[SUCCESS] Batch generation finished %d generators successfully in %s.", successes.intValue(), elapsed));
}
} catch (InterruptedException e) {
e.printStackTrace();
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1435,7 +1435,7 @@ protected File processTemplateToFile(Map<String, Object> templateData, String te
private final Set<String> seenFilesLower = new HashSet<>();

private File processTemplateToFile(Map<String, Object> templateData, String templateName, String outputFilename, boolean shouldGenerate, String skippedByOption, String intendedOutputDir) throws IOException {
String adjustedOutputFilename = outputFilename.replaceAll("//", "/").replace('/', File.separatorChar);
String adjustedOutputFilename = outputFilename.replace("//", "/").replace('/', File.separatorChar);
File target = new File(adjustedOutputFilename);
if (ignoreProcessor.allowsFile(target)) {
if (shouldGenerate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Pattern;

public class InlineModelResolver {
private static final Pattern LEADING_DIGIT = Pattern.compile("^[0-9]");
private static final Pattern NON_ALPHANUMERIC = Pattern.compile("[^A-Za-z0-9]");
private OpenAPI openAPI;
private Map<String, Schema> addedModels = new HashMap<>();
private Map<String, String> generatedSignature = new HashMap<>();
Expand Down Expand Up @@ -785,9 +788,9 @@ private void addGenerated(String name, Schema model) {
* @param name name to be processed to make sure it's sanitized
*/
private String sanitizeName(final String name) {
return name
.replaceAll("^[0-9]", "_$0") // e.g. 12object => _12object
.replaceAll("[^A-Za-z0-9]", "_"); // e.g. io.schema.User name => io_schema_User_name
return NON_ALPHANUMERIC.matcher(
LEADING_DIGIT.matcher(name).replaceFirst("_$0")) // e.g. 12object => _12object
.replaceAll("_"); // e.g. io.schema.User name => io_schema_User_name
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import java.io.File;
import java.util.*;
import java.util.regex.Pattern;

import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
import static org.openapitools.codegen.utils.StringUtils.camelize;
Expand Down Expand Up @@ -398,7 +399,7 @@ public String toModelName(final String name) {
}

// model name starts with number
if (result.matches("^\\d.*")) {
if (STARTS_WITH_DIGIT.matcher(result).matches()) {
String modelName = "Model_" + result; // e.g. 200Response => Model_200Response (after camelize)
LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", name,
modelName);
Expand Down Expand Up @@ -439,16 +440,16 @@ else if (getSymbolName(value) != null) {
else if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
varName = varName.replace("-", "MINUS_");
varName = varName.replace("+", "PLUS_");
varName = varName.replace(".", "_DOT_");
var = varName;
}

// string
else {
var = value.replaceAll("\\W+", "_").toUpperCase(Locale.ROOT);
if (var.matches("\\d.*")) {
var = NON_WORD_PLUS.matcher(value).replaceAll("_").toUpperCase(Locale.ROOT);
if (STARTS_WITH_DIGIT.matcher(var).matches()) {
var = "_" + var;
} else {
var = sanitizeName(var);
Expand Down Expand Up @@ -1094,7 +1095,7 @@ private List<CodegenSecurity> postProcessAuthMethod(List<CodegenSecurity> authMe
ident = name;
}
scopeIndex++;
ident = toAdaIdentifier(sanitizeName(ident.replaceAll(":", "_")), "S_");
ident = toAdaIdentifier(sanitizeName(ident.replace(":", "_")), "S_");
if (operationsScopes.containsValue(ident)) {
ident = ident + "_" + scopeIndex;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,25 @@
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Pattern;

import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
import static org.openapitools.codegen.utils.StringUtils.camelize;

public abstract class AbstractApexCodegen extends DefaultCodegen implements CodegenConfig {
private final Logger LOGGER = LoggerFactory.getLogger(AbstractApexCodegen.class);

@Setter protected Boolean serializableModel = false;
private static final Pattern DATE_FORMAT = Pattern.compile("^\\d{4}(-\\d{2}){2}");
private static final Pattern DATETIME_FORMAT = Pattern.compile("^\\d{4}([-T:]\\d{2}){5}.+");
private static final Pattern NON_NUMERIC = Pattern.compile("[^-0-9.]");
private static final Pattern UNSAFE_PACKAGE_CHARS = Pattern.compile("[^a-zA-Z0-9_.]");
private static final Pattern INTEGER_PATTERN = Pattern.compile("^-?\\d+$");
private static final Pattern UNDERSCORE_CLASS = Pattern.compile("^_*class$");
private static final Pattern DATE_SEP_ZERO = Pattern.compile("-0?");
private static final Pattern DATETIME_SEP_ZERO = Pattern.compile("[-T:]0?");

@Setter
protected Boolean serializableModel = false;

public AbstractApexCodegen() {
super();
Expand Down Expand Up @@ -77,11 +88,9 @@ public String escapeReservedWord(String name) {
public String sanitizeName(String name) {
name = super.sanitizeName(name);
if (name.contains("__")) { // Preventing namespacing
name = name.replaceAll("__", "_");
}
if (name.matches("^\\d.*")) { // Prevent named credentials with leading number
name = name.replaceAll("^\\d.*", "");
name = name.replace("__", "_");
}
name = STARTS_WITH_DIGIT.matcher(name).replaceAll(""); // Prevent named credentials with leading number
return name;
}

Expand All @@ -90,7 +99,7 @@ public String toVarName(String name) {
// sanitize name
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.

if (name.toLowerCase(Locale.ROOT).matches("^_*class$")) {
if (UNDERSCORE_CLASS.matcher(name.toLowerCase(Locale.ROOT)).matches()) {
return "propertyClass";
}

Expand All @@ -99,7 +108,7 @@ public String toVarName(String name) {
}

// if it's all upper case, do nothing
if (name.matches("^[A-Z_]*$")) {
if (ALL_UPPER_UNDERSCORE.matcher(name).matches()) {
if (isReservedWord(name)) {
name = escapeReservedWord(name);
}
Expand All @@ -115,7 +124,7 @@ public String toVarName(String name) {
name = camelize(name, LOWERCASE_FIRST_LETTER);

// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
if (isReservedWord(name) || STARTS_WITH_DIGIT.matcher(name).matches()) {
name = escapeReservedWord(name);
}

Expand Down Expand Up @@ -169,7 +178,7 @@ public String toModelName(final String name) {
}

// model name starts with number
if (camelizedName.matches("^\\d.*")) {
if (STARTS_WITH_DIGIT.matcher(camelizedName).matches()) {
final String modelName = "Model" + camelizedName; // e.g. 200Response => Model200Response (after camelize)
LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", name,
modelName);
Expand Down Expand Up @@ -318,8 +327,8 @@ public String toExampleValue(Schema p) {
p.setExample(example);
example = "EncodingUtil.base64Decode('" + example + "')";
} else if (ModelUtils.isDateSchema(p)) {
if (example.matches("^\\d{4}(-\\d{2}){2}")) {
example = example.substring(0, 10).replaceAll("-0?", ", ");
if (DATE_FORMAT.matcher(example).find()) {
example = DATE_SEP_ZERO.matcher(example.substring(0, 10)).replaceAll(", ");
} else if (example.isEmpty()) {
example = "2000, 1, 23";
} else {
Expand All @@ -329,8 +338,8 @@ public String toExampleValue(Schema p) {
}
example = "Date.newInstance(" + example + ")";
} else if (ModelUtils.isDateTimeSchema(p)) {
if (example.matches("^\\d{4}([-T:]\\d{2}){5}.+")) {
example = example.substring(0, 19).replaceAll("[-T:]0?", ", ");
if (DATETIME_FORMAT.matcher(example).find()) {
example = DATETIME_SEP_ZERO.matcher(example.substring(0, 19)).replaceAll(", ");
} else if (example.isEmpty()) {
example = "2000, 1, 23, 4, 56, 7";
} else {
Expand All @@ -340,7 +349,7 @@ public String toExampleValue(Schema p) {
}
example = "Datetime.newInstanceGmt(" + example + ")";
} else if (ModelUtils.isNumberSchema(p)) {
example = example.replaceAll("[^-0-9.]", "");
example = NON_NUMERIC.matcher(example).replaceAll("");
example = example.isEmpty() ? "1.3579" : example;
} else if (ModelUtils.isFileSchema(p)) {
if (example.isEmpty()) {
Expand Down Expand Up @@ -380,7 +389,7 @@ public String toExampleValue(Schema p) {
? "'046b6c7f-0b8a-43b9-b35d-6489e6daee91'"
: "'" + escapeText(example) + "'";
} else if (ModelUtils.isIntegerSchema(p)) {
example = example.matches("^-?\\d+$") ? example : "0";
example = INTEGER_PATTERN.matcher(example).matches() ? example : "0";
} else if (ModelUtils.isObjectSchema(p)) {
example = example.isEmpty() ? "null" : example;
} else {
Expand Down Expand Up @@ -524,15 +533,15 @@ public String toEnumVarName(String value, String datatype) {
if ("Integer".equals(datatype) || "Long".equals(datatype) ||
"Float".equals(datatype) || "Double".equals(datatype)) {
String varName = "NUMBER_" + value;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
varName = varName.replace("-", "MINUS_");
varName = varName.replace("+", "PLUS_");
varName = varName.replace(".", "_DOT_");
return varName;
}

// string
String var = value.replaceAll("\\W+", "_").toUpperCase(Locale.ROOT);
if (var.matches("\\d.*")) {
String var = NON_WORD_PLUS.matcher(value).replaceAll("_").toUpperCase(Locale.ROOT);
if (STARTS_WITH_DIGIT.matcher(var).matches()) {
return "_" + var;
} else {
return var;
Expand Down Expand Up @@ -618,7 +627,7 @@ private static CodegenModel reconcileInlineEnums(CodegenModel codegenModel, Code

private static String sanitizePackageName(String packageName) {
packageName = packageName.trim(); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_");
packageName = UNSAFE_PACKAGE_CHARS.matcher(packageName).replaceAll("_");
if (Strings.isNullOrEmpty(packageName)) {
return "invalidPackageName";
}
Expand All @@ -628,7 +637,7 @@ private static String sanitizePackageName(String packageName) {

private String sanitizePath(String p) {
//prefer replace a ", instead of a fuLL URL encode for readability
return p.replaceAll("\"", "%22");
return p.replace("\"", "%22");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@

public abstract class AbstractCSharpCodegen extends DefaultCodegen {

/** Matches a regex literal that carries modifier flags after the closing slash, e.g. {@code /foo/i}. */
private static final Pattern HAS_MODIFIERS = Pattern.compile(".*/[gmiyuvsdlnx]+$");
private static final Pattern UNESCAPED_DOUBLE_QUOTE = Pattern.compile("(?<!\\\\)\"");

protected boolean optionalAssemblyInfoFlag = true;
protected boolean optionalEmitDefaultValuesFlag = false;
protected boolean conditionalSerialization = false;
Expand Down Expand Up @@ -1420,7 +1424,7 @@ public String toOperationId(String operationId) {
}

// operationId starts with a number
if (operationId.matches("^\\d.*")) {
if (STARTS_WITH_DIGIT.matcher(operationId).find()) {
LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, camelize(sanitizeName("call_" + operationId)));
operationId = "call_" + operationId;
}
Expand All @@ -1439,7 +1443,7 @@ public String toVarName(String name) {
name = sanitizeName(name);

// if it's all upper case, do nothing
if (name.matches("^[A-Z_]*$")) {
if (ALL_UPPER_UNDERSCORE.matcher(name).matches()) {
return name;
}

Expand All @@ -1448,7 +1452,7 @@ public String toVarName(String name) {
name = camelize(name);

// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
if (isReservedWord(name) || STARTS_WITH_DIGIT.matcher(name).find()) {
name = escapeReservedWord(name);
}

Expand All @@ -1470,10 +1474,10 @@ public String toParamName(String name) {
name = sanitizeName(name);

// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_");
name = name.replace("-", "_");

// if it's all upper case, do nothing
if (name.matches("^[A-Z_]*$")) {
if (ALL_UPPER_UNDERSCORE.matcher(name).matches()) {
return name;
}

Expand All @@ -1495,7 +1499,7 @@ public String escapeReservedWord(CodegenModel model, String name) {
@Override
public String escapeReservedWord(String name) {
if (isReservedWord(name) ||
name.matches("^\\d.*")) {
STARTS_WITH_DIGIT.matcher(name).find()) {
name = AbstractCSharpCodegen.invalidParameterNamePrefix + camelize(name);
}
return name;
Expand Down Expand Up @@ -1673,7 +1677,7 @@ public String toModelName(String name) {
}

// model name starts with number
if (name.matches("^\\d.*")) {
if (STARTS_WITH_DIGIT.matcher(name).find()) {
LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", name,
camelize("model_" + name));
name = camelize("model_" + name); // e.g. 200Response => Model200Response (after camelize)
Expand Down Expand Up @@ -1768,11 +1772,11 @@ public String toEnumValue(String value, String datatype) {
return value;
}

final String partiallyEscaped = value
final String partiallyEscaped = UNESCAPED_DOUBLE_QUOTE.matcher(value
.replace("\n", "\\n")
.replace("\t", "\\t")
.replace("\r", "\\r")
.replaceAll("(?<!\\\\)\"", "\\\\\"");
.replace("\r", "\\r"))
.replaceAll("\\\\\"");

return escapeUnsafeCharacters(partiallyEscaped);
}
Expand All @@ -1794,12 +1798,12 @@ public String toEnumVarName(String name, String datatype) {

String enumName = sanitizeName(name);

enumName = enumName.replaceFirst("^_", "");
enumName = enumName.replaceFirst("_$", "");
enumName = FIRST_LEADING_UNDERSCORE.matcher(enumName).replaceFirst("");
enumName = LAST_TRAILING_UNDERSCORE.matcher(enumName).replaceFirst("");

enumName = adjustNamingStyle(enumName) + this.enumValueSuffix;

if (enumName.matches("\\d.*")) { // starts with number
if (STARTS_WITH_DIGIT.matcher(enumName).find()) { // starts with number
return "_" + enumName;
} else {
return enumName;
Expand Down Expand Up @@ -2039,9 +2043,7 @@ public void postProcessPattern(String pattern, Map<String, Object> vendorExtensi
// gmiyuvsd - ecma modifiers
// l - legacy modifier provided by this library, provides a way to opt out of culture invariant
// nx - c# modifiers https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options
Pattern hasModifiers = Pattern.compile(".*/[gmiyuvsdlnx]+$");

int end = hasModifiers.matcher(pattern).find()
int end = HAS_MODIFIERS.matcher(pattern).find()
? pattern.lastIndexOf('/')
: pattern.length() - 1;

Expand Down Expand Up @@ -2091,7 +2093,7 @@ public String addRegularExpressionDelimiter(String pattern) {
return pattern;
}

if (!pattern.matches("^/.*")) {
if (!pattern.startsWith("/")) {
return "/" + pattern + "/";
}

Expand Down
Loading
Loading