rnwind 0.0.1 → 0.0.3
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.
- package/lib/cjs/core/parser/animation.cjs +427 -0
- package/lib/cjs/core/parser/animation.cjs.map +1 -0
- package/lib/cjs/core/parser/animation.d.ts +126 -0
- package/lib/cjs/core/parser/border-dispatcher.cjs +180 -0
- package/lib/cjs/core/parser/border-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/border-dispatcher.d.ts +15 -0
- package/lib/cjs/core/parser/case-convert.cjs +15 -0
- package/lib/cjs/core/parser/case-convert.cjs.map +1 -0
- package/lib/cjs/core/parser/case-convert.d.ts +6 -0
- package/lib/cjs/core/parser/color-properties-dispatcher.cjs +84 -0
- package/lib/cjs/core/parser/color-properties-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/color-properties-dispatcher.d.ts +19 -0
- package/lib/cjs/core/parser/color.cjs +193 -0
- package/lib/cjs/core/parser/color.cjs.map +1 -0
- package/lib/cjs/core/parser/color.d.ts +12 -0
- package/lib/cjs/core/parser/constants.cjs +21 -0
- package/lib/cjs/core/parser/constants.cjs.map +1 -0
- package/lib/cjs/core/parser/constants.d.ts +8 -0
- package/lib/cjs/core/parser/declaration.cjs +347 -0
- package/lib/cjs/core/parser/declaration.cjs.map +1 -0
- package/lib/cjs/core/parser/declaration.d.ts +15 -0
- package/lib/cjs/core/parser/gradient.cjs +132 -0
- package/lib/cjs/core/parser/gradient.cjs.map +1 -0
- package/lib/cjs/core/parser/gradient.d.ts +59 -0
- package/lib/cjs/core/parser/haptics.cjs +73 -0
- package/lib/cjs/core/parser/haptics.cjs.map +1 -0
- package/lib/cjs/core/parser/haptics.d.ts +47 -0
- package/lib/cjs/core/parser/index.d.ts +8 -0
- package/lib/cjs/core/parser/keyframes.cjs +95 -0
- package/lib/cjs/core/parser/keyframes.cjs.map +1 -0
- package/lib/cjs/core/parser/keyframes.d.ts +26 -0
- package/lib/cjs/core/parser/layout-dispatcher.cjs +120 -0
- package/lib/cjs/core/parser/layout-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/layout-dispatcher.d.ts +14 -0
- package/lib/cjs/core/parser/length.cjs +110 -0
- package/lib/cjs/core/parser/length.cjs.map +1 -0
- package/lib/cjs/core/parser/length.d.ts +51 -0
- package/lib/cjs/core/parser/motion-dispatcher.cjs +77 -0
- package/lib/cjs/core/parser/motion-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/motion-dispatcher.d.ts +11 -0
- package/lib/cjs/core/parser/property.cjs +22 -0
- package/lib/cjs/core/parser/property.cjs.map +1 -0
- package/lib/cjs/core/parser/property.d.ts +8 -0
- package/lib/cjs/core/parser/safe-area.cjs +404 -0
- package/lib/cjs/core/parser/safe-area.cjs.map +1 -0
- package/lib/cjs/core/parser/safe-area.d.ts +39 -0
- package/lib/cjs/core/parser/selector.cjs +22 -0
- package/lib/cjs/core/parser/selector.cjs.map +1 -0
- package/lib/cjs/core/parser/selector.d.ts +11 -0
- package/lib/cjs/core/parser/shorthand.cjs +188 -0
- package/lib/cjs/core/parser/shorthand.cjs.map +1 -0
- package/lib/cjs/core/parser/shorthand.d.ts +67 -0
- package/lib/cjs/core/parser/text-truncate.cjs +78 -0
- package/lib/cjs/core/parser/text-truncate.cjs.map +1 -0
- package/lib/cjs/core/parser/text-truncate.d.ts +44 -0
- package/lib/cjs/core/parser/theme-vars.cjs +467 -0
- package/lib/cjs/core/parser/theme-vars.cjs.map +1 -0
- package/lib/cjs/core/parser/theme-vars.d.ts +82 -0
- package/lib/cjs/core/parser/tokens.cjs +486 -0
- package/lib/cjs/core/parser/tokens.cjs.map +1 -0
- package/lib/cjs/core/parser/tokens.d.ts +45 -0
- package/lib/cjs/core/parser/transform.cjs +198 -0
- package/lib/cjs/core/parser/transform.cjs.map +1 -0
- package/lib/cjs/core/parser/transform.d.ts +36 -0
- package/lib/cjs/core/parser/tw-parser.cjs +1680 -0
- package/lib/cjs/core/parser/tw-parser.cjs.map +1 -0
- package/lib/cjs/core/parser/tw-parser.d.ts +210 -0
- package/lib/cjs/core/parser/types.d.ts +37 -0
- package/lib/cjs/core/parser/typography-dispatcher.cjs +108 -0
- package/lib/cjs/core/parser/typography-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/typography-dispatcher.d.ts +11 -0
- package/lib/cjs/core/parser/typography.cjs +97 -0
- package/lib/cjs/core/parser/typography.cjs.map +1 -0
- package/lib/cjs/core/parser/typography.d.ts +43 -0
- package/lib/cjs/core/style-builder/build-style.cjs +444 -0
- package/lib/cjs/core/style-builder/build-style.cjs.map +1 -0
- package/lib/cjs/core/style-builder/build-style.d.ts +54 -0
- package/lib/cjs/core/style-builder/index.d.ts +3 -0
- package/lib/cjs/core/style-builder/union-builder.cjs +326 -0
- package/lib/cjs/core/style-builder/union-builder.cjs.map +1 -0
- package/lib/cjs/core/style-builder/union-builder.d.ts +128 -0
- package/lib/cjs/core/types.d.ts +14 -0
- package/lib/cjs/metro/dts.cjs +127 -0
- package/lib/cjs/metro/dts.cjs.map +1 -0
- package/lib/cjs/metro/dts.d.ts +16 -0
- package/lib/cjs/metro/index.cjs +19 -0
- package/lib/cjs/metro/index.cjs.map +1 -0
- package/lib/cjs/metro/index.d.ts +9 -0
- package/lib/cjs/metro/resolver.cjs +47 -0
- package/lib/cjs/metro/resolver.cjs.map +1 -0
- package/lib/cjs/metro/resolver.d.ts +22 -0
- package/lib/cjs/metro/state.cjs +301 -0
- package/lib/cjs/metro/state.cjs.map +1 -0
- package/lib/cjs/metro/state.d.ts +88 -0
- package/lib/cjs/metro/transform-ast.cjs +1472 -0
- package/lib/cjs/metro/transform-ast.cjs.map +1 -0
- package/lib/cjs/metro/transform-ast.d.ts +88 -0
- package/lib/cjs/metro/transformer.cjs +372 -0
- package/lib/cjs/metro/transformer.cjs.map +1 -0
- package/lib/cjs/metro/transformer.d.ts +47 -0
- package/lib/cjs/metro/warn-unknown-classes.cjs +86 -0
- package/lib/cjs/metro/warn-unknown-classes.cjs.map +1 -0
- package/lib/cjs/metro/warn-unknown-classes.d.ts +21 -0
- package/lib/cjs/metro/with-config.cjs +196 -0
- package/lib/cjs/metro/with-config.cjs.map +1 -0
- package/lib/cjs/metro/with-config.d.ts +79 -0
- package/lib/cjs/runtime/chain-handlers.cjs +37 -0
- package/lib/cjs/runtime/chain-handlers.cjs.map +1 -0
- package/lib/cjs/runtime/chain-handlers.d.ts +33 -0
- package/lib/cjs/runtime/components/rnwind-provider.cjs +98 -0
- package/lib/cjs/runtime/components/rnwind-provider.cjs.map +1 -0
- package/lib/cjs/runtime/components/rnwind-provider.d.ts +84 -0
- package/lib/cjs/runtime/gradient-types.d.ts +58 -0
- package/lib/cjs/runtime/haptics.cjs +113 -0
- package/lib/cjs/runtime/haptics.cjs.map +1 -0
- package/lib/cjs/runtime/haptics.d.ts +48 -0
- package/lib/cjs/runtime/hooks/use-css.cjs +21 -0
- package/lib/cjs/runtime/hooks/use-css.cjs.map +1 -0
- package/lib/cjs/runtime/hooks/use-css.d.ts +11 -0
- package/lib/cjs/runtime/hooks/use-interact.cjs +46 -0
- package/lib/cjs/runtime/hooks/use-interact.cjs.map +1 -0
- package/lib/cjs/runtime/hooks/use-interact.d.ts +42 -0
- package/lib/cjs/runtime/hooks/use-scheme.cjs +68 -0
- package/lib/cjs/runtime/hooks/use-scheme.cjs.map +1 -0
- package/lib/cjs/runtime/hooks/use-scheme.d.ts +34 -0
- package/lib/cjs/runtime/index.cjs +45 -0
- package/lib/cjs/runtime/index.cjs.map +1 -0
- package/lib/cjs/runtime/index.d.ts +27 -0
- package/lib/cjs/runtime/interactive-box.cjs +35 -0
- package/lib/cjs/runtime/interactive-box.cjs.map +1 -0
- package/lib/cjs/runtime/interactive-box.d.ts +40 -0
- package/lib/cjs/runtime/lookup-css.cjs +542 -0
- package/lib/cjs/runtime/lookup-css.cjs.map +1 -0
- package/lib/cjs/runtime/lookup-css.d.ts +164 -0
- package/lib/cjs/runtime/types.d.ts +29 -0
- package/lib/cjs/testing/index.cjs +367 -0
- package/lib/cjs/testing/index.cjs.map +1 -0
- package/lib/cjs/testing/index.d.ts +145 -0
- package/lib/esm/core/parser/animation.d.ts +126 -0
- package/lib/esm/core/parser/animation.mjs +408 -0
- package/lib/esm/core/parser/animation.mjs.map +1 -0
- package/lib/esm/core/parser/border-dispatcher.d.ts +15 -0
- package/lib/esm/core/parser/border-dispatcher.mjs +178 -0
- package/lib/esm/core/parser/border-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/case-convert.d.ts +6 -0
- package/lib/esm/core/parser/case-convert.mjs +13 -0
- package/lib/esm/core/parser/case-convert.mjs.map +1 -0
- package/lib/esm/core/parser/color-properties-dispatcher.d.ts +19 -0
- package/lib/esm/core/parser/color-properties-dispatcher.mjs +82 -0
- package/lib/esm/core/parser/color-properties-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/color.d.ts +12 -0
- package/lib/esm/core/parser/color.mjs +191 -0
- package/lib/esm/core/parser/color.mjs.map +1 -0
- package/lib/esm/core/parser/constants.d.ts +8 -0
- package/lib/esm/core/parser/constants.mjs +13 -0
- package/lib/esm/core/parser/constants.mjs.map +1 -0
- package/lib/esm/core/parser/declaration.d.ts +15 -0
- package/lib/esm/core/parser/declaration.mjs +345 -0
- package/lib/esm/core/parser/declaration.mjs.map +1 -0
- package/lib/esm/core/parser/gradient.d.ts +59 -0
- package/lib/esm/core/parser/gradient.mjs +130 -0
- package/lib/esm/core/parser/gradient.mjs.map +1 -0
- package/lib/esm/core/parser/haptics.d.ts +47 -0
- package/lib/esm/core/parser/haptics.mjs +71 -0
- package/lib/esm/core/parser/haptics.mjs.map +1 -0
- package/lib/esm/core/parser/index.d.ts +8 -0
- package/lib/esm/core/parser/keyframes.d.ts +26 -0
- package/lib/esm/core/parser/keyframes.mjs +91 -0
- package/lib/esm/core/parser/keyframes.mjs.map +1 -0
- package/lib/esm/core/parser/layout-dispatcher.d.ts +14 -0
- package/lib/esm/core/parser/layout-dispatcher.mjs +118 -0
- package/lib/esm/core/parser/layout-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/length.d.ts +51 -0
- package/lib/esm/core/parser/length.mjs +104 -0
- package/lib/esm/core/parser/length.mjs.map +1 -0
- package/lib/esm/core/parser/motion-dispatcher.d.ts +11 -0
- package/lib/esm/core/parser/motion-dispatcher.mjs +75 -0
- package/lib/esm/core/parser/motion-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/property.d.ts +8 -0
- package/lib/esm/core/parser/property.mjs +20 -0
- package/lib/esm/core/parser/property.mjs.map +1 -0
- package/lib/esm/core/parser/safe-area.d.ts +39 -0
- package/lib/esm/core/parser/safe-area.mjs +402 -0
- package/lib/esm/core/parser/safe-area.mjs.map +1 -0
- package/lib/esm/core/parser/selector.d.ts +11 -0
- package/lib/esm/core/parser/selector.mjs +20 -0
- package/lib/esm/core/parser/selector.mjs.map +1 -0
- package/lib/esm/core/parser/shorthand.d.ts +67 -0
- package/lib/esm/core/parser/shorthand.mjs +180 -0
- package/lib/esm/core/parser/shorthand.mjs.map +1 -0
- package/lib/esm/core/parser/text-truncate.d.ts +44 -0
- package/lib/esm/core/parser/text-truncate.mjs +75 -0
- package/lib/esm/core/parser/text-truncate.mjs.map +1 -0
- package/lib/esm/core/parser/theme-vars.d.ts +82 -0
- package/lib/esm/core/parser/theme-vars.mjs +461 -0
- package/lib/esm/core/parser/theme-vars.mjs.map +1 -0
- package/lib/esm/core/parser/tokens.d.ts +45 -0
- package/lib/esm/core/parser/tokens.mjs +480 -0
- package/lib/esm/core/parser/tokens.mjs.map +1 -0
- package/lib/esm/core/parser/transform.d.ts +36 -0
- package/lib/esm/core/parser/transform.mjs +193 -0
- package/lib/esm/core/parser/transform.mjs.map +1 -0
- package/lib/esm/core/parser/tw-parser.d.ts +210 -0
- package/lib/esm/core/parser/tw-parser.mjs +1678 -0
- package/lib/esm/core/parser/tw-parser.mjs.map +1 -0
- package/lib/esm/core/parser/types.d.ts +37 -0
- package/lib/esm/core/parser/typography-dispatcher.d.ts +11 -0
- package/lib/esm/core/parser/typography-dispatcher.mjs +106 -0
- package/lib/esm/core/parser/typography-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/typography.d.ts +43 -0
- package/lib/esm/core/parser/typography.mjs +91 -0
- package/lib/esm/core/parser/typography.mjs.map +1 -0
- package/lib/esm/core/style-builder/build-style.d.ts +54 -0
- package/lib/esm/core/style-builder/build-style.mjs +442 -0
- package/lib/esm/core/style-builder/build-style.mjs.map +1 -0
- package/lib/esm/core/style-builder/index.d.ts +3 -0
- package/lib/esm/core/style-builder/union-builder.d.ts +128 -0
- package/lib/esm/core/style-builder/union-builder.mjs +324 -0
- package/lib/esm/core/style-builder/union-builder.mjs.map +1 -0
- package/lib/esm/core/types.d.ts +14 -0
- package/lib/esm/metro/dts.d.ts +16 -0
- package/lib/esm/metro/dts.mjs +125 -0
- package/lib/esm/metro/dts.mjs.map +1 -0
- package/lib/esm/metro/index.d.ts +9 -0
- package/lib/esm/metro/index.mjs +6 -0
- package/lib/esm/metro/index.mjs.map +1 -0
- package/lib/esm/metro/resolver.d.ts +22 -0
- package/lib/esm/metro/resolver.mjs +43 -0
- package/lib/esm/metro/resolver.mjs.map +1 -0
- package/lib/esm/metro/state.d.ts +88 -0
- package/lib/esm/metro/state.mjs +291 -0
- package/lib/esm/metro/state.mjs.map +1 -0
- package/lib/esm/metro/transform-ast.d.ts +88 -0
- package/lib/esm/metro/transform-ast.mjs +1451 -0
- package/lib/esm/metro/transform-ast.mjs.map +1 -0
- package/lib/esm/metro/transformer.d.ts +47 -0
- package/lib/esm/metro/transformer.mjs +349 -0
- package/lib/esm/metro/transformer.mjs.map +1 -0
- package/lib/esm/metro/warn-unknown-classes.d.ts +21 -0
- package/lib/esm/metro/warn-unknown-classes.mjs +84 -0
- package/lib/esm/metro/warn-unknown-classes.mjs.map +1 -0
- package/lib/esm/metro/with-config.d.ts +79 -0
- package/lib/esm/metro/with-config.mjs +194 -0
- package/lib/esm/metro/with-config.mjs.map +1 -0
- package/lib/esm/runtime/chain-handlers.d.ts +33 -0
- package/lib/esm/runtime/chain-handlers.mjs +34 -0
- package/lib/esm/runtime/chain-handlers.mjs.map +1 -0
- package/lib/esm/runtime/components/rnwind-provider.d.ts +84 -0
- package/lib/esm/runtime/components/rnwind-provider.mjs +94 -0
- package/lib/esm/runtime/components/rnwind-provider.mjs.map +1 -0
- package/lib/esm/runtime/gradient-types.d.ts +58 -0
- package/lib/esm/runtime/haptics.d.ts +48 -0
- package/lib/esm/runtime/haptics.mjs +110 -0
- package/lib/esm/runtime/haptics.mjs.map +1 -0
- package/lib/esm/runtime/hooks/use-css.d.ts +11 -0
- package/lib/esm/runtime/hooks/use-css.mjs +19 -0
- package/lib/esm/runtime/hooks/use-css.mjs.map +1 -0
- package/lib/esm/runtime/hooks/use-interact.d.ts +42 -0
- package/lib/esm/runtime/hooks/use-interact.mjs +44 -0
- package/lib/esm/runtime/hooks/use-interact.mjs.map +1 -0
- package/lib/esm/runtime/hooks/use-scheme.d.ts +34 -0
- package/lib/esm/runtime/hooks/use-scheme.mjs +63 -0
- package/lib/esm/runtime/hooks/use-scheme.mjs.map +1 -0
- package/lib/esm/runtime/index.d.ts +27 -0
- package/lib/esm/runtime/index.mjs +18 -0
- package/lib/esm/runtime/index.mjs.map +1 -0
- package/lib/esm/runtime/interactive-box.d.ts +40 -0
- package/lib/esm/runtime/interactive-box.mjs +33 -0
- package/lib/esm/runtime/interactive-box.mjs.map +1 -0
- package/lib/esm/runtime/lookup-css.d.ts +164 -0
- package/lib/esm/runtime/lookup-css.mjs +531 -0
- package/lib/esm/runtime/lookup-css.mjs.map +1 -0
- package/lib/esm/runtime/types.d.ts +29 -0
- package/lib/esm/testing/index.d.ts +145 -0
- package/lib/esm/testing/index.mjs +344 -0
- package/lib/esm/testing/index.mjs.map +1 -0
- package/package.json +80 -13
- package/preset.css +1171 -0
- package/src/core/parser/animation.ts +404 -0
- package/src/core/parser/border-dispatcher.ts +176 -0
- package/src/core/parser/case-convert.ts +10 -0
- package/src/core/parser/color-properties-dispatcher.ts +78 -0
- package/src/core/parser/color.ts +191 -0
- package/src/core/parser/constants.ts +11 -0
- package/src/core/parser/declaration.ts +340 -0
- package/src/core/parser/gradient.ts +148 -0
- package/src/core/parser/haptics.ts +88 -0
- package/src/core/parser/index.ts +8 -0
- package/src/core/parser/keyframes.ts +84 -0
- package/src/core/parser/layout-dispatcher.ts +111 -0
- package/src/core/parser/length.ts +114 -0
- package/src/core/parser/motion-dispatcher.ts +89 -0
- package/src/core/parser/property.ts +15 -0
- package/src/core/parser/safe-area.ts +404 -0
- package/src/core/parser/selector.ts +17 -0
- package/src/core/parser/shorthand.ts +182 -0
- package/src/core/parser/text-truncate.ts +79 -0
- package/src/core/parser/theme-vars.ts +465 -0
- package/src/core/parser/tokens.ts +456 -0
- package/src/core/parser/transform.ts +195 -0
- package/src/core/parser/tw-parser.ts +1828 -0
- package/src/core/parser/types.ts +45 -0
- package/src/core/parser/typography-dispatcher.ts +97 -0
- package/src/core/parser/typography.ts +83 -0
- package/src/core/style-builder/build-style.ts +500 -0
- package/src/core/style-builder/index.ts +3 -0
- package/src/core/style-builder/union-builder.ts +328 -0
- package/src/core/types.ts +15 -0
- package/src/metro/dts.ts +128 -0
- package/src/metro/index.ts +9 -0
- package/src/metro/resolver.ts +42 -0
- package/src/metro/state.ts +305 -0
- package/src/metro/transform-ast.ts +1729 -0
- package/src/metro/transformer.ts +372 -0
- package/src/metro/warn-unknown-classes.ts +79 -0
- package/src/metro/with-config.ts +251 -0
- package/src/runtime/chain-handlers.ts +47 -0
- package/src/runtime/components/rnwind-provider.tsx +144 -0
- package/src/runtime/gradient-types.ts +60 -0
- package/src/runtime/haptics.ts +120 -0
- package/src/runtime/hooks/use-css.ts +16 -0
- package/src/runtime/hooks/use-interact.ts +65 -0
- package/src/runtime/hooks/use-scheme.ts +63 -0
- package/src/runtime/index.ts +54 -0
- package/src/runtime/interactive-box.tsx +57 -0
- package/src/runtime/lookup-css.ts +628 -0
- package/src/runtime/types.ts +32 -0
- package/src/testing/index.ts +507 -0
- package/src/types/tailwindcss-node.d.ts +33 -0
- package/src/index.ts +0 -1
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto'
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import type { KeyframeBlock, SchemedStyle, TailwindParser } from '../parser'
|
|
5
|
+
import { buildSchemeSources, type AtomSerializedCache } from './build-style'
|
|
6
|
+
|
|
7
|
+
/** Manifest module basename — the file SchemeProvider imports via the resolver. */
|
|
8
|
+
const MANIFEST_BASENAME = 'schemes.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Atomic file write — stage to a `.tmp.<pid>.<nonce>` sibling, then
|
|
12
|
+
* `rename()` into place. Skips the write entirely when the existing
|
|
13
|
+
* content matches.
|
|
14
|
+
* @param target Final destination path.
|
|
15
|
+
* @param content Bytes to write.
|
|
16
|
+
* @returns Whether the file was actually rewritten.
|
|
17
|
+
*/
|
|
18
|
+
function writeIfChanged(target: string, content: string): boolean {
|
|
19
|
+
if (existsSync(target)) {
|
|
20
|
+
try {
|
|
21
|
+
if (readFileSync(target, 'utf8') === content) return false
|
|
22
|
+
} catch {
|
|
23
|
+
// Unreadable — fall through to rewrite.
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
mkdirSync(path.dirname(target), { recursive: true })
|
|
27
|
+
const temporary = `${target}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`
|
|
28
|
+
try {
|
|
29
|
+
writeFileSync(temporary, content, 'utf8')
|
|
30
|
+
renameSync(temporary, target)
|
|
31
|
+
return true
|
|
32
|
+
} catch (error) {
|
|
33
|
+
rmSync(temporary, { force: true })
|
|
34
|
+
throw error
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* SHA-256 prefix of a string — cheap signature used to detect whether a
|
|
40
|
+
* per-scheme file's source has changed since the last write.
|
|
41
|
+
* @param text Input text.
|
|
42
|
+
* @returns 16-char hex digest.
|
|
43
|
+
*/
|
|
44
|
+
function signatureOf(text: string): string {
|
|
45
|
+
return createHash('sha256').update(text).digest('hex').slice(0, 16)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Compare two `Set<string>`s for equality — same size + every element
|
|
50
|
+
* of `a` present in `b`.
|
|
51
|
+
* @param a First set.
|
|
52
|
+
* @param b Second set.
|
|
53
|
+
* @returns Whether the two sets contain identical values.
|
|
54
|
+
*/
|
|
55
|
+
function setsEqual(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {
|
|
56
|
+
if (a.size !== b.size) return false
|
|
57
|
+
for (const v of a) if (!b.has(v)) return false
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Compute the absolute path of a per-scheme style file under the cache dir.
|
|
63
|
+
* @param cacheDir Absolute cache directory.
|
|
64
|
+
* @param scheme Registry key (`'common'` or a variant name).
|
|
65
|
+
* @returns Absolute path, e.g. `<cacheDir>/dark.style.js`.
|
|
66
|
+
*/
|
|
67
|
+
function schemeFilePath(cacheDir: string, scheme: string): string {
|
|
68
|
+
return path.join(cacheDir, `${scheme}.style.js`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* In-memory atom union + per-scheme style-file emitter.
|
|
73
|
+
*
|
|
74
|
+
* Correctness under multi-worker Metro relies on `ensureProjectScanned`:
|
|
75
|
+
* the FIRST `recordFile` / `writeSchemes` call in every worker drives
|
|
76
|
+
* the oxide Scanner across ALL project sources and hydrates the union
|
|
77
|
+
* with the complete set of candidates. Subsequent per-file
|
|
78
|
+
* `recordFile` calls only layer in atoms the scan already knew about,
|
|
79
|
+
* so writes are idempotent — different workers can't clobber each
|
|
80
|
+
* other's scheme files with partial views.
|
|
81
|
+
*
|
|
82
|
+
* Per-file deltas (atom set unchanged → early return) skip
|
|
83
|
+
* serialization entirely. On a theme-CSS change, `getRnwindState`
|
|
84
|
+
* builds a fresh parser + builder; the next call re-runs
|
|
85
|
+
* `ensureProjectScanned` against the new parser, producing scheme
|
|
86
|
+
* files with the new theme values.
|
|
87
|
+
*/
|
|
88
|
+
class UnionBuilder {
|
|
89
|
+
private readonly cacheDir: string
|
|
90
|
+
private readonly parser: TailwindParser
|
|
91
|
+
private readonly unionAtoms = new Map<string, SchemedStyle>()
|
|
92
|
+
private readonly unionKeyframes = new Map<string, KeyframeBlock>()
|
|
93
|
+
/**
|
|
94
|
+
* Responsive breakpoints captured from the parser. Refreshed on every
|
|
95
|
+
* `recordFile` / `ensureProjectScanned` so user-defined
|
|
96
|
+
* `--breakpoint-*` overrides land in the manifest the next time it's
|
|
97
|
+
* written. Identical for every parser call within one parser instance
|
|
98
|
+
* (theme is fixed for the parser's lifetime), so storing the latest
|
|
99
|
+
* snapshot is sufficient.
|
|
100
|
+
*/
|
|
101
|
+
private breakpoints: ReadonlyMap<string, number> = new Map()
|
|
102
|
+
/** file → set of atom names this file currently contributes. */
|
|
103
|
+
private readonly fileAtomSets = new Map<string, Set<string>>()
|
|
104
|
+
/** atom name → how many files currently contribute it (refcount). */
|
|
105
|
+
private readonly atomRefCount = new Map<string, number>()
|
|
106
|
+
/** scheme → last-written source SHA. Skips re-writing unchanged schemes. */
|
|
107
|
+
private readonly schemeSignatures = new Map<string, string>()
|
|
108
|
+
/**
|
|
109
|
+
* Per-atom serialized-value cache — identity-keyed on each atom's
|
|
110
|
+
* SchemedStyle reference. Carried across `writeSchemes` calls so the
|
|
111
|
+
* typical "user added one className" FR case re-stringifies ONE atom
|
|
112
|
+
* instead of all 175+. Cleared on `ensureProjectScanned` (full
|
|
113
|
+
* rescan replaces every reference) and individually invalidated for
|
|
114
|
+
* any atom `applyDiff` mutates.
|
|
115
|
+
*/
|
|
116
|
+
private readonly serializedCache: AtomSerializedCache = new Map()
|
|
117
|
+
/** Running count of stringify passes (cache misses). Test telemetry. */
|
|
118
|
+
private serializedMissesCount = 0
|
|
119
|
+
/** Set after `ensureProjectScanned` completes. */
|
|
120
|
+
private projectScanned = false
|
|
121
|
+
/** Promise guard so concurrent first-calls await ONE scan. */
|
|
122
|
+
private pendingScan: Promise<void> | null = null
|
|
123
|
+
|
|
124
|
+
constructor(cacheDir: string, parser: TailwindParser) {
|
|
125
|
+
this.cacheDir = cacheDir
|
|
126
|
+
this.parser = parser
|
|
127
|
+
mkdirSync(this.cacheDir, { recursive: true })
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Absolute path of the manifest module (`rnwind/__generated/schemes`). */
|
|
131
|
+
public get manifestPath(): string {
|
|
132
|
+
return path.join(this.cacheDir, MANIFEST_BASENAME)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Snapshot of every source file the builder has recorded atoms for
|
|
137
|
+
* this worker session. Used by `withRnwindConfig`'s CSS watcher to
|
|
138
|
+
* touch `mtime` on each and nudge Metro into re-transforming them
|
|
139
|
+
* with the new theme values.
|
|
140
|
+
* @returns Absolute source paths.
|
|
141
|
+
*/
|
|
142
|
+
public recordedFiles(): readonly string[] {
|
|
143
|
+
return [...this.fileAtomSets.keys()]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Cumulative cache-miss count — exposed for tests to assert cache behaviour. */
|
|
147
|
+
public get serializedMisses(): number {
|
|
148
|
+
return this.serializedMissesCount
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Absolute path of one scheme's style file.
|
|
153
|
+
* @param scheme Registry key.
|
|
154
|
+
* @returns Absolute path.
|
|
155
|
+
*/
|
|
156
|
+
public schemePath(scheme: string): string {
|
|
157
|
+
return schemeFilePath(this.cacheDir, scheme)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* One-shot oxide scan + compile across every source the parser was
|
|
162
|
+
* configured with. Idempotent — safe to call from any entry point.
|
|
163
|
+
* Concurrent callers share the same in-flight promise.
|
|
164
|
+
*/
|
|
165
|
+
public async ensureProjectScanned(): Promise<void> {
|
|
166
|
+
if (this.projectScanned) return
|
|
167
|
+
if (this.pendingScan) return this.pendingScan
|
|
168
|
+
this.pendingScan = (async () => {
|
|
169
|
+
const parsed = await this.parser.parseProject()
|
|
170
|
+
for (const [name, style] of parsed.atoms) this.unionAtoms.set(name, style)
|
|
171
|
+
for (const [name, kf] of parsed.keyframes) this.unionKeyframes.set(name, kf)
|
|
172
|
+
this.breakpoints = parsed.breakpoints
|
|
173
|
+
this.projectScanned = true
|
|
174
|
+
})()
|
|
175
|
+
try {
|
|
176
|
+
await this.pendingScan
|
|
177
|
+
} finally {
|
|
178
|
+
this.pendingScan = null
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Record one source file's resolved atoms + keyframes. Short-circuits
|
|
184
|
+
* when the file's atom name set hasn't changed — the common case on
|
|
185
|
+
* every Fast Refresh save of a file whose className literals are
|
|
186
|
+
* unchanged.
|
|
187
|
+
* @param file Absolute source file path.
|
|
188
|
+
* @param atoms Per-atom resolved schemed styles from this transform.
|
|
189
|
+
* @param keyframes Keyframe blocks referenced by this file's atoms.
|
|
190
|
+
* @returns `{ changed: true }` when the union shifted (new atom name,
|
|
191
|
+
* removed atom name, or new keyframe) — the transformer uses this
|
|
192
|
+
* to skip the serializer + `writeSchemes` when nothing changed.
|
|
193
|
+
*/
|
|
194
|
+
public async recordFile(
|
|
195
|
+
file: string,
|
|
196
|
+
atoms: ReadonlyMap<string, SchemedStyle>,
|
|
197
|
+
keyframes: ReadonlyMap<string, KeyframeBlock>,
|
|
198
|
+
): Promise<{ changed: boolean }> {
|
|
199
|
+
await this.ensureProjectScanned()
|
|
200
|
+
const newAtomNames = new Set(atoms.keys())
|
|
201
|
+
const previous = this.fileAtomSets.get(file)
|
|
202
|
+
if (previous && setsEqual(previous, newAtomNames)) {
|
|
203
|
+
// Atom set unchanged — skip the unionAtoms update entirely. The
|
|
204
|
+
// project scan already populated them, and re-setting a fresh
|
|
205
|
+
// object ref here would invalidate the per-atom serialization
|
|
206
|
+
// cache on every FR save for no gain (values are identical).
|
|
207
|
+
// Theme edits go through `getRnwindState` → new builder → fresh
|
|
208
|
+
// scan, so stale cache is impossible.
|
|
209
|
+
let keyframeAdded = false
|
|
210
|
+
for (const [name, kf] of keyframes) {
|
|
211
|
+
if (!this.unionKeyframes.has(name)) keyframeAdded = true
|
|
212
|
+
this.unionKeyframes.set(name, kf)
|
|
213
|
+
}
|
|
214
|
+
return { changed: keyframeAdded }
|
|
215
|
+
}
|
|
216
|
+
this.applyDiff(file, newAtomNames, atoms, keyframes)
|
|
217
|
+
return { changed: true }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Forget one source file's contribution. Idempotent — repeated calls
|
|
222
|
+
* for a file that's already dropped are no-ops. Does NOT remove the
|
|
223
|
+
* atom from the union when another file (or the project scan) still
|
|
224
|
+
* references it.
|
|
225
|
+
* @param file Absolute source file path.
|
|
226
|
+
*/
|
|
227
|
+
public dropFile(file: string): void {
|
|
228
|
+
const previous = this.fileAtomSets.get(file)
|
|
229
|
+
if (!previous) return
|
|
230
|
+
for (const name of previous) {
|
|
231
|
+
const count = (this.atomRefCount.get(name) ?? 0) - 1
|
|
232
|
+
if (count <= 0) this.atomRefCount.delete(name)
|
|
233
|
+
else this.atomRefCount.set(name, count)
|
|
234
|
+
}
|
|
235
|
+
this.fileAtomSets.delete(file)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Serialize the union into per-scheme files + manifest, writing only
|
|
240
|
+
* files whose source bytes changed. Called after every `recordFile`
|
|
241
|
+
* from the transformer — and once at Metro startup via
|
|
242
|
+
* `ensureFilesExist` to seed disk from the project scan alone.
|
|
243
|
+
* @returns List of scheme keys whose files were rewritten (empty
|
|
244
|
+
* when the union is byte-identical to the last flush).
|
|
245
|
+
*/
|
|
246
|
+
public async writeSchemes(): Promise<{ changedSchemes: readonly string[] }> {
|
|
247
|
+
await this.ensureProjectScanned()
|
|
248
|
+
const sortedAtomNames = [...this.unionAtoms.keys()].toSorted((a, b) => a.localeCompare(b))
|
|
249
|
+
const result = buildSchemeSources(sortedAtomNames, this.unionAtoms, this.unionKeyframes, this.serializedCache, this.breakpoints)
|
|
250
|
+
this.serializedMissesCount += result.serializedMisses
|
|
251
|
+
const { schemeSources, manifestSource } = result
|
|
252
|
+
|
|
253
|
+
const changed: string[] = []
|
|
254
|
+
for (const [scheme, source] of Object.entries(schemeSources)) {
|
|
255
|
+
const signature = signatureOf(source)
|
|
256
|
+
const target = schemeFilePath(this.cacheDir, scheme)
|
|
257
|
+
if (this.schemeSignatures.get(scheme) === signature && existsSync(target)) continue
|
|
258
|
+
if (writeIfChanged(target, source)) changed.push(scheme)
|
|
259
|
+
this.schemeSignatures.set(scheme, signature)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const manifestSignature = signatureOf(manifestSource)
|
|
263
|
+
const manifestTarget = path.join(this.cacheDir, MANIFEST_BASENAME)
|
|
264
|
+
if (this.schemeSignatures.get('__manifest') !== manifestSignature || !existsSync(manifestTarget)) {
|
|
265
|
+
if (writeIfChanged(manifestTarget, manifestSource)) changed.push('__manifest')
|
|
266
|
+
this.schemeSignatures.set('__manifest', manifestSignature)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return { changedSchemes: changed }
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Ensure the manifest + common scheme files exist on disk so Metro's
|
|
274
|
+
* resolver can SHA1 them at boot before the first transform runs.
|
|
275
|
+
*/
|
|
276
|
+
public async ensureFilesExist(): Promise<void> {
|
|
277
|
+
if (existsSync(this.manifestPath) && existsSync(schemeFilePath(this.cacheDir, 'common'))) {
|
|
278
|
+
// Still trigger the scan so the in-memory union is complete; file
|
|
279
|
+
// bytes may already be authoritative from a prior Metro run.
|
|
280
|
+
await this.ensureProjectScanned()
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
await this.writeSchemes()
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Apply one file's atom-name diff to the in-memory refcount + union.
|
|
288
|
+
* @param file Source file path.
|
|
289
|
+
* @param newAtoms New atom-name set for the file.
|
|
290
|
+
* @param resolvedAtoms Fresh parser output — carries the resolved
|
|
291
|
+
* styles for every entry in `newAtoms`.
|
|
292
|
+
* @param newKeyframes Keyframes this file's atoms reference.
|
|
293
|
+
*/
|
|
294
|
+
private applyDiff(
|
|
295
|
+
file: string,
|
|
296
|
+
newAtoms: ReadonlySet<string>,
|
|
297
|
+
resolvedAtoms: ReadonlyMap<string, SchemedStyle>,
|
|
298
|
+
newKeyframes: ReadonlyMap<string, KeyframeBlock>,
|
|
299
|
+
): void {
|
|
300
|
+
const previous = this.fileAtomSets.get(file) ?? new Set<string>()
|
|
301
|
+
for (const name of previous) {
|
|
302
|
+
if (newAtoms.has(name)) continue
|
|
303
|
+
const count = (this.atomRefCount.get(name) ?? 0) - 1
|
|
304
|
+
if (count <= 0) this.atomRefCount.delete(name)
|
|
305
|
+
else this.atomRefCount.set(name, count)
|
|
306
|
+
// Do NOT remove `name` from `unionAtoms` — the project scan still
|
|
307
|
+
// references it (orphaned atoms get reaped on the next Metro
|
|
308
|
+
// cold start when the scanner re-walks disk).
|
|
309
|
+
}
|
|
310
|
+
for (const name of newAtoms) {
|
|
311
|
+
if (!previous.has(name)) this.atomRefCount.set(name, (this.atomRefCount.get(name) ?? 0) + 1)
|
|
312
|
+
// Only install the resolved style when the atom is new to the
|
|
313
|
+
// union. Replacing an existing entry with a fresh parser-
|
|
314
|
+
// produced object would swap the identity guard the per-atom
|
|
315
|
+
// serialization cache uses and force a re-stringify for every
|
|
316
|
+
// atom on every FR save. CSS edits rebuild the whole builder
|
|
317
|
+
// (via `getRnwindState`) so stale values aren't possible.
|
|
318
|
+
if (!this.unionAtoms.has(name)) {
|
|
319
|
+
const style = resolvedAtoms.get(name)
|
|
320
|
+
if (style) this.unionAtoms.set(name, style)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
this.fileAtomSets.set(file, new Set(newAtoms))
|
|
324
|
+
for (const [name, kf] of newKeyframes) this.unionKeyframes.set(name, kf)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export { UnionBuilder }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolved values for every CSS custom property in one theme scheme.
|
|
3
|
+
* Keys are the raw custom-property names (e.g. `--color-primary`) as they
|
|
4
|
+
* appear in the theme CSS. Values are the string / number primitives the
|
|
5
|
+
* parser emits after Tailwind compile + lightningcss walk.
|
|
6
|
+
*/
|
|
7
|
+
export type ThemeTable = Record<string, string | number>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Map from scheme name to its resolved {@link ThemeTable}. The scheme name
|
|
11
|
+
* matches the identifier the user declared in `@variant <name> { ... }` —
|
|
12
|
+
* `'light'`, `'dark'`, `'brand'`, etc. A synthetic `'base'` key carries
|
|
13
|
+
* tokens declared outside any variant block.
|
|
14
|
+
*/
|
|
15
|
+
export type ThemeTables = Record<string, ThemeTable>
|
package/src/metro/dts.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* React Native component-props interfaces rnwind augments. Adding an
|
|
6
|
+
* optional `className?: string` to each lets TypeScript accept
|
|
7
|
+
* `<View className="…" />` without the user touching types by hand.
|
|
8
|
+
* The generic ones are written with a placeholder so the output type
|
|
9
|
+
* stays parameterised.
|
|
10
|
+
*/
|
|
11
|
+
const INTERFACES: ReadonlyArray<string | { name: string; generic: string }> = [
|
|
12
|
+
'ViewProps',
|
|
13
|
+
'TextProps',
|
|
14
|
+
'ImageProps',
|
|
15
|
+
'ImageBackgroundProps',
|
|
16
|
+
'ScrollViewProps',
|
|
17
|
+
'PressableProps',
|
|
18
|
+
'ModalProps',
|
|
19
|
+
'TextInputProps',
|
|
20
|
+
'TouchableOpacityProps',
|
|
21
|
+
'TouchableHighlightProps',
|
|
22
|
+
'TouchableNativeFeedbackProps',
|
|
23
|
+
'TouchableWithoutFeedbackProps',
|
|
24
|
+
'SafeAreaViewProps',
|
|
25
|
+
'KeyboardAvoidingViewProps',
|
|
26
|
+
'RefreshControlProps',
|
|
27
|
+
'StatusBarProps',
|
|
28
|
+
'SwitchProps',
|
|
29
|
+
'ActivityIndicatorProps',
|
|
30
|
+
'SectionListProps',
|
|
31
|
+
{ name: 'FlatListProps', generic: 'ItemT' },
|
|
32
|
+
{ name: 'VirtualizedListProps', generic: 'ItemT' },
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Built-in prefix wired into every install. Restricted to the interfaces
|
|
37
|
+
* that natively expose `contentContainerStyle` so TypeScript doesn't
|
|
38
|
+
* start accepting `<View contentContainerClassName="…" />` — RN would
|
|
39
|
+
* silently ignore it at runtime and a typed lint is more useful than a
|
|
40
|
+
* permissive one. User prefixes don't come with this restriction; rnwind
|
|
41
|
+
* can't know which component props they target.
|
|
42
|
+
*/
|
|
43
|
+
const BUILTIN_PREFIX = 'contentContainer'
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Interfaces that expose `contentContainerStyle` in React Native's own
|
|
47
|
+
* types — the set the built-in prefix's `.d.ts` augmentation targets.
|
|
48
|
+
* Everything else stays `className`-only by default.
|
|
49
|
+
*/
|
|
50
|
+
const CONTENT_CONTAINER_INTERFACES: ReadonlySet<string> = new Set([
|
|
51
|
+
'ScrollViewProps',
|
|
52
|
+
'FlatListProps',
|
|
53
|
+
'SectionListProps',
|
|
54
|
+
'VirtualizedListProps',
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build the body of one interface augmentation: `className?: string`
|
|
59
|
+
* plus `<prefix>ClassName?: string` for every prefix that applies to
|
|
60
|
+
* THIS interface. Emits a single-line body so the file stays easy to
|
|
61
|
+
* scan and diff.
|
|
62
|
+
* @param interfaceName Bare interface name (generic parameters stripped).
|
|
63
|
+
* @param userPrefixes Extra prefixes from the Metro config — applied to
|
|
64
|
+
* every interface the same way `className` is.
|
|
65
|
+
* @returns Space-separated property declarations.
|
|
66
|
+
*/
|
|
67
|
+
function buildInterfaceBody(interfaceName: string, userPrefixes: readonly string[]): string {
|
|
68
|
+
const props = ['className?: string']
|
|
69
|
+
if (CONTENT_CONTAINER_INTERFACES.has(interfaceName)) props.push(`${BUILTIN_PREFIX}ClassName?: string`)
|
|
70
|
+
for (const prefix of userPrefixes) {
|
|
71
|
+
if (prefix === BUILTIN_PREFIX) continue
|
|
72
|
+
props.push(`${prefix}ClassName?: string`)
|
|
73
|
+
}
|
|
74
|
+
return props.join('; ')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Write the rnwind TypeScript declaration file. The generated `.d.ts`
|
|
79
|
+
* declares a `rnwind` module augmentation for `react-native`'s
|
|
80
|
+
* component props — every interface gets an optional `className?:
|
|
81
|
+
* string` plus `<prefix>ClassName?: string` for each active prefix.
|
|
82
|
+
* Runtime-rendered schemes (`@variant` blocks) are reflected in the
|
|
83
|
+
* `Scheme` union so `useScheme()` returns the actual names.
|
|
84
|
+
*
|
|
85
|
+
* Called once at Metro-config time — overwrite-on-rewrite so the file
|
|
86
|
+
* stays in sync with the user's current theme CSS + prefix config.
|
|
87
|
+
* @param targetPath Absolute path to write (typically `rnwind-types.d.ts` at project root).
|
|
88
|
+
* @param schemes Scheme names from the user's `@variant` blocks (empty when none declared).
|
|
89
|
+
* @param classNamePrefixes Extra prefixes from the Metro config — merged
|
|
90
|
+
* on top of the built-in `'contentContainer'`. Defaults to empty.
|
|
91
|
+
*/
|
|
92
|
+
export function writeDtsFile(
|
|
93
|
+
targetPath: string,
|
|
94
|
+
schemes: readonly string[],
|
|
95
|
+
classNamePrefixes: readonly string[] = [],
|
|
96
|
+
): void {
|
|
97
|
+
const lines: string[] = [
|
|
98
|
+
'// Auto-generated by rnwind — do not edit by hand.',
|
|
99
|
+
'// Overwritten on Metro start / theme CSS change.',
|
|
100
|
+
'',
|
|
101
|
+
`declare module 'react-native' {`,
|
|
102
|
+
]
|
|
103
|
+
for (const entry of INTERFACES) {
|
|
104
|
+
const name = typeof entry === 'string' ? entry : entry.name
|
|
105
|
+
const body = buildInterfaceBody(name, classNamePrefixes)
|
|
106
|
+
if (typeof entry === 'string') {
|
|
107
|
+
lines.push(` interface ${entry} { ${body} }`)
|
|
108
|
+
continue
|
|
109
|
+
}
|
|
110
|
+
lines.push(` interface ${entry.name}<${entry.generic}> { ${body} }`)
|
|
111
|
+
}
|
|
112
|
+
lines.push('}', '')
|
|
113
|
+
if (schemes.length > 0) {
|
|
114
|
+
lines.push(`declare module 'rnwind' {`, ` export interface RnwindConfig {`)
|
|
115
|
+
const schemeLiterals = schemes.map((s) => `'${s}'`).join(', ')
|
|
116
|
+
lines.push(` themes: readonly [${schemeLiterals}]`, ` }`, '}', '')
|
|
117
|
+
}
|
|
118
|
+
// The `export {}` is mandatory — without at least one top-level
|
|
119
|
+
// import/export, TypeScript treats this file as a SCRIPT and the
|
|
120
|
+
// `declare module 'react-native'` block above becomes a complete
|
|
121
|
+
// *replacement* declaration (hiding the real RN exports like
|
|
122
|
+
// `Pressable`, `useColorScheme`, etc.). With `export {}` the file
|
|
123
|
+
// becomes a module and the `declare module` blocks are interpreted as
|
|
124
|
+
// *augmentations* — which is what we want.
|
|
125
|
+
lines.push('export {}', '')
|
|
126
|
+
mkdirSync(path.dirname(targetPath), { recursive: true })
|
|
127
|
+
writeFileSync(targetPath, lines.join('\n'), 'utf8')
|
|
128
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { withRnwindConfig } from './with-config'
|
|
2
|
+
export type { RnwindMetroOptions, MetroConfigLike } from './with-config'
|
|
3
|
+
export { createRnwindResolver } from './resolver'
|
|
4
|
+
export type { ResolveRequestFn } from './resolver'
|
|
5
|
+
export { writeDtsFile } from './dts'
|
|
6
|
+
export { transform } from './transformer'
|
|
7
|
+
export type { BabelTransformerArgs, BabelTransformerResult } from './transformer'
|
|
8
|
+
export { getRnwindState, configureRnwindState, resetRnwindState, manifestPathFor } from './state'
|
|
9
|
+
export type { RnwindState } from './state'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { manifestPathFor } from './state'
|
|
2
|
+
|
|
3
|
+
/** Specifier the transformer prepends — resolves to the scheme manifest. */
|
|
4
|
+
const SCHEMES_MODULE = 'rnwind/__generated/schemes'
|
|
5
|
+
|
|
6
|
+
/** Metro `resolveRequest` callable shape. Loose so we don't bind to Metro's internal types. */
|
|
7
|
+
export type ResolveRequestFn = (context: unknown, moduleName: string, platform: string | null) => unknown
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sentinel module specifier the transformer prepends to every rewritten
|
|
11
|
+
* file. The resolver maps it to the user's theme CSS so Metro watches
|
|
12
|
+
* that file as a real node in the dependency graph — when the user
|
|
13
|
+
* edits `global.css`, the CSS file's SHA1 changes, and Metro
|
|
14
|
+
* invalidates every JS file that imports the sentinel. The transformer
|
|
15
|
+
* recognises `.css` filenames and returns an empty `export {}` AST so
|
|
16
|
+
* Metro can still bundle it.
|
|
17
|
+
*/
|
|
18
|
+
export const THEME_SIGNATURE_MODULE = 'rnwind/__generated/theme-signature'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build a Metro `resolveRequest` hook that maps the scheme manifest
|
|
22
|
+
* specifier (and the theme-signature sentinel) to its on-disk path.
|
|
23
|
+
* Delegates every other request to the upstream resolver.
|
|
24
|
+
* @param upstream Previously-registered `resolveRequest` (kept in the chain).
|
|
25
|
+
* @returns Metro-compatible resolver.
|
|
26
|
+
*/
|
|
27
|
+
export function createRnwindResolver(upstream: ResolveRequestFn | null | undefined): ResolveRequestFn {
|
|
28
|
+
return (context, moduleName, platform) => {
|
|
29
|
+
if (moduleName === SCHEMES_MODULE) return { type: 'sourceFile', filePath: manifestPathFor() }
|
|
30
|
+
if (moduleName === THEME_SIGNATURE_MODULE) {
|
|
31
|
+
const cssPath = process.env.RNWIND_CSS_ENTRY_FILE
|
|
32
|
+
if (cssPath) return { type: 'sourceFile', filePath: cssPath }
|
|
33
|
+
}
|
|
34
|
+
if (upstream) return upstream(context, moduleName, platform)
|
|
35
|
+
const { resolveRequest } = context as { resolveRequest?: ResolveRequestFn }
|
|
36
|
+
if (resolveRequest) return resolveRequest(context, moduleName, platform)
|
|
37
|
+
return null as unknown
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Side-effect import specifier(s) the transformer injects on every rewritten file. */
|
|
42
|
+
export const STYLE_SPECIFIERS = [SCHEMES_MODULE] as const
|