expo 58.0.0-preview.6 → 58.0.0-preview.7
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/android/build.gradle +2 -2
- package/bundledNativeModules.json +35 -35
- package/package.json +11 -11
- package/scripts/spm/__tests__/app-target.test.js +370 -0
- package/scripts/spm/__tests__/cli.test.js +80 -0
- package/scripts/spm/__tests__/plugin.test.js +146 -1
- package/scripts/spm/__tests__/script-phases.test.js +69 -0
- package/scripts/spm/__tests__/with-node.test.js +278 -0
- package/scripts/spm/app-target.js +208 -0
- package/scripts/spm/cli.js +20 -1
- package/scripts/spm/plugin.js +54 -17
- package/scripts/spm/script-phases.js +104 -0
- package/template.tgz +0 -0
package/android/build.gradle
CHANGED
|
@@ -10,7 +10,7 @@ buildscript {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
group = 'host.exp.exponent'
|
|
13
|
-
version = '58.0.0-preview.
|
|
13
|
+
version = '58.0.0-preview.7'
|
|
14
14
|
|
|
15
15
|
expoModule {
|
|
16
16
|
// We can't prebuild the module because it depends on the generated files.
|
|
@@ -21,7 +21,7 @@ android {
|
|
|
21
21
|
namespace "expo.core"
|
|
22
22
|
defaultConfig {
|
|
23
23
|
versionCode 1
|
|
24
|
-
versionName "58.0.0-preview.
|
|
24
|
+
versionName "58.0.0-preview.7"
|
|
25
25
|
consumerProguardFiles("proguard-rules.pro")
|
|
26
26
|
}
|
|
27
27
|
testOptions {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"@expo/dom-webview": "~58.0.1",
|
|
3
3
|
"@expo/fingerprint": "~0.21.1",
|
|
4
|
-
"@expo/metro-runtime": "~58.0.
|
|
4
|
+
"@expo/metro-runtime": "~58.0.7",
|
|
5
5
|
"@expo/vector-icons": "^15.0.2",
|
|
6
|
-
"@expo/ui": "~58.0.
|
|
6
|
+
"@expo/ui": "~58.0.7",
|
|
7
7
|
"@react-native-async-storage/async-storage": "2.2.0",
|
|
8
8
|
"@react-native-community/datetimepicker": "9.2.1",
|
|
9
9
|
"@react-native-masked-view/masked-view": "0.3.2",
|
|
@@ -16,87 +16,87 @@
|
|
|
16
16
|
"eslint-config-expo": "~58.0.2",
|
|
17
17
|
"expo-analytics-amplitude": "~11.3.0",
|
|
18
18
|
"expo-app-auth": "~11.1.0",
|
|
19
|
-
"expo-app-intents": "~0.4.
|
|
19
|
+
"expo-app-intents": "~0.4.5",
|
|
20
20
|
"expo-app-loader-provider": "~8.0.0",
|
|
21
|
-
"expo-app-metrics": "~58.0.
|
|
21
|
+
"expo-app-metrics": "~58.0.7",
|
|
22
22
|
"expo-apple-authentication": "~58.0.1",
|
|
23
23
|
"expo-application": "~58.0.1",
|
|
24
|
-
"expo-asset": "~58.0.
|
|
24
|
+
"expo-asset": "~58.0.7",
|
|
25
25
|
"expo-audio": "~58.0.2",
|
|
26
|
-
"expo-auth-session": "~58.0.
|
|
27
|
-
"expo-background-fetch": "~58.0.
|
|
28
|
-
"expo-background-task": "~58.0.
|
|
26
|
+
"expo-auth-session": "~58.0.5",
|
|
27
|
+
"expo-background-fetch": "~58.0.7",
|
|
28
|
+
"expo-background-task": "~58.0.7",
|
|
29
29
|
"expo-battery": "~58.0.1",
|
|
30
30
|
"expo-blur": "~58.0.1",
|
|
31
31
|
"expo-brightness": "~58.0.0",
|
|
32
|
-
"expo-brownfield": "~58.0.
|
|
33
|
-
"expo-build-properties": "~58.0.
|
|
34
|
-
"expo-calendar": "~58.0.
|
|
32
|
+
"expo-brownfield": "~58.0.7",
|
|
33
|
+
"expo-build-properties": "~58.0.7",
|
|
34
|
+
"expo-calendar": "~58.0.3",
|
|
35
35
|
"expo-camera": "~58.0.3",
|
|
36
36
|
"expo-cellular": "~58.0.0",
|
|
37
37
|
"expo-checkbox": "~58.0.1",
|
|
38
38
|
"expo-clipboard": "~58.0.1",
|
|
39
|
-
"expo-constants": "~58.0.
|
|
39
|
+
"expo-constants": "~58.0.7",
|
|
40
40
|
"expo-contacts": "~58.0.2",
|
|
41
41
|
"expo-crypto": "~58.0.2",
|
|
42
|
-
"expo-dev-client": "~58.0.
|
|
42
|
+
"expo-dev-client": "~58.0.7",
|
|
43
43
|
"expo-device": "~58.0.2",
|
|
44
44
|
"expo-document-picker": "~58.0.1",
|
|
45
45
|
"expo-eas-client": "~58.0.0",
|
|
46
|
-
"expo-file-system": "~58.0.
|
|
46
|
+
"expo-file-system": "~58.0.2",
|
|
47
47
|
"expo-font": "~58.0.2",
|
|
48
48
|
"expo-gl": "~58.0.1",
|
|
49
49
|
"expo-glass-effect": "~58.0.2",
|
|
50
50
|
"expo-google-app-auth": "~8.3.0",
|
|
51
51
|
"expo-haptics": "~58.0.1",
|
|
52
|
-
"expo-image": "~58.0.
|
|
52
|
+
"expo-image": "~58.0.6",
|
|
53
53
|
"expo-image-loader": "~58.0.1",
|
|
54
|
-
"expo-image-manipulator": "~58.0.
|
|
55
|
-
"expo-image-picker": "~58.0.
|
|
54
|
+
"expo-image-manipulator": "~58.0.8",
|
|
55
|
+
"expo-image-picker": "~58.0.7",
|
|
56
56
|
"expo-intent-launcher": "~58.0.0",
|
|
57
|
-
"expo-insights": "~58.0.
|
|
57
|
+
"expo-insights": "~58.0.7",
|
|
58
58
|
"expo-keep-awake": "~58.0.1",
|
|
59
59
|
"expo-linear-gradient": "~58.0.1",
|
|
60
|
-
"expo-linking": "~58.0.
|
|
60
|
+
"expo-linking": "~58.0.7",
|
|
61
61
|
"expo-local-authentication": "~58.0.0",
|
|
62
62
|
"expo-localization": "~58.0.1",
|
|
63
|
-
"expo-location": "~58.0.
|
|
63
|
+
"expo-location": "~58.0.7",
|
|
64
64
|
"expo-mail-composer": "~58.0.0",
|
|
65
65
|
"expo-manifests": "~58.0.0",
|
|
66
66
|
"expo-maps": "~58.0.2",
|
|
67
67
|
"expo-mcp": "~0.2.1",
|
|
68
|
-
"expo-media-library": "~58.0.
|
|
68
|
+
"expo-media-library": "~58.0.2",
|
|
69
69
|
"expo-mesh-gradient": "~58.0.1",
|
|
70
|
-
"expo-module-template": "~58.0.
|
|
71
|
-
"expo-modules-core": "~58.0.
|
|
70
|
+
"expo-module-template": "~58.0.4",
|
|
71
|
+
"expo-modules-core": "~58.0.7",
|
|
72
72
|
"expo-navigation-bar": "~58.0.1",
|
|
73
73
|
"expo-network": "~58.0.1",
|
|
74
|
-
"expo-notifications": "~58.0.
|
|
75
|
-
"expo-observe": "~58.0.
|
|
74
|
+
"expo-notifications": "~58.0.7",
|
|
75
|
+
"expo-observe": "~58.0.9",
|
|
76
76
|
"expo-print": "~58.0.2",
|
|
77
77
|
"expo-live-photo": "~58.0.1",
|
|
78
|
-
"expo-router": "~58.0.
|
|
79
|
-
"expo-screen-capture": "~58.0.
|
|
78
|
+
"expo-router": "~58.0.8",
|
|
79
|
+
"expo-screen-capture": "~58.0.3",
|
|
80
80
|
"expo-screen-orientation": "~58.0.0",
|
|
81
81
|
"expo-secure-store": "~58.0.0",
|
|
82
82
|
"expo-sensors": "~58.0.0",
|
|
83
83
|
"expo-server": "~58.0.1",
|
|
84
|
-
"expo-sharing": "~58.0.
|
|
84
|
+
"expo-sharing": "~58.0.10",
|
|
85
85
|
"expo-sms": "~58.0.0",
|
|
86
|
-
"expo-speech": "~58.0.
|
|
86
|
+
"expo-speech": "~58.0.1",
|
|
87
87
|
"expo-splash-screen": "~58.0.1",
|
|
88
|
-
"expo-sqlite": "~58.0.
|
|
88
|
+
"expo-sqlite": "~58.0.6",
|
|
89
89
|
"expo-status-bar": "~58.0.1",
|
|
90
90
|
"expo-store-review": "~58.0.0",
|
|
91
91
|
"expo-symbols": "~58.0.2",
|
|
92
92
|
"expo-system-ui": "~58.0.2",
|
|
93
|
-
"expo-task-manager": "~58.0.
|
|
93
|
+
"expo-task-manager": "~58.0.8",
|
|
94
94
|
"expo-tracking-transparency": "~58.0.0",
|
|
95
|
-
"expo-updates": "~58.0.
|
|
95
|
+
"expo-updates": "~58.0.9",
|
|
96
96
|
"expo-video-thumbnails": "~58.0.0",
|
|
97
97
|
"expo-video": "~58.0.3",
|
|
98
98
|
"expo-web-browser": "~58.0.2",
|
|
99
|
-
"expo-widgets": "~58.0.
|
|
99
|
+
"expo-widgets": "~58.0.7",
|
|
100
100
|
"jest-expo": "~58.0.3",
|
|
101
101
|
"lottie-react-native": "~7.5.0",
|
|
102
102
|
"react": "19.3.0",
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
"react-native-keyboard-controller": "1.22.4",
|
|
108
108
|
"react-native-maps": "1.29.0",
|
|
109
109
|
"react-native-pager-view": "9.0.4",
|
|
110
|
-
"react-native-worklets": "0.
|
|
111
|
-
"react-native-reanimated": "4.
|
|
110
|
+
"react-native-worklets": "0.13.0",
|
|
111
|
+
"react-native-reanimated": "4.7.0",
|
|
112
112
|
"react-native-screens": "~4.28.0",
|
|
113
113
|
"react-native-safe-area-context": "~5.9.1",
|
|
114
114
|
"react-native-svg": "15.15.5",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo",
|
|
3
|
-
"version": "58.0.0-preview.
|
|
3
|
+
"version": "58.0.0-preview.7",
|
|
4
4
|
"description": "The Expo SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"expo"
|
|
@@ -200,36 +200,36 @@
|
|
|
200
200
|
},
|
|
201
201
|
"dependencies": {
|
|
202
202
|
"@babel/runtime": "^7.20.0",
|
|
203
|
-
"@expo/cli": "^58.0.
|
|
203
|
+
"@expo/cli": "^58.0.7",
|
|
204
204
|
"@expo/config": "~58.0.0",
|
|
205
205
|
"@expo/config-plugins": "~58.0.2",
|
|
206
206
|
"@expo/devtools": "~58.0.1",
|
|
207
207
|
"@expo/dom-webview": "~58.0.1",
|
|
208
208
|
"@expo/fingerprint": "^0.21.1",
|
|
209
209
|
"@expo/local-build-cache-provider": "^58.0.0",
|
|
210
|
-
"@expo/log-box": "^58.0.
|
|
210
|
+
"@expo/log-box": "^58.0.5",
|
|
211
211
|
"@expo/log-box-utils": "^58.0.0",
|
|
212
212
|
"@expo/metro": "~58.0.0-rc.0",
|
|
213
213
|
"@expo/metro-config": "~58.0.4",
|
|
214
214
|
"@ungap/structured-clone": "^1.3.0",
|
|
215
215
|
"babel-preset-expo": "~58.0.4",
|
|
216
|
-
"expo-asset": "~58.0.
|
|
217
|
-
"expo-constants": "~58.0.
|
|
218
|
-
"expo-file-system": "~58.0.
|
|
216
|
+
"expo-asset": "~58.0.7",
|
|
217
|
+
"expo-constants": "~58.0.7",
|
|
218
|
+
"expo-file-system": "~58.0.2",
|
|
219
219
|
"expo-font": "~58.0.2",
|
|
220
220
|
"expo-keep-awake": "~58.0.1",
|
|
221
|
-
"expo-modules-autolinking": "~58.0.
|
|
222
|
-
"expo-modules-core": "~58.0.
|
|
221
|
+
"expo-modules-autolinking": "~58.0.4",
|
|
222
|
+
"expo-modules-core": "~58.0.7",
|
|
223
223
|
"pretty-format": "^29.7.0",
|
|
224
224
|
"react-refresh": "^0.14.2",
|
|
225
225
|
"whatwg-url-minimum": "^0.2.0"
|
|
226
226
|
},
|
|
227
227
|
"devDependencies": {
|
|
228
228
|
"@expo/dom-webview": "58.0.1",
|
|
229
|
-
"@expo/metro-runtime": "58.0.
|
|
229
|
+
"@expo/metro-runtime": "58.0.7",
|
|
230
230
|
"@types/node": "^22.14.0",
|
|
231
231
|
"@types/react": "~19.3.0",
|
|
232
|
-
"expo-updates": "58.0.
|
|
232
|
+
"expo-updates": "58.0.9",
|
|
233
233
|
"npm-run-all2": "^8.0.4",
|
|
234
234
|
"react": "19.3.0",
|
|
235
235
|
"react-dom": "19.3.0",
|
|
@@ -269,7 +269,7 @@
|
|
|
269
269
|
"engines": {
|
|
270
270
|
"node": "^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0"
|
|
271
271
|
},
|
|
272
|
-
"gitHead": "
|
|
272
|
+
"gitHead": "ad41d067bd3df6dd12f1788acc6b54a68e7a650d",
|
|
273
273
|
"scripts": {
|
|
274
274
|
"build": "../expo-module-scripts/bin/expo-build src",
|
|
275
275
|
"clean": "rimraf build",
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const { resolveAppTarget } = require('../app-target');
|
|
8
|
+
|
|
9
|
+
// The real project of apps/minimal-swiftpm: the entitlements derivation reads an
|
|
10
|
+
// Xcode project, so mocking one out would only assert our own fixture back.
|
|
11
|
+
const TESTER_PBXPROJ = fs.readFileSync(
|
|
12
|
+
path.join(
|
|
13
|
+
__dirname,
|
|
14
|
+
'../../../../..',
|
|
15
|
+
'apps/minimal-swiftpm/ios/minimalswiftpm.xcodeproj/project.pbxproj'
|
|
16
|
+
),
|
|
17
|
+
'utf8'
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const ENTITLEMENTS_LINE = /^[ \t]*CODE_SIGN_ENTITLEMENTS = .*;\n/gm;
|
|
21
|
+
const DEBUG = 0;
|
|
22
|
+
const RELEASE = 1;
|
|
23
|
+
|
|
24
|
+
/** Rewrite the nth `CODE_SIGN_ENTITLEMENTS` line; the app target declares Debug first. */
|
|
25
|
+
function withEntitlementsSetting(pbxproj, index, replacement) {
|
|
26
|
+
let seen = 0;
|
|
27
|
+
return pbxproj.replace(ENTITLEMENTS_LINE, (line) =>
|
|
28
|
+
seen++ === index ? replacement.replace('$', line.match(/^[ \t]*/)[0]) : line
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function withoutEntitlementsSettings(pbxproj) {
|
|
33
|
+
return pbxproj.replace(ENTITLEMENTS_LINE, '');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Append a unit-test target declaring its own entitlements. The tester project has a
|
|
38
|
+
* single application target, so without a second one no test can tell a lookup by name
|
|
39
|
+
* apart from `findFirstNativeTarget`.
|
|
40
|
+
*/
|
|
41
|
+
function withTestTarget(pbxproj, name = 'minimalswiftpmTests') {
|
|
42
|
+
return pbxproj
|
|
43
|
+
.replace(
|
|
44
|
+
'/* End PBXNativeTarget section */',
|
|
45
|
+
`\t\tAAAA0000000000000000001 /* ${name} */ = {
|
|
46
|
+
\t\t\tisa = PBXNativeTarget;
|
|
47
|
+
\t\t\tbuildConfigurationList = AAAA0000000000000000002 /* Build configuration list for PBXNativeTarget "${name}" */;
|
|
48
|
+
\t\t\tbuildPhases = (
|
|
49
|
+
\t\t\t);
|
|
50
|
+
\t\t\tdependencies = (
|
|
51
|
+
\t\t\t);
|
|
52
|
+
\t\t\tname = ${name};
|
|
53
|
+
\t\t\tproductName = ${name};
|
|
54
|
+
\t\t\tproductType = "com.apple.product-type.bundle.unit-test";
|
|
55
|
+
\t\t};
|
|
56
|
+
/* End PBXNativeTarget section */`
|
|
57
|
+
)
|
|
58
|
+
.replace(
|
|
59
|
+
'/* End XCConfigurationList section */',
|
|
60
|
+
`\t\tAAAA0000000000000000002 /* Build configuration list for PBXNativeTarget "${name}" */ = {
|
|
61
|
+
\t\t\tisa = XCConfigurationList;
|
|
62
|
+
\t\t\tbuildConfigurations = (
|
|
63
|
+
\t\t\t\tAAAA0000000000000000003 /* Debug */,
|
|
64
|
+
\t\t\t\tAAAA0000000000000000004 /* Release */,
|
|
65
|
+
\t\t\t);
|
|
66
|
+
\t\t\tdefaultConfigurationIsVisible = 0;
|
|
67
|
+
\t\t\tdefaultConfigurationName = Release;
|
|
68
|
+
\t\t};
|
|
69
|
+
/* End XCConfigurationList section */`
|
|
70
|
+
)
|
|
71
|
+
.replace(
|
|
72
|
+
'/* End XCBuildConfiguration section */',
|
|
73
|
+
['Debug', 'Release']
|
|
74
|
+
.map(
|
|
75
|
+
(
|
|
76
|
+
configuration,
|
|
77
|
+
index
|
|
78
|
+
) => `\t\tAAAA000000000000000000${index + 3} /* ${configuration} */ = {
|
|
79
|
+
\t\t\tisa = XCBuildConfiguration;
|
|
80
|
+
\t\t\tbuildSettings = {
|
|
81
|
+
\t\t\t\tCODE_SIGN_ENTITLEMENTS = ${name}/${name}.entitlements;
|
|
82
|
+
\t\t\t};
|
|
83
|
+
\t\t\tname = ${configuration};
|
|
84
|
+
\t\t};
|
|
85
|
+
`
|
|
86
|
+
)
|
|
87
|
+
.join('') + '/* End XCBuildConfiguration section */'
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function makeApp({
|
|
92
|
+
pbxproj = TESTER_PBXPROJ,
|
|
93
|
+
entitlements = ['minimalswiftpm/minimalswiftpm.entitlements'],
|
|
94
|
+
marker = { target: 'minimalswiftpm' },
|
|
95
|
+
projectDirName = 'ios',
|
|
96
|
+
} = {}) {
|
|
97
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'expo-spm-app-target-'));
|
|
98
|
+
const appRoot = path.join(tmp, projectDirName);
|
|
99
|
+
const project = path.join(appRoot, 'minimalswiftpm.xcodeproj');
|
|
100
|
+
fs.mkdirSync(project, { recursive: true });
|
|
101
|
+
if (pbxproj != null) fs.writeFileSync(path.join(project, 'project.pbxproj'), pbxproj);
|
|
102
|
+
if (marker != null) {
|
|
103
|
+
fs.writeFileSync(path.join(project, '.spm-injected.json'), JSON.stringify(marker));
|
|
104
|
+
}
|
|
105
|
+
for (const relative of entitlements) {
|
|
106
|
+
const file = path.join(appRoot, relative);
|
|
107
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
108
|
+
fs.writeFileSync(file, '<plist version="1.0"><dict/></plist>');
|
|
109
|
+
}
|
|
110
|
+
return appRoot;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let warn;
|
|
114
|
+
beforeEach(() => {
|
|
115
|
+
warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
116
|
+
});
|
|
117
|
+
afterEach(() => warn.mockRestore());
|
|
118
|
+
|
|
119
|
+
const warnings = () => warn.mock.calls.map(([text]) => text).join('\n');
|
|
120
|
+
|
|
121
|
+
describe('the Xcode target name', () => {
|
|
122
|
+
it('comes from the injection marker of the Xcode project', () => {
|
|
123
|
+
expect(resolveAppTarget(makeApp()).targetName).toBe('minimalswiftpm');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('is omitted when no Xcode project carries a marker', () => {
|
|
127
|
+
expect(resolveAppTarget(makeApp({ marker: null })).targetName).toBeNull();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// RN's injector takes the first marker it finds; guessing the same one is not
|
|
131
|
+
// safe, but a silently dropped --target-name is undiagnosable, so say it.
|
|
132
|
+
it('is omitted with a warning when several Xcode projects carry a marker', () => {
|
|
133
|
+
const appRoot = makeApp();
|
|
134
|
+
const stale = path.join(appRoot, 'stale.xcodeproj');
|
|
135
|
+
fs.mkdirSync(stale, { recursive: true });
|
|
136
|
+
fs.writeFileSync(path.join(stale, 'project.pbxproj'), TESTER_PBXPROJ);
|
|
137
|
+
fs.writeFileSync(path.join(stale, '.spm-injected.json'), JSON.stringify({ target: 'stale' }));
|
|
138
|
+
|
|
139
|
+
expect(resolveAppTarget(appRoot).targetName).toBeNull();
|
|
140
|
+
expect(warnings()).toContain('minimalswiftpm.xcodeproj');
|
|
141
|
+
expect(warnings()).toContain('stale.xcodeproj');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// A leftover directory with no project in it is not a project RN can inject into.
|
|
145
|
+
it('ignores a marker in an .xcodeproj without a project.pbxproj', () => {
|
|
146
|
+
const appRoot = makeApp();
|
|
147
|
+
const stale = path.join(appRoot, 'Stale.xcodeproj');
|
|
148
|
+
fs.mkdirSync(stale);
|
|
149
|
+
fs.writeFileSync(path.join(stale, '.spm-injected.json'), JSON.stringify({ target: 'stale' }));
|
|
150
|
+
|
|
151
|
+
expect(resolveAppTarget(appRoot).targetName).toBe('minimalswiftpm');
|
|
152
|
+
expect(warn).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('is omitted when the marker is unreadable or names no target', () => {
|
|
156
|
+
expect(resolveAppTarget(makeApp({ marker: { rootUuid: 'ABC' } })).targetName).toBeNull();
|
|
157
|
+
|
|
158
|
+
const appRoot = makeApp({ marker: null });
|
|
159
|
+
fs.writeFileSync(
|
|
160
|
+
path.join(appRoot, 'minimalswiftpm.xcodeproj', '.spm-injected.json'),
|
|
161
|
+
'{ not json'
|
|
162
|
+
);
|
|
163
|
+
expect(resolveAppTarget(appRoot).targetName).toBeNull();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('is omitted when the Xcode project directory does not exist', () => {
|
|
167
|
+
expect(
|
|
168
|
+
resolveAppTarget(path.join(os.tmpdir(), 'expo-spm-absent', 'ios')).targetName
|
|
169
|
+
).toBeNull();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('the entitlements file', () => {
|
|
174
|
+
it('is the one the app target declares', () => {
|
|
175
|
+
const appRoot = makeApp();
|
|
176
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
177
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// CocoaPods scans every build configuration of the target. Reading only Release
|
|
182
|
+
// leaves an app that signs entitlements in Debug with empty app groups.
|
|
183
|
+
it('is found when only the Debug configuration declares it', () => {
|
|
184
|
+
const appRoot = makeApp({
|
|
185
|
+
pbxproj: withEntitlementsSetting(TESTER_PBXPROJ, RELEASE, ''),
|
|
186
|
+
});
|
|
187
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
188
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('is resolved for the target the marker names, not the first application target', () => {
|
|
193
|
+
const appRoot = makeApp({
|
|
194
|
+
pbxproj: withTestTarget(TESTER_PBXPROJ),
|
|
195
|
+
marker: { target: 'minimalswiftpmTests' },
|
|
196
|
+
entitlements: [
|
|
197
|
+
'minimalswiftpm/minimalswiftpm.entitlements',
|
|
198
|
+
'minimalswiftpmTests/minimalswiftpmTests.entitlements',
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
202
|
+
path.join(appRoot, 'minimalswiftpmTests/minimalswiftpmTests.entitlements')
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('is omitted when the marker names a target the project does not have', () => {
|
|
207
|
+
const appRoot = makeApp({ marker: { target: 'renamed' } });
|
|
208
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBeNull();
|
|
209
|
+
expect(warnings()).toContain('"renamed"');
|
|
210
|
+
expect(warnings()).toContain('react-native spm update');
|
|
211
|
+
// The project parsed fine; only the target was missing.
|
|
212
|
+
expect(warnings()).not.toContain('could not be read');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// An empty setting resolves to the project directory, which exists — so without a
|
|
216
|
+
// file check it wins and suppresses the file another configuration declares.
|
|
217
|
+
it('ignores a configuration whose entitlements setting is empty', () => {
|
|
218
|
+
const appRoot = makeApp({
|
|
219
|
+
pbxproj: withEntitlementsSetting(TESTER_PBXPROJ, DEBUG, '$CODE_SIGN_ENTITLEMENTS = "";\n'),
|
|
220
|
+
});
|
|
221
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
222
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it.each([['$(SRCROOT)'], ['${SRCROOT}']])(
|
|
227
|
+
'warns and skips a setting built from the %s build variable',
|
|
228
|
+
(variable) => {
|
|
229
|
+
const appRoot = makeApp({
|
|
230
|
+
pbxproj: withEntitlementsSetting(
|
|
231
|
+
TESTER_PBXPROJ,
|
|
232
|
+
DEBUG,
|
|
233
|
+
`$CODE_SIGN_ENTITLEMENTS = "${variable}/minimalswiftpm/minimalswiftpm.entitlements";\n`
|
|
234
|
+
),
|
|
235
|
+
});
|
|
236
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
237
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
238
|
+
);
|
|
239
|
+
expect(warnings()).toContain(variable);
|
|
240
|
+
// Skipped outright, so it is not one of two "different entitlements files".
|
|
241
|
+
expect(warnings()).not.toContain('declare different entitlements files');
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// An app that signs no entitlements at all is the common case, not a problem.
|
|
246
|
+
it('is omitted silently when no build configuration declares one', () => {
|
|
247
|
+
const pbxproj = withoutEntitlementsSettings(TESTER_PBXPROJ);
|
|
248
|
+
expect(resolveAppTarget(makeApp({ pbxproj })).entitlementPath).toBeNull();
|
|
249
|
+
expect(warn).not.toHaveBeenCalled();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('is omitted with a warning when the declared file is not on disk', () => {
|
|
253
|
+
const appRoot = makeApp({ entitlements: [] });
|
|
254
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBeNull();
|
|
255
|
+
expect(warnings()).toContain(path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements'));
|
|
256
|
+
expect(warnings()).toContain('app groups');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('is omitted with a warning when the Xcode project cannot be read', () => {
|
|
260
|
+
const appRoot = makeApp({ pbxproj: 'not a pbxproj' });
|
|
261
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBeNull();
|
|
262
|
+
expect(warnings()).toContain(path.join(appRoot, 'minimalswiftpm.xcodeproj'));
|
|
263
|
+
expect(warnings()).toContain('app groups');
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('is omitted with a warning when there is no Xcode project', () => {
|
|
267
|
+
const appRoot = makeApp({ pbxproj: null });
|
|
268
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBeNull();
|
|
269
|
+
expect(warnings()).toContain(appRoot);
|
|
270
|
+
expect(warnings()).toContain('no .xcodeproj');
|
|
271
|
+
expect(warnings()).toContain('app groups');
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('is read from a marked Xcode project only when it has a project.pbxproj', () => {
|
|
275
|
+
const appRoot = makeApp({ marker: null });
|
|
276
|
+
const stale = path.join(appRoot, 'Stale.xcodeproj');
|
|
277
|
+
fs.mkdirSync(stale);
|
|
278
|
+
fs.writeFileSync(
|
|
279
|
+
path.join(stale, '.spm-injected.json'),
|
|
280
|
+
JSON.stringify({ target: 'minimalswiftpm' })
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
284
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Matches IOSConfig.Paths.getAllPBXProjectPaths, which `expo prebuild` writes through.
|
|
289
|
+
it('is read from the Xcode project config-plugins would pick when none carries a marker', () => {
|
|
290
|
+
const appRoot = makeApp({ pbxproj: null, marker: null });
|
|
291
|
+
fs.mkdirSync(path.join(appRoot, 'Aardvark.xcodeproj'));
|
|
292
|
+
for (const [name, pbxproj] of [
|
|
293
|
+
['alpha', TESTER_PBXPROJ],
|
|
294
|
+
['Zebra', withoutEntitlementsSettings(TESTER_PBXPROJ)],
|
|
295
|
+
]) {
|
|
296
|
+
fs.mkdirSync(path.join(appRoot, `${name}.xcodeproj`));
|
|
297
|
+
fs.writeFileSync(path.join(appRoot, `${name}.xcodeproj`, 'project.pbxproj'), pbxproj);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
301
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('is found when the Xcode project directory is not named ios', () => {
|
|
306
|
+
const appRoot = makeApp({ projectDirName: 'App' });
|
|
307
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
308
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
309
|
+
);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Reading whichever project sorts first would miss the target and blame a rename.
|
|
313
|
+
it('is read from the Xcode project that carries the marker, not the first one', () => {
|
|
314
|
+
const appRoot = makeApp({
|
|
315
|
+
pbxproj: withTestTarget(TESTER_PBXPROJ),
|
|
316
|
+
marker: { target: 'minimalswiftpmTests' },
|
|
317
|
+
entitlements: ['minimalswiftpmTests/minimalswiftpmTests.entitlements'],
|
|
318
|
+
});
|
|
319
|
+
const unmarked = path.join(appRoot, 'Archived.xcodeproj');
|
|
320
|
+
fs.mkdirSync(unmarked);
|
|
321
|
+
fs.writeFileSync(path.join(unmarked, 'project.pbxproj'), TESTER_PBXPROJ);
|
|
322
|
+
|
|
323
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
324
|
+
path.join(appRoot, 'minimalswiftpmTests/minimalswiftpmTests.entitlements')
|
|
325
|
+
);
|
|
326
|
+
expect(warnings()).not.toContain('renamed');
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('is read from the first application target when no Xcode project carries a marker', () => {
|
|
330
|
+
const appRoot = makeApp({ marker: null });
|
|
331
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
332
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
333
|
+
);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Both configurations normally declare the same file; warning about that would
|
|
337
|
+
// put a spurious line in every sync.
|
|
338
|
+
it('says nothing when every build configuration declares the same file', () => {
|
|
339
|
+
expect(resolveAppTarget(makeApp()).entitlementPath).not.toBeNull();
|
|
340
|
+
expect(warn).not.toHaveBeenCalled();
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('warns when the build configurations declare different files', () => {
|
|
344
|
+
const appRoot = makeApp({
|
|
345
|
+
pbxproj: withEntitlementsSetting(
|
|
346
|
+
TESTER_PBXPROJ,
|
|
347
|
+
DEBUG,
|
|
348
|
+
'$CODE_SIGN_ENTITLEMENTS = minimalswiftpm/debug.entitlements;\n'
|
|
349
|
+
),
|
|
350
|
+
});
|
|
351
|
+
expect(resolveAppTarget(appRoot).entitlementPath).toBe(
|
|
352
|
+
path.join(appRoot, 'minimalswiftpm/minimalswiftpm.entitlements')
|
|
353
|
+
);
|
|
354
|
+
expect(warnings()).toContain('debug.entitlements');
|
|
355
|
+
expect(warnings()).toContain('minimalswiftpm.entitlements');
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
describe('the Podfile properties file', () => {
|
|
360
|
+
it('is taken from the Xcode project directory when it exists', () => {
|
|
361
|
+
const appRoot = makeApp();
|
|
362
|
+
const properties = path.join(appRoot, 'Podfile.properties.json');
|
|
363
|
+
fs.writeFileSync(properties, '{}');
|
|
364
|
+
expect(resolveAppTarget(appRoot).podfilePropertiesPath).toBe(properties);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('is omitted when the app has none', () => {
|
|
368
|
+
expect(resolveAppTarget(makeApp()).podfilePropertiesPath).toBeNull();
|
|
369
|
+
});
|
|
370
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
jest.mock('child_process', () => ({ execFileSync: jest.fn(() => '') }));
|
|
8
|
+
|
|
9
|
+
const { execFileSync } = require('child_process');
|
|
10
|
+
const { generateModulesProvider } = require('../cli');
|
|
11
|
+
|
|
12
|
+
function argvFor(options) {
|
|
13
|
+
execFileSync.mockClear();
|
|
14
|
+
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'expo-spm-cli-'));
|
|
15
|
+
generateModulesProvider({
|
|
16
|
+
appRoot: path.join(os.tmpdir(), 'app'),
|
|
17
|
+
outDir,
|
|
18
|
+
moduleNames: ['expo', 'expo-font'],
|
|
19
|
+
...options,
|
|
20
|
+
});
|
|
21
|
+
return execFileSync.mock.calls[0][1];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function valueOf(argv, flag) {
|
|
25
|
+
const index = argv.indexOf(flag);
|
|
26
|
+
return index === -1 ? null : argv[index + 1];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('generateModulesProvider', () => {
|
|
30
|
+
it('always passes the target, app root and platform', () => {
|
|
31
|
+
const argv = argvFor({});
|
|
32
|
+
expect(argv[1]).toBe('generate-modules-provider');
|
|
33
|
+
expect(valueOf(argv, '--target')).toMatch(/ExpoModulesProvider\.swift$/);
|
|
34
|
+
expect(valueOf(argv, '--app-root')).toBe(path.join(os.tmpdir(), 'app'));
|
|
35
|
+
expect(valueOf(argv, '--platform')).toBe('apple');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('passes the app target name, entitlements and Podfile properties when resolved', () => {
|
|
39
|
+
const argv = argvFor({
|
|
40
|
+
targetName: 'minimalswiftpm',
|
|
41
|
+
entitlementPath: '/app/ios/minimalswiftpm/minimalswiftpm.entitlements',
|
|
42
|
+
podfilePropertiesPath: '/app/ios/Podfile.properties.json',
|
|
43
|
+
});
|
|
44
|
+
expect(valueOf(argv, '--target-name')).toBe('minimalswiftpm');
|
|
45
|
+
expect(valueOf(argv, '--entitlement')).toBe(
|
|
46
|
+
'/app/ios/minimalswiftpm/minimalswiftpm.entitlements'
|
|
47
|
+
);
|
|
48
|
+
expect(valueOf(argv, '--podfile-properties-file-path')).toBe(
|
|
49
|
+
'/app/ios/Podfile.properties.json'
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('omits each flag the app does not provide', () => {
|
|
54
|
+
const argv = argvFor({
|
|
55
|
+
targetName: null,
|
|
56
|
+
entitlementPath: null,
|
|
57
|
+
podfilePropertiesPath: null,
|
|
58
|
+
});
|
|
59
|
+
expect(argv).not.toContain('--target-name');
|
|
60
|
+
expect(argv).not.toContain('--entitlement');
|
|
61
|
+
expect(argv).not.toContain('--podfile-properties-file-path');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// `--packages` is variadic, so anything after it is swallowed as a package name.
|
|
65
|
+
it('keeps the variadic package list last', () => {
|
|
66
|
+
const argv = argvFor({ targetName: 'minimalswiftpm' });
|
|
67
|
+
expect(argv.slice(-3)).toEqual(['--packages', 'expo', 'expo-font']);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Commander rejects a variadic option with no value, so an app that excludes
|
|
71
|
+
// every Expo module would fail the sync rather than generate an empty registry.
|
|
72
|
+
it('does not run the generator when no packages are autolinked', () => {
|
|
73
|
+
execFileSync.mockClear();
|
|
74
|
+
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'expo-spm-cli-'));
|
|
75
|
+
const appRoot = path.join(os.tmpdir(), 'app');
|
|
76
|
+
|
|
77
|
+
expect(generateModulesProvider({ appRoot, outDir, moduleNames: [] })).toBeNull();
|
|
78
|
+
expect(execFileSync).not.toHaveBeenCalled();
|
|
79
|
+
});
|
|
80
|
+
});
|