@expo/fingerprint 0.4.0 → 0.5.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/README.md +10 -0
- package/bin/cli.js +26 -5
- package/build/sourcer/Bare.js +13 -7
- package/build/sourcer/Bare.js.map +1 -1
- package/package.json +16 -9
- package/.eslintignore +0 -1
- package/CHANGELOG.md +0 -51
- package/__mocks__/@expo/spawn-async.ts +0 -30
- package/__mocks__/fs/promises.ts +0 -17
- package/__mocks__/fs.ts +0 -2
- package/__mocks__/resolve-from.ts +0 -24
- package/babel.config.js +0 -6
- package/e2e/__tests__/__snapshots__/managed-test.ts.snap +0 -193
- package/e2e/__tests__/bare-test.ts +0 -73
- package/e2e/__tests__/managed-test.ts +0 -163
- package/e2e/jest.config.js +0 -11
- package/jest.config.js +0 -10
- package/scripts/createFixture.ts +0 -81
- package/src/Dedup.ts +0 -97
- package/src/Fingerprint.ts +0 -60
- package/src/Fingerprint.types.ts +0 -110
- package/src/Options.ts +0 -81
- package/src/Sort.ts +0 -22
- package/src/__tests__/Dedup-test.ts +0 -177
- package/src/__tests__/Fingerprint-test.ts +0 -143
- package/src/__tests__/Sort-test.ts +0 -56
- package/src/hash/Hash.ts +0 -203
- package/src/hash/__tests__/Hash-test.ts +0 -238
- package/src/index.ts +0 -2
- package/src/sourcer/Bare.ts +0 -115
- package/src/sourcer/Expo.ts +0 -223
- package/src/sourcer/ExpoConfigLoader.ts +0 -84
- package/src/sourcer/PatchPackage.ts +0 -18
- package/src/sourcer/Sourcer.ts +0 -58
- package/src/sourcer/Utils.ts +0 -62
- package/src/sourcer/__tests__/Bare-test.ts +0 -88
- package/src/sourcer/__tests__/Expo-test.ts +0 -305
- package/src/sourcer/__tests__/PatchPackage-test.ts +0 -57
- package/src/sourcer/__tests__/Sourcer-test.ts +0 -21
- package/src/sourcer/__tests__/Utils-test.ts +0 -41
- package/src/sourcer/__tests__/__snapshots__/Bare-test.ts.snap +0 -21
- package/src/sourcer/__tests__/__snapshots__/Expo-test.ts.snap +0 -139
- package/src/sourcer/__tests__/fixtures/BareReactNative70Project.json +0 -47
- package/src/sourcer/__tests__/fixtures/ExpoAutolinkingAndroid.json +0 -82
- package/src/sourcer/__tests__/fixtures/ExpoAutolinkingIos.json +0 -114
- package/src/sourcer/__tests__/fixtures/ExpoManaged47Project.json +0 -6
- package/src/sourcer/__tests__/fixtures/PatchPackage.json +0 -4
- package/src/sourcer/__tests__/fixtures/RncliAutoLinking.json +0 -165
- package/src/utils/Path.ts +0 -26
- package/src/utils/Profile.ts +0 -47
- package/src/utils/__tests__/Path-test.ts +0 -36
- package/src/utils/__tests__/Profile-test.ts +0 -11
- package/tsconfig.json +0 -9
package/src/sourcer/Sourcer.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
getBareAndroidSourcesAsync,
|
|
5
|
-
getBareIosSourcesAsync,
|
|
6
|
-
getPackageJsonScriptSourcesAsync,
|
|
7
|
-
getGitIgnoreSourcesAsync,
|
|
8
|
-
getRncliAutolinkingSourcesAsync,
|
|
9
|
-
} from './Bare';
|
|
10
|
-
import {
|
|
11
|
-
getEasBuildSourcesAsync,
|
|
12
|
-
getExpoAutolinkingAndroidSourcesAsync,
|
|
13
|
-
getExpoAutolinkingIosSourcesAsync,
|
|
14
|
-
getExpoConfigSourcesAsync,
|
|
15
|
-
} from './Expo';
|
|
16
|
-
import { getPatchPackageSourcesAsync } from './PatchPackage';
|
|
17
|
-
import type { HashSource, NormalizedOptions } from '../Fingerprint.types';
|
|
18
|
-
import { profile } from '../utils/Profile';
|
|
19
|
-
|
|
20
|
-
const debug = require('debug')('expo:fingerprint:sourcer:Sourcer');
|
|
21
|
-
|
|
22
|
-
export async function getHashSourcesAsync(
|
|
23
|
-
projectRoot: string,
|
|
24
|
-
options: NormalizedOptions
|
|
25
|
-
): Promise<HashSource[]> {
|
|
26
|
-
const results = await Promise.all([
|
|
27
|
-
// expo
|
|
28
|
-
profile(getExpoAutolinkingAndroidSourcesAsync)(projectRoot, options),
|
|
29
|
-
profile(getExpoAutolinkingIosSourcesAsync)(projectRoot, options),
|
|
30
|
-
profile(getExpoConfigSourcesAsync)(projectRoot, options),
|
|
31
|
-
profile(getEasBuildSourcesAsync)(projectRoot, options),
|
|
32
|
-
|
|
33
|
-
// bare managed files
|
|
34
|
-
profile(getGitIgnoreSourcesAsync)(projectRoot, options),
|
|
35
|
-
profile(getPackageJsonScriptSourcesAsync)(projectRoot, options),
|
|
36
|
-
|
|
37
|
-
// bare native files
|
|
38
|
-
profile(getBareAndroidSourcesAsync)(projectRoot, options),
|
|
39
|
-
profile(getBareIosSourcesAsync)(projectRoot, options),
|
|
40
|
-
|
|
41
|
-
// rn-cli autolinking
|
|
42
|
-
profile(getRncliAutolinkingSourcesAsync)(projectRoot, options),
|
|
43
|
-
|
|
44
|
-
// patch-package
|
|
45
|
-
profile(getPatchPackageSourcesAsync)(projectRoot, options),
|
|
46
|
-
]);
|
|
47
|
-
|
|
48
|
-
// extra sources
|
|
49
|
-
if (options.extraSources) {
|
|
50
|
-
for (const source of options.extraSources) {
|
|
51
|
-
debug(`Adding extra source - ${chalk.dim(JSON.stringify(source))}`);
|
|
52
|
-
}
|
|
53
|
-
results.push(options.extraSources);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// flatten results
|
|
57
|
-
return ([] as HashSource[]).concat(...results);
|
|
58
|
-
}
|
package/src/sourcer/Utils.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
import type { HashSource } from '../Fingerprint.types';
|
|
5
|
-
|
|
6
|
-
export async function getFileBasedHashSourceAsync(
|
|
7
|
-
projectRoot: string,
|
|
8
|
-
filePath: string,
|
|
9
|
-
reason: string
|
|
10
|
-
): Promise<HashSource | null> {
|
|
11
|
-
let result: HashSource | null = null;
|
|
12
|
-
try {
|
|
13
|
-
const stat = await fs.stat(path.join(projectRoot, filePath));
|
|
14
|
-
result = {
|
|
15
|
-
type: stat.isDirectory() ? 'dir' : 'file',
|
|
16
|
-
filePath,
|
|
17
|
-
reasons: [reason],
|
|
18
|
-
};
|
|
19
|
-
} catch {
|
|
20
|
-
result = null;
|
|
21
|
-
}
|
|
22
|
-
return result;
|
|
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
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import spawnAsync from '@expo/spawn-async';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import { vol } from 'memfs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
import { normalizeOptionsAsync } from '../../Options';
|
|
7
|
-
import {
|
|
8
|
-
getBareAndroidSourcesAsync,
|
|
9
|
-
getBareIosSourcesAsync,
|
|
10
|
-
getRncliAutolinkingSourcesAsync,
|
|
11
|
-
} from '../Bare';
|
|
12
|
-
|
|
13
|
-
jest.mock('@expo/spawn-async');
|
|
14
|
-
jest.mock('fs/promises');
|
|
15
|
-
jest.mock('/app/package.json', () => ({}), { virtual: true });
|
|
16
|
-
|
|
17
|
-
describe('getBareSourcesAsync', () => {
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
vol.reset();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should contain android and ios folders in bare react-native project', async () => {
|
|
23
|
-
vol.fromJSON(require('./fixtures/BareReactNative70Project.json'));
|
|
24
|
-
let sources = await getBareAndroidSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
25
|
-
expect(sources).toContainEqual(expect.objectContaining({ filePath: 'android', type: 'dir' }));
|
|
26
|
-
|
|
27
|
-
sources = await getBareIosSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
28
|
-
expect(sources).toContainEqual(expect.objectContaining({ filePath: 'ios', type: 'dir' }));
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe(getRncliAutolinkingSourcesAsync, () => {
|
|
33
|
-
afterEach(() => {
|
|
34
|
-
vol.reset();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should contain rn-cli autolinking projects', async () => {
|
|
38
|
-
const mockSpawnAsync = spawnAsync as jest.MockedFunction<typeof spawnAsync>;
|
|
39
|
-
const fixture = fs.readFileSync(
|
|
40
|
-
path.join(__dirname, 'fixtures', 'RncliAutoLinking.json'),
|
|
41
|
-
'utf8'
|
|
42
|
-
);
|
|
43
|
-
mockSpawnAsync.mockResolvedValue({
|
|
44
|
-
stdout: fixture,
|
|
45
|
-
stderr: '',
|
|
46
|
-
status: 0,
|
|
47
|
-
signal: null,
|
|
48
|
-
output: [fixture, ''],
|
|
49
|
-
});
|
|
50
|
-
const sources = await getRncliAutolinkingSourcesAsync(
|
|
51
|
-
'/root/apps/demo',
|
|
52
|
-
await normalizeOptionsAsync('/app')
|
|
53
|
-
);
|
|
54
|
-
expect(sources).toContainEqual(
|
|
55
|
-
expect.objectContaining({
|
|
56
|
-
type: 'dir',
|
|
57
|
-
filePath: '../../node_modules/react-native-reanimated',
|
|
58
|
-
})
|
|
59
|
-
);
|
|
60
|
-
expect(sources).toMatchSnapshot();
|
|
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
|
-
});
|
|
88
|
-
});
|
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
import spawnAsync from '@expo/spawn-async';
|
|
2
|
-
import { getConfig } from 'expo/config';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import { vol, fs as volFS } from 'memfs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import resolveFrom from 'resolve-from';
|
|
7
|
-
|
|
8
|
-
import { HashSourceContents } from '../../Fingerprint.types';
|
|
9
|
-
import { normalizeOptionsAsync } from '../../Options';
|
|
10
|
-
import {
|
|
11
|
-
getEasBuildSourcesAsync,
|
|
12
|
-
getExpoAutolinkingAndroidSourcesAsync,
|
|
13
|
-
getExpoAutolinkingIosSourcesAsync,
|
|
14
|
-
getExpoConfigSourcesAsync,
|
|
15
|
-
sortExpoAutolinkingAndroidConfig,
|
|
16
|
-
} from '../Expo';
|
|
17
|
-
|
|
18
|
-
jest.mock('@expo/spawn-async');
|
|
19
|
-
jest.mock('find-up');
|
|
20
|
-
jest.mock('fs/promises');
|
|
21
|
-
jest.mock('resolve-from');
|
|
22
|
-
jest.mock('/app/package.json', () => {}, { virtual: true });
|
|
23
|
-
|
|
24
|
-
describe(getEasBuildSourcesAsync, () => {
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
vol.reset();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should contains `eas.json` file', async () => {
|
|
30
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
31
|
-
vol.writeFileSync(
|
|
32
|
-
'/app/eas.json',
|
|
33
|
-
`
|
|
34
|
-
{
|
|
35
|
-
"cli": {
|
|
36
|
-
"version": ">= 2.6.0"
|
|
37
|
-
},
|
|
38
|
-
"build": {
|
|
39
|
-
"development": {
|
|
40
|
-
"distribution": "internal",
|
|
41
|
-
"android": {
|
|
42
|
-
"gradleCommand": ":app:assembleDebug"
|
|
43
|
-
},
|
|
44
|
-
"ios": {
|
|
45
|
-
"buildConfiguration": "Debug"
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
"preview": {
|
|
49
|
-
"distribution": "internal"
|
|
50
|
-
},
|
|
51
|
-
"production": {}
|
|
52
|
-
},
|
|
53
|
-
"submit": {
|
|
54
|
-
"production": {}
|
|
55
|
-
}
|
|
56
|
-
}`
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
const sources = await getEasBuildSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
60
|
-
expect(sources).toContainEqual(
|
|
61
|
-
expect.objectContaining({
|
|
62
|
-
type: 'file',
|
|
63
|
-
filePath: 'eas.json',
|
|
64
|
-
})
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('getExpoAutolinkingSourcesAsync', () => {
|
|
70
|
-
beforeEach(() => {
|
|
71
|
-
const mockSpawnAsync = spawnAsync as jest.MockedFunction<typeof spawnAsync>;
|
|
72
|
-
const fixtureAndroid = fs.readFileSync(
|
|
73
|
-
path.join(__dirname, 'fixtures', 'ExpoAutolinkingAndroid.json'),
|
|
74
|
-
'utf8'
|
|
75
|
-
);
|
|
76
|
-
const fixtureIos = fs.readFileSync(
|
|
77
|
-
path.join(__dirname, 'fixtures', 'ExpoAutolinkingIos.json'),
|
|
78
|
-
'utf8'
|
|
79
|
-
);
|
|
80
|
-
mockSpawnAsync.mockResolvedValueOnce({
|
|
81
|
-
stdout: fixtureAndroid,
|
|
82
|
-
stderr: '',
|
|
83
|
-
status: 0,
|
|
84
|
-
signal: null,
|
|
85
|
-
output: [fixtureAndroid, ''],
|
|
86
|
-
});
|
|
87
|
-
mockSpawnAsync.mockResolvedValueOnce({
|
|
88
|
-
stdout: fixtureIos,
|
|
89
|
-
stderr: '',
|
|
90
|
-
status: 0,
|
|
91
|
-
signal: null,
|
|
92
|
-
output: [fixtureIos, ''],
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
afterEach(() => {
|
|
97
|
-
vol.reset();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should contain expo autolinking projects', async () => {
|
|
101
|
-
let sources = await getExpoAutolinkingAndroidSourcesAsync(
|
|
102
|
-
'/app',
|
|
103
|
-
await normalizeOptionsAsync('/app')
|
|
104
|
-
);
|
|
105
|
-
expect(sources).toContainEqual(
|
|
106
|
-
expect.objectContaining({
|
|
107
|
-
type: 'dir',
|
|
108
|
-
filePath: 'node_modules/expo-modules-core/android',
|
|
109
|
-
})
|
|
110
|
-
);
|
|
111
|
-
expect(sources).toMatchSnapshot();
|
|
112
|
-
|
|
113
|
-
sources = await getExpoAutolinkingIosSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
114
|
-
expect(sources).toContainEqual(
|
|
115
|
-
expect.objectContaining({ type: 'dir', filePath: 'node_modules/expo-modules-core' })
|
|
116
|
-
);
|
|
117
|
-
expect(sources).toMatchSnapshot();
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should not containt absolute path in contents', async () => {
|
|
121
|
-
let sources = await getExpoAutolinkingAndroidSourcesAsync(
|
|
122
|
-
'/app',
|
|
123
|
-
await normalizeOptionsAsync('/app')
|
|
124
|
-
);
|
|
125
|
-
for (const source of sources) {
|
|
126
|
-
if (source.type === 'contents') {
|
|
127
|
-
expect(source.contents.indexOf('/app/')).toBe(-1);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
sources = await getExpoAutolinkingIosSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
132
|
-
for (const source of sources) {
|
|
133
|
-
if (source.type === 'contents') {
|
|
134
|
-
expect(source.contents.indexOf('/app/')).toBe(-1);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
describe(getExpoConfigSourcesAsync, () => {
|
|
141
|
-
beforeAll(() => {
|
|
142
|
-
jest.doMock('fs', () => volFS);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
afterEach(() => {
|
|
146
|
-
vol.reset();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should return empty array when expo package is not installed', async () => {
|
|
150
|
-
vol.fromJSON(require('./fixtures/BareReactNative70Project.json'));
|
|
151
|
-
const mockedResolveFrom = resolveFrom.silent as jest.MockedFunction<typeof resolveFrom.silent>;
|
|
152
|
-
mockedResolveFrom.mockImplementationOnce((fromDirectory: string, moduleId: string) => {
|
|
153
|
-
const actualResolver = jest.requireActual('resolve-from').silent;
|
|
154
|
-
// To fake the case as no expo installed, trying to resolve as **nonexist/expo/config** module
|
|
155
|
-
return actualResolver(fromDirectory, 'nonexist/expo/config');
|
|
156
|
-
});
|
|
157
|
-
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
158
|
-
expect(sources.length).toBe(0);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('should contain expo config', async () => {
|
|
162
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
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'
|
|
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);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('should contain external icon file in app.json', async () => {
|
|
214
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
215
|
-
vol.mkdirSync('/app/assets');
|
|
216
|
-
vol.writeFileSync('/app/assets/icon.png', 'PNG data');
|
|
217
|
-
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
218
|
-
expect(sources).toContainEqual(
|
|
219
|
-
expect.objectContaining({
|
|
220
|
-
type: 'file',
|
|
221
|
-
filePath: './assets/icon.png',
|
|
222
|
-
})
|
|
223
|
-
);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it('should contain extra files from config plugins', async () => {
|
|
227
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
228
|
-
const config = await getConfig('/app', { skipSDKVersionRequirement: true });
|
|
229
|
-
const mockSpawnAsync = spawnAsync as jest.MockedFunction<typeof spawnAsync>;
|
|
230
|
-
const stdout = JSON.stringify({
|
|
231
|
-
config,
|
|
232
|
-
loadedModules: [
|
|
233
|
-
'node_modules/third-party/index.js',
|
|
234
|
-
'node_modules/third-party/node_modules/transitive-third-party/index.js',
|
|
235
|
-
],
|
|
236
|
-
});
|
|
237
|
-
mockSpawnAsync.mockResolvedValueOnce({
|
|
238
|
-
output: [],
|
|
239
|
-
stdout,
|
|
240
|
-
stderr: '',
|
|
241
|
-
signal: null,
|
|
242
|
-
status: 0,
|
|
243
|
-
});
|
|
244
|
-
const sources = await getExpoConfigSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
245
|
-
expect(sources).toContainEqual(
|
|
246
|
-
expect.objectContaining({
|
|
247
|
-
type: 'file',
|
|
248
|
-
filePath: 'node_modules/third-party/index.js',
|
|
249
|
-
})
|
|
250
|
-
);
|
|
251
|
-
expect(sources).toContainEqual(
|
|
252
|
-
expect.objectContaining({
|
|
253
|
-
type: 'file',
|
|
254
|
-
filePath: 'node_modules/third-party/node_modules/transitive-third-party/index.js',
|
|
255
|
-
})
|
|
256
|
-
);
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
describe('sortExpoAutolinkingConfig', () => {
|
|
261
|
-
it('should sort autolinking projects by name', () => {
|
|
262
|
-
const config = {
|
|
263
|
-
extraDependencies: { androidMavenRepos: [], iosPods: {} },
|
|
264
|
-
modules: [
|
|
265
|
-
{
|
|
266
|
-
packageName: 'expo',
|
|
267
|
-
packageVersion: '49.0.5',
|
|
268
|
-
projects: [
|
|
269
|
-
{
|
|
270
|
-
name: 'expo',
|
|
271
|
-
sourceDir: '/app/node_modules/expo/android',
|
|
272
|
-
},
|
|
273
|
-
],
|
|
274
|
-
modules: [],
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
packageName: 'expo-modules-core',
|
|
278
|
-
packageVersion: '1.5.8',
|
|
279
|
-
projects: [
|
|
280
|
-
{
|
|
281
|
-
name: 'expo-modules-core$android-annotation',
|
|
282
|
-
sourceDir: '/app/node_modules/expo-modules-core/android-annotation',
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
name: 'expo-modules-core',
|
|
286
|
-
sourceDir: '/app/node_modules/expo-modules-core/android',
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
name: 'expo-modules-core$android-annotation-processor',
|
|
290
|
-
sourceDir: '/app/node_modules/expo-modules-core/android-annotation-processor',
|
|
291
|
-
},
|
|
292
|
-
],
|
|
293
|
-
modules: [],
|
|
294
|
-
},
|
|
295
|
-
],
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
const result = sortExpoAutolinkingAndroidConfig(config);
|
|
299
|
-
expect(result.modules[1].projects[0].name).toBe('expo-modules-core');
|
|
300
|
-
expect(result.modules[1].projects[1].name).toBe('expo-modules-core$android-annotation');
|
|
301
|
-
expect(result.modules[1].projects[2].name).toBe(
|
|
302
|
-
'expo-modules-core$android-annotation-processor'
|
|
303
|
-
);
|
|
304
|
-
});
|
|
305
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { vol } from 'memfs';
|
|
2
|
-
|
|
3
|
-
import { normalizeOptionsAsync } from '../../Options';
|
|
4
|
-
import { getPatchPackageSourcesAsync } from '../PatchPackage';
|
|
5
|
-
import { getHashSourcesAsync } from '../Sourcer';
|
|
6
|
-
|
|
7
|
-
jest.mock('@expo/spawn-async');
|
|
8
|
-
jest.mock('fs');
|
|
9
|
-
jest.mock('fs/promises');
|
|
10
|
-
jest.mock('/app/package.json', () => ({}), { virtual: true });
|
|
11
|
-
|
|
12
|
-
describe(getPatchPackageSourcesAsync, () => {
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
vol.reset();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should contain patch-packages `patches` dir', async () => {
|
|
18
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
19
|
-
vol.fromJSON(require('./fixtures/PatchPackage.json'));
|
|
20
|
-
|
|
21
|
-
const sources = await getPatchPackageSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
22
|
-
expect(sources).toContainEqual(
|
|
23
|
-
expect.objectContaining({
|
|
24
|
-
type: 'dir',
|
|
25
|
-
filePath: 'patches',
|
|
26
|
-
})
|
|
27
|
-
);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('patch-package postinstall', () => {
|
|
32
|
-
it('should contain `package.json` scripts block for lifecycle patches', async () => {
|
|
33
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
34
|
-
const scriptsBlock = {
|
|
35
|
-
postinstall: 'npx patch-package',
|
|
36
|
-
};
|
|
37
|
-
jest.doMock(
|
|
38
|
-
'/app/package.json',
|
|
39
|
-
() => ({
|
|
40
|
-
name: 'app',
|
|
41
|
-
private: true,
|
|
42
|
-
scripts: scriptsBlock,
|
|
43
|
-
}),
|
|
44
|
-
{ virtual: true }
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const sources = await getHashSourcesAsync('/app', await normalizeOptionsAsync('/app'));
|
|
48
|
-
expect(sources).toContainEqual(
|
|
49
|
-
expect.objectContaining({
|
|
50
|
-
type: 'contents',
|
|
51
|
-
id: 'packageJson:scripts',
|
|
52
|
-
contents: JSON.stringify(scriptsBlock),
|
|
53
|
-
reasons: ['packageJson:scripts'],
|
|
54
|
-
})
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { vol } from 'memfs';
|
|
2
|
-
|
|
3
|
-
import { normalizeOptionsAsync } from '../../Options';
|
|
4
|
-
import { getHashSourcesAsync } from '../Sourcer';
|
|
5
|
-
|
|
6
|
-
jest.mock('@expo/spawn-async');
|
|
7
|
-
jest.mock('fs');
|
|
8
|
-
jest.mock('fs/promises');
|
|
9
|
-
|
|
10
|
-
describe(getHashSourcesAsync, () => {
|
|
11
|
-
it('should include `extraSources` from input parameter', async () => {
|
|
12
|
-
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
|
|
13
|
-
const sources = await getHashSourcesAsync(
|
|
14
|
-
'/app',
|
|
15
|
-
await normalizeOptionsAsync('/app', {
|
|
16
|
-
extraSources: [{ type: 'dir', filePath: '/app/scripts', reasons: ['extra'] }],
|
|
17
|
-
})
|
|
18
|
-
);
|
|
19
|
-
expect(sources).toContainEqual({ type: 'dir', filePath: '/app/scripts', reasons: ['extra'] });
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`getRncliAutolinkingSourcesAsync should contain rn-cli autolinking projects 1`] = `
|
|
4
|
-
[
|
|
5
|
-
{
|
|
6
|
-
"filePath": "../../node_modules/react-native-reanimated",
|
|
7
|
-
"reasons": [
|
|
8
|
-
"bareRncliAutolinking",
|
|
9
|
-
],
|
|
10
|
-
"type": "dir",
|
|
11
|
-
},
|
|
12
|
-
{
|
|
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",
|
|
15
|
-
"reasons": [
|
|
16
|
-
"bareRncliAutolinking",
|
|
17
|
-
],
|
|
18
|
-
"type": "contents",
|
|
19
|
-
},
|
|
20
|
-
]
|
|
21
|
-
`;
|