Skip to content

feat(validation): allow dots in change names as valid separators#842

Open
gqcn wants to merge 1 commit intoFission-AI:mainfrom
gqcn:main
Open

feat(validation): allow dots in change names as valid separators#842
gqcn wants to merge 1 commit intoFission-AI:mainfrom
gqcn:main

Conversation

@gqcn
Copy link

@gqcn gqcn commented Mar 14, 2026

Summary

  • Allow dots (.) as valid separators in change names alongside hyphens, enabling names like v1.2.0, add-auth.v2, feature.sub-task
  • Add dedicated error message for consecutive dots (..) to give clear feedback
  • Update validation regex, error messages, JSDoc comments, and tests

Motivation

Dotted naming conventions are common in versioning and hierarchical naming (e.g., v1.2.0, api.auth). The current strict kebab-case validation
rejects dots entirely, which limits expressiveness without a strong reason — path traversal can be prevented without banning dots altogether.

Changes

src/utils/change-utils.ts

  • Updated regex from /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/ to /^[a-z][a-z0-9]*([-.][a-z0-9]+)*$/
  • Added consecutive dots (..) check with specific error message
  • Updated fallback error message and JSDoc to reflect the new allowed character set

test/utils/change-utils.test.ts

  • Added 3 valid name tests: v1.2, add-auth.v2, feature.sub-task
  • Added 1 invalid name test: add..auth (consecutive dots)

Security

Path traversal is still fully prevented by the regex design:

  ┌────────────────────────┬───────────────────────────────────────────────────────────────┐
  │     Attack vector      │                          Prevention                           │
  ├────────────────────────┼───────────────────────────────────────────────────────────────┤
  │ .. (path traversal)    │ Separator must be followed by at least one [a-z0-9] character │
  ├────────────────────────┼───────────────────────────────────────────────────────────────┤
  │ .hidden (hidden files) │ Name must start with a lowercase letter [a-z]                 │
  ├────────────────────────┼───────────────────────────────────────────────────────────────┤
  │ name. (trailing dot)   │ Separator must be followed by at least one character          │
  └────────────────────────┴───────────────────────────────────────────────────────────────┘

Test plan

  • All 28 tests in change-utils.test.ts pass
  • Dotted names (v1.2, add-auth.v2) are accepted
  • Consecutive dots (add..auth) are rejected
  • Existing invalid names (uppercase, spaces, underscores, etc.) remain rejected

Summary by CodeRabbit

  • New Features

    • Change names now support dots (.) as separators alongside hyphens, enabling formats like "feature.sub-task" and "add-auth.v2".
  • Improvements

    • Validation error messages updated to clearly indicate allowed characters.
    • Consecutive dots are now detected and rejected with explicit error feedback.

Dots are now permitted alongside hyphens in change names (e.g., `v1.2`,
`add-auth.v2`). Path traversal is still prevented: consecutive dots,
leading dots, and trailing dots are all rejected by the regex.
@gqcn gqcn requested a review from TabishB as a code owner March 14, 2026 14:43
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 14, 2026

📝 Walkthrough

Walkthrough

Updates validation logic in change name validation to accept dots alongside hyphens as separators, expanding the kebab-case pattern from hyphen-only to hyphen-or-dot separators. Adds explicit validation to reject consecutive dots with corresponding error messaging. No public API changes.

Changes

Cohort / File(s) Summary
Validation Logic
src/utils/change-utils.ts
Modified kebab-case regex to allow dots or hyphens as separators between alphanumeric groups; added consecutive-dot validation check; updated error messages to reflect expanded character set (lowercase letters, numbers, hyphens, dots).
Test Coverage
test/utils/change-utils.test.ts
Added test cases validating dot-separated segments (v1.2, add-auth.v2, feature.sub-task) and rejection of consecutive dots (add..auth) with appropriate error messaging.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A dot here, a dot there,
No more hyphens, we now declare!
v1.2 dances with add-auth.v2,
Consecutive dots we bid adieu! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: allowing dots as valid separators in change name validation, which is exactly what the changeset implements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can approve the review once all CodeRabbit's comments are resolved.

Enable the reviews.request_changes_workflow setting to automatically approve the review once all CodeRabbit's comments are resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/utils/change-utils.ts (1)

48-91: Validation logic looks correct and security is preserved.

The updated regex /^[a-z][a-z0-9]*([-.][a-z0-9]+)*$/ properly prevents path traversal:

  • Names must start with a lowercase letter (no leading dots)
  • Separators must be followed by at least one alphanumeric character (no trailing dots, no ..)
  • The explicit consecutive-dot check at lines 77-79 provides a clear error message

Consider adding explicit checks for leading/trailing dots for clearer error messages.

Currently, names like .hidden or name. fail the regex silently and fall through to the generic fallback at line 87. Adding explicit checks (similar to lines 68-72 for hyphens) would provide more actionable feedback.

💡 Optional: Add explicit dot boundary checks for clearer errors
     if (/--/.test(name)) {
       return { valid: false, error: 'Change name cannot contain consecutive hyphens' };
     }
     if (/\.\./.test(name)) {
       return { valid: false, error: 'Change name cannot contain consecutive dots' };
     }
+    if (name.startsWith('.')) {
+      return { valid: false, error: 'Change name cannot start with a dot' };
+    }
+    if (name.endsWith('.')) {
+      return { valid: false, error: 'Change name cannot end with a dot' };
+    }
     if (/[^a-z0-9.\-]/.test(name)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/change-utils.ts` around lines 48 - 91, The regex in
validateChangeName and kebabCasePattern already blocks leading/trailing dots but
falls back to the generic error; add explicit checks for names starting or
ending with a dot (e.g., name.startsWith('.') and name.endsWith('.')) alongside
the existing hyphen checks so you return clear errors like 'Change name cannot
start with a dot' or 'Change name cannot end with a dot' before the final
generic message; update the branching inside validateChangeName (the block after
!kebabCasePattern.test(name)) to include these two dot-boundary tests.
test/utils/change-utils.test.ts (1)

117-123: Consider adding edge case tests for dot boundary conditions.

The consecutive dots test is good. For more comprehensive coverage, consider adding tests for:

  • Leading dot (.hidden) - should be rejected
  • Trailing dot (name.) - should be rejected
  • Mixed consecutive separators (add.-auth, add-.auth) - should be rejected
  • Multiple consecutive dots (a...b) - should be rejected

These would help ensure the regex handles all boundary conditions correctly.

💡 Optional: Additional edge case tests
   describe('invalid names - consecutive dots rejected', () => {
     it('should reject name with double dots', () => {
       const result = validateChangeName('add..auth');
       expect(result.valid).toBe(false);
       expect(result.error).toContain('consecutive dots');
     });
+
+    it('should reject name with leading dot', () => {
+      const result = validateChangeName('.hidden');
+      expect(result.valid).toBe(false);
+    });
+
+    it('should reject name with trailing dot', () => {
+      const result = validateChangeName('feature.');
+      expect(result.valid).toBe(false);
+    });
+
+    it('should reject name with mixed consecutive separators', () => {
+      const result = validateChangeName('add.-auth');
+      expect(result.valid).toBe(false);
+    });
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/change-utils.test.ts` around lines 117 - 123, Add additional unit
cases to the existing "invalid names - consecutive dots rejected" suite to cover
dot boundary edge cases by calling validateChangeName with leading dot
('.hidden'), trailing dot ('name.'), mixed consecutive separators ('add.-auth'
and 'add-.auth'), and multiple consecutive dots ('a...b') and asserting
result.valid is false and result.error contains an appropriate message (e.g.,
'invalid name' or specific 'consecutive'/'boundary' text); update the describe
block around validateChangeName to include these new it() tests so the regex
handling for validateChangeName is verified against leading/trailing dots, mixed
separator sequences, and multiple consecutive dots.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/utils/change-utils.ts`:
- Around line 48-91: The regex in validateChangeName and kebabCasePattern
already blocks leading/trailing dots but falls back to the generic error; add
explicit checks for names starting or ending with a dot (e.g.,
name.startsWith('.') and name.endsWith('.')) alongside the existing hyphen
checks so you return clear errors like 'Change name cannot start with a dot' or
'Change name cannot end with a dot' before the final generic message; update the
branching inside validateChangeName (the block after
!kebabCasePattern.test(name)) to include these two dot-boundary tests.

In `@test/utils/change-utils.test.ts`:
- Around line 117-123: Add additional unit cases to the existing "invalid names
- consecutive dots rejected" suite to cover dot boundary edge cases by calling
validateChangeName with leading dot ('.hidden'), trailing dot ('name.'), mixed
consecutive separators ('add.-auth' and 'add-.auth'), and multiple consecutive
dots ('a...b') and asserting result.valid is false and result.error contains an
appropriate message (e.g., 'invalid name' or specific 'consecutive'/'boundary'
text); update the describe block around validateChangeName to include these new
it() tests so the regex handling for validateChangeName is verified against
leading/trailing dots, mixed separator sequences, and multiple consecutive dots.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cb31f239-df47-41ba-a8f3-2b63c9d297a8

📥 Commits

Reviewing files that changed from the base of the PR and between afdca0d and 20b0567.

📒 Files selected for processing (2)
  • src/utils/change-utils.ts
  • test/utils/change-utils.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant