From 41e83855bb25f9f00207a19c11d2a37272e42f38 Mon Sep 17 00:00:00 2001 From: Mo Alras Date: Wed, 25 Mar 2026 14:47:23 +0100 Subject: [PATCH] Add UriParameterCamelCaseRule validation rule Validates that URI path parameters use lowerCamelCase naming convention. Catches violations like {ID}, {productID}, and {BusinessUnitKey}. Co-Authored-By: Claude Opus 4.6 --- .../validators/UriParameterCamelCaseRule.kt | 38 +++++++++++++++++++ .../rmf/validators/ValidatorRulesTest.groovy | 21 ++++++++++ .../uri-parameter-camelcase-rule.raml | 12 ++++++ 3 files changed, 71 insertions(+) create mode 100644 ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/UriParameterCamelCaseRule.kt create mode 100644 ctp-validators/src/test/resources/uri-parameter-camelcase-rule.raml diff --git a/ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/UriParameterCamelCaseRule.kt b/ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/UriParameterCamelCaseRule.kt new file mode 100644 index 00000000..00311321 --- /dev/null +++ b/ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/UriParameterCamelCaseRule.kt @@ -0,0 +1,38 @@ +package com.commercetools.rmf.validators + +import io.vrap.rmf.raml.model.resources.Resource +import io.vrap.rmf.raml.model.util.StringCaseFormat +import org.eclipse.emf.common.util.Diagnostic +import java.util.* + +@ValidatorSet +class UriParameterCamelCaseRule(severity: RuleSeverity, options: List? = null) : ResourcesRule(severity, options) { + + private val exclude: List = + (options?.filter { ruleOption -> ruleOption.type.lowercase(Locale.getDefault()) == RuleOptionType.EXCLUDE.toString() }?.map { ruleOption -> ruleOption.value }?.plus("") ?: defaultExcludes) + + override fun caseResource(resource: Resource): List { + val validationResults: MutableList = ArrayList() + + resource.relativeUri.variables.forEach { variableName -> + if (exclude.contains(variableName).not() && StringCaseFormat.LOWER_CAMEL_CASE.apply(variableName) != variableName) { + validationResults.add(create(resource, "URI parameter \"{0}\" in resource \"{1}\" must be lowerCamelCase", variableName, resource.fullUri.template)) + } + } + return validationResults + } + + companion object : ValidatorFactory { + private val defaultExcludes by lazy { listOf("") } + + @JvmStatic + override fun create(options: List?): UriParameterCamelCaseRule { + return UriParameterCamelCaseRule(RuleSeverity.ERROR, options) + } + + @JvmStatic + override fun create(severity: RuleSeverity, options: List?): UriParameterCamelCaseRule { + return UriParameterCamelCaseRule(severity, options) + } + } +} diff --git a/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy b/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy index 70ac193b..88b6be72 100644 --- a/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy +++ b/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy @@ -474,4 +474,25 @@ class ValidatorRulesTest extends Specification implements ValidatorFixtures { then: result.validationResults.size() == 17 } + + def "uri parameter camelCase rule"() { + when: + def options = singletonList(new RuleOption(RuleOptionType.EXCLUDE.toString(), "ID")) + def validators = Arrays.asList(new ResourcesValidator(Arrays.asList(UriParameterCamelCaseRule.create(options)))) + def uri = uriFromClasspath("/uri-parameter-camelcase-rule.raml") + def result = new RamlModelBuilder(validators).buildApi(uri) + then: + result.validationResults.size() == 2 + result.validationResults[0].message == "URI parameter \"productID\" in resource \"/{projectKey}/invalid/{productID}\" must be lowerCamelCase" + result.validationResults[1].message == "URI parameter \"BusinessUnitKey\" in resource \"/{projectKey}/invalid/{BusinessUnitKey}\" must be lowerCamelCase" + } + + def "uri parameter camelCase rule without exclusions"() { + when: + def validators = Arrays.asList(new ResourcesValidator(Arrays.asList(UriParameterCamelCaseRule.create(emptyList())))) + def uri = uriFromClasspath("/uri-parameter-camelcase-rule.raml") + def result = new RamlModelBuilder(validators).buildApi(uri) + then: + result.validationResults.size() == 3 + } } diff --git a/ctp-validators/src/test/resources/uri-parameter-camelcase-rule.raml b/ctp-validators/src/test/resources/uri-parameter-camelcase-rule.raml new file mode 100644 index 00000000..ef433a26 --- /dev/null +++ b/ctp-validators/src/test/resources/uri-parameter-camelcase-rule.raml @@ -0,0 +1,12 @@ +#%RAML 1.0 +title: uri parameter camelCase rule + +/{projectKey}: + /valid: + /{id}: + /key={key}: + /{associateId}: + /invalid: + /{ID}: + /{productID}: + /{BusinessUnitKey}: