Skip to content

Resolve the values that signs apply to like any other value - #136

Draft
nstepien wants to merge 1 commit into
mainfrom
signed-values
Draft

nstepien wants to merge 1 commit into
mainfrom
signed-values

Conversation

@nstepien

@nstepien nstepien commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Signs resolve their argument

resolveValue only accepted a sign (- or +) on a number literal, like ${-5}. It now resolves the argument recursively, like any other expression it supports. So a sign applies to any value that resolves:

  • a const, like ${-gap}
  • an import or a member of a namespace import, like ${-spacing} or ${-theme.spacing}
  • another signed value, like ${-negativeOffset} when const negativeOffset = -5

A signed value is returned as a promise only when its argument is one, so local values stay synchronous.

Conversion

Numbers are resolved as strings, so a sign converts the value with Number(), like JS does: -'5' is -5, and +'0.50' is 0.5. A number literal round-trips through its string, so ${-5} and ${-0.25} give the same CSS as before.

A sign on a value that is not a number doesn't resolve, so the block is skipped with a warning:

  • a string like a class name, which would be NaN at runtime
  • a namespace, which would throw

Other unary operators (~, !, typeof, and so on) still don't resolve.

Warnings

referenceNameOf now names a signed reference with its sign. So ${-gap}, when gap doesn't resolve, warns UNRESOLVED_INTERPOLATION with could not resolve "-gap", like ${gap} does. Before, it warned COMPLEX_INTERPOLATION. A sign on a complex expression, like ${-Math.random()}, still warns COMPLEX_INTERPOLATION.

Tests

  • The literal interpolation test replaces negatedConstClass, which was skipped, with:
    • signedValueClass, which resolves a signed const, a double sign through a const, a signed import, and a signed numeric string
    • signedStringClass, a sign on a non-numeric string, which is skipped
    • bitwiseNotClass, with ~, which is skipped
  • The complex interpolation test adds a signed complex expression and a signed identifier that doesn't resolve, next to their unsigned cases.

Coverage is the same as on main: line 260 (now 285) is the only uncovered line, and the 15 uncovered branches are the same ones.

I didn't benchmark: only signed interpolations take the new path.

Docs

The README example shows signs on a literal and on an import, and its list of skipped interpolations adds signed values that are not numbers. AGENTS.md's transform entry says the values can be signed.

Left out

The recursion now covers every expression that resolveValue supports. These wrappers around such expressions still don't resolve, and each would be a one-line recursive case:

  • parentheses, like ${-(gap)}, which the parser keeps as ParenthesizedExpression
  • TypeScript's as, satisfies, and !, like ${gap as number}

🤖 Generated with Claude Code

`resolveValue` now resolves the argument of a `-` or `+` sign recursively,
so a sign applies to any value that resolves: a literal, a `const`, an
import, or a member of a namespace import, like `${-gap}` or
`${-theme.spacing}`. The sign converts the value to a number like JS does,
so `-'5'` is `-5`. A value that is not a number, like a class name, which
would be `NaN`, or a namespace, which would throw, does not resolve.

Warnings name a signed reference with its sign, like "-gap".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 8, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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