rnwind 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,13 @@ const UNSUPPORTED_LOGICAL_PROPS = new Set([
26
26
  'border-block-start-style',
27
27
  'border-block-end-style',
28
28
  ]);
29
+ /** CSS single-sided logical-inline property → RN writing-direction Yoga key. */
30
+ const LOGICAL_INLINE_TO_RN = {
31
+ 'margin-inline-start': 'marginStart',
32
+ 'margin-inline-end': 'marginEnd',
33
+ 'padding-inline-start': 'paddingStart',
34
+ 'padding-inline-end': 'paddingEnd',
35
+ };
29
36
  /**
30
37
  * Pick the closest predefined CSS easing keyword for a `cubic-bezier`
31
38
  * control-point set. Mirrors {@link snapCubicBezierToKeyword} in
@@ -338,7 +345,8 @@ function declarationToRnEntries(decl, themeVars) {
338
345
  return [['flexBasis', v]];
339
346
  }
340
347
  default: {
341
- return (layoutDispatcher.dispatchLayoutDeclaration(decl) ??
348
+ return (dispatchLogicalInline(decl) ??
349
+ layoutDispatcher.dispatchLayoutDeclaration(decl) ??
342
350
  typographyDispatcher.dispatchTypographyDeclaration(decl) ??
343
351
  colorPropertiesDispatcher.dispatchColorPropertyDeclaration(decl) ??
344
352
  borderDispatcher.dispatchBorderDeclaration(decl) ??
@@ -347,6 +355,37 @@ function declarationToRnEntries(decl, themeVars) {
347
355
  }
348
356
  }
349
357
  }
358
+ /**
359
+ * Map single-sided CSS logical-inline props to RN's writing-direction-aware
360
+ * Yoga keys: `ms-2` → `marginStart`, `pe-4` → `paddingEnd`, `start-2` →
361
+ * `start`, `end-3` → `end`. RN resolves start/end against the layout
362
+ * direction, so these stay RTL-correct. Returns null for any other property
363
+ * (so the dispatch chain continues).
364
+ * @param decl One declaration from a lightningcss style rule.
365
+ * @returns RN entries, or null when not a logical-inline property.
366
+ */
367
+ function dispatchLogicalInline(decl) {
368
+ switch (decl.property) {
369
+ case 'margin-inline-start':
370
+ case 'margin-inline-end':
371
+ case 'padding-inline-start':
372
+ case 'padding-inline-end': {
373
+ const v = length.lengthPercentageOrAutoToValue(decl.value);
374
+ return v === null ? [] : [[LOGICAL_INLINE_TO_RN[decl.property], v]];
375
+ }
376
+ case 'inset-inline-start': {
377
+ const v = length.lengthPercentageOrAutoToValue(decl.value);
378
+ return v === null ? [] : [['start', v]];
379
+ }
380
+ case 'inset-inline-end': {
381
+ const v = length.lengthPercentageOrAutoToValue(decl.value);
382
+ return v === null ? [] : [['end', v]];
383
+ }
384
+ default: {
385
+ return null;
386
+ }
387
+ }
388
+ }
350
389
 
351
390
  exports.declarationToRnEntries = declarationToRnEntries;
352
391
  //# sourceMappingURL=declaration.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"declaration.cjs","sources":["../../../../../src/core/parser/declaration.ts"],"sourcesContent":["/* eslint-disable sonarjs/cognitive-complexity -- the main Declaration → RN-entries dispatcher is intentionally a flat switch so each branch keeps its narrowed value type */\nimport type { Declaration as LcDeclaration, TokenOrValue } from 'lightningcss'\nimport { kebabToCamel } from './case-convert'\nimport { cssColorToString } from './color'\nimport { dimensionPercentageToNumber, gapValueToValue, lengthPercentageOrAutoToValue, sizeLikeToValue } from './length'\nimport {\n expandBorderColor,\n expandBorderRadius,\n expandFourSided,\n expandGap,\n expandLogicalBlock,\n expandLogicalInline,\n flexToEntries,\n} from './shorthand'\nimport { coerceFontFamily, coerceUnparsedValue, serializeTokens, substituteThemeVars } from './tokens'\nimport { displayToEntries, fontSizeToPx, fontWeightToValue, zIndexToNumber } from './typography'\nimport { dispatchMotionDeclaration } from './motion-dispatcher'\nimport { dispatchTypographyDeclaration } from './typography-dispatcher'\nimport { dispatchLayoutDeclaration } from './layout-dispatcher'\nimport { dispatchColorPropertyDeclaration } from './color-properties-dispatcher'\nimport { dispatchBorderDeclaration } from './border-dispatcher'\nimport { detectSafeAreaMarker } from './safe-area'\nimport type { RNEntry } from './types'\n\n/** CSS timing-function properties that need `cubic-bezier(...)` snapping. */\nconst TIMING_FUNCTION_PROPS = new Set(['transition-timing-function', 'animation-timing-function'])\n\n/** CSS easing keywords Reanimated v4's CSS engine accepts as strings. */\nconst CSS_EASING_KEYWORDS = new Set(['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end'])\n\n/** CSS properties with no useful RN equivalent — silently dropped. */\nconst UNSUPPORTED_LOGICAL_PROPS = new Set([\n 'border-inline-style',\n 'border-block-style',\n 'border-inline-start-style',\n 'border-inline-end-style',\n 'border-block-start-style',\n 'border-block-end-style',\n])\n\n/**\n * Pick the closest predefined CSS easing keyword for a `cubic-bezier`\n * control-point set. Mirrors {@link snapCubicBezierToKeyword} in\n * `animation.ts` — kept here so the unparsed-string path doesn't need\n * to import a typed-only helper.\n * @param x1 First control-point x (0–1).\n * @param y1 First control-point y (0–1).\n * @param x2 Second control-point x (0–1).\n * @param y2 Second control-point y (0–1).\n * @returns CSS easing keyword.\n */\nfunction snapBezier(x1: number, y1: number, x2: number, y2: number): string {\n const tol = 0.01\n const eq = (a: number, b: number): boolean => Math.abs(a - b) < tol\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'linear'\n if (eq(x1, 0.25) && eq(y1, 0.1) && eq(x2, 0.25) && eq(y2, 1)) return 'ease'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'ease-in'\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-out'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-in-out'\n const startsFlat = x1 < 0.1\n const endsFlat = x2 > 0.9\n if (startsFlat && !endsFlat) return 'ease-out'\n if (!startsFlat && endsFlat) return 'ease-in'\n return 'ease-in-out'\n}\n\n/**\n * Snap a cubic-bezier expression string to the closest CSS keyword\n * Reanimated v4's CSS engine accepts. Strings that already are keywords\n * pass through unchanged.\n * @param value Resolved value text from an unparsed timing-function declaration.\n * @returns CSS easing keyword.\n */\nfunction coerceCubicBezierString(value: string): string {\n const text = value.trim()\n if (CSS_EASING_KEYWORDS.has(text)) return text\n const match = /^cubic-bezier\\(\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*\\)$/.exec(text)\n if (!match) return 'ease-in-out'\n const [, x1, y1, x2, y2] = match\n return snapBezier(Number(x1), Number(y1), Number(x2), Number(y2))\n}\n\n/**\n * Fast-path check for the handful of color property names Tailwind emits.\n * @param property Kebab-case CSS property name.\n * @returns Whether the property's value should be treated as a color.\n */\nfunction isColorProperty(property: string): boolean {\n return (\n property === 'color' ||\n property === 'background-color' ||\n (property.startsWith('border-') && property.endsWith('-color')) ||\n property.endsWith('-color')\n )\n}\n\n/**\n * Convert an unparsed declaration (typical Tailwind v4 output containing\n * `var()` / `calc()`) into RN entries. Serializes the token list, then\n * coerces the flat string into a number / keyword / length via a tight\n * set of shapes Tailwind actually emits.\n * @param property Real property name (kebab-case).\n * @param tokens Token list from lightningcss.\n * @param themeVars Optional lookup table for resolving `var(--x)` references.\n * @returns RN entries — usually one, empty when unusable.\n */\nfunction unparsedToEntries(\n property: string,\n tokens: readonly TokenOrValue[],\n themeVars: ReadonlyMap<string, string> | undefined,\n): readonly RNEntry[] {\n if (property.length === 0) return []\n // Safe-area detection runs BEFORE token serialization because\n // `env()` serializes to an empty string, which would strip the side\n // info we need. If the tokens encode a recognised `env(safe-area-inset-*)`\n // pattern (pure / `max(..., n)` / `calc(...+n)` / `h-screen-safe`),\n // emit a runtime-resolved marker instead.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n const safe = detectSafeAreaMarker(tokens, themeVars)\n if (safe !== null) return [[kebabToCamel(property), safe]]\n let text = serializeTokens(tokens)\n if (themeVars && themeVars.size > 0) text = substituteThemeVars(text, themeVars)\n const coerced = coerceUnparsedValue(text)\n if (coerced === null) return []\n // Skip values that didn't resolve past their `var()` wrapper — they\n // came from a `@property --tw-*` token without a real fallback.\n // Tailwind v4's `border-N` emits `border-style: var(--tw-border-style)`\n // expecting the cascade to fill it in; in RN we drop them and rely on\n // RN's default (solid).\n if (typeof coerced === 'string' && coerced.startsWith('var(')) return []\n // RN `fontFamily` is a single typeface, not a CSS fallback list — take\n // the first family so `--font-x: \"Name\", sans-serif` works out of the box.\n if (property === 'font-family' && typeof coerced === 'string') {\n return [['fontFamily', coerceFontFamily(coerced)]]\n }\n // Logical-direction CSS properties RN doesn't have direct equivalents\n // for. Keep the dropped names in one place so it's easy to audit.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n if (TIMING_FUNCTION_PROPS.has(property) && typeof coerced === 'string') {\n // `transition-colors` and similar emit `var(--tw-ease, cubic-bezier(...))`\n // which serializes to a cubic-bezier STRING after substitution.\n // Reanimated v4's CSS engine rejects those — snap to the closest\n // predefined keyword (same logic as the typed `EasingFunction` path).\n return [[kebabToCamel(property), coerceCubicBezierString(coerced)]]\n }\n if (isColorProperty(property) && typeof coerced === 'string') {\n // Resolved user-theme color strings (e.g. `#ff0099`) go straight to\n // the RN style — no further conversion needed.\n return [[kebabToCamel(property), coerced]]\n }\n return [[kebabToCamel(property), coerced]]\n}\n\n/**\n * Convert one lightningcss `Declaration` into zero-or-more RN style\n * entries. Shorthand declarations (padding/margin/border-radius/flex) can\n * emit multiple entries; skipped or unsupported properties emit none.\n *\n * The switch branches on `decl.property` so TypeScript narrows\n * `decl.value` to the exact typed shape for each branch — no casts\n * required. Unknown properties fall through to `[]`.\n * @param decl One declaration from a lightningcss style rule.\n * @param themeVars Optional lookup table for resolving `var(--x)` references inside unparsed values.\n * @returns Array of `[key, value]` entries.\n */\nexport function declarationToRnEntries(decl: LcDeclaration, themeVars?: ReadonlyMap<string, string>): readonly RNEntry[] {\n switch (decl.property) {\n case 'custom': {\n // Lightningcss routes two shapes through `custom`:\n // - Actual CSS custom properties (`--my-var`): no RN meaning, drop.\n // - Real properties it doesn't have a dedicated typed entry for\n // (e.g. `object-fit`, `pointer-events`, future CSS keyword-only\n // props): treat like an unparsed declaration so the keyword\n // surfaces in the RN style.\n const customName = decl.value.name\n if (customName.startsWith('--')) return []\n return unparsedToEntries(customName, decl.value.value ?? [], themeVars)\n }\n case 'unparsed': {\n return unparsedToEntries(decl.value.propertyId.property, decl.value.value, themeVars)\n }\n case 'color':\n case 'background-color':\n case 'border-top-color':\n case 'border-right-color':\n case 'border-bottom-color':\n case 'border-left-color': {\n // `background-color` narrows to `CssColor | 'background'` — the\n // literal keyword means UA default. Skip the keyword.\n if (typeof decl.value === 'string') return []\n return [[kebabToCamel(decl.property), cssColorToString(decl.value)]]\n }\n case 'border-color': {\n return expandBorderColor(decl.value)\n }\n case 'opacity': {\n // Lightningcss hands us an `f32` for opacity, so values like `0.8`\n // round-trip as `0.800000011920929`. Snap to 4 decimals to match the\n // rest of the parser's numeric convention.\n return [[decl.property, Math.round(decl.value * 10_000) / 10_000]]\n }\n case 'z-index': {\n return [['zIndex', zIndexToNumber(decl.value)]]\n }\n case 'top':\n case 'right':\n case 'bottom':\n case 'left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[decl.property, v]]\n }\n case 'inset': {\n const top = lengthPercentageOrAutoToValue(decl.value.top)\n const right = lengthPercentageOrAutoToValue(decl.value.right)\n const bottom = lengthPercentageOrAutoToValue(decl.value.bottom)\n const left = lengthPercentageOrAutoToValue(decl.value.left)\n if (top === null || right === null || bottom === null || left === null) return []\n return [\n ['top', top],\n ['right', right],\n ['bottom', bottom],\n ['left', left],\n ]\n }\n case 'inset-inline': {\n const start = lengthPercentageOrAutoToValue(decl.value.inlineStart)\n const end = lengthPercentageOrAutoToValue(decl.value.inlineEnd)\n if (start === null || end === null) return []\n return [\n ['left', start],\n ['right', end],\n ]\n }\n case 'inset-block': {\n const start = lengthPercentageOrAutoToValue(decl.value.blockStart)\n const end = lengthPercentageOrAutoToValue(decl.value.blockEnd)\n if (start === null || end === null) return []\n return [\n ['top', start],\n ['bottom', end],\n ]\n }\n case 'width':\n case 'height':\n case 'min-width':\n case 'min-height':\n case 'max-width':\n case 'max-height': {\n const v = sizeLikeToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'gap': {\n return expandGap(decl.value)\n }\n case 'row-gap':\n case 'column-gap': {\n const v = gapValueToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'font-style': {\n return [['fontStyle', decl.value.type]]\n }\n case 'display': {\n return displayToEntries(decl.value)\n }\n case 'position': {\n return [['position', decl.value.type]]\n }\n case 'font-size': {\n const px = fontSizeToPx(decl.value)\n if (px === null) return []\n return [['fontSize', px]]\n }\n case 'font-weight': {\n return [['fontWeight', fontWeightToValue(decl.value)]]\n }\n case 'padding': {\n return expandFourSided('padding', decl.value)\n }\n case 'margin': {\n return expandFourSided('margin', decl.value)\n }\n case 'padding-inline': {\n return expandLogicalInline('padding', decl.value)\n }\n case 'padding-block': {\n return expandLogicalBlock('padding', decl.value)\n }\n case 'margin-inline': {\n return expandLogicalInline('margin', decl.value)\n }\n case 'margin-block': {\n return expandLogicalBlock('margin', decl.value)\n }\n case 'padding-top':\n case 'padding-right':\n case 'padding-bottom':\n case 'padding-left':\n case 'margin-top':\n case 'margin-right':\n case 'margin-bottom':\n case 'margin-left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'border-radius': {\n return expandBorderRadius(decl.value)\n }\n case 'border-top-left-radius':\n case 'border-top-right-radius':\n case 'border-bottom-left-radius':\n case 'border-bottom-right-radius': {\n const [xAxis] = decl.value\n const v = dimensionPercentageToNumber(xAxis)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'flex': {\n return flexToEntries(decl.value)\n }\n case 'flex-grow':\n case 'flex-shrink': {\n return [[kebabToCamel(decl.property), decl.value]]\n }\n case 'flex-basis': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [['flexBasis', v]]\n }\n default: {\n return (\n dispatchLayoutDeclaration(decl) ??\n dispatchTypographyDeclaration(decl) ??\n dispatchColorPropertyDeclaration(decl) ??\n dispatchBorderDeclaration(decl) ??\n dispatchMotionDeclaration(decl) ??\n []\n )\n }\n }\n}\n"],"names":["tokens","detectSafeAreaMarker","kebabToCamel","serializeTokens","substituteThemeVars","coerceUnparsedValue","coerceFontFamily","cssColorToString","expandBorderColor","zIndexToNumber","lengthPercentageOrAutoToValue","sizeLikeToValue","expandGap","gapValueToValue","displayToEntries","fontSizeToPx","fontWeightToValue","expandFourSided","expandLogicalInline","expandLogicalBlock","expandBorderRadius","dimensionPercentageToNumber","flexToEntries","dispatchLayoutDeclaration","dispatchTypographyDeclaration","dispatchColorPropertyDeclaration","dispatchBorderDeclaration","dispatchMotionDeclaration"],"mappings":"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"}
1
+ {"version":3,"file":"declaration.cjs","sources":["../../../../../src/core/parser/declaration.ts"],"sourcesContent":["/* eslint-disable sonarjs/cognitive-complexity -- the main Declaration → RN-entries dispatcher is intentionally a flat switch so each branch keeps its narrowed value type */\nimport type { Declaration as LcDeclaration, TokenOrValue } from 'lightningcss'\nimport { kebabToCamel } from './case-convert'\nimport { cssColorToString } from './color'\nimport { dimensionPercentageToNumber, gapValueToValue, lengthPercentageOrAutoToValue, sizeLikeToValue } from './length'\nimport {\n expandBorderColor,\n expandBorderRadius,\n expandFourSided,\n expandGap,\n expandLogicalBlock,\n expandLogicalInline,\n flexToEntries,\n} from './shorthand'\nimport { coerceFontFamily, coerceUnparsedValue, serializeTokens, substituteThemeVars } from './tokens'\nimport { displayToEntries, fontSizeToPx, fontWeightToValue, zIndexToNumber } from './typography'\nimport { dispatchMotionDeclaration } from './motion-dispatcher'\nimport { dispatchTypographyDeclaration } from './typography-dispatcher'\nimport { dispatchLayoutDeclaration } from './layout-dispatcher'\nimport { dispatchColorPropertyDeclaration } from './color-properties-dispatcher'\nimport { dispatchBorderDeclaration } from './border-dispatcher'\nimport { detectSafeAreaMarker } from './safe-area'\nimport type { RNEntry } from './types'\n\n/** CSS timing-function properties that need `cubic-bezier(...)` snapping. */\nconst TIMING_FUNCTION_PROPS = new Set(['transition-timing-function', 'animation-timing-function'])\n\n/** CSS easing keywords Reanimated v4's CSS engine accepts as strings. */\nconst CSS_EASING_KEYWORDS = new Set(['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end'])\n\n/** CSS properties with no useful RN equivalent — silently dropped. */\nconst UNSUPPORTED_LOGICAL_PROPS = new Set([\n 'border-inline-style',\n 'border-block-style',\n 'border-inline-start-style',\n 'border-inline-end-style',\n 'border-block-start-style',\n 'border-block-end-style',\n])\n\n/** CSS single-sided logical-inline property → RN writing-direction Yoga key. */\nconst LOGICAL_INLINE_TO_RN: Record<string, string> = {\n 'margin-inline-start': 'marginStart',\n 'margin-inline-end': 'marginEnd',\n 'padding-inline-start': 'paddingStart',\n 'padding-inline-end': 'paddingEnd',\n}\n\n/**\n * Pick the closest predefined CSS easing keyword for a `cubic-bezier`\n * control-point set. Mirrors {@link snapCubicBezierToKeyword} in\n * `animation.ts` — kept here so the unparsed-string path doesn't need\n * to import a typed-only helper.\n * @param x1 First control-point x (0–1).\n * @param y1 First control-point y (0–1).\n * @param x2 Second control-point x (0–1).\n * @param y2 Second control-point y (0–1).\n * @returns CSS easing keyword.\n */\nfunction snapBezier(x1: number, y1: number, x2: number, y2: number): string {\n const tol = 0.01\n const eq = (a: number, b: number): boolean => Math.abs(a - b) < tol\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'linear'\n if (eq(x1, 0.25) && eq(y1, 0.1) && eq(x2, 0.25) && eq(y2, 1)) return 'ease'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'ease-in'\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-out'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-in-out'\n const startsFlat = x1 < 0.1\n const endsFlat = x2 > 0.9\n if (startsFlat && !endsFlat) return 'ease-out'\n if (!startsFlat && endsFlat) return 'ease-in'\n return 'ease-in-out'\n}\n\n/**\n * Snap a cubic-bezier expression string to the closest CSS keyword\n * Reanimated v4's CSS engine accepts. Strings that already are keywords\n * pass through unchanged.\n * @param value Resolved value text from an unparsed timing-function declaration.\n * @returns CSS easing keyword.\n */\nfunction coerceCubicBezierString(value: string): string {\n const text = value.trim()\n if (CSS_EASING_KEYWORDS.has(text)) return text\n const match = /^cubic-bezier\\(\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*\\)$/.exec(text)\n if (!match) return 'ease-in-out'\n const [, x1, y1, x2, y2] = match\n return snapBezier(Number(x1), Number(y1), Number(x2), Number(y2))\n}\n\n/**\n * Fast-path check for the handful of color property names Tailwind emits.\n * @param property Kebab-case CSS property name.\n * @returns Whether the property's value should be treated as a color.\n */\nfunction isColorProperty(property: string): boolean {\n return (\n property === 'color' ||\n property === 'background-color' ||\n (property.startsWith('border-') && property.endsWith('-color')) ||\n property.endsWith('-color')\n )\n}\n\n/**\n * Convert an unparsed declaration (typical Tailwind v4 output containing\n * `var()` / `calc()`) into RN entries. Serializes the token list, then\n * coerces the flat string into a number / keyword / length via a tight\n * set of shapes Tailwind actually emits.\n * @param property Real property name (kebab-case).\n * @param tokens Token list from lightningcss.\n * @param themeVars Optional lookup table for resolving `var(--x)` references.\n * @returns RN entries — usually one, empty when unusable.\n */\nfunction unparsedToEntries(\n property: string,\n tokens: readonly TokenOrValue[],\n themeVars: ReadonlyMap<string, string> | undefined,\n): readonly RNEntry[] {\n if (property.length === 0) return []\n // Safe-area detection runs BEFORE token serialization because\n // `env()` serializes to an empty string, which would strip the side\n // info we need. If the tokens encode a recognised `env(safe-area-inset-*)`\n // pattern (pure / `max(..., n)` / `calc(...+n)` / `h-screen-safe`),\n // emit a runtime-resolved marker instead.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n const safe = detectSafeAreaMarker(tokens, themeVars)\n if (safe !== null) return [[kebabToCamel(property), safe]]\n let text = serializeTokens(tokens)\n if (themeVars && themeVars.size > 0) text = substituteThemeVars(text, themeVars)\n const coerced = coerceUnparsedValue(text)\n if (coerced === null) return []\n // Skip values that didn't resolve past their `var()` wrapper — they\n // came from a `@property --tw-*` token without a real fallback.\n // Tailwind v4's `border-N` emits `border-style: var(--tw-border-style)`\n // expecting the cascade to fill it in; in RN we drop them and rely on\n // RN's default (solid).\n if (typeof coerced === 'string' && coerced.startsWith('var(')) return []\n // RN `fontFamily` is a single typeface, not a CSS fallback list — take\n // the first family so `--font-x: \"Name\", sans-serif` works out of the box.\n if (property === 'font-family' && typeof coerced === 'string') {\n return [['fontFamily', coerceFontFamily(coerced)]]\n }\n // Logical-direction CSS properties RN doesn't have direct equivalents\n // for. Keep the dropped names in one place so it's easy to audit.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n if (TIMING_FUNCTION_PROPS.has(property) && typeof coerced === 'string') {\n // `transition-colors` and similar emit `var(--tw-ease, cubic-bezier(...))`\n // which serializes to a cubic-bezier STRING after substitution.\n // Reanimated v4's CSS engine rejects those — snap to the closest\n // predefined keyword (same logic as the typed `EasingFunction` path).\n return [[kebabToCamel(property), coerceCubicBezierString(coerced)]]\n }\n if (isColorProperty(property) && typeof coerced === 'string') {\n // Resolved user-theme color strings (e.g. `#ff0099`) go straight to\n // the RN style — no further conversion needed.\n return [[kebabToCamel(property), coerced]]\n }\n return [[kebabToCamel(property), coerced]]\n}\n\n/**\n * Convert one lightningcss `Declaration` into zero-or-more RN style\n * entries. Shorthand declarations (padding/margin/border-radius/flex) can\n * emit multiple entries; skipped or unsupported properties emit none.\n *\n * The switch branches on `decl.property` so TypeScript narrows\n * `decl.value` to the exact typed shape for each branch — no casts\n * required. Unknown properties fall through to `[]`.\n * @param decl One declaration from a lightningcss style rule.\n * @param themeVars Optional lookup table for resolving `var(--x)` references inside unparsed values.\n * @returns Array of `[key, value]` entries.\n */\nexport function declarationToRnEntries(decl: LcDeclaration, themeVars?: ReadonlyMap<string, string>): readonly RNEntry[] {\n switch (decl.property) {\n case 'custom': {\n // Lightningcss routes two shapes through `custom`:\n // - Actual CSS custom properties (`--my-var`): no RN meaning, drop.\n // - Real properties it doesn't have a dedicated typed entry for\n // (e.g. `object-fit`, `pointer-events`, future CSS keyword-only\n // props): treat like an unparsed declaration so the keyword\n // surfaces in the RN style.\n const customName = decl.value.name\n if (customName.startsWith('--')) return []\n return unparsedToEntries(customName, decl.value.value ?? [], themeVars)\n }\n case 'unparsed': {\n return unparsedToEntries(decl.value.propertyId.property, decl.value.value, themeVars)\n }\n case 'color':\n case 'background-color':\n case 'border-top-color':\n case 'border-right-color':\n case 'border-bottom-color':\n case 'border-left-color': {\n // `background-color` narrows to `CssColor | 'background'` — the\n // literal keyword means UA default. Skip the keyword.\n if (typeof decl.value === 'string') return []\n return [[kebabToCamel(decl.property), cssColorToString(decl.value)]]\n }\n case 'border-color': {\n return expandBorderColor(decl.value)\n }\n case 'opacity': {\n // Lightningcss hands us an `f32` for opacity, so values like `0.8`\n // round-trip as `0.800000011920929`. Snap to 4 decimals to match the\n // rest of the parser's numeric convention.\n return [[decl.property, Math.round(decl.value * 10_000) / 10_000]]\n }\n case 'z-index': {\n return [['zIndex', zIndexToNumber(decl.value)]]\n }\n case 'top':\n case 'right':\n case 'bottom':\n case 'left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[decl.property, v]]\n }\n case 'inset': {\n const top = lengthPercentageOrAutoToValue(decl.value.top)\n const right = lengthPercentageOrAutoToValue(decl.value.right)\n const bottom = lengthPercentageOrAutoToValue(decl.value.bottom)\n const left = lengthPercentageOrAutoToValue(decl.value.left)\n if (top === null || right === null || bottom === null || left === null) return []\n return [\n ['top', top],\n ['right', right],\n ['bottom', bottom],\n ['left', left],\n ]\n }\n case 'inset-inline': {\n const start = lengthPercentageOrAutoToValue(decl.value.inlineStart)\n const end = lengthPercentageOrAutoToValue(decl.value.inlineEnd)\n if (start === null || end === null) return []\n return [\n ['left', start],\n ['right', end],\n ]\n }\n case 'inset-block': {\n const start = lengthPercentageOrAutoToValue(decl.value.blockStart)\n const end = lengthPercentageOrAutoToValue(decl.value.blockEnd)\n if (start === null || end === null) return []\n return [\n ['top', start],\n ['bottom', end],\n ]\n }\n case 'width':\n case 'height':\n case 'min-width':\n case 'min-height':\n case 'max-width':\n case 'max-height': {\n const v = sizeLikeToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'gap': {\n return expandGap(decl.value)\n }\n case 'row-gap':\n case 'column-gap': {\n const v = gapValueToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'font-style': {\n return [['fontStyle', decl.value.type]]\n }\n case 'display': {\n return displayToEntries(decl.value)\n }\n case 'position': {\n return [['position', decl.value.type]]\n }\n case 'font-size': {\n const px = fontSizeToPx(decl.value)\n if (px === null) return []\n return [['fontSize', px]]\n }\n case 'font-weight': {\n return [['fontWeight', fontWeightToValue(decl.value)]]\n }\n case 'padding': {\n return expandFourSided('padding', decl.value)\n }\n case 'margin': {\n return expandFourSided('margin', decl.value)\n }\n case 'padding-inline': {\n return expandLogicalInline('padding', decl.value)\n }\n case 'padding-block': {\n return expandLogicalBlock('padding', decl.value)\n }\n case 'margin-inline': {\n return expandLogicalInline('margin', decl.value)\n }\n case 'margin-block': {\n return expandLogicalBlock('margin', decl.value)\n }\n case 'padding-top':\n case 'padding-right':\n case 'padding-bottom':\n case 'padding-left':\n case 'margin-top':\n case 'margin-right':\n case 'margin-bottom':\n case 'margin-left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'border-radius': {\n return expandBorderRadius(decl.value)\n }\n case 'border-top-left-radius':\n case 'border-top-right-radius':\n case 'border-bottom-left-radius':\n case 'border-bottom-right-radius': {\n const [xAxis] = decl.value\n const v = dimensionPercentageToNumber(xAxis)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'flex': {\n return flexToEntries(decl.value)\n }\n case 'flex-grow':\n case 'flex-shrink': {\n return [[kebabToCamel(decl.property), decl.value]]\n }\n case 'flex-basis': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [['flexBasis', v]]\n }\n default: {\n return (\n dispatchLogicalInline(decl) ??\n dispatchLayoutDeclaration(decl) ??\n dispatchTypographyDeclaration(decl) ??\n dispatchColorPropertyDeclaration(decl) ??\n dispatchBorderDeclaration(decl) ??\n dispatchMotionDeclaration(decl) ??\n []\n )\n }\n }\n}\n\n/**\n * Map single-sided CSS logical-inline props to RN's writing-direction-aware\n * Yoga keys: `ms-2` → `marginStart`, `pe-4` → `paddingEnd`, `start-2` →\n * `start`, `end-3` → `end`. RN resolves start/end against the layout\n * direction, so these stay RTL-correct. Returns null for any other property\n * (so the dispatch chain continues).\n * @param decl One declaration from a lightningcss style rule.\n * @returns RN entries, or null when not a logical-inline property.\n */\nfunction dispatchLogicalInline(decl: LcDeclaration): readonly RNEntry[] | null {\n switch (decl.property) {\n case 'margin-inline-start':\n case 'margin-inline-end':\n case 'padding-inline-start':\n case 'padding-inline-end': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n return v === null ? [] : [[LOGICAL_INLINE_TO_RN[decl.property], v]]\n }\n case 'inset-inline-start': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n return v === null ? [] : [['start', v]]\n }\n case 'inset-inline-end': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n return v === null ? [] : [['end', v]]\n }\n default: {\n return null\n }\n }\n}\n"],"names":["tokens","detectSafeAreaMarker","kebabToCamel","serializeTokens","substituteThemeVars","coerceUnparsedValue","coerceFontFamily","cssColorToString","expandBorderColor","zIndexToNumber","lengthPercentageOrAutoToValue","sizeLikeToValue","expandGap","gapValueToValue","displayToEntries","fontSizeToPx","fontWeightToValue","expandFourSided","expandLogicalInline","expandLogicalBlock","expandBorderRadius","dimensionPercentageToNumber","flexToEntries","dispatchLayoutDeclaration","dispatchTypographyDeclaration","dispatchColorPropertyDeclaration","dispatchBorderDeclaration","dispatchMotionDeclaration"],"mappings":"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"}
@@ -31,6 +31,13 @@ var t__namespace = /*#__PURE__*/_interopNamespaceDefault(t);
31
31
 
32
32
  /** Env var that points at the upstream `babelTransformerPath` we override. */
33
33
  const UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER';
34
+ /**
35
+ * Matches a `useCss(` call. Files that resolve classes via the `useCss`
36
+ * hook (no JSX `className=`) must still be scanned so the classes inside
37
+ * `useCss("…")` get registered — common for theme/accent hooks living in a
38
+ * shared package the project scan may not reach.
39
+ */
40
+ const USE_CSS_CALL = /\buseCss\s*\(/;
34
41
  /** Cached upstream module — required once, reused across every transform call. */
35
42
  let cachedUpstream = null;
36
43
  const generateModule = generate.default ?? generate;
@@ -148,17 +155,25 @@ async function rewriteSource(args) {
148
155
  const ast = parseUserSource(args.src);
149
156
  if (!ast)
150
157
  return args.src;
151
- // Wrap host component imports so `<View className=…>` resolves at render
152
- // through the runtime `wrap` (works for literal, spread, and forwarded
153
- // classNames alike). No JSX is rewritten here.
154
- const wrapped = wrapImports.rewriteWrapImports(ast, state.getWrapModules());
155
- if (!/classname=/i.test(args.src)) {
158
+ const hasClassName = /classname=/i.test(args.src);
159
+ const hasUseCss = USE_CSS_CALL.test(args.src);
160
+ const hasSpread = /\{\s*\.\.\./.test(args.src);
161
+ // Wrap host component imports ONLY when className arrives through a
162
+ // component — written (`hasClassName`) or forwarded (`hasSpread`). A
163
+ // `useCss("…")`-only file resolves manually, so we must NOT wrap its
164
+ // imports: a non-RN drawing lib (e.g. skia's `LinearGradient` nested in
165
+ // `SkiaText`) breaks if its primitives are replaced by a wrapper.
166
+ const wrapped = hasClassName || hasSpread ? wrapImports.rewriteWrapImports(ast, state.getWrapModules()) : false;
167
+ if (!hasClassName && !hasUseCss) {
156
168
  // Import-only file: nothing to compile. Drop any stale atom
157
169
  // contribution (className may have just been removed) and emit the
158
170
  // wrapped imports — or the untouched source when nothing wrapped.
159
171
  dropFileSafely(args.filename, projectRootOf(args));
160
172
  return wrapped ? generateModule(ast).code : args.src;
161
173
  }
174
+ // Scan path — runs for `className=` literals AND/OR `useCss("…")` strings.
175
+ // oxide reads class candidates from the whole file content, so classes
176
+ // that only ever appear inside a `useCss("…")` call still register.
162
177
  const state$1 = state.getRnwindState(projectRootOf(args));
163
178
  const extension = extensionOf(args.filename);
164
179
  const parsed = await state$1.parser.parseAtoms({ content: args.src, extension });
@@ -403,13 +418,16 @@ function isRewriteCandidate(args) {
403
418
  // Process the file when it either:
404
419
  // - carries a `className=` / `<prefix>ClassName=` literal (case-
405
420
  // insensitive — `contentContainerClassName=` has a capital C), or
421
+ // - calls `useCss("…")` (classes that only ever appear in the hook must
422
+ // still be scanned + registered — common for theme/accent hooks), or
406
423
  // - spreads props (`{...rest}`) onto a host from a wrap-module, where a
407
424
  // forwarded className must still get its import wrapped (no literal
408
- // appears in this file). A style-less `<View/>` with neither is left
425
+ // appears in this file). A style-less `<View/>` with none is left
409
426
  // alone so it never pays for an unused wrapper.
410
427
  const hasClassName = /classname=/i.test(args.src);
428
+ const hasUseCss = USE_CSS_CALL.test(args.src);
411
429
  const isForwarder = /\{\s*\.\.\./.test(args.src) && mentionsWrapModule(args.src);
412
- if (!hasClassName && !isForwarder)
430
+ if (!hasClassName && !hasUseCss && !isForwarder)
413
431
  return false;
414
432
  if (!args.filename.includes('/node_modules/'))
415
433
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"transformer.cjs","sources":["../../../../src/metro/transformer.ts"],"sourcesContent":["import type { File } from '@babel/types'\nimport * as t from '@babel/types'\nimport { parse } from '@babel/parser'\nimport generate from '@babel/generator'\nimport { createHash } from 'node:crypto'\nimport { realpathSync } from 'node:fs'\nimport { getRnwindCacheKey, getRnwindState, getWrapModules, onThemeChange } from './state'\nimport { rewriteWrapImports } from './wrap-imports'\nimport { STYLE_SPECIFIERS, THEME_SIGNATURE_MODULE } from './resolver'\nimport { filterUnknownClassCandidates } from './warn-unknown-classes'\n\n/** The shape of the upstream module we delegate parsing/babel work to. */\ninterface UpstreamTransformer {\n transform: (args: BabelTransformerArgs) => Promise<BabelTransformerResult> | BabelTransformerResult\n}\n\n/** Env var that points at the upstream `babelTransformerPath` we override. */\nconst UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER'\n\n/** Cached upstream module — required once, reused across every transform call. */\nlet cachedUpstream: UpstreamTransformer | null = null\n\nconst generateModule = (generate as unknown as { default?: typeof generate }).default ?? generate\n\n/**\n * Parse user source with the broad plugin set (Flow + JSX + TypeScript\n * + class properties). Permissive on purpose so we don't reject any\n * file the upstream could have handled. Returns `null` when parse\n * fails — caller falls back to the raw source string.\n * @param source Source text.\n * @returns Parsed AST, or null on parse failure.\n */\nfunction parseUserSource(source: string): File | null {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['typescript', 'jsx'],\n }) as unknown as File\n } catch {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['flow', 'jsx'],\n }) as unknown as File\n } catch {\n return null\n }\n }\n}\n\n/**\n * Print Tailwind-shaped candidates oxide picked up but the parser\n * could NOT compile — typo, missing custom utility, or class not in\n * the user's theme. Filtering by candidates that ALSO appear inside a\n * `className=\"…\"` literal eliminates false positives from imports,\n * comments, and JSX prop values.\n * @param source Original source text — searched for className literals.\n * @param candidates Every candidate oxide surfaced from the source.\n * @param atoms Successfully resolved atoms (keys are class names).\n * @param filename Source path, prefixed onto the warning.\n * @param features Feature-atom maps (gradient / haptic) — their names are\n * known classes even though they carry no RN style, so they're excluded\n * from the unknown-class warning.\n */\nfunction warnUnknownClasses(\n source: string,\n candidates: readonly string[],\n atoms: ReadonlyMap<string, unknown>,\n filename: string,\n features: ReadonlyArray<ReadonlyMap<string, unknown>> = [],\n): void {\n // Feature atoms (gradient / haptic) resolve to no RN style, so they're\n // absent from `atoms` — but they're NOT unknown. Fold their names into\n // the known set so `active:haptic-rigid` etc. don't warn at build time.\n const known = new Set(atoms.keys())\n for (const map of features) for (const name of map.keys()) known.add(name)\n const unknown = filterUnknownClassCandidates(source, candidates, known)\n if (unknown.length === 0) return\n // eslint-disable-next-line no-console\n console.warn(`rnwind: unknown class${unknown.length > 1 ? 'es' : ''} in ${filename}: ${unknown.join(', ')}`)\n}\n\n/**\n * Extract the bare extension for oxide / internal switches.\n * @param filename Absolute path.\n * @returns Extension without the leading dot (`tsx` / `ts` / `js` / `jsx`).\n */\nfunction extensionOf(filename: string): string {\n const index = filename.lastIndexOf('.')\n if (index === -1) return 'tsx'\n return filename.slice(index + 1)\n}\n\n/**\n * Read the project root Metro hands us per-transform. Falls back to\n * `process.cwd()` only when the upstream harness doesn't set it (unit\n * tests, standalone). Metro's production pipeline always sets it.\n * @param args Metro transformer args.\n * @returns Absolute project root.\n */\nfunction projectRootOf(args: BabelTransformerArgs): string {\n const fromOptions = args.options?.projectRoot\n if (typeof fromOptions === 'string' && fromOptions.length > 0) return fromOptions\n return process.cwd()\n}\n\n/**\n * Whether a `.css` filename is the user's theme entry (the file\n * `withRnwindConfig` pointed us at via `RNWIND_CSS_ENTRY_FILE`).\n * Only the theme CSS should trigger a scheme rebuild — unrelated CSS\n * files in the project stay invisible to rnwind.\n * @param filename Absolute CSS path.\n * @returns Whether the file is the configured theme entry.\n */\nfunction isThemeCssEntry(filename: string): boolean {\n const cssEntry = process.env.RNWIND_CSS_ENTRY_FILE\n return typeof cssEntry === 'string' && cssEntry.length > 0 && cssEntry === filename\n}\n\n/**\n * Wrap host imports + compile any className literals, then regenerate\n * source. Two paths:\n * - **className present**: oxide-scan the file, record its atoms into\n * the union, and inject the generated-style + theme-signature\n * side-effect imports so the runtime registries populate.\n * - **import-only** (a `{...rest}` forwarder or a leaf with no literal\n * `className=`): just wrap the host imports so a forwarded className\n * still resolves at render — no oxide scan, no injected imports.\n *\n * On parse failure, fall back to the original source — a transient parse\n * error shouldn't crash Metro for a file the upstream might handle fine.\n * @param args Metro args; `src` is the original source text.\n * @returns Rewritten source text.\n */\nasync function rewriteSource(args: BabelTransformerArgs): Promise<string> {\n const ast = parseUserSource(args.src)\n if (!ast) return args.src\n\n // Wrap host component imports so `<View className=…>` resolves at render\n // through the runtime `wrap` (works for literal, spread, and forwarded\n // classNames alike). No JSX is rewritten here.\n const wrapped = rewriteWrapImports(ast, getWrapModules())\n\n if (!/classname=/i.test(args.src)) {\n // Import-only file: nothing to compile. Drop any stale atom\n // contribution (className may have just been removed) and emit the\n // wrapped imports — or the untouched source when nothing wrapped.\n dropFileSafely(args.filename, projectRootOf(args))\n return wrapped ? generateModule(ast).code : args.src\n }\n\n const state = getRnwindState(projectRootOf(args))\n const extension = extensionOf(args.filename)\n const parsed = await state.parser.parseAtoms({ content: args.src, extension })\n\n warnUnknownClasses(args.src, parsed.candidates, parsed.atoms, args.filename, [parsed.gradientAtoms, parsed.hapticAtoms])\n\n if (parsed.atoms.size === 0) {\n state.builder.dropFile(args.filename)\n await state.builder.writeSchemes()\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n }\n\n const literals = collectClassNameLiterals(ast)\n const { changed } = await state.builder.recordFile(args.filename, parsed.atoms, parsed.keyframes, literals)\n if (changed) await state.builder.writeSchemes()\n\n injectSideEffectImports(ast, STYLE_SPECIFIERS)\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n}\n\n/**\n * Drop a file's union contribution, swallowing the \"state not configured\"\n * error unit tests hit when they call the transformer without\n * `configureRnwindState`.\n * @param filename Absolute source path.\n * @param projectRoot Project root for state lookup.\n */\nfunction dropFileSafely(filename: string, projectRoot: string): void {\n try {\n getRnwindState(projectRoot).builder.dropFile(filename)\n } catch {\n // State not configured (standalone/unit test). Nothing to drop.\n }\n}\n\n/**\n * Whether a JSX attribute names a className-style prop (`className` or\n * any `<prefix>ClassName`).\n * @param node JSX attribute node.\n * @returns True when the attribute is a className prop.\n */\nfunction isClassNameAttribute(node: t.JSXAttribute): boolean {\n if (!t.isJSXIdentifier(node.name)) return false\n const {name} = node.name\n return name === 'className' || name.endsWith('ClassName')\n}\n\n/**\n * Pull static string literals out of a className expression. Handles a\n * bare string, a no-substitution template, and the branches of a\n * ternary / `&&` (so `cond ? 'a' : 'b'` and `flag && 'x'` both register\n * their literals). Dynamic interpolations are skipped — they resolve via\n * the runtime atom path.\n * @param expr Expression inside a `className={...}` container.\n * @param out Accumulator for discovered literals.\n */\nfunction collectLiteralsFromExpression(expr: t.Expression | t.JSXEmptyExpression | null | undefined, out: string[]): void {\n if (!expr) return\n if (t.isStringLiteral(expr)) {\n out.push(expr.value)\n return\n }\n if (t.isTemplateLiteral(expr) && expr.expressions.length === 0 && expr.quasis.length === 1) {\n const cooked = expr.quasis[0]?.value.cooked\n if (typeof cooked === 'string') out.push(cooked)\n return\n }\n if (t.isConditionalExpression(expr)) {\n collectLiteralsFromExpression(expr.consequent, out)\n collectLiteralsFromExpression(expr.alternate, out)\n return\n }\n if (t.isLogicalExpression(expr)) {\n collectLiteralsFromExpression(expr.right as t.Expression, out)\n }\n}\n\n/** AST node keys the literal walk skips — position / comment metadata. */\nconst SKIP_WALK_KEYS = new Set(['type', 'loc', 'start', 'end', 'range', 'leadingComments', 'trailingComments', 'innerComments'])\n\n/**\n * Collect the static literals from one className JSX attribute into the\n * dedup accumulator.\n * @param attribute The (already className-matched) JSX attribute.\n * @param seen Dedup set of literals already collected.\n * @param out Ordered accumulator.\n */\nfunction collectAttributeLiterals(attribute: t.JSXAttribute, seen: Set<string>, out: string[]): void {\n const { value } = attribute\n const found: string[] = []\n if (t.isStringLiteral(value)) found.push(value.value)\n else if (t.isJSXExpressionContainer(value)) collectLiteralsFromExpression(value.expression, found)\n for (const literal of found) {\n if (seen.has(literal)) continue\n seen.add(literal)\n out.push(literal)\n }\n}\n\n/**\n * Walk the AST for every `className=` / `<prefix>ClassName=` literal so\n * the builder can pre-merge each into a per-scheme molecule. A generic\n * node walk (no scope build) keeps it cheap; only JSX attribute nodes do\n * any work.\n * @param ast Parsed Babel file.\n * @returns Distinct literal className strings, in first-seen order.\n */\nfunction collectClassNameLiterals(ast: File): readonly string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const visit = (node: unknown): void => {\n if (!node || typeof node !== 'object') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n const typed = node as { type?: string; [key: string]: unknown }\n if (typeof typed.type !== 'string') return\n if (typed.type === 'JSXAttribute' && isClassNameAttribute(node as t.JSXAttribute)) {\n collectAttributeLiterals(node as t.JSXAttribute, seen, out)\n }\n for (const key in typed) {\n if (SKIP_WALK_KEYS.has(key)) continue\n visit(typed[key])\n }\n }\n visit(ast.program)\n return out\n}\n\n/**\n * Prepend side-effect imports (`import '<spec>'`) so the generated\n * per-scheme style + manifest modules load — registering this file's\n * atoms / molecules / features into the runtime registries the wrapper's\n * `resolve` reads.\n * @param ast Babel File AST to mutate in place.\n * @param specifiers Module specifiers to side-effect-import.\n */\nfunction injectSideEffectImports(ast: File, specifiers: readonly string[]): void {\n for (const specifier of specifiers) {\n ast.program.body.unshift(t.importDeclaration([], t.stringLiteral(specifier)))\n }\n}\n\n/**\n * Prepend `import 'rnwind/__generated/theme-signature'` to every\n * rnwind-transformed file. The resolver maps that specifier to the\n * user's theme CSS so Metro's dependency graph carries a real edge\n * from this JS file to the CSS. When the user edits `global.css`,\n * the CSS module's SHA1 changes, and Metro invalidates every JS file\n * holding this import — forcing them to re-transform with the new\n * theme. The `.css` branch in {@link transform} returns an empty\n * `export {}` module so the runtime cost is one extra `require()`.\n * @param ast Babel File AST to mutate in place.\n */\nfunction injectThemeSignatureImport(ast: File): void {\n const declaration = t.importDeclaration([], t.stringLiteral(THEME_SIGNATURE_MODULE))\n ast.program.body.unshift(declaration)\n}\n\n/**\n * Read the upstream transformer's `getCacheKey()` so our cache-key\n * contribution composes with — rather than replaces — whatever the\n * host framework wants to mix in.\n * @returns Upstream cache key, or `null` when no upstream exposes one.\n */\nfunction loadUpstreamCacheKey(): string | null {\n const upstream = loadUpstream() as (UpstreamTransformer & { getCacheKey?: () => string }) | null\n if (!upstream) return null\n try {\n return typeof upstream.getCacheKey === 'function' ? upstream.getCacheKey() : null\n } catch {\n return null\n }\n}\n\n/**\n * Invoke the upstream `babelTransformerPath` Metro originally had\n * configured. The path is read from `RNWIND_UPSTREAM_TRANSFORMER`,\n * which `withRnwindConfig` sets at Metro startup. When the env var is\n * unset (unit tests, standalone use), fall back to a typescript+jsx\n * parse.\n * @param args Metro's per-file args.\n * @returns Upstream transform result containing the post-babel AST.\n */\nasync function runUpstream(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n if (args.ast && !process.env[UPSTREAM_ENV]) return { ast: args.ast }\n const upstream = loadUpstream()\n if (upstream) return await Promise.resolve(upstream.transform(args))\n if (args.ast) return { ast: args.ast }\n return { ast: parseSource(args.src) }\n}\n\n/**\n * Lazily require the upstream transformer module. Cached after first\n * load so per-file overhead is one cache lookup.\n * @returns Upstream module, or null when env is unset.\n */\nfunction loadUpstream(): UpstreamTransformer | null {\n if (cachedUpstream) return cachedUpstream\n const upstreamPath = process.env[UPSTREAM_ENV]\n if (!upstreamPath || upstreamPath.length === 0) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const required = require(upstreamPath) as UpstreamTransformer | { default?: UpstreamTransformer }\n const upstream = (required as { default?: UpstreamTransformer }).default ?? (required as UpstreamTransformer)\n if (typeof upstream.transform !== 'function') return null\n cachedUpstream = upstream\n return upstream\n } catch (error) {\n // eslint-disable-next-line no-console\n if (process.env.RNWIND_DEBUG) console.error('rnwind: failed to load upstream transformer:', error)\n return null\n }\n}\n\n/**\n * Cheap guard — the file has to look JS/TS, live outside `node_modules`,\n * and mention `className=` before we spend AST cycles on it.\n *\n * Symlink awareness: monorepo workspaces (yarn / pnpm / bun workspaces)\n * symlink each package into the consumer's `node_modules/<name>`, so a\n * file from `packages/ui/src/Foo.tsx` ends up reaching the transformer\n * as `<root>/node_modules/ui/src/Foo.tsx`. The naïve `/node_modules/`\n * check would skip every workspace UI file. We `realpath` the filename\n * once and only bail when the resolved real path is ALSO under\n * node_modules — true third-party installs.\n * @param args Metro args.\n * @returns Whether the file might need the rnwind pass.\n */\nfunction isRewriteCandidate(args: BabelTransformerArgs): boolean {\n if (!/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename)) return false\n // Process the file when it either:\n // - carries a `className=` / `<prefix>ClassName=` literal (case-\n // insensitive — `contentContainerClassName=` has a capital C), or\n // - spreads props (`{...rest}`) onto a host from a wrap-module, where a\n // forwarded className must still get its import wrapped (no literal\n // appears in this file). A style-less `<View/>` with neither is left\n // alone so it never pays for an unused wrapper.\n const hasClassName = /classname=/i.test(args.src)\n const isForwarder = /\\{\\s*\\.\\.\\./.test(args.src) && mentionsWrapModule(args.src)\n if (!hasClassName && !isForwarder) return false\n if (!args.filename.includes('/node_modules/')) return true\n // node_modules in path → could be a workspace symlink; resolve it.\n try {\n return !realpathSync(args.filename).includes('/node_modules/')\n } catch {\n // realpath failed (broken symlink, missing file). Fall back to skipping.\n return false\n }\n}\n\n/**\n * Cheap pre-parse check: does the source import from any configured\n * wrap-module? A quoted specifier match is enough — `rewriteWrapImports`\n * re-verifies precisely on the AST, so a false positive only costs a\n * no-op parse.\n * @param source Source text.\n * @returns True when a wrap-module specifier appears in the source.\n */\nfunction mentionsWrapModule(source: string): boolean {\n for (const moduleName of getWrapModules().keys()) {\n if (source.includes(`'${moduleName}'`) || source.includes(`\"${moduleName}\"`)) return true\n }\n return false\n}\n\n/**\n * Fallback parse when no upstream is configured AND Metro didn't hand\n * us an AST. Used by unit tests and standalone setups.\n * @param source Source text.\n * @returns Parsed Babel File.\n */\nfunction parseSource(source: string): File {\n return parse(source, { sourceType: 'module', plugins: ['typescript', 'jsx'] }) as unknown as File\n}\n\n/** Metro's babel transformer signature. */\nexport interface BabelTransformerArgs {\n filename: string\n src: string\n options: { projectRoot?: string; [key: string]: unknown }\n ast?: File\n plugins?: readonly unknown[]\n}\n\n/** Return shape Metro expects from a babel transformer. */\nexport interface BabelTransformerResult {\n ast: File\n metadata?: unknown\n}\n\n/**\n * rnwind's Metro babel transformer. Two phases per source file:\n *\n * 1. **Pre-process the source string before handing it to the upstream\n * babel pipeline.** babel-preset-expo / React's JSX transform run\n * inside the upstream and convert `<View className=\"...\"/>` into\n * `React.createElement(View, {className})`. If we walked the AST\n * AFTER the upstream, there'd be no JSX attributes left to\n * rewrite. So we parse, run our pass, regenerate code, and feed\n * THAT to the upstream as `src`.\n * 2. **Delegate to the upstream `babelTransformerPath`** (Expo's\n * default handles Flow stripping, expo-router macros, etc.).\n *\n * Skip both phases when the file isn't a JS/TS source under user\n * code, or doesn't mention `className=` — hand straight to upstream.\n * @param args Metro's per-file args.\n * @returns Mutated AST + metadata.\n */\nexport async function transform(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n // Short-circuit `.css` inputs: the theme CSS is pulled into the dep\n // graph as a sentinel (see `THEME_SIGNATURE_MODULE` in resolver.ts)\n // so Metro watches it and invalidates importers on edit, but the\n // file's CSS syntax can't go through a JS babel transformer.\n //\n // When the CSS being transformed IS the user's theme entry, we\n // piggyback on Metro's own file-watcher: Metro calls us here on\n // every CSS save; we trigger `onThemeChange` to rebuild parser +\n // rewrite scheme files with the new values. Metro's dep graph then\n // HMRs the regenerated `common.style.js` to the running app.\n //\n // Emitting the CSS content hash in the fake JS output is what makes\n // Metro propagate invalidation to downstream importers — constant\n // `export {}` bytes would never look changed and Metro would skip\n // the chain.\n if (args.filename.endsWith('.css')) {\n if (isThemeCssEntry(args.filename)) {\n try {\n await onThemeChange(projectRootOf(args))\n } catch {\n // CSS edit happened outside a configured project (e.g. tests).\n }\n }\n const themeHash = createHash('sha256').update(args.src).digest('hex').slice(0, 16)\n const stub = `export const __rnwindThemeHash = ${JSON.stringify(themeHash)};\\n`\n return { ast: parse(stub, { sourceType: 'module' }) as unknown as File }\n }\n if (!isRewriteCandidate(args)) {\n if (/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename) && !args.filename.includes('/node_modules/')) {\n try {\n getRnwindState(projectRootOf(args)).builder.dropFile(args.filename)\n } catch {\n // State not configured (e.g. test). Nothing to drop.\n }\n }\n return runUpstream(args)\n }\n\n const rewrittenSource = await rewriteSource(args)\n return runUpstream({ ...args, src: rewrittenSource, ast: undefined })\n}\n\n/**\n * Metro's babel-transformer contract: a `getCacheKey()` export is\n * sampled per-file and mixed into the transform cache key. Returning\n * a string that includes the theme CSS content hash invalidates every\n * cached transform on every CSS edit — so the bundle rebuilds with\n * the new theme automatically on the next request.\n * @returns Cache-key segment that includes rnwind's current theme hash.\n */\nexport function getCacheKey(): string {\n const upstreamKey = loadUpstreamCacheKey()\n const ownKey = getRnwindCacheKey()\n return upstreamKey ? `${upstreamKey}|${ownKey}` : ownKey\n}\n\n/** Test-only — drop the cached upstream so a new env var picks up next call. */\nexport function __resetUpstreamCache(): void {\n cachedUpstream = null\n}\n"],"names":["parse","filterUnknownClassCandidates","rewriteWrapImports","getWrapModules","state","getRnwindState","STYLE_SPECIFIERS","t","THEME_SIGNATURE_MODULE","realpathSync","onThemeChange","createHash","getRnwindCacheKey"],"mappings":"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"}
1
+ {"version":3,"file":"transformer.cjs","sources":["../../../../src/metro/transformer.ts"],"sourcesContent":["import type { File } from '@babel/types'\nimport * as t from '@babel/types'\nimport { parse } from '@babel/parser'\nimport generate from '@babel/generator'\nimport { createHash } from 'node:crypto'\nimport { realpathSync } from 'node:fs'\nimport { getRnwindCacheKey, getRnwindState, getWrapModules, onThemeChange } from './state'\nimport { rewriteWrapImports } from './wrap-imports'\nimport { STYLE_SPECIFIERS, THEME_SIGNATURE_MODULE } from './resolver'\nimport { filterUnknownClassCandidates } from './warn-unknown-classes'\n\n/** The shape of the upstream module we delegate parsing/babel work to. */\ninterface UpstreamTransformer {\n transform: (args: BabelTransformerArgs) => Promise<BabelTransformerResult> | BabelTransformerResult\n}\n\n/** Env var that points at the upstream `babelTransformerPath` we override. */\nconst UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER'\n\n/**\n * Matches a `useCss(` call. Files that resolve classes via the `useCss`\n * hook (no JSX `className=`) must still be scanned so the classes inside\n * `useCss(\"…\")` get registered — common for theme/accent hooks living in a\n * shared package the project scan may not reach.\n */\nconst USE_CSS_CALL = /\\buseCss\\s*\\(/\n\n/** Cached upstream module — required once, reused across every transform call. */\nlet cachedUpstream: UpstreamTransformer | null = null\n\nconst generateModule = (generate as unknown as { default?: typeof generate }).default ?? generate\n\n/**\n * Parse user source with the broad plugin set (Flow + JSX + TypeScript\n * + class properties). Permissive on purpose so we don't reject any\n * file the upstream could have handled. Returns `null` when parse\n * fails — caller falls back to the raw source string.\n * @param source Source text.\n * @returns Parsed AST, or null on parse failure.\n */\nfunction parseUserSource(source: string): File | null {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['typescript', 'jsx'],\n }) as unknown as File\n } catch {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['flow', 'jsx'],\n }) as unknown as File\n } catch {\n return null\n }\n }\n}\n\n/**\n * Print Tailwind-shaped candidates oxide picked up but the parser\n * could NOT compile — typo, missing custom utility, or class not in\n * the user's theme. Filtering by candidates that ALSO appear inside a\n * `className=\"…\"` literal eliminates false positives from imports,\n * comments, and JSX prop values.\n * @param source Original source text — searched for className literals.\n * @param candidates Every candidate oxide surfaced from the source.\n * @param atoms Successfully resolved atoms (keys are class names).\n * @param filename Source path, prefixed onto the warning.\n * @param features Feature-atom maps (gradient / haptic) — their names are\n * known classes even though they carry no RN style, so they're excluded\n * from the unknown-class warning.\n */\nfunction warnUnknownClasses(\n source: string,\n candidates: readonly string[],\n atoms: ReadonlyMap<string, unknown>,\n filename: string,\n features: ReadonlyArray<ReadonlyMap<string, unknown>> = [],\n): void {\n // Feature atoms (gradient / haptic) resolve to no RN style, so they're\n // absent from `atoms` — but they're NOT unknown. Fold their names into\n // the known set so `active:haptic-rigid` etc. don't warn at build time.\n const known = new Set(atoms.keys())\n for (const map of features) for (const name of map.keys()) known.add(name)\n const unknown = filterUnknownClassCandidates(source, candidates, known)\n if (unknown.length === 0) return\n // eslint-disable-next-line no-console\n console.warn(`rnwind: unknown class${unknown.length > 1 ? 'es' : ''} in ${filename}: ${unknown.join(', ')}`)\n}\n\n/**\n * Extract the bare extension for oxide / internal switches.\n * @param filename Absolute path.\n * @returns Extension without the leading dot (`tsx` / `ts` / `js` / `jsx`).\n */\nfunction extensionOf(filename: string): string {\n const index = filename.lastIndexOf('.')\n if (index === -1) return 'tsx'\n return filename.slice(index + 1)\n}\n\n/**\n * Read the project root Metro hands us per-transform. Falls back to\n * `process.cwd()` only when the upstream harness doesn't set it (unit\n * tests, standalone). Metro's production pipeline always sets it.\n * @param args Metro transformer args.\n * @returns Absolute project root.\n */\nfunction projectRootOf(args: BabelTransformerArgs): string {\n const fromOptions = args.options?.projectRoot\n if (typeof fromOptions === 'string' && fromOptions.length > 0) return fromOptions\n return process.cwd()\n}\n\n/**\n * Whether a `.css` filename is the user's theme entry (the file\n * `withRnwindConfig` pointed us at via `RNWIND_CSS_ENTRY_FILE`).\n * Only the theme CSS should trigger a scheme rebuild — unrelated CSS\n * files in the project stay invisible to rnwind.\n * @param filename Absolute CSS path.\n * @returns Whether the file is the configured theme entry.\n */\nfunction isThemeCssEntry(filename: string): boolean {\n const cssEntry = process.env.RNWIND_CSS_ENTRY_FILE\n return typeof cssEntry === 'string' && cssEntry.length > 0 && cssEntry === filename\n}\n\n/**\n * Wrap host imports + compile any className literals, then regenerate\n * source. Two paths:\n * - **className present**: oxide-scan the file, record its atoms into\n * the union, and inject the generated-style + theme-signature\n * side-effect imports so the runtime registries populate.\n * - **import-only** (a `{...rest}` forwarder or a leaf with no literal\n * `className=`): just wrap the host imports so a forwarded className\n * still resolves at render — no oxide scan, no injected imports.\n *\n * On parse failure, fall back to the original source — a transient parse\n * error shouldn't crash Metro for a file the upstream might handle fine.\n * @param args Metro args; `src` is the original source text.\n * @returns Rewritten source text.\n */\nasync function rewriteSource(args: BabelTransformerArgs): Promise<string> {\n const ast = parseUserSource(args.src)\n if (!ast) return args.src\n\n const hasClassName = /classname=/i.test(args.src)\n const hasUseCss = USE_CSS_CALL.test(args.src)\n const hasSpread = /\\{\\s*\\.\\.\\./.test(args.src)\n\n // Wrap host component imports ONLY when className arrives through a\n // component — written (`hasClassName`) or forwarded (`hasSpread`). A\n // `useCss(\"…\")`-only file resolves manually, so we must NOT wrap its\n // imports: a non-RN drawing lib (e.g. skia's `LinearGradient` nested in\n // `SkiaText`) breaks if its primitives are replaced by a wrapper.\n const wrapped = hasClassName || hasSpread ? rewriteWrapImports(ast, getWrapModules()) : false\n\n if (!hasClassName && !hasUseCss) {\n // Import-only file: nothing to compile. Drop any stale atom\n // contribution (className may have just been removed) and emit the\n // wrapped imports — or the untouched source when nothing wrapped.\n dropFileSafely(args.filename, projectRootOf(args))\n return wrapped ? generateModule(ast).code : args.src\n }\n\n // Scan path — runs for `className=` literals AND/OR `useCss(\"…\")` strings.\n // oxide reads class candidates from the whole file content, so classes\n // that only ever appear inside a `useCss(\"…\")` call still register.\n const state = getRnwindState(projectRootOf(args))\n const extension = extensionOf(args.filename)\n const parsed = await state.parser.parseAtoms({ content: args.src, extension })\n\n warnUnknownClasses(args.src, parsed.candidates, parsed.atoms, args.filename, [parsed.gradientAtoms, parsed.hapticAtoms])\n\n if (parsed.atoms.size === 0) {\n state.builder.dropFile(args.filename)\n await state.builder.writeSchemes()\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n }\n\n const literals = collectClassNameLiterals(ast)\n const { changed } = await state.builder.recordFile(args.filename, parsed.atoms, parsed.keyframes, literals)\n if (changed) await state.builder.writeSchemes()\n\n injectSideEffectImports(ast, STYLE_SPECIFIERS)\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n}\n\n/**\n * Drop a file's union contribution, swallowing the \"state not configured\"\n * error unit tests hit when they call the transformer without\n * `configureRnwindState`.\n * @param filename Absolute source path.\n * @param projectRoot Project root for state lookup.\n */\nfunction dropFileSafely(filename: string, projectRoot: string): void {\n try {\n getRnwindState(projectRoot).builder.dropFile(filename)\n } catch {\n // State not configured (standalone/unit test). Nothing to drop.\n }\n}\n\n/**\n * Whether a JSX attribute names a className-style prop (`className` or\n * any `<prefix>ClassName`).\n * @param node JSX attribute node.\n * @returns True when the attribute is a className prop.\n */\nfunction isClassNameAttribute(node: t.JSXAttribute): boolean {\n if (!t.isJSXIdentifier(node.name)) return false\n const {name} = node.name\n return name === 'className' || name.endsWith('ClassName')\n}\n\n/**\n * Pull static string literals out of a className expression. Handles a\n * bare string, a no-substitution template, and the branches of a\n * ternary / `&&` (so `cond ? 'a' : 'b'` and `flag && 'x'` both register\n * their literals). Dynamic interpolations are skipped — they resolve via\n * the runtime atom path.\n * @param expr Expression inside a `className={...}` container.\n * @param out Accumulator for discovered literals.\n */\nfunction collectLiteralsFromExpression(expr: t.Expression | t.JSXEmptyExpression | null | undefined, out: string[]): void {\n if (!expr) return\n if (t.isStringLiteral(expr)) {\n out.push(expr.value)\n return\n }\n if (t.isTemplateLiteral(expr) && expr.expressions.length === 0 && expr.quasis.length === 1) {\n const cooked = expr.quasis[0]?.value.cooked\n if (typeof cooked === 'string') out.push(cooked)\n return\n }\n if (t.isConditionalExpression(expr)) {\n collectLiteralsFromExpression(expr.consequent, out)\n collectLiteralsFromExpression(expr.alternate, out)\n return\n }\n if (t.isLogicalExpression(expr)) {\n collectLiteralsFromExpression(expr.right as t.Expression, out)\n }\n}\n\n/** AST node keys the literal walk skips — position / comment metadata. */\nconst SKIP_WALK_KEYS = new Set(['type', 'loc', 'start', 'end', 'range', 'leadingComments', 'trailingComments', 'innerComments'])\n\n/**\n * Collect the static literals from one className JSX attribute into the\n * dedup accumulator.\n * @param attribute The (already className-matched) JSX attribute.\n * @param seen Dedup set of literals already collected.\n * @param out Ordered accumulator.\n */\nfunction collectAttributeLiterals(attribute: t.JSXAttribute, seen: Set<string>, out: string[]): void {\n const { value } = attribute\n const found: string[] = []\n if (t.isStringLiteral(value)) found.push(value.value)\n else if (t.isJSXExpressionContainer(value)) collectLiteralsFromExpression(value.expression, found)\n for (const literal of found) {\n if (seen.has(literal)) continue\n seen.add(literal)\n out.push(literal)\n }\n}\n\n/**\n * Walk the AST for every `className=` / `<prefix>ClassName=` literal so\n * the builder can pre-merge each into a per-scheme molecule. A generic\n * node walk (no scope build) keeps it cheap; only JSX attribute nodes do\n * any work.\n * @param ast Parsed Babel file.\n * @returns Distinct literal className strings, in first-seen order.\n */\nfunction collectClassNameLiterals(ast: File): readonly string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const visit = (node: unknown): void => {\n if (!node || typeof node !== 'object') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n const typed = node as { type?: string; [key: string]: unknown }\n if (typeof typed.type !== 'string') return\n if (typed.type === 'JSXAttribute' && isClassNameAttribute(node as t.JSXAttribute)) {\n collectAttributeLiterals(node as t.JSXAttribute, seen, out)\n }\n for (const key in typed) {\n if (SKIP_WALK_KEYS.has(key)) continue\n visit(typed[key])\n }\n }\n visit(ast.program)\n return out\n}\n\n/**\n * Prepend side-effect imports (`import '<spec>'`) so the generated\n * per-scheme style + manifest modules load — registering this file's\n * atoms / molecules / features into the runtime registries the wrapper's\n * `resolve` reads.\n * @param ast Babel File AST to mutate in place.\n * @param specifiers Module specifiers to side-effect-import.\n */\nfunction injectSideEffectImports(ast: File, specifiers: readonly string[]): void {\n for (const specifier of specifiers) {\n ast.program.body.unshift(t.importDeclaration([], t.stringLiteral(specifier)))\n }\n}\n\n/**\n * Prepend `import 'rnwind/__generated/theme-signature'` to every\n * rnwind-transformed file. The resolver maps that specifier to the\n * user's theme CSS so Metro's dependency graph carries a real edge\n * from this JS file to the CSS. When the user edits `global.css`,\n * the CSS module's SHA1 changes, and Metro invalidates every JS file\n * holding this import — forcing them to re-transform with the new\n * theme. The `.css` branch in {@link transform} returns an empty\n * `export {}` module so the runtime cost is one extra `require()`.\n * @param ast Babel File AST to mutate in place.\n */\nfunction injectThemeSignatureImport(ast: File): void {\n const declaration = t.importDeclaration([], t.stringLiteral(THEME_SIGNATURE_MODULE))\n ast.program.body.unshift(declaration)\n}\n\n/**\n * Read the upstream transformer's `getCacheKey()` so our cache-key\n * contribution composes with — rather than replaces — whatever the\n * host framework wants to mix in.\n * @returns Upstream cache key, or `null` when no upstream exposes one.\n */\nfunction loadUpstreamCacheKey(): string | null {\n const upstream = loadUpstream() as (UpstreamTransformer & { getCacheKey?: () => string }) | null\n if (!upstream) return null\n try {\n return typeof upstream.getCacheKey === 'function' ? upstream.getCacheKey() : null\n } catch {\n return null\n }\n}\n\n/**\n * Invoke the upstream `babelTransformerPath` Metro originally had\n * configured. The path is read from `RNWIND_UPSTREAM_TRANSFORMER`,\n * which `withRnwindConfig` sets at Metro startup. When the env var is\n * unset (unit tests, standalone use), fall back to a typescript+jsx\n * parse.\n * @param args Metro's per-file args.\n * @returns Upstream transform result containing the post-babel AST.\n */\nasync function runUpstream(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n if (args.ast && !process.env[UPSTREAM_ENV]) return { ast: args.ast }\n const upstream = loadUpstream()\n if (upstream) return await Promise.resolve(upstream.transform(args))\n if (args.ast) return { ast: args.ast }\n return { ast: parseSource(args.src) }\n}\n\n/**\n * Lazily require the upstream transformer module. Cached after first\n * load so per-file overhead is one cache lookup.\n * @returns Upstream module, or null when env is unset.\n */\nfunction loadUpstream(): UpstreamTransformer | null {\n if (cachedUpstream) return cachedUpstream\n const upstreamPath = process.env[UPSTREAM_ENV]\n if (!upstreamPath || upstreamPath.length === 0) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const required = require(upstreamPath) as UpstreamTransformer | { default?: UpstreamTransformer }\n const upstream = (required as { default?: UpstreamTransformer }).default ?? (required as UpstreamTransformer)\n if (typeof upstream.transform !== 'function') return null\n cachedUpstream = upstream\n return upstream\n } catch (error) {\n // eslint-disable-next-line no-console\n if (process.env.RNWIND_DEBUG) console.error('rnwind: failed to load upstream transformer:', error)\n return null\n }\n}\n\n/**\n * Cheap guard — the file has to look JS/TS, live outside `node_modules`,\n * and mention `className=` before we spend AST cycles on it.\n *\n * Symlink awareness: monorepo workspaces (yarn / pnpm / bun workspaces)\n * symlink each package into the consumer's `node_modules/<name>`, so a\n * file from `packages/ui/src/Foo.tsx` ends up reaching the transformer\n * as `<root>/node_modules/ui/src/Foo.tsx`. The naïve `/node_modules/`\n * check would skip every workspace UI file. We `realpath` the filename\n * once and only bail when the resolved real path is ALSO under\n * node_modules — true third-party installs.\n * @param args Metro args.\n * @returns Whether the file might need the rnwind pass.\n */\nfunction isRewriteCandidate(args: BabelTransformerArgs): boolean {\n if (!/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename)) return false\n // Process the file when it either:\n // - carries a `className=` / `<prefix>ClassName=` literal (case-\n // insensitive — `contentContainerClassName=` has a capital C), or\n // - calls `useCss(\"…\")` (classes that only ever appear in the hook must\n // still be scanned + registered — common for theme/accent hooks), or\n // - spreads props (`{...rest}`) onto a host from a wrap-module, where a\n // forwarded className must still get its import wrapped (no literal\n // appears in this file). A style-less `<View/>` with none is left\n // alone so it never pays for an unused wrapper.\n const hasClassName = /classname=/i.test(args.src)\n const hasUseCss = USE_CSS_CALL.test(args.src)\n const isForwarder = /\\{\\s*\\.\\.\\./.test(args.src) && mentionsWrapModule(args.src)\n if (!hasClassName && !hasUseCss && !isForwarder) return false\n if (!args.filename.includes('/node_modules/')) return true\n // node_modules in path → could be a workspace symlink; resolve it.\n try {\n return !realpathSync(args.filename).includes('/node_modules/')\n } catch {\n // realpath failed (broken symlink, missing file). Fall back to skipping.\n return false\n }\n}\n\n/**\n * Cheap pre-parse check: does the source import from any configured\n * wrap-module? A quoted specifier match is enough — `rewriteWrapImports`\n * re-verifies precisely on the AST, so a false positive only costs a\n * no-op parse.\n * @param source Source text.\n * @returns True when a wrap-module specifier appears in the source.\n */\nfunction mentionsWrapModule(source: string): boolean {\n for (const moduleName of getWrapModules().keys()) {\n if (source.includes(`'${moduleName}'`) || source.includes(`\"${moduleName}\"`)) return true\n }\n return false\n}\n\n/**\n * Fallback parse when no upstream is configured AND Metro didn't hand\n * us an AST. Used by unit tests and standalone setups.\n * @param source Source text.\n * @returns Parsed Babel File.\n */\nfunction parseSource(source: string): File {\n return parse(source, { sourceType: 'module', plugins: ['typescript', 'jsx'] }) as unknown as File\n}\n\n/** Metro's babel transformer signature. */\nexport interface BabelTransformerArgs {\n filename: string\n src: string\n options: { projectRoot?: string; [key: string]: unknown }\n ast?: File\n plugins?: readonly unknown[]\n}\n\n/** Return shape Metro expects from a babel transformer. */\nexport interface BabelTransformerResult {\n ast: File\n metadata?: unknown\n}\n\n/**\n * rnwind's Metro babel transformer. Two phases per source file:\n *\n * 1. **Pre-process the source string before handing it to the upstream\n * babel pipeline.** babel-preset-expo / React's JSX transform run\n * inside the upstream and convert `<View className=\"...\"/>` into\n * `React.createElement(View, {className})`. If we walked the AST\n * AFTER the upstream, there'd be no JSX attributes left to\n * rewrite. So we parse, run our pass, regenerate code, and feed\n * THAT to the upstream as `src`.\n * 2. **Delegate to the upstream `babelTransformerPath`** (Expo's\n * default handles Flow stripping, expo-router macros, etc.).\n *\n * Skip both phases when the file isn't a JS/TS source under user\n * code, or doesn't mention `className=` — hand straight to upstream.\n * @param args Metro's per-file args.\n * @returns Mutated AST + metadata.\n */\nexport async function transform(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n // Short-circuit `.css` inputs: the theme CSS is pulled into the dep\n // graph as a sentinel (see `THEME_SIGNATURE_MODULE` in resolver.ts)\n // so Metro watches it and invalidates importers on edit, but the\n // file's CSS syntax can't go through a JS babel transformer.\n //\n // When the CSS being transformed IS the user's theme entry, we\n // piggyback on Metro's own file-watcher: Metro calls us here on\n // every CSS save; we trigger `onThemeChange` to rebuild parser +\n // rewrite scheme files with the new values. Metro's dep graph then\n // HMRs the regenerated `common.style.js` to the running app.\n //\n // Emitting the CSS content hash in the fake JS output is what makes\n // Metro propagate invalidation to downstream importers — constant\n // `export {}` bytes would never look changed and Metro would skip\n // the chain.\n if (args.filename.endsWith('.css')) {\n if (isThemeCssEntry(args.filename)) {\n try {\n await onThemeChange(projectRootOf(args))\n } catch {\n // CSS edit happened outside a configured project (e.g. tests).\n }\n }\n const themeHash = createHash('sha256').update(args.src).digest('hex').slice(0, 16)\n const stub = `export const __rnwindThemeHash = ${JSON.stringify(themeHash)};\\n`\n return { ast: parse(stub, { sourceType: 'module' }) as unknown as File }\n }\n if (!isRewriteCandidate(args)) {\n if (/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename) && !args.filename.includes('/node_modules/')) {\n try {\n getRnwindState(projectRootOf(args)).builder.dropFile(args.filename)\n } catch {\n // State not configured (e.g. test). Nothing to drop.\n }\n }\n return runUpstream(args)\n }\n\n const rewrittenSource = await rewriteSource(args)\n return runUpstream({ ...args, src: rewrittenSource, ast: undefined })\n}\n\n/**\n * Metro's babel-transformer contract: a `getCacheKey()` export is\n * sampled per-file and mixed into the transform cache key. Returning\n * a string that includes the theme CSS content hash invalidates every\n * cached transform on every CSS edit — so the bundle rebuilds with\n * the new theme automatically on the next request.\n * @returns Cache-key segment that includes rnwind's current theme hash.\n */\nexport function getCacheKey(): string {\n const upstreamKey = loadUpstreamCacheKey()\n const ownKey = getRnwindCacheKey()\n return upstreamKey ? `${upstreamKey}|${ownKey}` : ownKey\n}\n\n/** Test-only — drop the cached upstream so a new env var picks up next call. */\nexport function __resetUpstreamCache(): void {\n cachedUpstream = null\n}\n"],"names":["parse","filterUnknownClassCandidates","rewriteWrapImports","getWrapModules","state","getRnwindState","STYLE_SPECIFIERS","t","THEME_SIGNATURE_MODULE","realpathSync","onThemeChange","createHash","getRnwindCacheKey"],"mappings":"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"}
@@ -24,6 +24,13 @@ const UNSUPPORTED_LOGICAL_PROPS = new Set([
24
24
  'border-block-start-style',
25
25
  'border-block-end-style',
26
26
  ]);
27
+ /** CSS single-sided logical-inline property → RN writing-direction Yoga key. */
28
+ const LOGICAL_INLINE_TO_RN = {
29
+ 'margin-inline-start': 'marginStart',
30
+ 'margin-inline-end': 'marginEnd',
31
+ 'padding-inline-start': 'paddingStart',
32
+ 'padding-inline-end': 'paddingEnd',
33
+ };
27
34
  /**
28
35
  * Pick the closest predefined CSS easing keyword for a `cubic-bezier`
29
36
  * control-point set. Mirrors {@link snapCubicBezierToKeyword} in
@@ -336,7 +343,8 @@ function declarationToRnEntries(decl, themeVars) {
336
343
  return [['flexBasis', v]];
337
344
  }
338
345
  default: {
339
- return (dispatchLayoutDeclaration(decl) ??
346
+ return (dispatchLogicalInline(decl) ??
347
+ dispatchLayoutDeclaration(decl) ??
340
348
  dispatchTypographyDeclaration(decl) ??
341
349
  dispatchColorPropertyDeclaration(decl) ??
342
350
  dispatchBorderDeclaration(decl) ??
@@ -345,6 +353,37 @@ function declarationToRnEntries(decl, themeVars) {
345
353
  }
346
354
  }
347
355
  }
356
+ /**
357
+ * Map single-sided CSS logical-inline props to RN's writing-direction-aware
358
+ * Yoga keys: `ms-2` → `marginStart`, `pe-4` → `paddingEnd`, `start-2` →
359
+ * `start`, `end-3` → `end`. RN resolves start/end against the layout
360
+ * direction, so these stay RTL-correct. Returns null for any other property
361
+ * (so the dispatch chain continues).
362
+ * @param decl One declaration from a lightningcss style rule.
363
+ * @returns RN entries, or null when not a logical-inline property.
364
+ */
365
+ function dispatchLogicalInline(decl) {
366
+ switch (decl.property) {
367
+ case 'margin-inline-start':
368
+ case 'margin-inline-end':
369
+ case 'padding-inline-start':
370
+ case 'padding-inline-end': {
371
+ const v = lengthPercentageOrAutoToValue(decl.value);
372
+ return v === null ? [] : [[LOGICAL_INLINE_TO_RN[decl.property], v]];
373
+ }
374
+ case 'inset-inline-start': {
375
+ const v = lengthPercentageOrAutoToValue(decl.value);
376
+ return v === null ? [] : [['start', v]];
377
+ }
378
+ case 'inset-inline-end': {
379
+ const v = lengthPercentageOrAutoToValue(decl.value);
380
+ return v === null ? [] : [['end', v]];
381
+ }
382
+ default: {
383
+ return null;
384
+ }
385
+ }
386
+ }
348
387
 
349
388
  export { declarationToRnEntries };
350
389
  //# sourceMappingURL=declaration.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"declaration.mjs","sources":["../../../../../src/core/parser/declaration.ts"],"sourcesContent":["/* eslint-disable sonarjs/cognitive-complexity -- the main Declaration → RN-entries dispatcher is intentionally a flat switch so each branch keeps its narrowed value type */\nimport type { Declaration as LcDeclaration, TokenOrValue } from 'lightningcss'\nimport { kebabToCamel } from './case-convert'\nimport { cssColorToString } from './color'\nimport { dimensionPercentageToNumber, gapValueToValue, lengthPercentageOrAutoToValue, sizeLikeToValue } from './length'\nimport {\n expandBorderColor,\n expandBorderRadius,\n expandFourSided,\n expandGap,\n expandLogicalBlock,\n expandLogicalInline,\n flexToEntries,\n} from './shorthand'\nimport { coerceFontFamily, coerceUnparsedValue, serializeTokens, substituteThemeVars } from './tokens'\nimport { displayToEntries, fontSizeToPx, fontWeightToValue, zIndexToNumber } from './typography'\nimport { dispatchMotionDeclaration } from './motion-dispatcher'\nimport { dispatchTypographyDeclaration } from './typography-dispatcher'\nimport { dispatchLayoutDeclaration } from './layout-dispatcher'\nimport { dispatchColorPropertyDeclaration } from './color-properties-dispatcher'\nimport { dispatchBorderDeclaration } from './border-dispatcher'\nimport { detectSafeAreaMarker } from './safe-area'\nimport type { RNEntry } from './types'\n\n/** CSS timing-function properties that need `cubic-bezier(...)` snapping. */\nconst TIMING_FUNCTION_PROPS = new Set(['transition-timing-function', 'animation-timing-function'])\n\n/** CSS easing keywords Reanimated v4's CSS engine accepts as strings. */\nconst CSS_EASING_KEYWORDS = new Set(['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end'])\n\n/** CSS properties with no useful RN equivalent — silently dropped. */\nconst UNSUPPORTED_LOGICAL_PROPS = new Set([\n 'border-inline-style',\n 'border-block-style',\n 'border-inline-start-style',\n 'border-inline-end-style',\n 'border-block-start-style',\n 'border-block-end-style',\n])\n\n/**\n * Pick the closest predefined CSS easing keyword for a `cubic-bezier`\n * control-point set. Mirrors {@link snapCubicBezierToKeyword} in\n * `animation.ts` — kept here so the unparsed-string path doesn't need\n * to import a typed-only helper.\n * @param x1 First control-point x (0–1).\n * @param y1 First control-point y (0–1).\n * @param x2 Second control-point x (0–1).\n * @param y2 Second control-point y (0–1).\n * @returns CSS easing keyword.\n */\nfunction snapBezier(x1: number, y1: number, x2: number, y2: number): string {\n const tol = 0.01\n const eq = (a: number, b: number): boolean => Math.abs(a - b) < tol\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'linear'\n if (eq(x1, 0.25) && eq(y1, 0.1) && eq(x2, 0.25) && eq(y2, 1)) return 'ease'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'ease-in'\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-out'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-in-out'\n const startsFlat = x1 < 0.1\n const endsFlat = x2 > 0.9\n if (startsFlat && !endsFlat) return 'ease-out'\n if (!startsFlat && endsFlat) return 'ease-in'\n return 'ease-in-out'\n}\n\n/**\n * Snap a cubic-bezier expression string to the closest CSS keyword\n * Reanimated v4's CSS engine accepts. Strings that already are keywords\n * pass through unchanged.\n * @param value Resolved value text from an unparsed timing-function declaration.\n * @returns CSS easing keyword.\n */\nfunction coerceCubicBezierString(value: string): string {\n const text = value.trim()\n if (CSS_EASING_KEYWORDS.has(text)) return text\n const match = /^cubic-bezier\\(\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*\\)$/.exec(text)\n if (!match) return 'ease-in-out'\n const [, x1, y1, x2, y2] = match\n return snapBezier(Number(x1), Number(y1), Number(x2), Number(y2))\n}\n\n/**\n * Fast-path check for the handful of color property names Tailwind emits.\n * @param property Kebab-case CSS property name.\n * @returns Whether the property's value should be treated as a color.\n */\nfunction isColorProperty(property: string): boolean {\n return (\n property === 'color' ||\n property === 'background-color' ||\n (property.startsWith('border-') && property.endsWith('-color')) ||\n property.endsWith('-color')\n )\n}\n\n/**\n * Convert an unparsed declaration (typical Tailwind v4 output containing\n * `var()` / `calc()`) into RN entries. Serializes the token list, then\n * coerces the flat string into a number / keyword / length via a tight\n * set of shapes Tailwind actually emits.\n * @param property Real property name (kebab-case).\n * @param tokens Token list from lightningcss.\n * @param themeVars Optional lookup table for resolving `var(--x)` references.\n * @returns RN entries — usually one, empty when unusable.\n */\nfunction unparsedToEntries(\n property: string,\n tokens: readonly TokenOrValue[],\n themeVars: ReadonlyMap<string, string> | undefined,\n): readonly RNEntry[] {\n if (property.length === 0) return []\n // Safe-area detection runs BEFORE token serialization because\n // `env()` serializes to an empty string, which would strip the side\n // info we need. If the tokens encode a recognised `env(safe-area-inset-*)`\n // pattern (pure / `max(..., n)` / `calc(...+n)` / `h-screen-safe`),\n // emit a runtime-resolved marker instead.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n const safe = detectSafeAreaMarker(tokens, themeVars)\n if (safe !== null) return [[kebabToCamel(property), safe]]\n let text = serializeTokens(tokens)\n if (themeVars && themeVars.size > 0) text = substituteThemeVars(text, themeVars)\n const coerced = coerceUnparsedValue(text)\n if (coerced === null) return []\n // Skip values that didn't resolve past their `var()` wrapper — they\n // came from a `@property --tw-*` token without a real fallback.\n // Tailwind v4's `border-N` emits `border-style: var(--tw-border-style)`\n // expecting the cascade to fill it in; in RN we drop them and rely on\n // RN's default (solid).\n if (typeof coerced === 'string' && coerced.startsWith('var(')) return []\n // RN `fontFamily` is a single typeface, not a CSS fallback list — take\n // the first family so `--font-x: \"Name\", sans-serif` works out of the box.\n if (property === 'font-family' && typeof coerced === 'string') {\n return [['fontFamily', coerceFontFamily(coerced)]]\n }\n // Logical-direction CSS properties RN doesn't have direct equivalents\n // for. Keep the dropped names in one place so it's easy to audit.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n if (TIMING_FUNCTION_PROPS.has(property) && typeof coerced === 'string') {\n // `transition-colors` and similar emit `var(--tw-ease, cubic-bezier(...))`\n // which serializes to a cubic-bezier STRING after substitution.\n // Reanimated v4's CSS engine rejects those — snap to the closest\n // predefined keyword (same logic as the typed `EasingFunction` path).\n return [[kebabToCamel(property), coerceCubicBezierString(coerced)]]\n }\n if (isColorProperty(property) && typeof coerced === 'string') {\n // Resolved user-theme color strings (e.g. `#ff0099`) go straight to\n // the RN style — no further conversion needed.\n return [[kebabToCamel(property), coerced]]\n }\n return [[kebabToCamel(property), coerced]]\n}\n\n/**\n * Convert one lightningcss `Declaration` into zero-or-more RN style\n * entries. Shorthand declarations (padding/margin/border-radius/flex) can\n * emit multiple entries; skipped or unsupported properties emit none.\n *\n * The switch branches on `decl.property` so TypeScript narrows\n * `decl.value` to the exact typed shape for each branch — no casts\n * required. Unknown properties fall through to `[]`.\n * @param decl One declaration from a lightningcss style rule.\n * @param themeVars Optional lookup table for resolving `var(--x)` references inside unparsed values.\n * @returns Array of `[key, value]` entries.\n */\nexport function declarationToRnEntries(decl: LcDeclaration, themeVars?: ReadonlyMap<string, string>): readonly RNEntry[] {\n switch (decl.property) {\n case 'custom': {\n // Lightningcss routes two shapes through `custom`:\n // - Actual CSS custom properties (`--my-var`): no RN meaning, drop.\n // - Real properties it doesn't have a dedicated typed entry for\n // (e.g. `object-fit`, `pointer-events`, future CSS keyword-only\n // props): treat like an unparsed declaration so the keyword\n // surfaces in the RN style.\n const customName = decl.value.name\n if (customName.startsWith('--')) return []\n return unparsedToEntries(customName, decl.value.value ?? [], themeVars)\n }\n case 'unparsed': {\n return unparsedToEntries(decl.value.propertyId.property, decl.value.value, themeVars)\n }\n case 'color':\n case 'background-color':\n case 'border-top-color':\n case 'border-right-color':\n case 'border-bottom-color':\n case 'border-left-color': {\n // `background-color` narrows to `CssColor | 'background'` — the\n // literal keyword means UA default. Skip the keyword.\n if (typeof decl.value === 'string') return []\n return [[kebabToCamel(decl.property), cssColorToString(decl.value)]]\n }\n case 'border-color': {\n return expandBorderColor(decl.value)\n }\n case 'opacity': {\n // Lightningcss hands us an `f32` for opacity, so values like `0.8`\n // round-trip as `0.800000011920929`. Snap to 4 decimals to match the\n // rest of the parser's numeric convention.\n return [[decl.property, Math.round(decl.value * 10_000) / 10_000]]\n }\n case 'z-index': {\n return [['zIndex', zIndexToNumber(decl.value)]]\n }\n case 'top':\n case 'right':\n case 'bottom':\n case 'left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[decl.property, v]]\n }\n case 'inset': {\n const top = lengthPercentageOrAutoToValue(decl.value.top)\n const right = lengthPercentageOrAutoToValue(decl.value.right)\n const bottom = lengthPercentageOrAutoToValue(decl.value.bottom)\n const left = lengthPercentageOrAutoToValue(decl.value.left)\n if (top === null || right === null || bottom === null || left === null) return []\n return [\n ['top', top],\n ['right', right],\n ['bottom', bottom],\n ['left', left],\n ]\n }\n case 'inset-inline': {\n const start = lengthPercentageOrAutoToValue(decl.value.inlineStart)\n const end = lengthPercentageOrAutoToValue(decl.value.inlineEnd)\n if (start === null || end === null) return []\n return [\n ['left', start],\n ['right', end],\n ]\n }\n case 'inset-block': {\n const start = lengthPercentageOrAutoToValue(decl.value.blockStart)\n const end = lengthPercentageOrAutoToValue(decl.value.blockEnd)\n if (start === null || end === null) return []\n return [\n ['top', start],\n ['bottom', end],\n ]\n }\n case 'width':\n case 'height':\n case 'min-width':\n case 'min-height':\n case 'max-width':\n case 'max-height': {\n const v = sizeLikeToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'gap': {\n return expandGap(decl.value)\n }\n case 'row-gap':\n case 'column-gap': {\n const v = gapValueToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'font-style': {\n return [['fontStyle', decl.value.type]]\n }\n case 'display': {\n return displayToEntries(decl.value)\n }\n case 'position': {\n return [['position', decl.value.type]]\n }\n case 'font-size': {\n const px = fontSizeToPx(decl.value)\n if (px === null) return []\n return [['fontSize', px]]\n }\n case 'font-weight': {\n return [['fontWeight', fontWeightToValue(decl.value)]]\n }\n case 'padding': {\n return expandFourSided('padding', decl.value)\n }\n case 'margin': {\n return expandFourSided('margin', decl.value)\n }\n case 'padding-inline': {\n return expandLogicalInline('padding', decl.value)\n }\n case 'padding-block': {\n return expandLogicalBlock('padding', decl.value)\n }\n case 'margin-inline': {\n return expandLogicalInline('margin', decl.value)\n }\n case 'margin-block': {\n return expandLogicalBlock('margin', decl.value)\n }\n case 'padding-top':\n case 'padding-right':\n case 'padding-bottom':\n case 'padding-left':\n case 'margin-top':\n case 'margin-right':\n case 'margin-bottom':\n case 'margin-left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'border-radius': {\n return expandBorderRadius(decl.value)\n }\n case 'border-top-left-radius':\n case 'border-top-right-radius':\n case 'border-bottom-left-radius':\n case 'border-bottom-right-radius': {\n const [xAxis] = decl.value\n const v = dimensionPercentageToNumber(xAxis)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'flex': {\n return flexToEntries(decl.value)\n }\n case 'flex-grow':\n case 'flex-shrink': {\n return [[kebabToCamel(decl.property), decl.value]]\n }\n case 'flex-basis': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [['flexBasis', v]]\n }\n default: {\n return (\n dispatchLayoutDeclaration(decl) ??\n dispatchTypographyDeclaration(decl) ??\n dispatchColorPropertyDeclaration(decl) ??\n dispatchBorderDeclaration(decl) ??\n dispatchMotionDeclaration(decl) ??\n []\n )\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"declaration.mjs","sources":["../../../../../src/core/parser/declaration.ts"],"sourcesContent":["/* eslint-disable sonarjs/cognitive-complexity -- the main Declaration → RN-entries dispatcher is intentionally a flat switch so each branch keeps its narrowed value type */\nimport type { Declaration as LcDeclaration, TokenOrValue } from 'lightningcss'\nimport { kebabToCamel } from './case-convert'\nimport { cssColorToString } from './color'\nimport { dimensionPercentageToNumber, gapValueToValue, lengthPercentageOrAutoToValue, sizeLikeToValue } from './length'\nimport {\n expandBorderColor,\n expandBorderRadius,\n expandFourSided,\n expandGap,\n expandLogicalBlock,\n expandLogicalInline,\n flexToEntries,\n} from './shorthand'\nimport { coerceFontFamily, coerceUnparsedValue, serializeTokens, substituteThemeVars } from './tokens'\nimport { displayToEntries, fontSizeToPx, fontWeightToValue, zIndexToNumber } from './typography'\nimport { dispatchMotionDeclaration } from './motion-dispatcher'\nimport { dispatchTypographyDeclaration } from './typography-dispatcher'\nimport { dispatchLayoutDeclaration } from './layout-dispatcher'\nimport { dispatchColorPropertyDeclaration } from './color-properties-dispatcher'\nimport { dispatchBorderDeclaration } from './border-dispatcher'\nimport { detectSafeAreaMarker } from './safe-area'\nimport type { RNEntry } from './types'\n\n/** CSS timing-function properties that need `cubic-bezier(...)` snapping. */\nconst TIMING_FUNCTION_PROPS = new Set(['transition-timing-function', 'animation-timing-function'])\n\n/** CSS easing keywords Reanimated v4's CSS engine accepts as strings. */\nconst CSS_EASING_KEYWORDS = new Set(['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end'])\n\n/** CSS properties with no useful RN equivalent — silently dropped. */\nconst UNSUPPORTED_LOGICAL_PROPS = new Set([\n 'border-inline-style',\n 'border-block-style',\n 'border-inline-start-style',\n 'border-inline-end-style',\n 'border-block-start-style',\n 'border-block-end-style',\n])\n\n/** CSS single-sided logical-inline property → RN writing-direction Yoga key. */\nconst LOGICAL_INLINE_TO_RN: Record<string, string> = {\n 'margin-inline-start': 'marginStart',\n 'margin-inline-end': 'marginEnd',\n 'padding-inline-start': 'paddingStart',\n 'padding-inline-end': 'paddingEnd',\n}\n\n/**\n * Pick the closest predefined CSS easing keyword for a `cubic-bezier`\n * control-point set. Mirrors {@link snapCubicBezierToKeyword} in\n * `animation.ts` — kept here so the unparsed-string path doesn't need\n * to import a typed-only helper.\n * @param x1 First control-point x (0–1).\n * @param y1 First control-point y (0–1).\n * @param x2 Second control-point x (0–1).\n * @param y2 Second control-point y (0–1).\n * @returns CSS easing keyword.\n */\nfunction snapBezier(x1: number, y1: number, x2: number, y2: number): string {\n const tol = 0.01\n const eq = (a: number, b: number): boolean => Math.abs(a - b) < tol\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'linear'\n if (eq(x1, 0.25) && eq(y1, 0.1) && eq(x2, 0.25) && eq(y2, 1)) return 'ease'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 1) && eq(y2, 1)) return 'ease-in'\n if (eq(x1, 0) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-out'\n if (eq(x1, 0.4) && eq(y1, 0) && eq(x2, 0.2) && eq(y2, 1)) return 'ease-in-out'\n const startsFlat = x1 < 0.1\n const endsFlat = x2 > 0.9\n if (startsFlat && !endsFlat) return 'ease-out'\n if (!startsFlat && endsFlat) return 'ease-in'\n return 'ease-in-out'\n}\n\n/**\n * Snap a cubic-bezier expression string to the closest CSS keyword\n * Reanimated v4's CSS engine accepts. Strings that already are keywords\n * pass through unchanged.\n * @param value Resolved value text from an unparsed timing-function declaration.\n * @returns CSS easing keyword.\n */\nfunction coerceCubicBezierString(value: string): string {\n const text = value.trim()\n if (CSS_EASING_KEYWORDS.has(text)) return text\n const match = /^cubic-bezier\\(\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*,\\s*([\\d.-]+)\\s*\\)$/.exec(text)\n if (!match) return 'ease-in-out'\n const [, x1, y1, x2, y2] = match\n return snapBezier(Number(x1), Number(y1), Number(x2), Number(y2))\n}\n\n/**\n * Fast-path check for the handful of color property names Tailwind emits.\n * @param property Kebab-case CSS property name.\n * @returns Whether the property's value should be treated as a color.\n */\nfunction isColorProperty(property: string): boolean {\n return (\n property === 'color' ||\n property === 'background-color' ||\n (property.startsWith('border-') && property.endsWith('-color')) ||\n property.endsWith('-color')\n )\n}\n\n/**\n * Convert an unparsed declaration (typical Tailwind v4 output containing\n * `var()` / `calc()`) into RN entries. Serializes the token list, then\n * coerces the flat string into a number / keyword / length via a tight\n * set of shapes Tailwind actually emits.\n * @param property Real property name (kebab-case).\n * @param tokens Token list from lightningcss.\n * @param themeVars Optional lookup table for resolving `var(--x)` references.\n * @returns RN entries — usually one, empty when unusable.\n */\nfunction unparsedToEntries(\n property: string,\n tokens: readonly TokenOrValue[],\n themeVars: ReadonlyMap<string, string> | undefined,\n): readonly RNEntry[] {\n if (property.length === 0) return []\n // Safe-area detection runs BEFORE token serialization because\n // `env()` serializes to an empty string, which would strip the side\n // info we need. If the tokens encode a recognised `env(safe-area-inset-*)`\n // pattern (pure / `max(..., n)` / `calc(...+n)` / `h-screen-safe`),\n // emit a runtime-resolved marker instead.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n const safe = detectSafeAreaMarker(tokens, themeVars)\n if (safe !== null) return [[kebabToCamel(property), safe]]\n let text = serializeTokens(tokens)\n if (themeVars && themeVars.size > 0) text = substituteThemeVars(text, themeVars)\n const coerced = coerceUnparsedValue(text)\n if (coerced === null) return []\n // Skip values that didn't resolve past their `var()` wrapper — they\n // came from a `@property --tw-*` token without a real fallback.\n // Tailwind v4's `border-N` emits `border-style: var(--tw-border-style)`\n // expecting the cascade to fill it in; in RN we drop them and rely on\n // RN's default (solid).\n if (typeof coerced === 'string' && coerced.startsWith('var(')) return []\n // RN `fontFamily` is a single typeface, not a CSS fallback list — take\n // the first family so `--font-x: \"Name\", sans-serif` works out of the box.\n if (property === 'font-family' && typeof coerced === 'string') {\n return [['fontFamily', coerceFontFamily(coerced)]]\n }\n // Logical-direction CSS properties RN doesn't have direct equivalents\n // for. Keep the dropped names in one place so it's easy to audit.\n if (UNSUPPORTED_LOGICAL_PROPS.has(property)) return []\n if (TIMING_FUNCTION_PROPS.has(property) && typeof coerced === 'string') {\n // `transition-colors` and similar emit `var(--tw-ease, cubic-bezier(...))`\n // which serializes to a cubic-bezier STRING after substitution.\n // Reanimated v4's CSS engine rejects those — snap to the closest\n // predefined keyword (same logic as the typed `EasingFunction` path).\n return [[kebabToCamel(property), coerceCubicBezierString(coerced)]]\n }\n if (isColorProperty(property) && typeof coerced === 'string') {\n // Resolved user-theme color strings (e.g. `#ff0099`) go straight to\n // the RN style — no further conversion needed.\n return [[kebabToCamel(property), coerced]]\n }\n return [[kebabToCamel(property), coerced]]\n}\n\n/**\n * Convert one lightningcss `Declaration` into zero-or-more RN style\n * entries. Shorthand declarations (padding/margin/border-radius/flex) can\n * emit multiple entries; skipped or unsupported properties emit none.\n *\n * The switch branches on `decl.property` so TypeScript narrows\n * `decl.value` to the exact typed shape for each branch — no casts\n * required. Unknown properties fall through to `[]`.\n * @param decl One declaration from a lightningcss style rule.\n * @param themeVars Optional lookup table for resolving `var(--x)` references inside unparsed values.\n * @returns Array of `[key, value]` entries.\n */\nexport function declarationToRnEntries(decl: LcDeclaration, themeVars?: ReadonlyMap<string, string>): readonly RNEntry[] {\n switch (decl.property) {\n case 'custom': {\n // Lightningcss routes two shapes through `custom`:\n // - Actual CSS custom properties (`--my-var`): no RN meaning, drop.\n // - Real properties it doesn't have a dedicated typed entry for\n // (e.g. `object-fit`, `pointer-events`, future CSS keyword-only\n // props): treat like an unparsed declaration so the keyword\n // surfaces in the RN style.\n const customName = decl.value.name\n if (customName.startsWith('--')) return []\n return unparsedToEntries(customName, decl.value.value ?? [], themeVars)\n }\n case 'unparsed': {\n return unparsedToEntries(decl.value.propertyId.property, decl.value.value, themeVars)\n }\n case 'color':\n case 'background-color':\n case 'border-top-color':\n case 'border-right-color':\n case 'border-bottom-color':\n case 'border-left-color': {\n // `background-color` narrows to `CssColor | 'background'` — the\n // literal keyword means UA default. Skip the keyword.\n if (typeof decl.value === 'string') return []\n return [[kebabToCamel(decl.property), cssColorToString(decl.value)]]\n }\n case 'border-color': {\n return expandBorderColor(decl.value)\n }\n case 'opacity': {\n // Lightningcss hands us an `f32` for opacity, so values like `0.8`\n // round-trip as `0.800000011920929`. Snap to 4 decimals to match the\n // rest of the parser's numeric convention.\n return [[decl.property, Math.round(decl.value * 10_000) / 10_000]]\n }\n case 'z-index': {\n return [['zIndex', zIndexToNumber(decl.value)]]\n }\n case 'top':\n case 'right':\n case 'bottom':\n case 'left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[decl.property, v]]\n }\n case 'inset': {\n const top = lengthPercentageOrAutoToValue(decl.value.top)\n const right = lengthPercentageOrAutoToValue(decl.value.right)\n const bottom = lengthPercentageOrAutoToValue(decl.value.bottom)\n const left = lengthPercentageOrAutoToValue(decl.value.left)\n if (top === null || right === null || bottom === null || left === null) return []\n return [\n ['top', top],\n ['right', right],\n ['bottom', bottom],\n ['left', left],\n ]\n }\n case 'inset-inline': {\n const start = lengthPercentageOrAutoToValue(decl.value.inlineStart)\n const end = lengthPercentageOrAutoToValue(decl.value.inlineEnd)\n if (start === null || end === null) return []\n return [\n ['left', start],\n ['right', end],\n ]\n }\n case 'inset-block': {\n const start = lengthPercentageOrAutoToValue(decl.value.blockStart)\n const end = lengthPercentageOrAutoToValue(decl.value.blockEnd)\n if (start === null || end === null) return []\n return [\n ['top', start],\n ['bottom', end],\n ]\n }\n case 'width':\n case 'height':\n case 'min-width':\n case 'min-height':\n case 'max-width':\n case 'max-height': {\n const v = sizeLikeToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'gap': {\n return expandGap(decl.value)\n }\n case 'row-gap':\n case 'column-gap': {\n const v = gapValueToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'font-style': {\n return [['fontStyle', decl.value.type]]\n }\n case 'display': {\n return displayToEntries(decl.value)\n }\n case 'position': {\n return [['position', decl.value.type]]\n }\n case 'font-size': {\n const px = fontSizeToPx(decl.value)\n if (px === null) return []\n return [['fontSize', px]]\n }\n case 'font-weight': {\n return [['fontWeight', fontWeightToValue(decl.value)]]\n }\n case 'padding': {\n return expandFourSided('padding', decl.value)\n }\n case 'margin': {\n return expandFourSided('margin', decl.value)\n }\n case 'padding-inline': {\n return expandLogicalInline('padding', decl.value)\n }\n case 'padding-block': {\n return expandLogicalBlock('padding', decl.value)\n }\n case 'margin-inline': {\n return expandLogicalInline('margin', decl.value)\n }\n case 'margin-block': {\n return expandLogicalBlock('margin', decl.value)\n }\n case 'padding-top':\n case 'padding-right':\n case 'padding-bottom':\n case 'padding-left':\n case 'margin-top':\n case 'margin-right':\n case 'margin-bottom':\n case 'margin-left': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'border-radius': {\n return expandBorderRadius(decl.value)\n }\n case 'border-top-left-radius':\n case 'border-top-right-radius':\n case 'border-bottom-left-radius':\n case 'border-bottom-right-radius': {\n const [xAxis] = decl.value\n const v = dimensionPercentageToNumber(xAxis)\n if (v === null) return []\n return [[kebabToCamel(decl.property), v]]\n }\n case 'flex': {\n return flexToEntries(decl.value)\n }\n case 'flex-grow':\n case 'flex-shrink': {\n return [[kebabToCamel(decl.property), decl.value]]\n }\n case 'flex-basis': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n if (v === null) return []\n return [['flexBasis', v]]\n }\n default: {\n return (\n dispatchLogicalInline(decl) ??\n dispatchLayoutDeclaration(decl) ??\n dispatchTypographyDeclaration(decl) ??\n dispatchColorPropertyDeclaration(decl) ??\n dispatchBorderDeclaration(decl) ??\n dispatchMotionDeclaration(decl) ??\n []\n )\n }\n }\n}\n\n/**\n * Map single-sided CSS logical-inline props to RN's writing-direction-aware\n * Yoga keys: `ms-2` → `marginStart`, `pe-4` → `paddingEnd`, `start-2` →\n * `start`, `end-3` → `end`. RN resolves start/end against the layout\n * direction, so these stay RTL-correct. Returns null for any other property\n * (so the dispatch chain continues).\n * @param decl One declaration from a lightningcss style rule.\n * @returns RN entries, or null when not a logical-inline property.\n */\nfunction dispatchLogicalInline(decl: LcDeclaration): readonly RNEntry[] | null {\n switch (decl.property) {\n case 'margin-inline-start':\n case 'margin-inline-end':\n case 'padding-inline-start':\n case 'padding-inline-end': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n return v === null ? [] : [[LOGICAL_INLINE_TO_RN[decl.property], v]]\n }\n case 'inset-inline-start': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n return v === null ? [] : [['start', v]]\n }\n case 'inset-inline-end': {\n const v = lengthPercentageOrAutoToValue(decl.value)\n return v === null ? [] : [['end', v]]\n }\n default: {\n return null\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -10,6 +10,13 @@ import { filterUnknownClassCandidates } from './warn-unknown-classes.mjs';
10
10
 
11
11
  /** Env var that points at the upstream `babelTransformerPath` we override. */
12
12
  const UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER';
13
+ /**
14
+ * Matches a `useCss(` call. Files that resolve classes via the `useCss`
15
+ * hook (no JSX `className=`) must still be scanned so the classes inside
16
+ * `useCss("…")` get registered — common for theme/accent hooks living in a
17
+ * shared package the project scan may not reach.
18
+ */
19
+ const USE_CSS_CALL = /\buseCss\s*\(/;
13
20
  /** Cached upstream module — required once, reused across every transform call. */
14
21
  let cachedUpstream = null;
15
22
  const generateModule = generate.default ?? generate;
@@ -127,17 +134,25 @@ async function rewriteSource(args) {
127
134
  const ast = parseUserSource(args.src);
128
135
  if (!ast)
129
136
  return args.src;
130
- // Wrap host component imports so `<View className=…>` resolves at render
131
- // through the runtime `wrap` (works for literal, spread, and forwarded
132
- // classNames alike). No JSX is rewritten here.
133
- const wrapped = rewriteWrapImports(ast, getWrapModules());
134
- if (!/classname=/i.test(args.src)) {
137
+ const hasClassName = /classname=/i.test(args.src);
138
+ const hasUseCss = USE_CSS_CALL.test(args.src);
139
+ const hasSpread = /\{\s*\.\.\./.test(args.src);
140
+ // Wrap host component imports ONLY when className arrives through a
141
+ // component — written (`hasClassName`) or forwarded (`hasSpread`). A
142
+ // `useCss("…")`-only file resolves manually, so we must NOT wrap its
143
+ // imports: a non-RN drawing lib (e.g. skia's `LinearGradient` nested in
144
+ // `SkiaText`) breaks if its primitives are replaced by a wrapper.
145
+ const wrapped = hasClassName || hasSpread ? rewriteWrapImports(ast, getWrapModules()) : false;
146
+ if (!hasClassName && !hasUseCss) {
135
147
  // Import-only file: nothing to compile. Drop any stale atom
136
148
  // contribution (className may have just been removed) and emit the
137
149
  // wrapped imports — or the untouched source when nothing wrapped.
138
150
  dropFileSafely(args.filename, projectRootOf(args));
139
151
  return wrapped ? generateModule(ast).code : args.src;
140
152
  }
153
+ // Scan path — runs for `className=` literals AND/OR `useCss("…")` strings.
154
+ // oxide reads class candidates from the whole file content, so classes
155
+ // that only ever appear inside a `useCss("…")` call still register.
141
156
  const state = getRnwindState(projectRootOf(args));
142
157
  const extension = extensionOf(args.filename);
143
158
  const parsed = await state.parser.parseAtoms({ content: args.src, extension });
@@ -382,13 +397,16 @@ function isRewriteCandidate(args) {
382
397
  // Process the file when it either:
383
398
  // - carries a `className=` / `<prefix>ClassName=` literal (case-
384
399
  // insensitive — `contentContainerClassName=` has a capital C), or
400
+ // - calls `useCss("…")` (classes that only ever appear in the hook must
401
+ // still be scanned + registered — common for theme/accent hooks), or
385
402
  // - spreads props (`{...rest}`) onto a host from a wrap-module, where a
386
403
  // forwarded className must still get its import wrapped (no literal
387
- // appears in this file). A style-less `<View/>` with neither is left
404
+ // appears in this file). A style-less `<View/>` with none is left
388
405
  // alone so it never pays for an unused wrapper.
389
406
  const hasClassName = /classname=/i.test(args.src);
407
+ const hasUseCss = USE_CSS_CALL.test(args.src);
390
408
  const isForwarder = /\{\s*\.\.\./.test(args.src) && mentionsWrapModule(args.src);
391
- if (!hasClassName && !isForwarder)
409
+ if (!hasClassName && !hasUseCss && !isForwarder)
392
410
  return false;
393
411
  if (!args.filename.includes('/node_modules/'))
394
412
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"transformer.mjs","sources":["../../../../src/metro/transformer.ts"],"sourcesContent":["import type { File } from '@babel/types'\nimport * as t from '@babel/types'\nimport { parse } from '@babel/parser'\nimport generate from '@babel/generator'\nimport { createHash } from 'node:crypto'\nimport { realpathSync } from 'node:fs'\nimport { getRnwindCacheKey, getRnwindState, getWrapModules, onThemeChange } from './state'\nimport { rewriteWrapImports } from './wrap-imports'\nimport { STYLE_SPECIFIERS, THEME_SIGNATURE_MODULE } from './resolver'\nimport { filterUnknownClassCandidates } from './warn-unknown-classes'\n\n/** The shape of the upstream module we delegate parsing/babel work to. */\ninterface UpstreamTransformer {\n transform: (args: BabelTransformerArgs) => Promise<BabelTransformerResult> | BabelTransformerResult\n}\n\n/** Env var that points at the upstream `babelTransformerPath` we override. */\nconst UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER'\n\n/** Cached upstream module — required once, reused across every transform call. */\nlet cachedUpstream: UpstreamTransformer | null = null\n\nconst generateModule = (generate as unknown as { default?: typeof generate }).default ?? generate\n\n/**\n * Parse user source with the broad plugin set (Flow + JSX + TypeScript\n * + class properties). Permissive on purpose so we don't reject any\n * file the upstream could have handled. Returns `null` when parse\n * fails — caller falls back to the raw source string.\n * @param source Source text.\n * @returns Parsed AST, or null on parse failure.\n */\nfunction parseUserSource(source: string): File | null {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['typescript', 'jsx'],\n }) as unknown as File\n } catch {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['flow', 'jsx'],\n }) as unknown as File\n } catch {\n return null\n }\n }\n}\n\n/**\n * Print Tailwind-shaped candidates oxide picked up but the parser\n * could NOT compile — typo, missing custom utility, or class not in\n * the user's theme. Filtering by candidates that ALSO appear inside a\n * `className=\"…\"` literal eliminates false positives from imports,\n * comments, and JSX prop values.\n * @param source Original source text — searched for className literals.\n * @param candidates Every candidate oxide surfaced from the source.\n * @param atoms Successfully resolved atoms (keys are class names).\n * @param filename Source path, prefixed onto the warning.\n * @param features Feature-atom maps (gradient / haptic) — their names are\n * known classes even though they carry no RN style, so they're excluded\n * from the unknown-class warning.\n */\nfunction warnUnknownClasses(\n source: string,\n candidates: readonly string[],\n atoms: ReadonlyMap<string, unknown>,\n filename: string,\n features: ReadonlyArray<ReadonlyMap<string, unknown>> = [],\n): void {\n // Feature atoms (gradient / haptic) resolve to no RN style, so they're\n // absent from `atoms` — but they're NOT unknown. Fold their names into\n // the known set so `active:haptic-rigid` etc. don't warn at build time.\n const known = new Set(atoms.keys())\n for (const map of features) for (const name of map.keys()) known.add(name)\n const unknown = filterUnknownClassCandidates(source, candidates, known)\n if (unknown.length === 0) return\n // eslint-disable-next-line no-console\n console.warn(`rnwind: unknown class${unknown.length > 1 ? 'es' : ''} in ${filename}: ${unknown.join(', ')}`)\n}\n\n/**\n * Extract the bare extension for oxide / internal switches.\n * @param filename Absolute path.\n * @returns Extension without the leading dot (`tsx` / `ts` / `js` / `jsx`).\n */\nfunction extensionOf(filename: string): string {\n const index = filename.lastIndexOf('.')\n if (index === -1) return 'tsx'\n return filename.slice(index + 1)\n}\n\n/**\n * Read the project root Metro hands us per-transform. Falls back to\n * `process.cwd()` only when the upstream harness doesn't set it (unit\n * tests, standalone). Metro's production pipeline always sets it.\n * @param args Metro transformer args.\n * @returns Absolute project root.\n */\nfunction projectRootOf(args: BabelTransformerArgs): string {\n const fromOptions = args.options?.projectRoot\n if (typeof fromOptions === 'string' && fromOptions.length > 0) return fromOptions\n return process.cwd()\n}\n\n/**\n * Whether a `.css` filename is the user's theme entry (the file\n * `withRnwindConfig` pointed us at via `RNWIND_CSS_ENTRY_FILE`).\n * Only the theme CSS should trigger a scheme rebuild — unrelated CSS\n * files in the project stay invisible to rnwind.\n * @param filename Absolute CSS path.\n * @returns Whether the file is the configured theme entry.\n */\nfunction isThemeCssEntry(filename: string): boolean {\n const cssEntry = process.env.RNWIND_CSS_ENTRY_FILE\n return typeof cssEntry === 'string' && cssEntry.length > 0 && cssEntry === filename\n}\n\n/**\n * Wrap host imports + compile any className literals, then regenerate\n * source. Two paths:\n * - **className present**: oxide-scan the file, record its atoms into\n * the union, and inject the generated-style + theme-signature\n * side-effect imports so the runtime registries populate.\n * - **import-only** (a `{...rest}` forwarder or a leaf with no literal\n * `className=`): just wrap the host imports so a forwarded className\n * still resolves at render — no oxide scan, no injected imports.\n *\n * On parse failure, fall back to the original source — a transient parse\n * error shouldn't crash Metro for a file the upstream might handle fine.\n * @param args Metro args; `src` is the original source text.\n * @returns Rewritten source text.\n */\nasync function rewriteSource(args: BabelTransformerArgs): Promise<string> {\n const ast = parseUserSource(args.src)\n if (!ast) return args.src\n\n // Wrap host component imports so `<View className=…>` resolves at render\n // through the runtime `wrap` (works for literal, spread, and forwarded\n // classNames alike). No JSX is rewritten here.\n const wrapped = rewriteWrapImports(ast, getWrapModules())\n\n if (!/classname=/i.test(args.src)) {\n // Import-only file: nothing to compile. Drop any stale atom\n // contribution (className may have just been removed) and emit the\n // wrapped imports — or the untouched source when nothing wrapped.\n dropFileSafely(args.filename, projectRootOf(args))\n return wrapped ? generateModule(ast).code : args.src\n }\n\n const state = getRnwindState(projectRootOf(args))\n const extension = extensionOf(args.filename)\n const parsed = await state.parser.parseAtoms({ content: args.src, extension })\n\n warnUnknownClasses(args.src, parsed.candidates, parsed.atoms, args.filename, [parsed.gradientAtoms, parsed.hapticAtoms])\n\n if (parsed.atoms.size === 0) {\n state.builder.dropFile(args.filename)\n await state.builder.writeSchemes()\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n }\n\n const literals = collectClassNameLiterals(ast)\n const { changed } = await state.builder.recordFile(args.filename, parsed.atoms, parsed.keyframes, literals)\n if (changed) await state.builder.writeSchemes()\n\n injectSideEffectImports(ast, STYLE_SPECIFIERS)\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n}\n\n/**\n * Drop a file's union contribution, swallowing the \"state not configured\"\n * error unit tests hit when they call the transformer without\n * `configureRnwindState`.\n * @param filename Absolute source path.\n * @param projectRoot Project root for state lookup.\n */\nfunction dropFileSafely(filename: string, projectRoot: string): void {\n try {\n getRnwindState(projectRoot).builder.dropFile(filename)\n } catch {\n // State not configured (standalone/unit test). Nothing to drop.\n }\n}\n\n/**\n * Whether a JSX attribute names a className-style prop (`className` or\n * any `<prefix>ClassName`).\n * @param node JSX attribute node.\n * @returns True when the attribute is a className prop.\n */\nfunction isClassNameAttribute(node: t.JSXAttribute): boolean {\n if (!t.isJSXIdentifier(node.name)) return false\n const {name} = node.name\n return name === 'className' || name.endsWith('ClassName')\n}\n\n/**\n * Pull static string literals out of a className expression. Handles a\n * bare string, a no-substitution template, and the branches of a\n * ternary / `&&` (so `cond ? 'a' : 'b'` and `flag && 'x'` both register\n * their literals). Dynamic interpolations are skipped — they resolve via\n * the runtime atom path.\n * @param expr Expression inside a `className={...}` container.\n * @param out Accumulator for discovered literals.\n */\nfunction collectLiteralsFromExpression(expr: t.Expression | t.JSXEmptyExpression | null | undefined, out: string[]): void {\n if (!expr) return\n if (t.isStringLiteral(expr)) {\n out.push(expr.value)\n return\n }\n if (t.isTemplateLiteral(expr) && expr.expressions.length === 0 && expr.quasis.length === 1) {\n const cooked = expr.quasis[0]?.value.cooked\n if (typeof cooked === 'string') out.push(cooked)\n return\n }\n if (t.isConditionalExpression(expr)) {\n collectLiteralsFromExpression(expr.consequent, out)\n collectLiteralsFromExpression(expr.alternate, out)\n return\n }\n if (t.isLogicalExpression(expr)) {\n collectLiteralsFromExpression(expr.right as t.Expression, out)\n }\n}\n\n/** AST node keys the literal walk skips — position / comment metadata. */\nconst SKIP_WALK_KEYS = new Set(['type', 'loc', 'start', 'end', 'range', 'leadingComments', 'trailingComments', 'innerComments'])\n\n/**\n * Collect the static literals from one className JSX attribute into the\n * dedup accumulator.\n * @param attribute The (already className-matched) JSX attribute.\n * @param seen Dedup set of literals already collected.\n * @param out Ordered accumulator.\n */\nfunction collectAttributeLiterals(attribute: t.JSXAttribute, seen: Set<string>, out: string[]): void {\n const { value } = attribute\n const found: string[] = []\n if (t.isStringLiteral(value)) found.push(value.value)\n else if (t.isJSXExpressionContainer(value)) collectLiteralsFromExpression(value.expression, found)\n for (const literal of found) {\n if (seen.has(literal)) continue\n seen.add(literal)\n out.push(literal)\n }\n}\n\n/**\n * Walk the AST for every `className=` / `<prefix>ClassName=` literal so\n * the builder can pre-merge each into a per-scheme molecule. A generic\n * node walk (no scope build) keeps it cheap; only JSX attribute nodes do\n * any work.\n * @param ast Parsed Babel file.\n * @returns Distinct literal className strings, in first-seen order.\n */\nfunction collectClassNameLiterals(ast: File): readonly string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const visit = (node: unknown): void => {\n if (!node || typeof node !== 'object') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n const typed = node as { type?: string; [key: string]: unknown }\n if (typeof typed.type !== 'string') return\n if (typed.type === 'JSXAttribute' && isClassNameAttribute(node as t.JSXAttribute)) {\n collectAttributeLiterals(node as t.JSXAttribute, seen, out)\n }\n for (const key in typed) {\n if (SKIP_WALK_KEYS.has(key)) continue\n visit(typed[key])\n }\n }\n visit(ast.program)\n return out\n}\n\n/**\n * Prepend side-effect imports (`import '<spec>'`) so the generated\n * per-scheme style + manifest modules load — registering this file's\n * atoms / molecules / features into the runtime registries the wrapper's\n * `resolve` reads.\n * @param ast Babel File AST to mutate in place.\n * @param specifiers Module specifiers to side-effect-import.\n */\nfunction injectSideEffectImports(ast: File, specifiers: readonly string[]): void {\n for (const specifier of specifiers) {\n ast.program.body.unshift(t.importDeclaration([], t.stringLiteral(specifier)))\n }\n}\n\n/**\n * Prepend `import 'rnwind/__generated/theme-signature'` to every\n * rnwind-transformed file. The resolver maps that specifier to the\n * user's theme CSS so Metro's dependency graph carries a real edge\n * from this JS file to the CSS. When the user edits `global.css`,\n * the CSS module's SHA1 changes, and Metro invalidates every JS file\n * holding this import — forcing them to re-transform with the new\n * theme. The `.css` branch in {@link transform} returns an empty\n * `export {}` module so the runtime cost is one extra `require()`.\n * @param ast Babel File AST to mutate in place.\n */\nfunction injectThemeSignatureImport(ast: File): void {\n const declaration = t.importDeclaration([], t.stringLiteral(THEME_SIGNATURE_MODULE))\n ast.program.body.unshift(declaration)\n}\n\n/**\n * Read the upstream transformer's `getCacheKey()` so our cache-key\n * contribution composes with — rather than replaces — whatever the\n * host framework wants to mix in.\n * @returns Upstream cache key, or `null` when no upstream exposes one.\n */\nfunction loadUpstreamCacheKey(): string | null {\n const upstream = loadUpstream() as (UpstreamTransformer & { getCacheKey?: () => string }) | null\n if (!upstream) return null\n try {\n return typeof upstream.getCacheKey === 'function' ? upstream.getCacheKey() : null\n } catch {\n return null\n }\n}\n\n/**\n * Invoke the upstream `babelTransformerPath` Metro originally had\n * configured. The path is read from `RNWIND_UPSTREAM_TRANSFORMER`,\n * which `withRnwindConfig` sets at Metro startup. When the env var is\n * unset (unit tests, standalone use), fall back to a typescript+jsx\n * parse.\n * @param args Metro's per-file args.\n * @returns Upstream transform result containing the post-babel AST.\n */\nasync function runUpstream(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n if (args.ast && !process.env[UPSTREAM_ENV]) return { ast: args.ast }\n const upstream = loadUpstream()\n if (upstream) return await Promise.resolve(upstream.transform(args))\n if (args.ast) return { ast: args.ast }\n return { ast: parseSource(args.src) }\n}\n\n/**\n * Lazily require the upstream transformer module. Cached after first\n * load so per-file overhead is one cache lookup.\n * @returns Upstream module, or null when env is unset.\n */\nfunction loadUpstream(): UpstreamTransformer | null {\n if (cachedUpstream) return cachedUpstream\n const upstreamPath = process.env[UPSTREAM_ENV]\n if (!upstreamPath || upstreamPath.length === 0) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const required = require(upstreamPath) as UpstreamTransformer | { default?: UpstreamTransformer }\n const upstream = (required as { default?: UpstreamTransformer }).default ?? (required as UpstreamTransformer)\n if (typeof upstream.transform !== 'function') return null\n cachedUpstream = upstream\n return upstream\n } catch (error) {\n // eslint-disable-next-line no-console\n if (process.env.RNWIND_DEBUG) console.error('rnwind: failed to load upstream transformer:', error)\n return null\n }\n}\n\n/**\n * Cheap guard — the file has to look JS/TS, live outside `node_modules`,\n * and mention `className=` before we spend AST cycles on it.\n *\n * Symlink awareness: monorepo workspaces (yarn / pnpm / bun workspaces)\n * symlink each package into the consumer's `node_modules/<name>`, so a\n * file from `packages/ui/src/Foo.tsx` ends up reaching the transformer\n * as `<root>/node_modules/ui/src/Foo.tsx`. The naïve `/node_modules/`\n * check would skip every workspace UI file. We `realpath` the filename\n * once and only bail when the resolved real path is ALSO under\n * node_modules — true third-party installs.\n * @param args Metro args.\n * @returns Whether the file might need the rnwind pass.\n */\nfunction isRewriteCandidate(args: BabelTransformerArgs): boolean {\n if (!/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename)) return false\n // Process the file when it either:\n // - carries a `className=` / `<prefix>ClassName=` literal (case-\n // insensitive — `contentContainerClassName=` has a capital C), or\n // - spreads props (`{...rest}`) onto a host from a wrap-module, where a\n // forwarded className must still get its import wrapped (no literal\n // appears in this file). A style-less `<View/>` with neither is left\n // alone so it never pays for an unused wrapper.\n const hasClassName = /classname=/i.test(args.src)\n const isForwarder = /\\{\\s*\\.\\.\\./.test(args.src) && mentionsWrapModule(args.src)\n if (!hasClassName && !isForwarder) return false\n if (!args.filename.includes('/node_modules/')) return true\n // node_modules in path → could be a workspace symlink; resolve it.\n try {\n return !realpathSync(args.filename).includes('/node_modules/')\n } catch {\n // realpath failed (broken symlink, missing file). Fall back to skipping.\n return false\n }\n}\n\n/**\n * Cheap pre-parse check: does the source import from any configured\n * wrap-module? A quoted specifier match is enough — `rewriteWrapImports`\n * re-verifies precisely on the AST, so a false positive only costs a\n * no-op parse.\n * @param source Source text.\n * @returns True when a wrap-module specifier appears in the source.\n */\nfunction mentionsWrapModule(source: string): boolean {\n for (const moduleName of getWrapModules().keys()) {\n if (source.includes(`'${moduleName}'`) || source.includes(`\"${moduleName}\"`)) return true\n }\n return false\n}\n\n/**\n * Fallback parse when no upstream is configured AND Metro didn't hand\n * us an AST. Used by unit tests and standalone setups.\n * @param source Source text.\n * @returns Parsed Babel File.\n */\nfunction parseSource(source: string): File {\n return parse(source, { sourceType: 'module', plugins: ['typescript', 'jsx'] }) as unknown as File\n}\n\n/** Metro's babel transformer signature. */\nexport interface BabelTransformerArgs {\n filename: string\n src: string\n options: { projectRoot?: string; [key: string]: unknown }\n ast?: File\n plugins?: readonly unknown[]\n}\n\n/** Return shape Metro expects from a babel transformer. */\nexport interface BabelTransformerResult {\n ast: File\n metadata?: unknown\n}\n\n/**\n * rnwind's Metro babel transformer. Two phases per source file:\n *\n * 1. **Pre-process the source string before handing it to the upstream\n * babel pipeline.** babel-preset-expo / React's JSX transform run\n * inside the upstream and convert `<View className=\"...\"/>` into\n * `React.createElement(View, {className})`. If we walked the AST\n * AFTER the upstream, there'd be no JSX attributes left to\n * rewrite. So we parse, run our pass, regenerate code, and feed\n * THAT to the upstream as `src`.\n * 2. **Delegate to the upstream `babelTransformerPath`** (Expo's\n * default handles Flow stripping, expo-router macros, etc.).\n *\n * Skip both phases when the file isn't a JS/TS source under user\n * code, or doesn't mention `className=` — hand straight to upstream.\n * @param args Metro's per-file args.\n * @returns Mutated AST + metadata.\n */\nexport async function transform(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n // Short-circuit `.css` inputs: the theme CSS is pulled into the dep\n // graph as a sentinel (see `THEME_SIGNATURE_MODULE` in resolver.ts)\n // so Metro watches it and invalidates importers on edit, but the\n // file's CSS syntax can't go through a JS babel transformer.\n //\n // When the CSS being transformed IS the user's theme entry, we\n // piggyback on Metro's own file-watcher: Metro calls us here on\n // every CSS save; we trigger `onThemeChange` to rebuild parser +\n // rewrite scheme files with the new values. Metro's dep graph then\n // HMRs the regenerated `common.style.js` to the running app.\n //\n // Emitting the CSS content hash in the fake JS output is what makes\n // Metro propagate invalidation to downstream importers — constant\n // `export {}` bytes would never look changed and Metro would skip\n // the chain.\n if (args.filename.endsWith('.css')) {\n if (isThemeCssEntry(args.filename)) {\n try {\n await onThemeChange(projectRootOf(args))\n } catch {\n // CSS edit happened outside a configured project (e.g. tests).\n }\n }\n const themeHash = createHash('sha256').update(args.src).digest('hex').slice(0, 16)\n const stub = `export const __rnwindThemeHash = ${JSON.stringify(themeHash)};\\n`\n return { ast: parse(stub, { sourceType: 'module' }) as unknown as File }\n }\n if (!isRewriteCandidate(args)) {\n if (/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename) && !args.filename.includes('/node_modules/')) {\n try {\n getRnwindState(projectRootOf(args)).builder.dropFile(args.filename)\n } catch {\n // State not configured (e.g. test). Nothing to drop.\n }\n }\n return runUpstream(args)\n }\n\n const rewrittenSource = await rewriteSource(args)\n return runUpstream({ ...args, src: rewrittenSource, ast: undefined })\n}\n\n/**\n * Metro's babel-transformer contract: a `getCacheKey()` export is\n * sampled per-file and mixed into the transform cache key. Returning\n * a string that includes the theme CSS content hash invalidates every\n * cached transform on every CSS edit — so the bundle rebuilds with\n * the new theme automatically on the next request.\n * @returns Cache-key segment that includes rnwind's current theme hash.\n */\nexport function getCacheKey(): string {\n const upstreamKey = loadUpstreamCacheKey()\n const ownKey = getRnwindCacheKey()\n return upstreamKey ? `${upstreamKey}|${ownKey}` : ownKey\n}\n\n/** Test-only — drop the cached upstream so a new env var picks up next call. */\nexport function __resetUpstreamCache(): void {\n cachedUpstream = null\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transformer.mjs","sources":["../../../../src/metro/transformer.ts"],"sourcesContent":["import type { File } from '@babel/types'\nimport * as t from '@babel/types'\nimport { parse } from '@babel/parser'\nimport generate from '@babel/generator'\nimport { createHash } from 'node:crypto'\nimport { realpathSync } from 'node:fs'\nimport { getRnwindCacheKey, getRnwindState, getWrapModules, onThemeChange } from './state'\nimport { rewriteWrapImports } from './wrap-imports'\nimport { STYLE_SPECIFIERS, THEME_SIGNATURE_MODULE } from './resolver'\nimport { filterUnknownClassCandidates } from './warn-unknown-classes'\n\n/** The shape of the upstream module we delegate parsing/babel work to. */\ninterface UpstreamTransformer {\n transform: (args: BabelTransformerArgs) => Promise<BabelTransformerResult> | BabelTransformerResult\n}\n\n/** Env var that points at the upstream `babelTransformerPath` we override. */\nconst UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER'\n\n/**\n * Matches a `useCss(` call. Files that resolve classes via the `useCss`\n * hook (no JSX `className=`) must still be scanned so the classes inside\n * `useCss(\"…\")` get registered — common for theme/accent hooks living in a\n * shared package the project scan may not reach.\n */\nconst USE_CSS_CALL = /\\buseCss\\s*\\(/\n\n/** Cached upstream module — required once, reused across every transform call. */\nlet cachedUpstream: UpstreamTransformer | null = null\n\nconst generateModule = (generate as unknown as { default?: typeof generate }).default ?? generate\n\n/**\n * Parse user source with the broad plugin set (Flow + JSX + TypeScript\n * + class properties). Permissive on purpose so we don't reject any\n * file the upstream could have handled. Returns `null` when parse\n * fails — caller falls back to the raw source string.\n * @param source Source text.\n * @returns Parsed AST, or null on parse failure.\n */\nfunction parseUserSource(source: string): File | null {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['typescript', 'jsx'],\n }) as unknown as File\n } catch {\n try {\n return parse(source, {\n sourceType: 'unambiguous',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n plugins: ['flow', 'jsx'],\n }) as unknown as File\n } catch {\n return null\n }\n }\n}\n\n/**\n * Print Tailwind-shaped candidates oxide picked up but the parser\n * could NOT compile — typo, missing custom utility, or class not in\n * the user's theme. Filtering by candidates that ALSO appear inside a\n * `className=\"…\"` literal eliminates false positives from imports,\n * comments, and JSX prop values.\n * @param source Original source text — searched for className literals.\n * @param candidates Every candidate oxide surfaced from the source.\n * @param atoms Successfully resolved atoms (keys are class names).\n * @param filename Source path, prefixed onto the warning.\n * @param features Feature-atom maps (gradient / haptic) — their names are\n * known classes even though they carry no RN style, so they're excluded\n * from the unknown-class warning.\n */\nfunction warnUnknownClasses(\n source: string,\n candidates: readonly string[],\n atoms: ReadonlyMap<string, unknown>,\n filename: string,\n features: ReadonlyArray<ReadonlyMap<string, unknown>> = [],\n): void {\n // Feature atoms (gradient / haptic) resolve to no RN style, so they're\n // absent from `atoms` — but they're NOT unknown. Fold their names into\n // the known set so `active:haptic-rigid` etc. don't warn at build time.\n const known = new Set(atoms.keys())\n for (const map of features) for (const name of map.keys()) known.add(name)\n const unknown = filterUnknownClassCandidates(source, candidates, known)\n if (unknown.length === 0) return\n // eslint-disable-next-line no-console\n console.warn(`rnwind: unknown class${unknown.length > 1 ? 'es' : ''} in ${filename}: ${unknown.join(', ')}`)\n}\n\n/**\n * Extract the bare extension for oxide / internal switches.\n * @param filename Absolute path.\n * @returns Extension without the leading dot (`tsx` / `ts` / `js` / `jsx`).\n */\nfunction extensionOf(filename: string): string {\n const index = filename.lastIndexOf('.')\n if (index === -1) return 'tsx'\n return filename.slice(index + 1)\n}\n\n/**\n * Read the project root Metro hands us per-transform. Falls back to\n * `process.cwd()` only when the upstream harness doesn't set it (unit\n * tests, standalone). Metro's production pipeline always sets it.\n * @param args Metro transformer args.\n * @returns Absolute project root.\n */\nfunction projectRootOf(args: BabelTransformerArgs): string {\n const fromOptions = args.options?.projectRoot\n if (typeof fromOptions === 'string' && fromOptions.length > 0) return fromOptions\n return process.cwd()\n}\n\n/**\n * Whether a `.css` filename is the user's theme entry (the file\n * `withRnwindConfig` pointed us at via `RNWIND_CSS_ENTRY_FILE`).\n * Only the theme CSS should trigger a scheme rebuild — unrelated CSS\n * files in the project stay invisible to rnwind.\n * @param filename Absolute CSS path.\n * @returns Whether the file is the configured theme entry.\n */\nfunction isThemeCssEntry(filename: string): boolean {\n const cssEntry = process.env.RNWIND_CSS_ENTRY_FILE\n return typeof cssEntry === 'string' && cssEntry.length > 0 && cssEntry === filename\n}\n\n/**\n * Wrap host imports + compile any className literals, then regenerate\n * source. Two paths:\n * - **className present**: oxide-scan the file, record its atoms into\n * the union, and inject the generated-style + theme-signature\n * side-effect imports so the runtime registries populate.\n * - **import-only** (a `{...rest}` forwarder or a leaf with no literal\n * `className=`): just wrap the host imports so a forwarded className\n * still resolves at render — no oxide scan, no injected imports.\n *\n * On parse failure, fall back to the original source — a transient parse\n * error shouldn't crash Metro for a file the upstream might handle fine.\n * @param args Metro args; `src` is the original source text.\n * @returns Rewritten source text.\n */\nasync function rewriteSource(args: BabelTransformerArgs): Promise<string> {\n const ast = parseUserSource(args.src)\n if (!ast) return args.src\n\n const hasClassName = /classname=/i.test(args.src)\n const hasUseCss = USE_CSS_CALL.test(args.src)\n const hasSpread = /\\{\\s*\\.\\.\\./.test(args.src)\n\n // Wrap host component imports ONLY when className arrives through a\n // component — written (`hasClassName`) or forwarded (`hasSpread`). A\n // `useCss(\"…\")`-only file resolves manually, so we must NOT wrap its\n // imports: a non-RN drawing lib (e.g. skia's `LinearGradient` nested in\n // `SkiaText`) breaks if its primitives are replaced by a wrapper.\n const wrapped = hasClassName || hasSpread ? rewriteWrapImports(ast, getWrapModules()) : false\n\n if (!hasClassName && !hasUseCss) {\n // Import-only file: nothing to compile. Drop any stale atom\n // contribution (className may have just been removed) and emit the\n // wrapped imports — or the untouched source when nothing wrapped.\n dropFileSafely(args.filename, projectRootOf(args))\n return wrapped ? generateModule(ast).code : args.src\n }\n\n // Scan path — runs for `className=` literals AND/OR `useCss(\"…\")` strings.\n // oxide reads class candidates from the whole file content, so classes\n // that only ever appear inside a `useCss(\"…\")` call still register.\n const state = getRnwindState(projectRootOf(args))\n const extension = extensionOf(args.filename)\n const parsed = await state.parser.parseAtoms({ content: args.src, extension })\n\n warnUnknownClasses(args.src, parsed.candidates, parsed.atoms, args.filename, [parsed.gradientAtoms, parsed.hapticAtoms])\n\n if (parsed.atoms.size === 0) {\n state.builder.dropFile(args.filename)\n await state.builder.writeSchemes()\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n }\n\n const literals = collectClassNameLiterals(ast)\n const { changed } = await state.builder.recordFile(args.filename, parsed.atoms, parsed.keyframes, literals)\n if (changed) await state.builder.writeSchemes()\n\n injectSideEffectImports(ast, STYLE_SPECIFIERS)\n injectThemeSignatureImport(ast)\n return generateModule(ast).code\n}\n\n/**\n * Drop a file's union contribution, swallowing the \"state not configured\"\n * error unit tests hit when they call the transformer without\n * `configureRnwindState`.\n * @param filename Absolute source path.\n * @param projectRoot Project root for state lookup.\n */\nfunction dropFileSafely(filename: string, projectRoot: string): void {\n try {\n getRnwindState(projectRoot).builder.dropFile(filename)\n } catch {\n // State not configured (standalone/unit test). Nothing to drop.\n }\n}\n\n/**\n * Whether a JSX attribute names a className-style prop (`className` or\n * any `<prefix>ClassName`).\n * @param node JSX attribute node.\n * @returns True when the attribute is a className prop.\n */\nfunction isClassNameAttribute(node: t.JSXAttribute): boolean {\n if (!t.isJSXIdentifier(node.name)) return false\n const {name} = node.name\n return name === 'className' || name.endsWith('ClassName')\n}\n\n/**\n * Pull static string literals out of a className expression. Handles a\n * bare string, a no-substitution template, and the branches of a\n * ternary / `&&` (so `cond ? 'a' : 'b'` and `flag && 'x'` both register\n * their literals). Dynamic interpolations are skipped — they resolve via\n * the runtime atom path.\n * @param expr Expression inside a `className={...}` container.\n * @param out Accumulator for discovered literals.\n */\nfunction collectLiteralsFromExpression(expr: t.Expression | t.JSXEmptyExpression | null | undefined, out: string[]): void {\n if (!expr) return\n if (t.isStringLiteral(expr)) {\n out.push(expr.value)\n return\n }\n if (t.isTemplateLiteral(expr) && expr.expressions.length === 0 && expr.quasis.length === 1) {\n const cooked = expr.quasis[0]?.value.cooked\n if (typeof cooked === 'string') out.push(cooked)\n return\n }\n if (t.isConditionalExpression(expr)) {\n collectLiteralsFromExpression(expr.consequent, out)\n collectLiteralsFromExpression(expr.alternate, out)\n return\n }\n if (t.isLogicalExpression(expr)) {\n collectLiteralsFromExpression(expr.right as t.Expression, out)\n }\n}\n\n/** AST node keys the literal walk skips — position / comment metadata. */\nconst SKIP_WALK_KEYS = new Set(['type', 'loc', 'start', 'end', 'range', 'leadingComments', 'trailingComments', 'innerComments'])\n\n/**\n * Collect the static literals from one className JSX attribute into the\n * dedup accumulator.\n * @param attribute The (already className-matched) JSX attribute.\n * @param seen Dedup set of literals already collected.\n * @param out Ordered accumulator.\n */\nfunction collectAttributeLiterals(attribute: t.JSXAttribute, seen: Set<string>, out: string[]): void {\n const { value } = attribute\n const found: string[] = []\n if (t.isStringLiteral(value)) found.push(value.value)\n else if (t.isJSXExpressionContainer(value)) collectLiteralsFromExpression(value.expression, found)\n for (const literal of found) {\n if (seen.has(literal)) continue\n seen.add(literal)\n out.push(literal)\n }\n}\n\n/**\n * Walk the AST for every `className=` / `<prefix>ClassName=` literal so\n * the builder can pre-merge each into a per-scheme molecule. A generic\n * node walk (no scope build) keeps it cheap; only JSX attribute nodes do\n * any work.\n * @param ast Parsed Babel file.\n * @returns Distinct literal className strings, in first-seen order.\n */\nfunction collectClassNameLiterals(ast: File): readonly string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const visit = (node: unknown): void => {\n if (!node || typeof node !== 'object') return\n if (Array.isArray(node)) {\n for (const child of node) visit(child)\n return\n }\n const typed = node as { type?: string; [key: string]: unknown }\n if (typeof typed.type !== 'string') return\n if (typed.type === 'JSXAttribute' && isClassNameAttribute(node as t.JSXAttribute)) {\n collectAttributeLiterals(node as t.JSXAttribute, seen, out)\n }\n for (const key in typed) {\n if (SKIP_WALK_KEYS.has(key)) continue\n visit(typed[key])\n }\n }\n visit(ast.program)\n return out\n}\n\n/**\n * Prepend side-effect imports (`import '<spec>'`) so the generated\n * per-scheme style + manifest modules load — registering this file's\n * atoms / molecules / features into the runtime registries the wrapper's\n * `resolve` reads.\n * @param ast Babel File AST to mutate in place.\n * @param specifiers Module specifiers to side-effect-import.\n */\nfunction injectSideEffectImports(ast: File, specifiers: readonly string[]): void {\n for (const specifier of specifiers) {\n ast.program.body.unshift(t.importDeclaration([], t.stringLiteral(specifier)))\n }\n}\n\n/**\n * Prepend `import 'rnwind/__generated/theme-signature'` to every\n * rnwind-transformed file. The resolver maps that specifier to the\n * user's theme CSS so Metro's dependency graph carries a real edge\n * from this JS file to the CSS. When the user edits `global.css`,\n * the CSS module's SHA1 changes, and Metro invalidates every JS file\n * holding this import — forcing them to re-transform with the new\n * theme. The `.css` branch in {@link transform} returns an empty\n * `export {}` module so the runtime cost is one extra `require()`.\n * @param ast Babel File AST to mutate in place.\n */\nfunction injectThemeSignatureImport(ast: File): void {\n const declaration = t.importDeclaration([], t.stringLiteral(THEME_SIGNATURE_MODULE))\n ast.program.body.unshift(declaration)\n}\n\n/**\n * Read the upstream transformer's `getCacheKey()` so our cache-key\n * contribution composes with — rather than replaces — whatever the\n * host framework wants to mix in.\n * @returns Upstream cache key, or `null` when no upstream exposes one.\n */\nfunction loadUpstreamCacheKey(): string | null {\n const upstream = loadUpstream() as (UpstreamTransformer & { getCacheKey?: () => string }) | null\n if (!upstream) return null\n try {\n return typeof upstream.getCacheKey === 'function' ? upstream.getCacheKey() : null\n } catch {\n return null\n }\n}\n\n/**\n * Invoke the upstream `babelTransformerPath` Metro originally had\n * configured. The path is read from `RNWIND_UPSTREAM_TRANSFORMER`,\n * which `withRnwindConfig` sets at Metro startup. When the env var is\n * unset (unit tests, standalone use), fall back to a typescript+jsx\n * parse.\n * @param args Metro's per-file args.\n * @returns Upstream transform result containing the post-babel AST.\n */\nasync function runUpstream(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n if (args.ast && !process.env[UPSTREAM_ENV]) return { ast: args.ast }\n const upstream = loadUpstream()\n if (upstream) return await Promise.resolve(upstream.transform(args))\n if (args.ast) return { ast: args.ast }\n return { ast: parseSource(args.src) }\n}\n\n/**\n * Lazily require the upstream transformer module. Cached after first\n * load so per-file overhead is one cache lookup.\n * @returns Upstream module, or null when env is unset.\n */\nfunction loadUpstream(): UpstreamTransformer | null {\n if (cachedUpstream) return cachedUpstream\n const upstreamPath = process.env[UPSTREAM_ENV]\n if (!upstreamPath || upstreamPath.length === 0) return null\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n const required = require(upstreamPath) as UpstreamTransformer | { default?: UpstreamTransformer }\n const upstream = (required as { default?: UpstreamTransformer }).default ?? (required as UpstreamTransformer)\n if (typeof upstream.transform !== 'function') return null\n cachedUpstream = upstream\n return upstream\n } catch (error) {\n // eslint-disable-next-line no-console\n if (process.env.RNWIND_DEBUG) console.error('rnwind: failed to load upstream transformer:', error)\n return null\n }\n}\n\n/**\n * Cheap guard — the file has to look JS/TS, live outside `node_modules`,\n * and mention `className=` before we spend AST cycles on it.\n *\n * Symlink awareness: monorepo workspaces (yarn / pnpm / bun workspaces)\n * symlink each package into the consumer's `node_modules/<name>`, so a\n * file from `packages/ui/src/Foo.tsx` ends up reaching the transformer\n * as `<root>/node_modules/ui/src/Foo.tsx`. The naïve `/node_modules/`\n * check would skip every workspace UI file. We `realpath` the filename\n * once and only bail when the resolved real path is ALSO under\n * node_modules — true third-party installs.\n * @param args Metro args.\n * @returns Whether the file might need the rnwind pass.\n */\nfunction isRewriteCandidate(args: BabelTransformerArgs): boolean {\n if (!/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename)) return false\n // Process the file when it either:\n // - carries a `className=` / `<prefix>ClassName=` literal (case-\n // insensitive — `contentContainerClassName=` has a capital C), or\n // - calls `useCss(\"…\")` (classes that only ever appear in the hook must\n // still be scanned + registered — common for theme/accent hooks), or\n // - spreads props (`{...rest}`) onto a host from a wrap-module, where a\n // forwarded className must still get its import wrapped (no literal\n // appears in this file). A style-less `<View/>` with none is left\n // alone so it never pays for an unused wrapper.\n const hasClassName = /classname=/i.test(args.src)\n const hasUseCss = USE_CSS_CALL.test(args.src)\n const isForwarder = /\\{\\s*\\.\\.\\./.test(args.src) && mentionsWrapModule(args.src)\n if (!hasClassName && !hasUseCss && !isForwarder) return false\n if (!args.filename.includes('/node_modules/')) return true\n // node_modules in path → could be a workspace symlink; resolve it.\n try {\n return !realpathSync(args.filename).includes('/node_modules/')\n } catch {\n // realpath failed (broken symlink, missing file). Fall back to skipping.\n return false\n }\n}\n\n/**\n * Cheap pre-parse check: does the source import from any configured\n * wrap-module? A quoted specifier match is enough — `rewriteWrapImports`\n * re-verifies precisely on the AST, so a false positive only costs a\n * no-op parse.\n * @param source Source text.\n * @returns True when a wrap-module specifier appears in the source.\n */\nfunction mentionsWrapModule(source: string): boolean {\n for (const moduleName of getWrapModules().keys()) {\n if (source.includes(`'${moduleName}'`) || source.includes(`\"${moduleName}\"`)) return true\n }\n return false\n}\n\n/**\n * Fallback parse when no upstream is configured AND Metro didn't hand\n * us an AST. Used by unit tests and standalone setups.\n * @param source Source text.\n * @returns Parsed Babel File.\n */\nfunction parseSource(source: string): File {\n return parse(source, { sourceType: 'module', plugins: ['typescript', 'jsx'] }) as unknown as File\n}\n\n/** Metro's babel transformer signature. */\nexport interface BabelTransformerArgs {\n filename: string\n src: string\n options: { projectRoot?: string; [key: string]: unknown }\n ast?: File\n plugins?: readonly unknown[]\n}\n\n/** Return shape Metro expects from a babel transformer. */\nexport interface BabelTransformerResult {\n ast: File\n metadata?: unknown\n}\n\n/**\n * rnwind's Metro babel transformer. Two phases per source file:\n *\n * 1. **Pre-process the source string before handing it to the upstream\n * babel pipeline.** babel-preset-expo / React's JSX transform run\n * inside the upstream and convert `<View className=\"...\"/>` into\n * `React.createElement(View, {className})`. If we walked the AST\n * AFTER the upstream, there'd be no JSX attributes left to\n * rewrite. So we parse, run our pass, regenerate code, and feed\n * THAT to the upstream as `src`.\n * 2. **Delegate to the upstream `babelTransformerPath`** (Expo's\n * default handles Flow stripping, expo-router macros, etc.).\n *\n * Skip both phases when the file isn't a JS/TS source under user\n * code, or doesn't mention `className=` — hand straight to upstream.\n * @param args Metro's per-file args.\n * @returns Mutated AST + metadata.\n */\nexport async function transform(args: BabelTransformerArgs): Promise<BabelTransformerResult> {\n // Short-circuit `.css` inputs: the theme CSS is pulled into the dep\n // graph as a sentinel (see `THEME_SIGNATURE_MODULE` in resolver.ts)\n // so Metro watches it and invalidates importers on edit, but the\n // file's CSS syntax can't go through a JS babel transformer.\n //\n // When the CSS being transformed IS the user's theme entry, we\n // piggyback on Metro's own file-watcher: Metro calls us here on\n // every CSS save; we trigger `onThemeChange` to rebuild parser +\n // rewrite scheme files with the new values. Metro's dep graph then\n // HMRs the regenerated `common.style.js` to the running app.\n //\n // Emitting the CSS content hash in the fake JS output is what makes\n // Metro propagate invalidation to downstream importers — constant\n // `export {}` bytes would never look changed and Metro would skip\n // the chain.\n if (args.filename.endsWith('.css')) {\n if (isThemeCssEntry(args.filename)) {\n try {\n await onThemeChange(projectRootOf(args))\n } catch {\n // CSS edit happened outside a configured project (e.g. tests).\n }\n }\n const themeHash = createHash('sha256').update(args.src).digest('hex').slice(0, 16)\n const stub = `export const __rnwindThemeHash = ${JSON.stringify(themeHash)};\\n`\n return { ast: parse(stub, { sourceType: 'module' }) as unknown as File }\n }\n if (!isRewriteCandidate(args)) {\n if (/\\.(?:tsx|ts|jsx|js)$/i.test(args.filename) && !args.filename.includes('/node_modules/')) {\n try {\n getRnwindState(projectRootOf(args)).builder.dropFile(args.filename)\n } catch {\n // State not configured (e.g. test). Nothing to drop.\n }\n }\n return runUpstream(args)\n }\n\n const rewrittenSource = await rewriteSource(args)\n return runUpstream({ ...args, src: rewrittenSource, ast: undefined })\n}\n\n/**\n * Metro's babel-transformer contract: a `getCacheKey()` export is\n * sampled per-file and mixed into the transform cache key. Returning\n * a string that includes the theme CSS content hash invalidates every\n * cached transform on every CSS edit — so the bundle rebuilds with\n * the new theme automatically on the next request.\n * @returns Cache-key segment that includes rnwind's current theme hash.\n */\nexport function getCacheKey(): string {\n const upstreamKey = loadUpstreamCacheKey()\n const ownKey = getRnwindCacheKey()\n return upstreamKey ? `${upstreamKey}|${ownKey}` : ownKey\n}\n\n/** Test-only — drop the cached upstream so a new env var picks up next call. */\nexport function __resetUpstreamCache(): void {\n cachedUpstream = null\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnwind",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Tailwind for React Native",
5
5
  "author": "https://github.com/sagltd",
6
6
  "license": "MIT",
@@ -38,6 +38,14 @@ const UNSUPPORTED_LOGICAL_PROPS = new Set([
38
38
  'border-block-end-style',
39
39
  ])
40
40
 
41
+ /** CSS single-sided logical-inline property → RN writing-direction Yoga key. */
42
+ const LOGICAL_INLINE_TO_RN: Record<string, string> = {
43
+ 'margin-inline-start': 'marginStart',
44
+ 'margin-inline-end': 'marginEnd',
45
+ 'padding-inline-start': 'paddingStart',
46
+ 'padding-inline-end': 'paddingEnd',
47
+ }
48
+
41
49
  /**
42
50
  * Pick the closest predefined CSS easing keyword for a `cubic-bezier`
43
51
  * control-point set. Mirrors {@link snapCubicBezierToKeyword} in
@@ -333,6 +341,7 @@ export function declarationToRnEntries(decl: LcDeclaration, themeVars?: Readonly
333
341
  }
334
342
  default: {
335
343
  return (
344
+ dispatchLogicalInline(decl) ??
336
345
  dispatchLayoutDeclaration(decl) ??
337
346
  dispatchTypographyDeclaration(decl) ??
338
347
  dispatchColorPropertyDeclaration(decl) ??
@@ -343,3 +352,35 @@ export function declarationToRnEntries(decl: LcDeclaration, themeVars?: Readonly
343
352
  }
344
353
  }
345
354
  }
355
+
356
+ /**
357
+ * Map single-sided CSS logical-inline props to RN's writing-direction-aware
358
+ * Yoga keys: `ms-2` → `marginStart`, `pe-4` → `paddingEnd`, `start-2` →
359
+ * `start`, `end-3` → `end`. RN resolves start/end against the layout
360
+ * direction, so these stay RTL-correct. Returns null for any other property
361
+ * (so the dispatch chain continues).
362
+ * @param decl One declaration from a lightningcss style rule.
363
+ * @returns RN entries, or null when not a logical-inline property.
364
+ */
365
+ function dispatchLogicalInline(decl: LcDeclaration): readonly RNEntry[] | null {
366
+ switch (decl.property) {
367
+ case 'margin-inline-start':
368
+ case 'margin-inline-end':
369
+ case 'padding-inline-start':
370
+ case 'padding-inline-end': {
371
+ const v = lengthPercentageOrAutoToValue(decl.value)
372
+ return v === null ? [] : [[LOGICAL_INLINE_TO_RN[decl.property], v]]
373
+ }
374
+ case 'inset-inline-start': {
375
+ const v = lengthPercentageOrAutoToValue(decl.value)
376
+ return v === null ? [] : [['start', v]]
377
+ }
378
+ case 'inset-inline-end': {
379
+ const v = lengthPercentageOrAutoToValue(decl.value)
380
+ return v === null ? [] : [['end', v]]
381
+ }
382
+ default: {
383
+ return null
384
+ }
385
+ }
386
+ }
@@ -17,6 +17,14 @@ interface UpstreamTransformer {
17
17
  /** Env var that points at the upstream `babelTransformerPath` we override. */
18
18
  const UPSTREAM_ENV = 'RNWIND_UPSTREAM_TRANSFORMER'
19
19
 
20
+ /**
21
+ * Matches a `useCss(` call. Files that resolve classes via the `useCss`
22
+ * hook (no JSX `className=`) must still be scanned so the classes inside
23
+ * `useCss("…")` get registered — common for theme/accent hooks living in a
24
+ * shared package the project scan may not reach.
25
+ */
26
+ const USE_CSS_CALL = /\buseCss\s*\(/
27
+
20
28
  /** Cached upstream module — required once, reused across every transform call. */
21
29
  let cachedUpstream: UpstreamTransformer | null = null
22
30
 
@@ -140,12 +148,18 @@ async function rewriteSource(args: BabelTransformerArgs): Promise<string> {
140
148
  const ast = parseUserSource(args.src)
141
149
  if (!ast) return args.src
142
150
 
143
- // Wrap host component imports so `<View className=…>` resolves at render
144
- // through the runtime `wrap` (works for literal, spread, and forwarded
145
- // classNames alike). No JSX is rewritten here.
146
- const wrapped = rewriteWrapImports(ast, getWrapModules())
151
+ const hasClassName = /classname=/i.test(args.src)
152
+ const hasUseCss = USE_CSS_CALL.test(args.src)
153
+ const hasSpread = /\{\s*\.\.\./.test(args.src)
154
+
155
+ // Wrap host component imports ONLY when className arrives through a
156
+ // component — written (`hasClassName`) or forwarded (`hasSpread`). A
157
+ // `useCss("…")`-only file resolves manually, so we must NOT wrap its
158
+ // imports: a non-RN drawing lib (e.g. skia's `LinearGradient` nested in
159
+ // `SkiaText`) breaks if its primitives are replaced by a wrapper.
160
+ const wrapped = hasClassName || hasSpread ? rewriteWrapImports(ast, getWrapModules()) : false
147
161
 
148
- if (!/classname=/i.test(args.src)) {
162
+ if (!hasClassName && !hasUseCss) {
149
163
  // Import-only file: nothing to compile. Drop any stale atom
150
164
  // contribution (className may have just been removed) and emit the
151
165
  // wrapped imports — or the untouched source when nothing wrapped.
@@ -153,6 +167,9 @@ async function rewriteSource(args: BabelTransformerArgs): Promise<string> {
153
167
  return wrapped ? generateModule(ast).code : args.src
154
168
  }
155
169
 
170
+ // Scan path — runs for `className=` literals AND/OR `useCss("…")` strings.
171
+ // oxide reads class candidates from the whole file content, so classes
172
+ // that only ever appear inside a `useCss("…")` call still register.
156
173
  const state = getRnwindState(projectRootOf(args))
157
174
  const extension = extensionOf(args.filename)
158
175
  const parsed = await state.parser.parseAtoms({ content: args.src, extension })
@@ -390,13 +407,16 @@ function isRewriteCandidate(args: BabelTransformerArgs): boolean {
390
407
  // Process the file when it either:
391
408
  // - carries a `className=` / `<prefix>ClassName=` literal (case-
392
409
  // insensitive — `contentContainerClassName=` has a capital C), or
410
+ // - calls `useCss("…")` (classes that only ever appear in the hook must
411
+ // still be scanned + registered — common for theme/accent hooks), or
393
412
  // - spreads props (`{...rest}`) onto a host from a wrap-module, where a
394
413
  // forwarded className must still get its import wrapped (no literal
395
- // appears in this file). A style-less `<View/>` with neither is left
414
+ // appears in this file). A style-less `<View/>` with none is left
396
415
  // alone so it never pays for an unused wrapper.
397
416
  const hasClassName = /classname=/i.test(args.src)
417
+ const hasUseCss = USE_CSS_CALL.test(args.src)
398
418
  const isForwarder = /\{\s*\.\.\./.test(args.src) && mentionsWrapModule(args.src)
399
- if (!hasClassName && !isForwarder) return false
419
+ if (!hasClassName && !hasUseCss && !isForwarder) return false
400
420
  if (!args.filename.includes('/node_modules/')) return true
401
421
  // node_modules in path → could be a workspace symlink; resolve it.
402
422
  try {