@vxrn/utils 2.10.0 → 2.11.0
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/dist/cjs/desktopReactNativeResolve.cjs +152 -0
- package/dist/cjs/desktopReactNativeResolve.native.cjs +188 -0
- package/dist/cjs/desktopReactNativeResolve.native.js +190 -0
- package/dist/cjs/desktopReactNativeResolve.native.js.map +1 -0
- package/dist/cjs/platformEnv.cjs +27 -2
- package/dist/cjs/platformEnv.native.cjs +27 -2
- package/dist/cjs/platformEnv.native.js +27 -2
- package/dist/cjs/platformEnv.native.js.map +1 -1
- package/dist/esm/desktopReactNativeResolve.mjs +129 -0
- package/dist/esm/desktopReactNativeResolve.mjs.map +1 -0
- package/dist/esm/desktopReactNativeResolve.native.js +163 -0
- package/dist/esm/desktopReactNativeResolve.native.js.map +1 -0
- package/dist/esm/platformEnv.mjs +27 -3
- package/dist/esm/platformEnv.mjs.map +1 -1
- package/dist/esm/platformEnv.native.js +27 -3
- package/dist/esm/platformEnv.native.js.map +1 -1
- package/package.json +10 -5
- package/src/desktopReactNativeResolve.ts +148 -0
- package/src/platformEnv.test.ts +4 -1
- package/src/platformEnv.ts +28 -6
- package/types/desktopReactNativeResolve.d.ts +12 -0
- package/types/desktopReactNativeResolve.d.ts.map +1 -0
- package/types/platformEnv.d.ts +6 -4
- package/types/platformEnv.d.ts.map +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import { dirname, join, relative, resolve } from 'node:path'
|
|
4
|
+
|
|
5
|
+
export type DesktopPlatform = 'macos' | 'linux'
|
|
6
|
+
|
|
7
|
+
const IOS_EXTENSIONS = ['.ios.tsx', '.ios.ts', '.ios.jsx', '.ios.js']
|
|
8
|
+
const OVERRIDE_EXTENSIONS = ['', '.tsx', '.ts', '.jsx', '.js']
|
|
9
|
+
|
|
10
|
+
const reactNativeRootCache = new Map<string, string | null>()
|
|
11
|
+
|
|
12
|
+
export function findOnePackageRoot(appRoot: string): string | null {
|
|
13
|
+
try {
|
|
14
|
+
const req = createRequire(join(appRoot, 'package.json'))
|
|
15
|
+
return dirname(req.resolve('one/package.json'))
|
|
16
|
+
} catch {
|
|
17
|
+
return null
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function requireOnePackageRoot(appRoot: string, platform: DesktopPlatform): string {
|
|
22
|
+
const root = findOnePackageRoot(appRoot)
|
|
23
|
+
if (!root) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`${platform} build cannot resolve one from ${appRoot}. Add "one" as a dependency.`
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
return root
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function reactNativeRootOf(importerFile: string): string | null {
|
|
32
|
+
const start = dirname(importerFile)
|
|
33
|
+
const cached = reactNativeRootCache.get(start)
|
|
34
|
+
if (cached !== undefined) return cached
|
|
35
|
+
let dir = start
|
|
36
|
+
let found: string | null = null
|
|
37
|
+
for (let i = 0; i < 12; i++) {
|
|
38
|
+
const manifest = join(dir, 'package.json')
|
|
39
|
+
if (existsSync(manifest)) {
|
|
40
|
+
try {
|
|
41
|
+
const name = JSON.parse(readFileSync(manifest, 'utf8')).name
|
|
42
|
+
if (name === 'react-native') found = realpathSync(dir)
|
|
43
|
+
} catch {
|
|
44
|
+
found = null
|
|
45
|
+
}
|
|
46
|
+
break
|
|
47
|
+
}
|
|
48
|
+
const parent = dirname(dir)
|
|
49
|
+
if (parent === dir) break
|
|
50
|
+
dir = parent
|
|
51
|
+
}
|
|
52
|
+
reactNativeRootCache.set(start, found)
|
|
53
|
+
return found
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fileIfPresent(path: string): string | null {
|
|
57
|
+
if (!existsSync(path)) return null
|
|
58
|
+
try {
|
|
59
|
+
return statSync(path).isFile() ? path : null
|
|
60
|
+
} catch {
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const PLATFORM_MODULE = 'Libraries/Utilities/Platform'
|
|
66
|
+
const BARE_PLATFORM = /^react-native\/Libraries\/Utilities\/Platform(?:\.(?:js|ts|tsx|jsx))?$/
|
|
67
|
+
|
|
68
|
+
function slashRelative(from: string, to: string): string {
|
|
69
|
+
return relative(from, to).split('\\').join('/')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isPackageEntry(importerFile: string, rnRoot: string): boolean {
|
|
73
|
+
try {
|
|
74
|
+
return slashRelative(rnRoot, realpathSync(importerFile)) === 'index.js'
|
|
75
|
+
} catch {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isPlatformTarget(rnRoot: string, target: string): boolean {
|
|
81
|
+
const rel = slashRelative(rnRoot, target).replace(/\.(tsx|ts|jsx|js)$/, '')
|
|
82
|
+
return rel === PLATFORM_MODULE
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function platformOverrideFile(oneRoot: string, platform: DesktopPlatform): string | null {
|
|
86
|
+
return fileIfPresent(join(oneRoot, platform, 'react-native', PLATFORM_MODULE + '.js'))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The desktop platforms load react-native's iOS files, and only for importers
|
|
91
|
+
* inside that package. React Native's own modules keep Platform.ios.js, so
|
|
92
|
+
* Platform.OS stays ios there. The package entry and every importer outside
|
|
93
|
+
* react-native get the one Platform override, where OS is the desktop
|
|
94
|
+
* platform. Returns an absolute file, or null to keep the normal resolver.
|
|
95
|
+
*/
|
|
96
|
+
export function desktopReactNativeFile(
|
|
97
|
+
importerFile: string | undefined,
|
|
98
|
+
source: string,
|
|
99
|
+
oneRoot: string | null,
|
|
100
|
+
platform: DesktopPlatform
|
|
101
|
+
): string | null {
|
|
102
|
+
if (BARE_PLATFORM.test(source)) {
|
|
103
|
+
if (!oneRoot) return null
|
|
104
|
+
if (importerFile) {
|
|
105
|
+
const rnRoot = reactNativeRootOf(importerFile)
|
|
106
|
+
if (rnRoot && !isPackageEntry(importerFile, rnRoot)) {
|
|
107
|
+
let dir = dirname(importerFile)
|
|
108
|
+
try {
|
|
109
|
+
dir = realpathSync(dir)
|
|
110
|
+
} catch {
|
|
111
|
+
// keep the unresolved directory
|
|
112
|
+
}
|
|
113
|
+
const inside = slashRelative(rnRoot, dir)
|
|
114
|
+
if (!inside.startsWith('..')) return null
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return platformOverrideFile(oneRoot, platform)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!importerFile || !source.startsWith('.')) return null
|
|
121
|
+
const rnRoot = reactNativeRootOf(importerFile)
|
|
122
|
+
if (!rnRoot) return null
|
|
123
|
+
let importerReal: string
|
|
124
|
+
try {
|
|
125
|
+
importerReal = realpathSync(dirname(importerFile))
|
|
126
|
+
} catch {
|
|
127
|
+
return null
|
|
128
|
+
}
|
|
129
|
+
const fromRoot = relative(rnRoot, importerReal)
|
|
130
|
+
if (fromRoot.startsWith('..')) return null
|
|
131
|
+
|
|
132
|
+
const target = resolve(dirname(importerFile), source)
|
|
133
|
+
// the package entry re-exports Platform. its importer is index.js, so the
|
|
134
|
+
// public Platform is the override, while library files keep the ios one.
|
|
135
|
+
const internalPlatform = isPlatformTarget(rnRoot, target) && !isPackageEntry(importerFile, rnRoot)
|
|
136
|
+
if (oneRoot && !internalPlatform) {
|
|
137
|
+
const overrideBase = join(oneRoot, platform, 'react-native', relative(rnRoot, target))
|
|
138
|
+
for (const ext of OVERRIDE_EXTENSIONS) {
|
|
139
|
+
const file = fileIfPresent(overrideBase + ext)
|
|
140
|
+
if (file) return file
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const ext of IOS_EXTENSIONS) {
|
|
144
|
+
const file = fileIfPresent(target + ext)
|
|
145
|
+
if (file) return file
|
|
146
|
+
}
|
|
147
|
+
return null
|
|
148
|
+
}
|
package/src/platformEnv.test.ts
CHANGED
|
@@ -9,12 +9,14 @@ describe('one platform env contract', () => {
|
|
|
9
9
|
it('exposes ONE_PLATFORM for every vite environment', () => {
|
|
10
10
|
expect(getPlatformEnv('ios').ONE_PLATFORM).toBe('ios')
|
|
11
11
|
expect(getPlatformEnv('android').ONE_PLATFORM).toBe('android')
|
|
12
|
+
expect(getPlatformEnv('macos').ONE_PLATFORM).toBe('macos')
|
|
13
|
+
expect(getPlatformEnv('linux').ONE_PLATFORM).toBe('linux')
|
|
12
14
|
expect(getPlatformEnv('client').ONE_PLATFORM).toBe('web')
|
|
13
15
|
expect(getPlatformEnv('ssr').ONE_PLATFORM).toBe('web')
|
|
14
16
|
})
|
|
15
17
|
|
|
16
18
|
it('defines the Expo platform alias only on native', () => {
|
|
17
|
-
for (const environment of ['ios', 'android'] as const) {
|
|
19
|
+
for (const environment of ['ios', 'android', 'macos', 'linux'] as const) {
|
|
18
20
|
expect(getPlatformEnv(environment).EXPO_OS).toBe(
|
|
19
21
|
getPlatformEnv(environment).ONE_PLATFORM
|
|
20
22
|
)
|
|
@@ -38,6 +40,7 @@ describe('one platform env contract', () => {
|
|
|
38
40
|
it('maps metro platforms to vite environments without probing', () => {
|
|
39
41
|
expect(metroPlatformToViteEnvironment('ios')).toBe('ios')
|
|
40
42
|
expect(metroPlatformToViteEnvironment('android')).toBe('android')
|
|
43
|
+
expect(metroPlatformToViteEnvironment('macos')).toBe('macos')
|
|
41
44
|
expect(metroPlatformToViteEnvironment(null)).toBe('client')
|
|
42
45
|
expect(metroPlatformToViteEnvironment(undefined)).toBe('client')
|
|
43
46
|
})
|
package/src/platformEnv.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type
|
|
1
|
+
export type NativePlatform = 'ios' | 'android' | 'macos' | 'linux'
|
|
2
|
+
export type Platform = NativePlatform | 'web'
|
|
3
|
+
export type ViteEnvironment = 'client' | 'ssr' | NativePlatform
|
|
3
4
|
|
|
4
5
|
export type PlatformEnv = {
|
|
5
6
|
VITE_ENVIRONMENT: ViteEnvironment
|
|
6
7
|
VITE_NATIVE: '' | '1'
|
|
7
|
-
ONE_PLATFORM:
|
|
8
|
-
EXPO_OS?:
|
|
8
|
+
ONE_PLATFORM: Platform
|
|
9
|
+
EXPO_OS?: NativePlatform
|
|
9
10
|
TAMAGUI_TARGET: 'web' | 'native'
|
|
10
11
|
TAMAGUI_ENVIRONMENT: ViteEnvironment
|
|
11
12
|
}
|
|
@@ -41,6 +42,28 @@ const platformEnvMap: Record<ViteEnvironment, PlatformEnv> = {
|
|
|
41
42
|
TAMAGUI_TARGET: 'native',
|
|
42
43
|
TAMAGUI_ENVIRONMENT: 'android',
|
|
43
44
|
},
|
|
45
|
+
macos: {
|
|
46
|
+
VITE_ENVIRONMENT: 'macos',
|
|
47
|
+
VITE_NATIVE: '1',
|
|
48
|
+
ONE_PLATFORM: 'macos',
|
|
49
|
+
EXPO_OS: 'macos',
|
|
50
|
+
TAMAGUI_TARGET: 'native',
|
|
51
|
+
TAMAGUI_ENVIRONMENT: 'macos',
|
|
52
|
+
},
|
|
53
|
+
linux: {
|
|
54
|
+
VITE_ENVIRONMENT: 'linux',
|
|
55
|
+
VITE_NATIVE: '1',
|
|
56
|
+
ONE_PLATFORM: 'linux',
|
|
57
|
+
EXPO_OS: 'linux',
|
|
58
|
+
TAMAGUI_TARGET: 'native',
|
|
59
|
+
TAMAGUI_ENVIRONMENT: 'linux',
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const nativePlatforms = new Set<string>(['ios', 'android', 'macos', 'linux'])
|
|
64
|
+
|
|
65
|
+
export function isNativePlatform(platform: string | null | undefined): platform is NativePlatform {
|
|
66
|
+
return platform != null && nativePlatforms.has(platform)
|
|
44
67
|
}
|
|
45
68
|
|
|
46
69
|
export function getPlatformEnv(environment: ViteEnvironment): PlatformEnv {
|
|
@@ -50,8 +73,7 @@ export function getPlatformEnv(environment: ViteEnvironment): PlatformEnv {
|
|
|
50
73
|
export function metroPlatformToViteEnvironment(
|
|
51
74
|
platform: Platform | string | null | undefined
|
|
52
75
|
): ViteEnvironment {
|
|
53
|
-
if (platform
|
|
54
|
-
if (platform === 'android') return 'android'
|
|
76
|
+
if (isNativePlatform(platform)) return platform
|
|
55
77
|
return 'client'
|
|
56
78
|
}
|
|
57
79
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type DesktopPlatform = 'macos' | 'linux';
|
|
2
|
+
export declare function findOnePackageRoot(appRoot: string): string | null;
|
|
3
|
+
export declare function requireOnePackageRoot(appRoot: string, platform: DesktopPlatform): string;
|
|
4
|
+
/**
|
|
5
|
+
* The desktop platforms load react-native's iOS files, and only for importers
|
|
6
|
+
* inside that package. React Native's own modules keep Platform.ios.js, so
|
|
7
|
+
* Platform.OS stays ios there. The package entry and every importer outside
|
|
8
|
+
* react-native get the one Platform override, where OS is the desktop
|
|
9
|
+
* platform. Returns an absolute file, or null to keep the normal resolver.
|
|
10
|
+
*/
|
|
11
|
+
export declare function desktopReactNativeFile(importerFile: string | undefined, source: string, oneRoot: string | null, platform: DesktopPlatform): string | null;
|
|
12
|
+
//# sourceMappingURL=desktopReactNativeResolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktopReactNativeResolve.d.ts","sourceRoot":"","sources":["../src/desktopReactNativeResolve.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,CAAA;AAO/C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOjE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CAQxF;AA4DD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,QAAQ,EAAE,eAAe,GACxB,MAAM,GAAG,IAAI,CA+Cf"}
|
package/types/platformEnv.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type
|
|
1
|
+
export type NativePlatform = 'ios' | 'android' | 'macos' | 'linux';
|
|
2
|
+
export type Platform = NativePlatform | 'web';
|
|
3
|
+
export type ViteEnvironment = 'client' | 'ssr' | NativePlatform;
|
|
3
4
|
export type PlatformEnv = {
|
|
4
5
|
VITE_ENVIRONMENT: ViteEnvironment;
|
|
5
6
|
VITE_NATIVE: '' | '1';
|
|
6
|
-
ONE_PLATFORM:
|
|
7
|
-
EXPO_OS?:
|
|
7
|
+
ONE_PLATFORM: Platform;
|
|
8
|
+
EXPO_OS?: NativePlatform;
|
|
8
9
|
TAMAGUI_TARGET: 'web' | 'native';
|
|
9
10
|
TAMAGUI_ENVIRONMENT: ViteEnvironment;
|
|
10
11
|
};
|
|
12
|
+
export declare function isNativePlatform(platform: string | null | undefined): platform is NativePlatform;
|
|
11
13
|
export declare function getPlatformEnv(environment: ViteEnvironment): PlatformEnv;
|
|
12
14
|
export declare function metroPlatformToViteEnvironment(platform: Platform | string | null | undefined): ViteEnvironment;
|
|
13
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformEnv.d.ts","sourceRoot":"","sources":["../src/platformEnv.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"platformEnv.d.ts","sourceRoot":"","sources":["../src/platformEnv.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;AAClE,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,KAAK,CAAA;AAC7C,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,GAAG,cAAc,CAAA;AAE/D,MAAM,MAAM,WAAW,GAAG;IACxB,gBAAgB,EAAE,eAAe,CAAA;IACjC,WAAW,EAAE,EAAE,GAAG,GAAG,CAAA;IACrB,YAAY,EAAE,QAAQ,CAAA;IACtB,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB,cAAc,EAAE,KAAK,GAAG,QAAQ,CAAA;IAChC,mBAAmB,EAAE,eAAe,CAAA;CACrC,CAAA;AAqDD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,IAAI,cAAc,CAEhG;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,WAAW,CAExE;AAED,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7C,eAAe,CAGjB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,eAAe,GAC3B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxB"}
|