feat(flags): add semver targeting to local evaluation#3186
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Size Change: +9.8 kB (+0.15%) Total Size: 6.66 MB
ℹ️ View Unchanged
|
| switch (operator) { | ||
| case 'semver_eq': | ||
| return cmp === 0 | ||
| case 'semver_neq': | ||
| return cmp !== 0 | ||
| case 'semver_gt': | ||
| return cmp > 0 | ||
| case 'semver_gte': | ||
| return cmp >= 0 | ||
| case 'semver_lt': | ||
| return cmp < 0 | ||
| case 'semver_lte': | ||
| return cmp <= 0 | ||
| default: | ||
| throw new InconclusiveMatchError(`Unknown semver operator: ${operator}`) | ||
| } |
There was a problem hiding this comment.
The nested switch statement (lines 1095–1110) contains unreachable dead code. The outer case block already constrains operator to one of six semver operators (semver_eq, semver_neq, semver_gt, semver_gte, semver_lt, semver_lte), so the inner switch's default branch can never execute.
Consider restructuring to avoid the nested switch entirely—for example, using a lookup map or individual outer case blocks (as done for semver_tilde, semver_caret, semver_wildcard).
There was a problem hiding this comment.
This is legit.
| const parsePart = (part: string | undefined): number => { | ||
| if (part === undefined || part === '') { | ||
| return 0 | ||
| } | ||
| const num = parseInt(part, 10) | ||
| if (isNaN(num)) { | ||
| throw new InconclusiveMatchError(`Invalid semver: ${value}`) | ||
| } | ||
| return num | ||
| } |
There was a problem hiding this comment.
The parseInt() call in parsePart (line 1305) silently truncates trailing non-numeric characters. For example, parseInt('3alpha', 10) returns 3, not NaN. This means malformed version strings like '1.2.3alpha' (missing the - separator for pre-release) will parse as [1, 2, 3] instead of throwing an InconclusiveMatchError.
Add an explicit digit-only check before parsing:
const parsePart = (part: string | undefined): number => {
if (part === undefined || part === '') {
return 0
}
if (!/^\d+$/.test(part)) {
throw new InconclusiveMatchError(`Invalid semver: ${value}`)
}
const num = parseInt(part, 10)
if (isNaN(num)) {
throw new InconclusiveMatchError(`Invalid semver: ${value}`)
}
return num
}🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| switch (operator) { | ||
| case 'semver_eq': | ||
| return cmp === 0 | ||
| case 'semver_neq': | ||
| return cmp !== 0 | ||
| case 'semver_gt': | ||
| return cmp > 0 | ||
| case 'semver_gte': | ||
| return cmp >= 0 | ||
| case 'semver_lt': | ||
| return cmp < 0 | ||
| case 'semver_lte': | ||
| return cmp <= 0 | ||
| default: | ||
| throw new InconclusiveMatchError(`Unknown semver operator: ${operator}`) | ||
| } |
There was a problem hiding this comment.
This is legit.
There was a problem hiding this comment.
Nice work on the tests.
|
Don't forget the release label. |
- Remove unreachable dead code by replacing nested switch with individual case blocks for each semver comparison operator - Add explicit digit-only check in parsePart to reject malformed versions like '1.2.3alpha' (parseInt would silently truncate to 3) - Add test case for malformed version strings with trailing characters 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Problem
Users cannot locally evaluate feature flags that use semver (semantic versioning) property filters. When a flag uses operators like
semver_gtorsemver_caret, the Node SDK must fall back to server-side evaluation, adding latency and requiring network calls.This brings the posthog-node SDK in line with:
user_blast_radiusposthog#44596Changes
matchProperty:semver_eq,semver_neq— equality/inequality comparisonssemver_gt,semver_gte,semver_lt,semver_lte— standard comparisonssemver_tilde— patch-level range (~1.2.3 means >=1.2.3 and <1.3.0)semver_caret— compatible-with range per semver spec (handles 0.x specially)semver_wildcard— wildcard range (1.2.* means >=1.2.0 <1.3.0)parseSemverfunction that:InconclusiveMatchErrorfor invalid inputcomputeTildeBounds,computeCaretBounds,computeWildcardBoundsparseSemverfor testingImplementation notes:
1.2.3-alpha==1.2.3)Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset file