@expo/fingerprint 0.0.10 → 0.2.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 +35 -0
- package/build/Fingerprint.d.ts +4 -0
- package/build/Fingerprint.js +12 -6
- package/build/Fingerprint.js.map +1 -1
- package/build/Fingerprint.types.d.ts +12 -1
- package/build/Fingerprint.types.js.map +1 -1
- package/build/Options.d.ts +3 -1
- package/build/Options.js +39 -9
- package/build/Options.js.map +1 -1
- package/build/hash/Hash.d.ts +6 -1
- package/build/hash/Hash.js +28 -13
- package/build/hash/Hash.js.map +1 -1
- package/build/sourcer/Bare.js +21 -23
- package/build/sourcer/Bare.js.map +1 -1
- package/build/sourcer/Expo.js +14 -11
- package/build/sourcer/Expo.js.map +1 -1
- package/build/sourcer/Utils.d.ts +4 -0
- package/build/sourcer/Utils.js +38 -1
- package/build/sourcer/Utils.js.map +1 -1
- package/e2e/__tests__/__snapshots__/managed-test.ts.snap +5 -12
- package/e2e/__tests__/managed-test.ts +9 -15
- package/package.json +2 -2
- package/src/Fingerprint.ts +14 -5
- package/src/Fingerprint.types.ts +13 -1
- package/src/Options.ts +45 -7
- package/src/__tests__/Fingerprint-test.ts +43 -17
- package/src/hash/Hash.ts +38 -14
- package/src/hash/__tests__/Hash-test.ts +98 -16
- package/src/sourcer/Bare.ts +24 -24
- package/src/sourcer/Expo.ts +17 -18
- package/src/sourcer/Utils.ts +39 -0
- package/src/sourcer/__tests__/Bare-test.ts +34 -5
- package/src/sourcer/__tests__/Expo-test.ts +75 -20
- package/src/sourcer/__tests__/PatchPackage-test.ts +3 -3
- package/src/sourcer/__tests__/Sourcer-test.ts +2 -2
- package/src/sourcer/__tests__/Utils-test.ts +41 -0
- package/src/sourcer/__tests__/__snapshots__/Bare-test.ts.snap +3 -11
- package/src/sourcer/__tests__/fixtures/RncliAutoLinking.json +9 -9
package/src/sourcer/Bare.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import spawnAsync from '@expo/spawn-async';
|
|
2
|
+
import assert from 'assert';
|
|
2
3
|
import chalk from 'chalk';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import resolveFrom from 'resolve-from';
|
|
5
6
|
|
|
6
7
|
import { getFileBasedHashSourceAsync } from './Utils';
|
|
7
|
-
import type { HashSource, NormalizedOptions
|
|
8
|
+
import type { HashSource, NormalizedOptions } from '../Fingerprint.types';
|
|
8
9
|
|
|
9
10
|
const debug = require('debug')('expo:fingerprint:sourcer:Bare');
|
|
10
11
|
|
|
@@ -80,36 +81,35 @@ export async function getRncliAutolinkingSourcesAsync(
|
|
|
80
81
|
const config = JSON.parse(stdout);
|
|
81
82
|
const { root } = config;
|
|
82
83
|
const reasons = ['bareRncliAutolinking'];
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const autolinkingConfig: Record<string, any> = {};
|
|
85
|
+
for (const [depName, depData] of Object.entries<any>(config.dependencies)) {
|
|
86
|
+
stripRncliAutolinkingAbsolutePaths(depData, root);
|
|
87
|
+
const filePath = depData.root;
|
|
86
88
|
debug(`Adding react-native-cli autolinking dir - ${chalk.dim(filePath)}`);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
results.push({
|
|
91
|
-
type: 'contents',
|
|
92
|
-
id: `rncliAutolinkingConfig:${depData.name}:${platform}`,
|
|
93
|
-
contents: platformData,
|
|
94
|
-
reasons,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
89
|
+
results.push({ type: 'dir', filePath, reasons });
|
|
90
|
+
|
|
91
|
+
autolinkingConfig[depName] = depData;
|
|
98
92
|
}
|
|
93
|
+
|
|
94
|
+
results.push({
|
|
95
|
+
type: 'contents',
|
|
96
|
+
id: 'rncliAutolinkingConfig',
|
|
97
|
+
contents: JSON.stringify(autolinkingConfig),
|
|
98
|
+
reasons,
|
|
99
|
+
});
|
|
99
100
|
return results;
|
|
100
101
|
} catch {
|
|
101
102
|
return [];
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
function
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
function stripRncliAutolinkingAbsolutePaths(dependency: any, root: string): void {
|
|
107
|
+
assert(dependency.root);
|
|
108
|
+
const dependencyRoot = dependency.root;
|
|
109
|
+
dependency.root = path.relative(root, dependencyRoot);
|
|
110
|
+
for (const platformData of Object.values<any>(dependency.platforms)) {
|
|
111
|
+
for (const [key, value] of Object.entries<any>(platformData)) {
|
|
112
|
+
platformData[key] = value.startsWith?.(dependencyRoot) ? path.relative(root, value) : value;
|
|
113
|
+
}
|
|
113
114
|
}
|
|
114
|
-
return JSON.stringify(json);
|
|
115
115
|
}
|
package/src/sourcer/Expo.ts
CHANGED
|
@@ -6,7 +6,7 @@ import findUp from 'find-up';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import resolveFrom from 'resolve-from';
|
|
8
8
|
|
|
9
|
-
import { getFileBasedHashSourceAsync } from './Utils';
|
|
9
|
+
import { getFileBasedHashSourceAsync, stringifyJsonSorted } from './Utils';
|
|
10
10
|
import type { HashSource, NormalizedOptions } from '../Fingerprint.types';
|
|
11
11
|
|
|
12
12
|
const debug = require('debug')('expo:fingerprint:sourcer:Expo');
|
|
@@ -15,32 +15,23 @@ export async function getExpoConfigSourcesAsync(
|
|
|
15
15
|
projectRoot: string,
|
|
16
16
|
options: NormalizedOptions
|
|
17
17
|
): Promise<HashSource[]> {
|
|
18
|
+
const results: HashSource[] = [];
|
|
19
|
+
|
|
18
20
|
let config: ProjectConfig;
|
|
19
21
|
try {
|
|
20
22
|
const { getConfig } = require(resolveFrom(path.resolve(projectRoot), 'expo/config'));
|
|
21
23
|
config = await getConfig(projectRoot, { skipSDKVersionRequirement: true });
|
|
24
|
+
results.push({
|
|
25
|
+
type: 'contents',
|
|
26
|
+
id: 'expoConfig',
|
|
27
|
+
contents: normalizeExpoConfig(config.exp),
|
|
28
|
+
reasons: ['expoConfig'],
|
|
29
|
+
});
|
|
22
30
|
} catch (e: unknown) {
|
|
23
31
|
debug('Cannot get Expo config: ' + e);
|
|
24
32
|
return [];
|
|
25
33
|
}
|
|
26
34
|
|
|
27
|
-
const results: HashSource[] = [];
|
|
28
|
-
|
|
29
|
-
// app config files
|
|
30
|
-
const configFiles = ['app.config.ts', 'app.config.js', 'app.config.json', 'app.json'];
|
|
31
|
-
const configFileSources = (
|
|
32
|
-
await Promise.all(
|
|
33
|
-
configFiles.map(async (file) => {
|
|
34
|
-
const result = await getFileBasedHashSourceAsync(projectRoot, file, 'expoConfig');
|
|
35
|
-
if (result != null) {
|
|
36
|
-
debug(`Adding config file - ${chalk.dim(file)}`);
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
})
|
|
40
|
-
)
|
|
41
|
-
).filter(Boolean) as HashSource[];
|
|
42
|
-
results.push(...configFileSources);
|
|
43
|
-
|
|
44
35
|
// external files in config
|
|
45
36
|
const isAndroid = options.platforms.includes('android');
|
|
46
37
|
const isIos = options.platforms.includes('ios');
|
|
@@ -99,6 +90,14 @@ function findUpPluginRoot(entryFile: string): string {
|
|
|
99
90
|
return path.dirname(packageJson);
|
|
100
91
|
}
|
|
101
92
|
|
|
93
|
+
function normalizeExpoConfig(config: ExpoConfig): string {
|
|
94
|
+
// Deep clone by JSON.parse/stringify that assumes the config is serializable.
|
|
95
|
+
const normalizedConfig: ExpoConfig = JSON.parse(JSON.stringify(config));
|
|
96
|
+
delete normalizedConfig.runtimeVersion;
|
|
97
|
+
delete normalizedConfig._internal;
|
|
98
|
+
return stringifyJsonSorted(normalizedConfig);
|
|
99
|
+
}
|
|
100
|
+
|
|
102
101
|
function getConfigPluginSourcesAsync(
|
|
103
102
|
projectRoot: string,
|
|
104
103
|
plugins: ExpoConfig['plugins']
|
package/src/sourcer/Utils.ts
CHANGED
|
@@ -21,3 +21,42 @@ export async function getFileBasedHashSourceAsync(
|
|
|
21
21
|
}
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A version of `JSON.stringify` that keeps the keys sorted
|
|
27
|
+
*/
|
|
28
|
+
export function stringifyJsonSorted(target: any, space?: string | number | undefined): string {
|
|
29
|
+
return JSON.stringify(target, (_, value) => sortJson(value), space);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function sortJson(json: any): any {
|
|
33
|
+
if (Array.isArray(json)) {
|
|
34
|
+
return json.sort((a, b) => {
|
|
35
|
+
// Sort array items by their stringified value.
|
|
36
|
+
// We don't need the array to be sorted in meaningful way, just to be sorted in deterministic.
|
|
37
|
+
// E.g. `[{ b: '2' }, {}, { a: '3' }, null]` -> `[null, { a : '3' }, { b: '2' }, {}]`
|
|
38
|
+
// This result is not a perfect solution, but it's good enough for our use case.
|
|
39
|
+
const stringifiedA = stringifyJsonSorted(a);
|
|
40
|
+
const stringifiedB = stringifyJsonSorted(b);
|
|
41
|
+
if (stringifiedA < stringifiedB) {
|
|
42
|
+
return -1;
|
|
43
|
+
} else if (stringifiedA > stringifiedB) {
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (json != null && typeof json === 'object') {
|
|
51
|
+
// Sort object items by keys
|
|
52
|
+
return Object.keys(json)
|
|
53
|
+
.sort()
|
|
54
|
+
.reduce((acc: any, key: string) => {
|
|
55
|
+
acc[key] = json[key];
|
|
56
|
+
return acc;
|
|
57
|
+
}, {});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Return primitives
|
|
61
|
+
return json;
|
|
62
|
+
}
|
|
@@ -3,7 +3,7 @@ import fs from 'fs';
|
|
|
3
3
|
import { vol } from 'memfs';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { normalizeOptionsAsync } from '../../Options';
|
|
7
7
|
import {
|
|
8
8
|
getBareAndroidSourcesAsync,
|
|
9
9
|
getBareIosSourcesAsync,
|
|
@@ -21,10 +21,10 @@ describe('getBareSourcesAsync', () => {
|
|
|
21
21
|
|
|
22
22
|
it('should contain android and ios folders in bare react-native project', async () => {
|
|
23
23
|
vol.fromJSON(require('./fixtures/BareReactNative70Project.json'));
|
|
24
|
-
let sources = await getBareAndroidSourcesAsync('/app',
|
|
24
|
+
let sources = await getBareAndroidSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
25
25
|
expect(sources).toContainEqual(expect.objectContaining({ filePath: 'android', type: 'dir' }));
|
|
26
26
|
|
|
27
|
-
sources = await getBareIosSourcesAsync('/app',
|
|
27
|
+
sources = await getBareIosSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
28
28
|
expect(sources).toContainEqual(expect.objectContaining({ filePath: 'ios', type: 'dir' }));
|
|
29
29
|
});
|
|
30
30
|
});
|
|
@@ -47,13 +47,42 @@ describe(getRncliAutolinkingSourcesAsync, () => {
|
|
|
47
47
|
signal: null,
|
|
48
48
|
output: [fixture, ''],
|
|
49
49
|
});
|
|
50
|
-
const sources = await getRncliAutolinkingSourcesAsync(
|
|
50
|
+
const sources = await getRncliAutolinkingSourcesAsync(
|
|
51
|
+
'/root/apps/demo',
|
|
52
|
+
await normalizeOptionsAsync('/app')
|
|
53
|
+
);
|
|
51
54
|
expect(sources).toContainEqual(
|
|
52
55
|
expect.objectContaining({
|
|
53
56
|
type: 'dir',
|
|
54
|
-
filePath: 'node_modules/react-native-reanimated',
|
|
57
|
+
filePath: '../../node_modules/react-native-reanimated',
|
|
55
58
|
})
|
|
56
59
|
);
|
|
57
60
|
expect(sources).toMatchSnapshot();
|
|
58
61
|
});
|
|
62
|
+
|
|
63
|
+
it('should not contain absolute paths', async () => {
|
|
64
|
+
const mockSpawnAsync = spawnAsync as jest.MockedFunction<typeof spawnAsync>;
|
|
65
|
+
const fixture = fs.readFileSync(
|
|
66
|
+
path.join(__dirname, 'fixtures', 'RncliAutoLinking.json'),
|
|
67
|
+
'utf8'
|
|
68
|
+
);
|
|
69
|
+
mockSpawnAsync.mockResolvedValue({
|
|
70
|
+
stdout: fixture,
|
|
71
|
+
stderr: '',
|
|
72
|
+
status: 0,
|
|
73
|
+
signal: null,
|
|
74
|
+
output: [fixture, ''],
|
|
75
|
+
});
|
|
76
|
+
const sources = await getRncliAutolinkingSourcesAsync(
|
|
77
|
+
'/root/apps/demo',
|
|
78
|
+
await normalizeOptionsAsync('/app')
|
|
79
|
+
);
|
|
80
|
+
for (const source of sources) {
|
|
81
|
+
if (source.type === 'dir' || source.type === 'file') {
|
|
82
|
+
expect(source.filePath).not.toMatch(/^\/root/);
|
|
83
|
+
} else {
|
|
84
|
+
expect(source.contents).not.toMatch(/"\/root\//);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
59
88
|
});
|
|
@@ -5,7 +5,8 @@ import { vol, fs as volFS } from 'memfs';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import resolveFrom from 'resolve-from';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { HashSourceContents } from '../../Fingerprint.types';
|
|
9
|
+
import { normalizeOptionsAsync } from '../../Options';
|
|
9
10
|
import {
|
|
10
11
|
getEasBuildSourcesAsync,
|
|
11
12
|
getExpoAutolinkingAndroidSourcesAsync,
|
|
@@ -55,7 +56,7 @@ describe(getEasBuildSourcesAsync, () => {
|
|
|
55
56
|
}`
|
|
56
57
|
);
|
|
57
58
|
|
|
58
|
-
const sources = await getEasBuildSourcesAsync('/app',
|
|
59
|
+
const sources = await getEasBuildSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
59
60
|
expect(sources).toContainEqual(
|
|
60
61
|
expect.objectContaining({
|
|
61
62
|
type: 'file',
|
|
@@ -97,7 +98,10 @@ describe('getExpoAutolinkingSourcesAsync', () => {
|
|
|
97
98
|
});
|
|
98
99
|
|
|
99
100
|
it('should contain expo autolinking projects', async () => {
|
|
100
|
-
let sources = await getExpoAutolinkingAndroidSourcesAsync(
|
|
101
|
+
let sources = await getExpoAutolinkingAndroidSourcesAsync(
|
|
102
|
+
'/app',
|
|
103
|
+
await normalizeOptionsAsync('/app')
|
|
104
|
+
);
|
|
101
105
|
expect(sources).toContainEqual(
|
|
102
106
|
expect.objectContaining({
|
|
103
107
|
type: 'dir',
|
|
@@ -106,7 +110,7 @@ describe('getExpoAutolinkingSourcesAsync', () => {
|
|
|
106
110
|
);
|
|
107
111
|
expect(sources).toMatchSnapshot();
|
|
108
112
|
|
|
109
|
-
sources = await getExpoAutolinkingIosSourcesAsync('/app',
|
|
113
|
+
sources = await getExpoAutolinkingIosSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
110
114
|
expect(sources).toContainEqual(
|
|
111
115
|
expect.objectContaining({ type: 'dir', filePath: 'node_modules/expo-modules-core' })
|
|
112
116
|
);
|
|
@@ -114,14 +118,17 @@ describe('getExpoAutolinkingSourcesAsync', () => {
|
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
it('should not containt absolute path in contents', async () => {
|
|
117
|
-
let sources = await getExpoAutolinkingAndroidSourcesAsync(
|
|
121
|
+
let sources = await getExpoAutolinkingAndroidSourcesAsync(
|
|
122
|
+
'/app',
|
|
123
|
+
await normalizeOptionsAsync('/app')
|
|
124
|
+
);
|
|
118
125
|
for (const source of sources) {
|
|
119
126
|
if (source.type === 'contents') {
|
|
120
127
|
expect(source.contents.indexOf('/app/')).toBe(-1);
|
|
121
128
|
}
|
|
122
129
|
}
|
|
123
130
|
|
|
124
|
-
sources = await getExpoAutolinkingIosSourcesAsync('/app',
|
|
131
|
+
sources = await getExpoAutolinkingIosSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
125
132
|
for (const source of sources) {
|
|
126
133
|
if (source.type === 'contents') {
|
|
127
134
|
expect(source.contents.indexOf('/app/')).toBe(-1);
|
|
@@ -147,26 +154,67 @@ describe(getExpoConfigSourcesAsync, () => {
|
|
|
147
154
|
// To fake the case as no expo installed, trying to resolve as **nonexist/expo/config** module
|
|
148
155
|
return actualResolver(fromDirectory, 'nonexist/expo/config');
|
|
149
156
|
});
|
|
150
|
-
const sources = await getExpoConfigSourcesAsync('/app',
|
|
157
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
151
158
|
expect(sources.length).toBe(0);
|
|
152
159
|
});
|
|
153
160
|
|
|
154
|
-
it('should contain
|
|
161
|
+
it('should contain expo config', async () => {
|
|
155
162
|
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
const appJson = JSON.parse(vol.readFileSync('/app/app.json', 'utf8').toString());
|
|
164
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
165
|
+
const expoConfigSource = sources.find<HashSourceContents>(
|
|
166
|
+
(source): source is HashSourceContents =>
|
|
167
|
+
source.type === 'contents' && source.id === 'expoConfig'
|
|
168
|
+
);
|
|
169
|
+
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
|
|
170
|
+
expect(expoConfig).not.toBeNull();
|
|
171
|
+
expect(expoConfig.name).toEqual(appJson.expo.name);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should not contain runtimeVersion in expo config', async () => {
|
|
175
|
+
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
176
|
+
vol.writeFileSync(
|
|
177
|
+
'/app/app.config.js',
|
|
178
|
+
`\
|
|
179
|
+
export default ({ config }) => {
|
|
180
|
+
config.runtimeVersion = '1.0.0';
|
|
181
|
+
return config;
|
|
182
|
+
};`
|
|
183
|
+
);
|
|
184
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
185
|
+
const expoConfigSource = sources.find<HashSourceContents>(
|
|
186
|
+
(source): source is HashSourceContents =>
|
|
187
|
+
source.type === 'contents' && source.id === 'expoConfig'
|
|
162
188
|
);
|
|
189
|
+
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
|
|
190
|
+
expect(expoConfig).not.toBeNull();
|
|
191
|
+
expect(expoConfig.runtimeVersion).toBeUndefined();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should keep expo config contents in deterministic order', async () => {
|
|
195
|
+
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
196
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
197
|
+
|
|
198
|
+
const appJsonContents = vol.readFileSync('/app/app.json', 'utf8').toString();
|
|
199
|
+
const appJson = JSON.parse(appJsonContents);
|
|
200
|
+
const { name } = appJson.expo;
|
|
201
|
+
// Re-insert name to change the object order
|
|
202
|
+
delete appJson.expo.name;
|
|
203
|
+
appJson.expo.name = name;
|
|
204
|
+
const newAppJsonContents = JSON.stringify(appJson);
|
|
205
|
+
expect(newAppJsonContents).not.toEqual(appJsonContents);
|
|
206
|
+
vol.writeFileSync('/app/app.json', newAppJsonContents);
|
|
207
|
+
|
|
208
|
+
// Even new app.json contents changed its order, the source contents should be the same.
|
|
209
|
+
const sources2 = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
210
|
+
expect(sources).toEqual(sources2);
|
|
163
211
|
});
|
|
164
212
|
|
|
165
213
|
it('should contain external icon file in app.json', async () => {
|
|
166
214
|
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
167
215
|
vol.mkdirSync('/app/assets');
|
|
168
216
|
vol.writeFileSync('/app/assets/icon.png', 'PNG data');
|
|
169
|
-
const sources = await getExpoConfigSourcesAsync('/app',
|
|
217
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
170
218
|
expect(sources).toContainEqual(
|
|
171
219
|
expect.objectContaining({
|
|
172
220
|
type: 'file',
|
|
@@ -221,7 +269,7 @@ describe(`getExpoConfigSourcesAsync - config-plugins`, () => {
|
|
|
221
269
|
},
|
|
222
270
|
})
|
|
223
271
|
);
|
|
224
|
-
const sources = await getExpoConfigSourcesAsync('/app',
|
|
272
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
225
273
|
expect(sources).toContainEqual(
|
|
226
274
|
expect.objectContaining({
|
|
227
275
|
type: 'dir',
|
|
@@ -243,7 +291,7 @@ describe(`getExpoConfigSourcesAsync - config-plugins`, () => {
|
|
|
243
291
|
},
|
|
244
292
|
})
|
|
245
293
|
);
|
|
246
|
-
const sources = await getExpoConfigSourcesAsync('/app',
|
|
294
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
247
295
|
expect(sources).toContainEqual(
|
|
248
296
|
expect.objectContaining({
|
|
249
297
|
type: 'dir',
|
|
@@ -260,7 +308,7 @@ export default ({ config }) => {
|
|
|
260
308
|
return config;
|
|
261
309
|
};`
|
|
262
310
|
);
|
|
263
|
-
const sources = await getExpoConfigSourcesAsync('/app',
|
|
311
|
+
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
264
312
|
|
|
265
313
|
vol.writeFileSync(
|
|
266
314
|
'/app/app.config.js',
|
|
@@ -272,9 +320,16 @@ export default ({ config }) => {
|
|
|
272
320
|
return config;
|
|
273
321
|
};`
|
|
274
322
|
);
|
|
275
|
-
const sources2 = await getExpoConfigSourcesAsync('/app',
|
|
323
|
+
const sources2 = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
276
324
|
|
|
277
|
-
|
|
325
|
+
// sources2 will contain the plugins from expo config, but sources will not.
|
|
326
|
+
const sourcesWithoutExpoConfig = sources.filter(
|
|
327
|
+
(item) => item.type !== 'contents' || item.id !== 'expoConfig'
|
|
328
|
+
);
|
|
329
|
+
const sources2WithoutExpoConfig = sources2.filter(
|
|
330
|
+
(item) => item.type !== 'contents' || item.id !== 'expoConfig'
|
|
331
|
+
);
|
|
332
|
+
expect(sourcesWithoutExpoConfig).toEqual(sources2WithoutExpoConfig);
|
|
278
333
|
});
|
|
279
334
|
});
|
|
280
335
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { vol } from 'memfs';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { normalizeOptionsAsync } from '../../Options';
|
|
4
4
|
import { getPatchPackageSourcesAsync } from '../PatchPackage';
|
|
5
5
|
import { getHashSourcesAsync } from '../Sourcer';
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ describe(getPatchPackageSourcesAsync, () => {
|
|
|
16
16
|
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
17
17
|
vol.fromJSON(require('./fixtures/PatchPackage.json'));
|
|
18
18
|
|
|
19
|
-
const sources = await getPatchPackageSourcesAsync('/app',
|
|
19
|
+
const sources = await getPatchPackageSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
20
20
|
expect(sources).toContainEqual(
|
|
21
21
|
expect.objectContaining({
|
|
22
22
|
type: 'dir',
|
|
@@ -41,7 +41,7 @@ describe('patch-package postinstall', () => {
|
|
|
41
41
|
{ virtual: true }
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
const sources = await getHashSourcesAsync('/app',
|
|
44
|
+
const sources = await getHashSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
45
45
|
expect(sources).toContainEqual(
|
|
46
46
|
expect.objectContaining({
|
|
47
47
|
type: 'contents',
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeOptionsAsync } from '../../Options';
|
|
2
2
|
import { getHashSourcesAsync } from '../Sourcer';
|
|
3
3
|
|
|
4
4
|
describe(getHashSourcesAsync, () => {
|
|
5
5
|
it('should include `extraSources` from input parameter', async () => {
|
|
6
6
|
const sources = await getHashSourcesAsync(
|
|
7
7
|
'/app',
|
|
8
|
-
|
|
8
|
+
await normalizeOptionsAsync('/app', {
|
|
9
9
|
extraSources: [{ type: 'dir', filePath: '/app/scripts', reasons: ['extra'] }],
|
|
10
10
|
})
|
|
11
11
|
);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { stringifyJsonSorted } from '../Utils';
|
|
2
|
+
|
|
3
|
+
describe(stringifyJsonSorted, () => {
|
|
4
|
+
it('should support primitive types', () => {
|
|
5
|
+
expect(stringifyJsonSorted(1)).toEqual('1');
|
|
6
|
+
expect(stringifyJsonSorted('s')).toEqual('"s"');
|
|
7
|
+
expect(stringifyJsonSorted(true)).toEqual('true');
|
|
8
|
+
expect(stringifyJsonSorted(false)).toEqual('false');
|
|
9
|
+
expect(stringifyJsonSorted(null)).toEqual('null');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should sort array', () => {
|
|
13
|
+
expect(stringifyJsonSorted([])).toEqual('[]');
|
|
14
|
+
expect(stringifyJsonSorted([2, 'a', 1, false, 6, 4, 5, 's', 3, 0, true, 1, 1])).toEqual(
|
|
15
|
+
'["a","s",0,1,1,1,2,3,4,5,6,false,true]'
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should sort object by keys', () => {
|
|
20
|
+
expect(stringifyJsonSorted({})).toEqual('{}');
|
|
21
|
+
expect(stringifyJsonSorted({ c: '1', a: '3', b: '2' })).toEqual('{"a":"3","b":"2","c":"1"}');
|
|
22
|
+
expect(
|
|
23
|
+
stringifyJsonSorted({ c: '1', a: '3', b: '2', nested: { c: '1', a: '3', b: '2' } })
|
|
24
|
+
).toEqual('{"a":"3","b":"2","c":"1","nested":{"a":"3","b":"2","c":"1"}}');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should support mixed array/object', () => {
|
|
28
|
+
expect(stringifyJsonSorted([{ b: '2' }, { c: '1' }, { a: '3' }])).toEqual(
|
|
29
|
+
'[{"a":"3"},{"b":"2"},{"c":"1"}]'
|
|
30
|
+
);
|
|
31
|
+
expect(stringifyJsonSorted([{ b: '2' }, {}, { a: '3' }, null])).toEqual(
|
|
32
|
+
'[null,{"a":"3"},{"b":"2"},{}]'
|
|
33
|
+
);
|
|
34
|
+
expect(
|
|
35
|
+
stringifyJsonSorted({
|
|
36
|
+
array: [3, 2, 1],
|
|
37
|
+
nestedData: { nestedArray: [{ b: '2' }, { c: '1' }, { a: '3' }] },
|
|
38
|
+
})
|
|
39
|
+
).toEqual('{"array":[1,2,3],"nestedData":{"nestedArray":[{"a":"3"},{"b":"2"},{"c":"1"}]}}');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -3,23 +3,15 @@
|
|
|
3
3
|
exports[`getRncliAutolinkingSourcesAsync should contain rn-cli autolinking projects 1`] = `
|
|
4
4
|
[
|
|
5
5
|
{
|
|
6
|
-
"filePath": "node_modules/react-native-reanimated",
|
|
6
|
+
"filePath": "../../node_modules/react-native-reanimated",
|
|
7
7
|
"reasons": [
|
|
8
8
|
"bareRncliAutolinking",
|
|
9
9
|
],
|
|
10
10
|
"type": "dir",
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
|
-
"contents": "{"sourceDir":"node_modules/react-native-reanimated/android","packageImportPath":"import com.swmansion.reanimated.ReanimatedPackage;","packageInstance":"new ReanimatedPackage()","buildTypes":[],"componentDescriptors":[],"androidMkPath":"node_modules/react-native-reanimated/android/build/generated/source/codegen/jni/Android.mk","cmakeListsPath":"node_modules/react-native-reanimated/android/build/generated/source/codegen/jni/CMakeLists.txt"}",
|
|
14
|
-
"id": "rncliAutolinkingConfig
|
|
15
|
-
"reasons": [
|
|
16
|
-
"bareRncliAutolinking",
|
|
17
|
-
],
|
|
18
|
-
"type": "contents",
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"contents": "{"podspecPath":"node_modules/react-native-reanimated/RNReanimated.podspec","configurations":[],"scriptPhases":[]}",
|
|
22
|
-
"id": "rncliAutolinkingConfig:react-native-reanimated:ios",
|
|
13
|
+
"contents": "{"react-native-reanimated":{"root":"../../node_modules/react-native-reanimated","name":"react-native-reanimated","platforms":{"ios":{"podspecPath":"../../node_modules/react-native-reanimated/RNReanimated.podspec","configurations":[],"scriptPhases":[]},"android":{"sourceDir":"../../node_modules/react-native-reanimated/android","packageImportPath":"import com.swmansion.reanimated.ReanimatedPackage;","packageInstance":"new ReanimatedPackage()","buildTypes":[],"componentDescriptors":[],"androidMkPath":"../../node_modules/react-native-reanimated/android/build/generated/source/codegen/jni/Android.mk","cmakeListsPath":"../../node_modules/react-native-reanimated/android/build/generated/source/codegen/jni/CMakeLists.txt"}}}}",
|
|
14
|
+
"id": "rncliAutolinkingConfig",
|
|
23
15
|
"reasons": [
|
|
24
16
|
"bareRncliAutolinking",
|
|
25
17
|
],
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"root": "/
|
|
3
|
-
"reactNativePath": "/
|
|
2
|
+
"root": "/root/apps/demo",
|
|
3
|
+
"reactNativePath": "/root/node_modules/react-native",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"react-native-reanimated": {
|
|
6
|
-
"root": "/
|
|
6
|
+
"root": "/root/node_modules/react-native-reanimated",
|
|
7
7
|
"name": "react-native-reanimated",
|
|
8
8
|
"platforms": {
|
|
9
9
|
"ios": {
|
|
10
|
-
"podspecPath": "/
|
|
10
|
+
"podspecPath": "/root/node_modules/react-native-reanimated/RNReanimated.podspec",
|
|
11
11
|
"configurations": [],
|
|
12
12
|
"scriptPhases": []
|
|
13
13
|
},
|
|
14
14
|
"android": {
|
|
15
|
-
"sourceDir": "/
|
|
15
|
+
"sourceDir": "/root/node_modules/react-native-reanimated/android",
|
|
16
16
|
"packageImportPath": "import com.swmansion.reanimated.ReanimatedPackage;",
|
|
17
17
|
"packageInstance": "new ReanimatedPackage()",
|
|
18
18
|
"buildTypes": [],
|
|
19
19
|
"componentDescriptors": [],
|
|
20
|
-
"androidMkPath": "/
|
|
21
|
-
"cmakeListsPath": "/
|
|
20
|
+
"androidMkPath": "/root/node_modules/react-native-reanimated/android/build/generated/source/codegen/jni/Android.mk",
|
|
21
|
+
"cmakeListsPath": "/root/node_modules/react-native-reanimated/android/build/generated/source/codegen/jni/CMakeLists.txt"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -150,14 +150,14 @@
|
|
|
150
150
|
},
|
|
151
151
|
"project": {
|
|
152
152
|
"ios": {
|
|
153
|
-
"sourceDir": "/
|
|
153
|
+
"sourceDir": "/root/apps/demo/ios",
|
|
154
154
|
"xcodeProject": {
|
|
155
155
|
"name": "RN070.xcworkspace",
|
|
156
156
|
"isWorkspace": true
|
|
157
157
|
}
|
|
158
158
|
},
|
|
159
159
|
"android": {
|
|
160
|
-
"sourceDir": "/
|
|
160
|
+
"sourceDir": "/root/apps/demo/android",
|
|
161
161
|
"appName": "app",
|
|
162
162
|
"packageName": "com.rn070"
|
|
163
163
|
}
|