@ankhorage/expo-runtime 2.5.1 → 2.7.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/CHANGELOG.md +12 -0
- package/README.md +1 -2
- package/dist/ExpoBarcodeScannerAdapter.d.ts.map +1 -1
- package/dist/ExpoBarcodeScannerAdapter.js +4 -16
- package/dist/ExpoBarcodeScannerAdapter.js.map +1 -1
- package/dist/barcodeScanRuntime.d.ts +4 -1
- package/dist/barcodeScanRuntime.d.ts.map +1 -1
- package/dist/barcodeScanRuntime.js +15 -1
- package/dist/barcodeScanRuntime.js.map +1 -1
- package/dist/expoRuntimePlanningMetadata.d.ts +59 -0
- package/dist/expoRuntimePlanningMetadata.d.ts.map +1 -0
- package/dist/expoRuntimePlanningMetadata.js +133 -0
- package/dist/expoRuntimePlanningMetadata.js.map +1 -0
- package/dist/mediaPicker/documentPicker.d.ts +1 -2
- package/dist/mediaPicker/documentPicker.d.ts.map +1 -1
- package/dist/mediaPicker/documentPicker.js +1 -1
- package/dist/mediaPicker/documentPicker.js.map +1 -1
- package/dist/mediaPicker/photoLibraryPicker.d.ts +1 -2
- package/dist/mediaPicker/photoLibraryPicker.d.ts.map +1 -1
- package/dist/mediaPicker/photoLibraryPicker.js +1 -1
- package/dist/mediaPicker/photoLibraryPicker.js.map +1 -1
- package/dist/mediaPicker/readSelectedBytes.d.ts +1 -4
- package/dist/mediaPicker/readSelectedBytes.d.ts.map +1 -1
- package/dist/mediaPicker/readSelectedBytes.js +7 -1
- package/dist/mediaPicker/readSelectedBytes.js.map +1 -1
- package/dist/planning.d.ts +1 -1
- package/dist/planning.d.ts.map +1 -1
- package/dist/planning.js.map +1 -1
- package/dist/platform.d.ts +83 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +81 -0
- package/dist/platform.js.map +1 -0
- package/dist/resolveExpoRuntimePlan.d.ts +14 -25
- package/dist/resolveExpoRuntimePlan.d.ts.map +1 -1
- package/dist/resolveExpoRuntimePlan.js +154 -186
- package/dist/resolveExpoRuntimePlan.js.map +1 -1
- package/package.json +45 -29
- package/src/ExpoBarcodeScannerAdapter.test.tsx +47 -4
- package/src/ExpoBarcodeScannerAdapter.tsx +10 -19
- package/src/barcodeScanRuntime.ts +27 -2
- package/src/expoRuntimePlanningMetadata.ts +190 -0
- package/src/generatedAppOutput.test.ts +29 -7
- package/src/mediaPicker/documentPicker.ts +1 -6
- package/src/mediaPicker/photoLibraryPicker.ts +1 -6
- package/src/mediaPicker/readSelectedBytes.ts +12 -3
- package/src/oauthBrowserRuntime.test.ts +1 -1
- package/src/planning.ts +2 -0
- package/src/platform.test.ts +34 -0
- package/src/platform.ts +88 -0
- package/src/resolveExpoRuntimePlan.test.ts +154 -101
- package/src/resolveExpoRuntimePlan.ts +226 -246
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AnkhorageCapabilityName,
|
|
3
|
-
AppManifest,
|
|
4
3
|
ScreenCapabilityRequirement,
|
|
5
4
|
ScreenPermissionRequirement,
|
|
6
5
|
} from '@ankhorage/contracts';
|
|
@@ -12,26 +11,39 @@ import {
|
|
|
12
11
|
type PermissionSupport,
|
|
13
12
|
} from '@ankhorage/permissions/expo/manifest';
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
import {
|
|
15
|
+
EXPO_CAPABILITY_RUNTIME_REGISTRY,
|
|
16
|
+
EXPO_RUNTIME_PROVIDER_PACKAGES,
|
|
17
|
+
type ExpoRuntimeAdapterId,
|
|
18
|
+
type ExpoRuntimeCapabilityMetadata,
|
|
19
|
+
type ExpoRuntimeConfigPlugin,
|
|
20
|
+
type ExpoRuntimeDiagnostic,
|
|
21
|
+
type ExpoRuntimeProviderId,
|
|
22
|
+
findCapabilityMetadata,
|
|
23
|
+
findConfigHintMetadata,
|
|
24
|
+
GENERATED_RUNTIME_DEPENDENCY_VERSIONS,
|
|
25
|
+
unknownCapabilityDiagnostic,
|
|
26
|
+
unknownPermissionDiagnostic,
|
|
27
|
+
unsupportedPermissionDiagnostic,
|
|
28
|
+
} from './expoRuntimePlanningMetadata';
|
|
29
|
+
|
|
30
|
+
export type { ExpoRuntimeAdapterId, ExpoRuntimeProviderId };
|
|
31
|
+
|
|
32
|
+
export interface ExpoRuntimePlanningScreen {
|
|
33
|
+
readonly requires?: {
|
|
34
|
+
readonly capabilities?: readonly ScreenCapabilityRequirement[];
|
|
35
|
+
readonly permissions?: readonly ScreenPermissionRequirement[];
|
|
36
|
+
};
|
|
19
37
|
}
|
|
20
38
|
|
|
21
|
-
interface
|
|
22
|
-
readonly
|
|
23
|
-
readonly options?: Readonly<Record<string, boolean | string>>;
|
|
39
|
+
export interface ExpoRuntimePlanningManifest {
|
|
40
|
+
readonly screens: Readonly<Record<string, ExpoRuntimePlanningScreen>>;
|
|
24
41
|
}
|
|
25
42
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
readonly severity: 'error' | 'warning';
|
|
31
|
-
readonly requirementType: 'capability' | 'configHint' | 'package' | 'permission';
|
|
32
|
-
readonly requirement: string;
|
|
33
|
-
readonly message: string;
|
|
34
|
-
readonly support?: PermissionSupport;
|
|
43
|
+
interface ExpoRuntimeDependency {
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly version: string;
|
|
46
|
+
readonly reasons: readonly string[];
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
export interface ExpoRuntimePlan {
|
|
@@ -51,20 +63,6 @@ export interface ExpoRuntimePlan {
|
|
|
51
63
|
readonly diagnostics: readonly ExpoRuntimeDiagnostic[];
|
|
52
64
|
}
|
|
53
65
|
|
|
54
|
-
interface ExpoRuntimeCapabilityMetadata {
|
|
55
|
-
readonly impliedPermissions?: readonly ScreenPermissionRequirement[];
|
|
56
|
-
readonly requiredPackages?: readonly string[];
|
|
57
|
-
readonly providers?: readonly ExpoRuntimeProviderId[];
|
|
58
|
-
readonly runtimeAdapters?: readonly ExpoRuntimeAdapterId[];
|
|
59
|
-
readonly androidPermissions?: readonly string[];
|
|
60
|
-
readonly plugins?: readonly ExpoRuntimeConfigPlugin[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
interface ExpoRuntimeHintMetadata {
|
|
64
|
-
readonly androidPermissions?: readonly string[];
|
|
65
|
-
readonly plugin?: ExpoRuntimeConfigPlugin;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
66
|
interface ResolveExpoRuntimePlanOptions {
|
|
69
67
|
readonly capabilityRegistry?: Readonly<
|
|
70
68
|
Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>
|
|
@@ -73,263 +71,245 @@ interface ResolveExpoRuntimePlanOptions {
|
|
|
73
71
|
readonly permissionSupport?: Readonly<Record<Permission, ExpoPermissionMetadata>>;
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
74
|
+
interface PlanningState {
|
|
75
|
+
readonly permissions: Map<string, ScreenPermissionRequirement>;
|
|
76
|
+
readonly impliedPermissions: Map<string, ScreenPermissionRequirement>;
|
|
77
|
+
readonly capabilities: Map<string, ScreenCapabilityRequirement>;
|
|
78
|
+
readonly diagnostics: ExpoRuntimeDiagnostic[];
|
|
79
|
+
readonly dependencies: Map<string, ExpoRuntimeDependency>;
|
|
80
|
+
readonly pluginOptions: Map<string, Record<string, boolean | string>>;
|
|
81
|
+
readonly configHints: Set<string>;
|
|
82
|
+
readonly androidPermissions: Set<string>;
|
|
83
|
+
readonly providers: Set<ExpoRuntimeProviderId>;
|
|
84
|
+
readonly runtimeAdapters: Set<ExpoRuntimeAdapterId>;
|
|
85
|
+
}
|
|
88
86
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
} as const satisfies Readonly<Record<string, ExpoRuntimeHintMetadata>>;
|
|
87
|
+
interface PlanningContext {
|
|
88
|
+
readonly state: PlanningState;
|
|
89
|
+
readonly capabilityRegistry: Readonly<
|
|
90
|
+
Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>
|
|
91
|
+
>;
|
|
92
|
+
readonly dependencyVersions: Readonly<Record<string, string>>;
|
|
93
|
+
readonly permissionSupport: Readonly<Record<Permission, ExpoPermissionMetadata>>;
|
|
94
|
+
}
|
|
100
95
|
|
|
101
|
-
const
|
|
102
|
-
barcodeScanner: {
|
|
103
|
-
impliedPermissions: [{ permission: 'camera' }],
|
|
104
|
-
requiredPackages: ['expo-camera'],
|
|
105
|
-
providers: ['permissions'],
|
|
106
|
-
runtimeAdapters: ['ExpoBarcodeScannerAdapter'],
|
|
107
|
-
androidPermissions: [CAMERA_ANDROID_PERMISSION],
|
|
108
|
-
plugins: [
|
|
109
|
-
{
|
|
110
|
-
name: 'expo-camera',
|
|
111
|
-
options: {
|
|
112
|
-
cameraPermission: 'Allow camera access to scan barcodes.',
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
},
|
|
117
|
-
} as const satisfies Readonly<
|
|
118
|
-
Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>
|
|
119
|
-
>;
|
|
96
|
+
const EXPO_RUNTIME_PACKAGE_NAME = '@ankhorage/expo-runtime';
|
|
120
97
|
|
|
121
98
|
export function resolveExpoRuntimePlan(
|
|
122
|
-
manifest:
|
|
99
|
+
manifest: ExpoRuntimePlanningManifest,
|
|
123
100
|
options: ResolveExpoRuntimePlanOptions = {},
|
|
124
101
|
): ExpoRuntimePlan {
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const capabilityRegistry: Readonly<
|
|
139
|
-
Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>
|
|
140
|
-
> = options.capabilityRegistry ?? EXPO_CAPABILITY_RUNTIME_REGISTRY;
|
|
141
|
-
|
|
142
|
-
for (const capabilityRequirement of capabilitiesByName.values()) {
|
|
143
|
-
capabilityRegistry[capabilityRequirement.capability]?.impliedPermissions?.forEach(
|
|
144
|
-
(permissionRequirement: ScreenPermissionRequirement) => {
|
|
145
|
-
if (!permissionsByName.has(permissionRequirement.permission)) {
|
|
146
|
-
permissionsByName.set(permissionRequirement.permission, permissionRequirement);
|
|
147
|
-
impliedPermissionsByName.set(permissionRequirement.permission, permissionRequirement);
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
);
|
|
102
|
+
const state = createPlanningState(manifest);
|
|
103
|
+
const context: PlanningContext = {
|
|
104
|
+
state,
|
|
105
|
+
capabilityRegistry: options.capabilityRegistry ?? EXPO_CAPABILITY_RUNTIME_REGISTRY,
|
|
106
|
+
dependencyVersions: options.dependencyVersions ?? GENERATED_RUNTIME_DEPENDENCY_VERSIONS,
|
|
107
|
+
permissionSupport: options.permissionSupport ?? EXPO_PERMISSION_SUPPORT,
|
|
108
|
+
};
|
|
109
|
+
addImpliedPermissions(context);
|
|
110
|
+
planPermissions(context);
|
|
111
|
+
planCapabilities(context);
|
|
112
|
+
if (state.providers.size > 0 || state.runtimeAdapters.size > 0) {
|
|
113
|
+
addDependency(context, EXPO_RUNTIME_PACKAGE_NAME, 'runtime:expo');
|
|
151
114
|
}
|
|
115
|
+
return buildPlan(state);
|
|
116
|
+
}
|
|
152
117
|
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const runtimeAdapters = new Set<ExpoRuntimeAdapterId>();
|
|
160
|
-
const dependencyVersions: Readonly<Record<string, string>> =
|
|
161
|
-
options.dependencyVersions ?? GENERATED_EXPO_DEPENDENCY_VERSIONS;
|
|
162
|
-
const permissionSupport = options.permissionSupport ?? EXPO_PERMISSION_SUPPORT;
|
|
163
|
-
const configHintRegistry: Readonly<Record<string, ExpoRuntimeHintMetadata>> =
|
|
164
|
-
EXPO_RUNTIME_CONFIG_HINTS;
|
|
165
|
-
|
|
166
|
-
const addDependency = (name: string, reason: string) => {
|
|
167
|
-
const version = dependencyVersions[name];
|
|
168
|
-
if (version === undefined) {
|
|
169
|
-
diagnostics.push({
|
|
170
|
-
severity: 'warning',
|
|
171
|
-
requirementType: 'package',
|
|
172
|
-
requirement: name,
|
|
173
|
-
message: `No generated-app dependency version is registered for '${name}'.`,
|
|
174
|
-
});
|
|
175
|
-
return;
|
|
118
|
+
function createPlanningState(manifest: ExpoRuntimePlanningManifest): PlanningState {
|
|
119
|
+
const permissions = new Map<string, ScreenPermissionRequirement>();
|
|
120
|
+
const capabilities = new Map<string, ScreenCapabilityRequirement>();
|
|
121
|
+
for (const screen of Object.values(manifest.screens)) {
|
|
122
|
+
for (const requirement of screen.requires?.permissions ?? []) {
|
|
123
|
+
permissions.set(requirement.permission, requirement);
|
|
176
124
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (existing) {
|
|
180
|
-
dependencies.set(name, {
|
|
181
|
-
...existing,
|
|
182
|
-
reasons: Array.from(new Set([...existing.reasons, reason])),
|
|
183
|
-
});
|
|
184
|
-
return;
|
|
125
|
+
for (const requirement of screen.requires?.capabilities ?? []) {
|
|
126
|
+
capabilities.set(requirement.capability, requirement);
|
|
185
127
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const addPlugin = (plugin: ExpoRuntimeConfigPlugin) => {
|
|
200
|
-
const existingOptions = pluginOptions.get(plugin.name) ?? {};
|
|
201
|
-
pluginOptions.set(plugin.name, {
|
|
202
|
-
...existingOptions,
|
|
203
|
-
...(plugin.options ?? {}),
|
|
204
|
-
});
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
permissions,
|
|
131
|
+
capabilities,
|
|
132
|
+
impliedPermissions: new Map(),
|
|
133
|
+
diagnostics: [],
|
|
134
|
+
dependencies: new Map(),
|
|
135
|
+
pluginOptions: new Map(),
|
|
136
|
+
configHints: new Set(),
|
|
137
|
+
androidPermissions: new Set(),
|
|
138
|
+
providers: new Set(),
|
|
139
|
+
runtimeAdapters: new Set(),
|
|
205
140
|
};
|
|
141
|
+
}
|
|
206
142
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const supportMetadata = permissionSupport[permissionRequirement.permission];
|
|
219
|
-
if (
|
|
220
|
-
supportMetadata.support === 'unsupported' ||
|
|
221
|
-
supportMetadata.support === 'notImplemented' ||
|
|
222
|
-
supportMetadata.support === 'limited'
|
|
223
|
-
) {
|
|
224
|
-
diagnostics.push({
|
|
225
|
-
severity: supportMetadata.support === 'limited' ? 'warning' : 'error',
|
|
226
|
-
requirementType: 'permission',
|
|
227
|
-
requirement: permissionRequirement.permission,
|
|
228
|
-
message: `Expo runtime support for '${permissionRequirement.permission}' is '${supportMetadata.support}'.`,
|
|
229
|
-
support: supportMetadata.support,
|
|
230
|
-
});
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (supportMetadata.support === 'notRequired') {
|
|
235
|
-
continue;
|
|
143
|
+
function addImpliedPermissions(context: PlanningContext): void {
|
|
144
|
+
const { state } = context;
|
|
145
|
+
for (const capability of state.capabilities.values()) {
|
|
146
|
+
const metadata = findCapabilityMetadata(context.capabilityRegistry, capability);
|
|
147
|
+
for (const permission of metadata?.impliedPermissions ?? []) {
|
|
148
|
+
if (!state.permissions.has(permission.permission)) {
|
|
149
|
+
state.permissions.set(permission.permission, permission);
|
|
150
|
+
state.impliedPermissions.set(permission.permission, permission);
|
|
151
|
+
}
|
|
236
152
|
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
237
155
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
supportMetadata.configHints.forEach((configHint) => {
|
|
244
|
-
configHints.add(configHint);
|
|
245
|
-
const configHintMetadata = configHintRegistry[configHint];
|
|
246
|
-
if (!configHintMetadata) {
|
|
247
|
-
diagnostics.push({
|
|
248
|
-
severity: 'warning',
|
|
249
|
-
requirementType: 'configHint',
|
|
250
|
-
requirement: configHint,
|
|
251
|
-
message: `Config hint '${configHint}' is not translated into generated Expo config yet.`,
|
|
252
|
-
});
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
156
|
+
function planPermissions(context: PlanningContext): void {
|
|
157
|
+
for (const requirement of context.state.permissions.values()) {
|
|
158
|
+
planPermission(context, requirement);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
255
161
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
162
|
+
function planPermission(context: PlanningContext, requirement: ScreenPermissionRequirement): void {
|
|
163
|
+
if (!isPermission(requirement.permission)) {
|
|
164
|
+
context.state.diagnostics.push(unknownPermissionDiagnostic(requirement.permission));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const metadata = findPermissionSupport(context.permissionSupport, requirement.permission);
|
|
168
|
+
if (isUnsupported(metadata.support)) {
|
|
169
|
+
context.state.diagnostics.push(
|
|
170
|
+
unsupportedPermissionDiagnostic(requirement.permission, metadata.support),
|
|
171
|
+
);
|
|
172
|
+
return;
|
|
263
173
|
}
|
|
174
|
+
if (metadata.support === 'notRequired') {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const reason = `permission:${requirement.permission}`;
|
|
178
|
+
addProvider(context, 'permissions', reason);
|
|
179
|
+
metadata.requiredPackages.forEach((name) => addDependency(context, name, reason));
|
|
180
|
+
metadata.configHints.forEach((hint) => applyConfigHint(context.state, hint));
|
|
181
|
+
}
|
|
264
182
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
requirementType: 'capability',
|
|
271
|
-
requirement: capabilityRequirement.capability,
|
|
272
|
-
message: `No Expo runtime metadata is registered for capability '${capabilityRequirement.capability}'.`,
|
|
273
|
-
});
|
|
183
|
+
function planCapabilities(context: PlanningContext): void {
|
|
184
|
+
for (const requirement of context.state.capabilities.values()) {
|
|
185
|
+
const metadata = findCapabilityMetadata(context.capabilityRegistry, requirement);
|
|
186
|
+
if (metadata === undefined) {
|
|
187
|
+
context.state.diagnostics.push(unknownCapabilityDiagnostic(requirement.capability));
|
|
274
188
|
continue;
|
|
275
189
|
}
|
|
190
|
+
const reason = `capability:${requirement.capability}`;
|
|
191
|
+
metadata.requiredPackages?.forEach((name) => addDependency(context, name, reason));
|
|
192
|
+
metadata.providers?.forEach((provider) => addProvider(context, provider, reason));
|
|
193
|
+
metadata.runtimeAdapters?.forEach((adapter) => context.state.runtimeAdapters.add(adapter));
|
|
194
|
+
metadata.androidPermissions?.forEach((permission) =>
|
|
195
|
+
context.state.androidPermissions.add(permission),
|
|
196
|
+
);
|
|
197
|
+
metadata.plugins?.forEach((plugin) => addPlugin(context.state, plugin));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
276
200
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
201
|
+
function applyConfigHint(state: PlanningState, configHint: string): void {
|
|
202
|
+
state.configHints.add(configHint);
|
|
203
|
+
const metadata = findConfigHintMetadata(configHint);
|
|
204
|
+
if (metadata === undefined) {
|
|
205
|
+
state.diagnostics.push({
|
|
206
|
+
severity: 'warning',
|
|
207
|
+
requirementType: 'configHint',
|
|
208
|
+
requirement: configHint,
|
|
209
|
+
message: `Config hint '${configHint}' is not translated into generated Expo config yet.`,
|
|
282
210
|
});
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
metadata.androidPermissions?.forEach((permission) => state.androidPermissions.add(permission));
|
|
214
|
+
if (metadata.plugin !== undefined) {
|
|
215
|
+
addPlugin(state, metadata.plugin);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function addDependency(context: PlanningContext, name: string, reason: string): void {
|
|
220
|
+
const version = findDependencyVersion(context.dependencyVersions, name);
|
|
221
|
+
if (version === undefined) {
|
|
222
|
+
context.state.diagnostics.push({
|
|
223
|
+
severity: 'warning',
|
|
224
|
+
requirementType: 'package',
|
|
225
|
+
requirement: name,
|
|
226
|
+
message: `No generated-app dependency version is registered for '${name}'.`,
|
|
288
227
|
});
|
|
289
|
-
|
|
228
|
+
return;
|
|
290
229
|
}
|
|
230
|
+
const existing = context.state.dependencies.get(name);
|
|
231
|
+
context.state.dependencies.set(name, {
|
|
232
|
+
name,
|
|
233
|
+
version,
|
|
234
|
+
reasons: existing === undefined ? [reason] : Array.from(new Set([...existing.reasons, reason])),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
291
237
|
|
|
292
|
-
|
|
293
|
-
|
|
238
|
+
function addProvider(
|
|
239
|
+
context: PlanningContext,
|
|
240
|
+
provider: ExpoRuntimeProviderId,
|
|
241
|
+
reason: string,
|
|
242
|
+
): void {
|
|
243
|
+
context.state.providers.add(provider);
|
|
244
|
+
const packageName = Object.entries(EXPO_RUNTIME_PROVIDER_PACKAGES).find(
|
|
245
|
+
([name]) => name === String(provider),
|
|
246
|
+
)?.[1];
|
|
247
|
+
if (packageName === undefined) {
|
|
248
|
+
throw new Error(`Runtime package metadata is missing for provider '${provider}'.`);
|
|
294
249
|
}
|
|
250
|
+
addDependency(context, packageName, reason);
|
|
251
|
+
}
|
|
295
252
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}))
|
|
301
|
-
.sort((left, right) => left.name.localeCompare(right.name));
|
|
253
|
+
function addPlugin(state: PlanningState, plugin: ExpoRuntimeConfigPlugin): void {
|
|
254
|
+
const existingOptions = state.pluginOptions.get(plugin.name) ?? {};
|
|
255
|
+
state.pluginOptions.set(plugin.name, { ...existingOptions, ...(plugin.options ?? {}) });
|
|
256
|
+
}
|
|
302
257
|
|
|
258
|
+
function buildPlan(state: PlanningState): ExpoRuntimePlan {
|
|
259
|
+
const plugins = Array.from(state.pluginOptions, ([name, options]) => ({
|
|
260
|
+
name,
|
|
261
|
+
options: Object.keys(options).length > 0 ? options : undefined,
|
|
262
|
+
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
303
263
|
return {
|
|
304
|
-
permissions: Array.from(
|
|
305
|
-
capabilities: Array.from(
|
|
306
|
-
impliedPermissions: Array.from(
|
|
307
|
-
|
|
308
|
-
),
|
|
309
|
-
dependencies: Array.from(dependencies.values()).sort((left, right) =>
|
|
264
|
+
permissions: Array.from(state.permissions.values()).sort(comparePermissions),
|
|
265
|
+
capabilities: Array.from(state.capabilities.values()).sort(compareCapabilities),
|
|
266
|
+
impliedPermissions: Array.from(state.impliedPermissions.values()).sort(comparePermissions),
|
|
267
|
+
dependencies: Array.from(state.dependencies.values()).sort((left, right) =>
|
|
310
268
|
left.name.localeCompare(right.name),
|
|
311
269
|
),
|
|
312
270
|
nativeConfig: {
|
|
313
|
-
androidPermissions: Array.from(androidPermissions).sort(),
|
|
314
|
-
configHints: Array.from(configHints).sort(),
|
|
271
|
+
androidPermissions: Array.from(state.androidPermissions).sort(),
|
|
272
|
+
configHints: Array.from(state.configHints).sort(),
|
|
315
273
|
plugins,
|
|
316
274
|
},
|
|
317
|
-
providers: Array.from(providers).sort(),
|
|
318
|
-
runtimeAdapters: Array.from(runtimeAdapters).sort(),
|
|
319
|
-
usesExpoRuntimeRegistry: runtimeAdapters.size > 0,
|
|
320
|
-
needsPermissionsProvider: providers.has('permissions'),
|
|
321
|
-
diagnostics,
|
|
275
|
+
providers: Array.from(state.providers).sort(),
|
|
276
|
+
runtimeAdapters: Array.from(state.runtimeAdapters).sort(),
|
|
277
|
+
usesExpoRuntimeRegistry: state.runtimeAdapters.size > 0,
|
|
278
|
+
needsPermissionsProvider: state.providers.has('permissions'),
|
|
279
|
+
diagnostics: state.diagnostics,
|
|
322
280
|
};
|
|
323
281
|
}
|
|
324
282
|
|
|
325
|
-
function
|
|
283
|
+
function findPermissionSupport(
|
|
284
|
+
registry: Readonly<Record<Permission, ExpoPermissionMetadata>>,
|
|
285
|
+
permission: Permission,
|
|
286
|
+
): ExpoPermissionMetadata {
|
|
287
|
+
const metadata = Object.entries(registry).find(([name]) => name === String(permission))?.[1];
|
|
288
|
+
if (metadata === undefined) {
|
|
289
|
+
throw new Error(`Permission metadata is missing for '${permission}'.`);
|
|
290
|
+
}
|
|
291
|
+
return metadata;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function findDependencyVersion(
|
|
295
|
+
versions: Readonly<Record<string, string>>,
|
|
296
|
+
name: string,
|
|
297
|
+
): string | undefined {
|
|
298
|
+
return Object.entries(versions).find(([candidate]) => candidate === name)?.[1];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function isUnsupported(support: PermissionSupport): boolean {
|
|
302
|
+
return support === 'unsupported' || support === 'notImplemented' || support === 'limited';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function compareCapabilities(
|
|
326
306
|
left: ScreenCapabilityRequirement,
|
|
327
307
|
right: ScreenCapabilityRequirement,
|
|
328
308
|
): number {
|
|
329
309
|
return left.capability.localeCompare(right.capability);
|
|
330
310
|
}
|
|
331
311
|
|
|
332
|
-
function
|
|
312
|
+
function comparePermissions(
|
|
333
313
|
left: ScreenPermissionRequirement,
|
|
334
314
|
right: ScreenPermissionRequirement,
|
|
335
315
|
): number {
|