@expo/fingerprint 0.4.1 → 0.6.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.
Files changed (53) hide show
  1. package/README.md +60 -6
  2. package/bin/cli.js +26 -5
  3. package/build/sourcer/Bare.js +13 -7
  4. package/build/sourcer/Bare.js.map +1 -1
  5. package/package.json +16 -9
  6. package/.eslintignore +0 -1
  7. package/CHANGELOG.md +0 -55
  8. package/__mocks__/@expo/spawn-async.ts +0 -30
  9. package/__mocks__/fs/promises.ts +0 -17
  10. package/__mocks__/fs.ts +0 -2
  11. package/__mocks__/resolve-from.ts +0 -24
  12. package/babel.config.js +0 -6
  13. package/e2e/__tests__/__snapshots__/managed-test.ts.snap +0 -242
  14. package/e2e/__tests__/bare-test.ts +0 -72
  15. package/e2e/__tests__/managed-test.ts +0 -165
  16. package/e2e/jest.config.js +0 -11
  17. package/jest.config.js +0 -10
  18. package/scripts/createFixture.ts +0 -81
  19. package/src/Dedup.ts +0 -97
  20. package/src/Fingerprint.ts +0 -60
  21. package/src/Fingerprint.types.ts +0 -110
  22. package/src/Options.ts +0 -81
  23. package/src/Sort.ts +0 -22
  24. package/src/__tests__/Dedup-test.ts +0 -177
  25. package/src/__tests__/Fingerprint-test.ts +0 -143
  26. package/src/__tests__/Sort-test.ts +0 -56
  27. package/src/hash/Hash.ts +0 -203
  28. package/src/hash/__tests__/Hash-test.ts +0 -238
  29. package/src/index.ts +0 -2
  30. package/src/sourcer/Bare.ts +0 -115
  31. package/src/sourcer/Expo.ts +0 -223
  32. package/src/sourcer/ExpoConfigLoader.ts +0 -84
  33. package/src/sourcer/PatchPackage.ts +0 -18
  34. package/src/sourcer/Sourcer.ts +0 -58
  35. package/src/sourcer/Utils.ts +0 -62
  36. package/src/sourcer/__tests__/Bare-test.ts +0 -88
  37. package/src/sourcer/__tests__/Expo-test.ts +0 -305
  38. package/src/sourcer/__tests__/PatchPackage-test.ts +0 -57
  39. package/src/sourcer/__tests__/Sourcer-test.ts +0 -21
  40. package/src/sourcer/__tests__/Utils-test.ts +0 -41
  41. package/src/sourcer/__tests__/__snapshots__/Bare-test.ts.snap +0 -21
  42. package/src/sourcer/__tests__/__snapshots__/Expo-test.ts.snap +0 -139
  43. package/src/sourcer/__tests__/fixtures/BareReactNative70Project.json +0 -47
  44. package/src/sourcer/__tests__/fixtures/ExpoAutolinkingAndroid.json +0 -82
  45. package/src/sourcer/__tests__/fixtures/ExpoAutolinkingIos.json +0 -114
  46. package/src/sourcer/__tests__/fixtures/ExpoManaged47Project.json +0 -6
  47. package/src/sourcer/__tests__/fixtures/PatchPackage.json +0 -4
  48. package/src/sourcer/__tests__/fixtures/RncliAutoLinking.json +0 -165
  49. package/src/utils/Path.ts +0 -26
  50. package/src/utils/Profile.ts +0 -47
  51. package/src/utils/__tests__/Path-test.ts +0 -36
  52. package/src/utils/__tests__/Profile-test.ts +0 -11
  53. package/tsconfig.json +0 -9
@@ -1,72 +0,0 @@
1
- import spawnAsync from '@expo/spawn-async';
2
- import fs from 'fs/promises';
3
- import path from 'path';
4
- import rimraf from 'rimraf';
5
-
6
- import { createProjectHashAsync } from '../../src/Fingerprint';
7
-
8
- jest.mock('../../src/sourcer/ExpoConfigLoader', () => ({
9
- // Mock the getExpoConfigLoaderPath to use the built version rather than the typescript version from src
10
- getExpoConfigLoaderPath: jest.fn(() =>
11
- path.resolve(__dirname, '..', '..', 'build', 'sourcer', 'ExpoConfigLoader.js')
12
- ),
13
- }));
14
-
15
- describe('bare project test', () => {
16
- jest.setTimeout(600000);
17
- const tmpDir = require('temp-dir');
18
- const projectName = 'fingerprint-e2e-bare';
19
- const projectRoot = path.join(tmpDir, projectName);
20
-
21
- beforeAll(async () => {
22
- rimraf.sync(projectRoot);
23
- await spawnAsync('bunx', ['create-expo-app', '-t', 'bare-minimum', projectName], {
24
- stdio: 'inherit',
25
- cwd: tmpDir,
26
- });
27
- });
28
-
29
- afterAll(async () => {
30
- rimraf.sync(projectRoot);
31
- });
32
-
33
- it('should have same hash after adding js only library', async () => {
34
- const hash = await createProjectHashAsync(projectRoot);
35
- await spawnAsync('npx', ['expo', 'install', '@react-navigation/core'], {
36
- stdio: 'ignore',
37
- cwd: projectRoot,
38
- });
39
- const hash2 = await createProjectHashAsync(projectRoot);
40
- expect(hash).toBe(hash2);
41
- });
42
-
43
- it('should have different hash after adding native library', async () => {
44
- const hash = await createProjectHashAsync(projectRoot);
45
- await spawnAsync('npx', ['expo', 'install', 'react-native-reanimated'], {
46
- stdio: 'ignore',
47
- cwd: projectRoot,
48
- });
49
- const hash2 = await createProjectHashAsync(projectRoot);
50
- expect(hash).not.toBe(hash2);
51
- });
52
-
53
- it('should have different hash after changing podfile', async () => {
54
- const hash = await createProjectHashAsync(projectRoot);
55
- const filePath = path.join(projectRoot, 'ios', 'Podfile');
56
- let contents = await fs.readFile(filePath, 'utf8');
57
- contents = contents.replace(/(:fabric_enabled)\s*=>.*,$/gm, '$1 => true,');
58
- await fs.writeFile(filePath, contents);
59
- const hash2 = await createProjectHashAsync(projectRoot);
60
- expect(hash).not.toBe(hash2);
61
- });
62
-
63
- it('should have same hash for specifing android platform after changing podfile', async () => {
64
- const hash = await createProjectHashAsync(projectRoot, { platforms: ['android'] });
65
- const filePath = path.join(projectRoot, 'ios', 'Podfile');
66
- let contents = await fs.readFile(filePath, 'utf8');
67
- contents = contents.replace(/(:fabric_enabled)\s*=>.*$/gm, '$1 => false,');
68
- await fs.writeFile(filePath, contents);
69
- const hash2 = await createProjectHashAsync(projectRoot, { platforms: ['android'] });
70
- expect(hash).toBe(hash2);
71
- });
72
- });
@@ -1,165 +0,0 @@
1
- import spawnAsync from '@expo/spawn-async';
2
- import fs from 'fs/promises';
3
- import path from 'path';
4
- import rimraf from 'rimraf';
5
-
6
- import {
7
- createFingerprintAsync,
8
- createProjectHashAsync,
9
- diffFingerprintChangesAsync,
10
- } from '../../src/Fingerprint';
11
- import { normalizeOptionsAsync } from '../../src/Options';
12
- import { getHashSourcesAsync } from '../../src/sourcer/Sourcer';
13
-
14
- jest.mock('../../src/sourcer/ExpoConfigLoader', () => ({
15
- // Mock the getExpoConfigLoaderPath to use the built version rather than the typescript version from src
16
- getExpoConfigLoaderPath: jest.fn(() =>
17
- path.resolve(__dirname, '..', '..', 'build', 'sourcer', 'ExpoConfigLoader.js')
18
- ),
19
- }));
20
-
21
- describe('managed project test', () => {
22
- jest.setTimeout(600000);
23
- const tmpDir = require('temp-dir');
24
- const projectName = 'fingerprint-e2e-managed';
25
- const projectRoot = path.join(tmpDir, projectName);
26
-
27
- beforeAll(async () => {
28
- rimraf.sync(projectRoot);
29
- await spawnAsync('bunx', ['create-expo-app', '-t', 'blank', projectName], {
30
- stdio: 'inherit',
31
- cwd: tmpDir,
32
- });
33
- });
34
-
35
- afterAll(async () => {
36
- rimraf.sync(projectRoot);
37
- });
38
-
39
- it('should have same hash after adding js only library', async () => {
40
- const hash = await createProjectHashAsync(projectRoot);
41
- await spawnAsync('npx', ['expo', 'install', '@react-navigation/core'], {
42
- stdio: 'ignore',
43
- cwd: projectRoot,
44
- });
45
- const hash2 = await createProjectHashAsync(projectRoot);
46
- expect(hash).toBe(hash2);
47
- });
48
-
49
- it('should have same hash after updating js code', async () => {
50
- const hash = await createProjectHashAsync(projectRoot);
51
-
52
- const jsPath = path.join(projectRoot, 'App.js');
53
- const js = await fs.readFile(jsPath, 'utf8');
54
- await fs.writeFile(jsPath, `${js}\n// adding comments`);
55
-
56
- const hash2 = await createProjectHashAsync(projectRoot);
57
- expect(hash).toBe(hash2);
58
- });
59
-
60
- it('should have different hash after adding native library', async () => {
61
- const hash = await createProjectHashAsync(projectRoot);
62
- await spawnAsync('npx', ['expo', 'install', 'expo-updates'], {
63
- stdio: 'ignore',
64
- cwd: projectRoot,
65
- });
66
- const hash2 = await createProjectHashAsync(projectRoot);
67
- expect(hash).not.toBe(hash2);
68
- });
69
-
70
- it('should have different hash after updating `jsEngine`', async () => {
71
- const hash = await createProjectHashAsync(projectRoot);
72
-
73
- const configPath = path.join(projectRoot, 'app.json');
74
- const config = JSON.parse(await fs.readFile(configPath, 'utf8'));
75
- config.expo.jsEngine = 'hermes';
76
- await fs.writeFile(configPath, JSON.stringify(config, null, 2));
77
-
78
- const hash2 = await createProjectHashAsync(projectRoot);
79
- expect(hash).not.toBe(hash2);
80
- });
81
-
82
- it('should have different hash after updating icon file', async () => {
83
- const hash = await createProjectHashAsync(projectRoot);
84
-
85
- const iconPath = path.join(projectRoot, 'assets', 'icon.png');
86
- await fs.writeFile(iconPath, '');
87
-
88
- const hash2 = await createProjectHashAsync(projectRoot);
89
- expect(hash).not.toBe(hash2);
90
- });
91
-
92
- it('should have different hash after adding js only config-plugin', async () => {
93
- const hash = await createProjectHashAsync(projectRoot);
94
- await spawnAsync('npx', ['expo', 'install', 'expo-build-properties'], {
95
- stdio: 'ignore',
96
- cwd: projectRoot,
97
- });
98
- const hash2 = await createProjectHashAsync(projectRoot);
99
- expect(hash).not.toBe(hash2);
100
- });
101
-
102
- it('diffFingerprintChangesAsync - should return diff after adding native library', async () => {
103
- const fingerprint = await createFingerprintAsync(projectRoot);
104
- await spawnAsync('bun', ['install', '--save', '@react-native-community/netinfo@9.3.7'], {
105
- stdio: 'ignore',
106
- cwd: projectRoot,
107
- });
108
- const diff = await diffFingerprintChangesAsync(fingerprint, projectRoot);
109
- expect(diff).toMatchInlineSnapshot(`
110
- [
111
- {
112
- "filePath": "node_modules/@react-native-community/netinfo",
113
- "hash": "8a255b59e10118a8cf5c1660d12d6b2e9293ed5c",
114
- "reasons": [
115
- "bareRncliAutolinking",
116
- ],
117
- "type": "dir",
118
- },
119
- {
120
- "contents": "{"@react-native-community/netinfo":{"root":"node_modules/@react-native-community/netinfo","name":"@react-native-community/netinfo","platforms":{"ios":{"podspecPath":"node_modules/@react-native-community/netinfo/react-native-netinfo.podspec","configurations":[],"scriptPhases":[]},"android":{"sourceDir":"node_modules/@react-native-community/netinfo/android","packageImportPath":"import com.reactnativecommunity.netinfo.NetInfoPackage;","packageInstance":"new NetInfoPackage()","buildTypes":[],"componentDescriptors":[],"cmakeListsPath":"node_modules/@react-native-community/netinfo/android/build/generated/source/codegen/jni/CMakeLists.txt"}}},"expo":{"root":"node_modules/expo","name":"expo","platforms":{"ios":{"podspecPath":"node_modules/expo/Expo.podspec","configurations":[],"scriptPhases":[]},"android":{"sourceDir":"node_modules/expo/android","packageImportPath":"import expo.modules.ExpoModulesPackage;","packageInstance":"new ExpoModulesPackage()","buildTypes":[],"componentDescriptors":[],"cmakeListsPath":"node_modules/expo/android/build/generated/source/codegen/jni/CMakeLists.txt"}}}}",
121
- "hash": "ac75722bd87eb0189440be83faa2249079da5839",
122
- "id": "rncliAutolinkingConfig",
123
- "reasons": [
124
- "bareRncliAutolinking",
125
- ],
126
- "type": "contents",
127
- },
128
- ]
129
- `);
130
- });
131
- });
132
-
133
- describe(`getHashSourcesAsync - managed project`, () => {
134
- jest.setTimeout(600000);
135
- const tmpDir = require('temp-dir');
136
- const projectName = 'fingerprint-e2e-managed';
137
- const projectRoot = path.join(tmpDir, projectName);
138
-
139
- beforeAll(async () => {
140
- rimraf.sync(projectRoot);
141
- // Pin the SDK version to prevent the latest version breaking snapshots
142
- await spawnAsync('bunx', ['create-expo-app', '-t', 'blank@sdk-49', projectName], {
143
- stdio: 'inherit',
144
- cwd: tmpDir,
145
- });
146
-
147
- // Pin the `expo` package version to prevent the latest version breaking snapshots
148
- await spawnAsync('bun', ['install', '--save', 'expo@49.0.16'], {
149
- stdio: 'ignore',
150
- cwd: projectRoot,
151
- });
152
- });
153
-
154
- afterAll(async () => {
155
- rimraf.sync(projectRoot);
156
- });
157
-
158
- it('should match snapshot', async () => {
159
- const sources = await getHashSourcesAsync(
160
- projectRoot,
161
- await normalizeOptionsAsync(projectRoot)
162
- );
163
- expect(sources).toMatchSnapshot();
164
- });
165
- });
@@ -1,11 +0,0 @@
1
- const path = require('path');
2
-
3
- module.exports = {
4
- testEnvironment: 'node',
5
- preset: 'ts-jest',
6
- testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
7
- watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
8
- rootDir: path.resolve(__dirname),
9
- displayName: require('../package').name,
10
- roots: ['.'],
11
- };
package/jest.config.js DELETED
@@ -1,10 +0,0 @@
1
- const path = require('path');
2
-
3
- module.exports = {
4
- testEnvironment: 'node',
5
- testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
6
- watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
7
- rootDir: path.resolve(__dirname),
8
- displayName: require('./package').name,
9
- roots: ['__mocks__', 'src'],
10
- };
@@ -1,81 +0,0 @@
1
- /**
2
- * Tool to generate vol JSON fixture from a project.
3
- *
4
- * Usage: npx ts-node scripts/createFixture /path/to/app /path/to/output.json
5
- */
6
- import realFS from 'fs';
7
- import glob from 'glob';
8
- import { fs, vol } from 'memfs';
9
- import path from 'path';
10
-
11
- function globAsync(pattern: string, options: Parameters<typeof glob>[1]): Promise<string[]> {
12
- return new Promise((resolve, reject) => {
13
- glob(pattern, options, (err, matches) => {
14
- if (err != null) {
15
- reject(err);
16
- } else {
17
- resolve(matches);
18
- }
19
- });
20
- });
21
- }
22
-
23
- async function createFixtureAsync(targetDir: string, outputFile: string) {
24
- const files = await globAsync('**/*', {
25
- cwd: targetDir,
26
- ignore: [
27
- // binary files
28
- '**/*.{jpg,png}',
29
-
30
- // lock files
31
- '**/*.lock',
32
-
33
- // node files
34
- '**/node_modules/**',
35
-
36
- // generated files
37
- '**/build/**',
38
-
39
- // ios files
40
- 'ios/Pods/**',
41
- 'vendor/**',
42
- '**/xcuserdata/**',
43
- '**/*.xcassets/**',
44
- '**/IDEWorkspaceChecks.plist',
45
-
46
- // android files
47
- '**/*.jar',
48
- '**/*.keystore',
49
- '**/gradlew',
50
- '**/gradlew.bat',
51
- '**/gradle/wrapper/**',
52
- ],
53
- nodir: true,
54
- });
55
- for (const file of files) {
56
- const content = realFS.readFileSync(path.join(targetDir, file), 'utf8');
57
- fs.mkdirSync(path.join('/', path.dirname(file)), { recursive: true });
58
- fs.writeFileSync(path.join('/', file), content);
59
- }
60
- const resultJSON: Record<string, string | null> = {};
61
- for (const [key, value] of Object.entries(vol.toJSON())) {
62
- resultJSON[path.join('/app', path.relative('/', key))] = value;
63
- }
64
- realFS.writeFileSync(outputFile, JSON.stringify(resultJSON, null, 2));
65
- }
66
-
67
- (async () => {
68
- if (process.argv.length !== 4) {
69
- console.log(`Usage: ${path.basename(process.argv[1])} targetDir outputFile`);
70
- process.exit(1);
71
- }
72
- const targetDir = process.argv[2];
73
- const outputFile = process.argv[3];
74
-
75
- try {
76
- await createFixtureAsync(targetDir, outputFile);
77
- } catch (e) {
78
- console.error('Uncaught Error', e);
79
- process.exit(1);
80
- }
81
- })();
package/src/Dedup.ts DELETED
@@ -1,97 +0,0 @@
1
- import assert from 'assert';
2
- import path from 'path';
3
-
4
- import type { HashSource, HashSourceDir, HashSourceFile } from './Fingerprint.types';
5
-
6
- const debug = require('debug')('expo:fingerprint:Dedup');
7
-
8
- /**
9
- * Strip duplicated sources, mainly for duplicated file or dir
10
- */
11
- export function dedupSources(sources: HashSource[], projectRoot: string): HashSource[] {
12
- const newSources: HashSource[] = [];
13
- for (const source of sources) {
14
- const [duplicatedItemIndex, shouldSwapSource] = findDuplicatedSourceIndex(
15
- newSources,
16
- source,
17
- projectRoot
18
- );
19
- if (duplicatedItemIndex >= 0) {
20
- const duplicatedItem = newSources[duplicatedItemIndex];
21
- debug(`Skipping duplicated source: ${source}`);
22
- if (shouldSwapSource) {
23
- newSources[duplicatedItemIndex] = {
24
- ...source,
25
- reasons: [...source.reasons, ...duplicatedItem.reasons],
26
- };
27
- } else {
28
- duplicatedItem.reasons.push(...source.reasons);
29
- }
30
- } else {
31
- newSources.push(source);
32
- }
33
- }
34
-
35
- return newSources;
36
- }
37
-
38
- /**
39
- * When two sources are duplicated, merge `src`'s reasons into `dst`
40
- */
41
- export function mergeSourceWithReasons(dst: HashSource, src: HashSource): HashSource {
42
- return dst;
43
- }
44
-
45
- /**
46
- * Find the duplicated `source` in `newSources`
47
- * @return tuple of [duplicatedItemIndexInNewSources, shouldSwapSource]
48
- */
49
- function findDuplicatedSourceIndex(
50
- newSources: HashSource[],
51
- source: HashSource,
52
- projectRoot: string
53
- ): [number, boolean] {
54
- let shouldSwapSource = false;
55
- if (source.type === 'contents') {
56
- return [
57
- newSources.findIndex((item) => item.type === source.type && item.id === source.id) ?? null,
58
- shouldSwapSource,
59
- ];
60
- }
61
-
62
- for (const [index, existingSource] of newSources.entries()) {
63
- if (existingSource.type === 'contents') {
64
- continue;
65
- }
66
- if (isDescendant(source, existingSource, projectRoot)) {
67
- return [index, shouldSwapSource];
68
- }
69
- // If the new source is ancestor of existing source, replace swap the existing source with the new source
70
- if (isDescendant(existingSource, source, projectRoot)) {
71
- shouldSwapSource = true;
72
- return [index, shouldSwapSource];
73
- }
74
- }
75
- return [-1, shouldSwapSource];
76
- }
77
-
78
- function isDescendant(
79
- from: HashSourceDir | HashSourceFile,
80
- to: HashSourceDir | HashSourceFile,
81
- projectRoot: string
82
- ): boolean {
83
- if (from === to) {
84
- return true;
85
- }
86
-
87
- const fromPath = path.join(projectRoot, from.filePath);
88
- const toPath = path.join(projectRoot, to.filePath);
89
- const result = path.relative(fromPath, toPath).match(/^[./\\/]*$/) != null;
90
- if (result) {
91
- assert(
92
- !(to.type === 'file' && from.type === 'dir'),
93
- `Unexpected case which a dir is a descendant of a file - from[${fromPath}] to[${toPath}]`
94
- );
95
- }
96
- return result;
97
- }
@@ -1,60 +0,0 @@
1
- import { dedupSources } from './Dedup';
2
- import type { Fingerprint, FingerprintSource, Options } from './Fingerprint.types';
3
- import { normalizeOptionsAsync } from './Options';
4
- import { sortSources } from './Sort';
5
- import { createFingerprintFromSourcesAsync } from './hash/Hash';
6
- import { getHashSourcesAsync } from './sourcer/Sourcer';
7
-
8
- /**
9
- * Create a fingerprint from project
10
- */
11
- export async function createFingerprintAsync(
12
- projectRoot: string,
13
- options?: Options
14
- ): Promise<Fingerprint> {
15
- const opts = await normalizeOptionsAsync(projectRoot, options);
16
- const sources = await getHashSourcesAsync(projectRoot, opts);
17
- const normalizedSources = sortSources(dedupSources(sources, projectRoot));
18
- const fingerprint = await createFingerprintFromSourcesAsync(normalizedSources, projectRoot, opts);
19
- return fingerprint;
20
- }
21
-
22
- /**
23
- * Create a native hash value from project
24
- */
25
- export async function createProjectHashAsync(
26
- projectRoot: string,
27
- options?: Options
28
- ): Promise<string> {
29
- const fingerprint = await createFingerprintAsync(projectRoot, options);
30
- return fingerprint.hash;
31
- }
32
-
33
- /**
34
- * Differentiate given `fingerprint` with the current project fingerprint state
35
- */
36
- export async function diffFingerprintChangesAsync(
37
- fingerprint: Fingerprint,
38
- projectRoot: string,
39
- options?: Options
40
- ): Promise<FingerprintSource[]> {
41
- const newFingerprint = await createFingerprintAsync(projectRoot, options);
42
- if (fingerprint.hash === newFingerprint.hash) {
43
- return [];
44
- }
45
- return diffFingerprints(fingerprint, newFingerprint);
46
- }
47
-
48
- /**
49
- * Differentiate two fingerprints
50
- */
51
- export function diffFingerprints(
52
- fingerprint1: Fingerprint,
53
- fingerprint2: Fingerprint
54
- ): FingerprintSource[] {
55
- return fingerprint2.sources.filter((newItem) => {
56
- return !fingerprint1.sources.find(
57
- (item) => item.type === newItem.type && item.hash === newItem.hash
58
- );
59
- });
60
- }
@@ -1,110 +0,0 @@
1
- export type FingerprintSource = HashSource & {
2
- /**
3
- * Hash value of the `source`.
4
- * If the source is excluding by `Options.dirExcludes`, the value will be null.
5
- */
6
- hash: string | null;
7
- };
8
-
9
- export interface Fingerprint {
10
- /**
11
- * Sources and their hash values to generate a fingerprint
12
- */
13
- sources: FingerprintSource[];
14
-
15
- /**
16
- * The final hash value of the whole fingerprint
17
- */
18
- hash: string;
19
- }
20
-
21
- export type Platform = 'android' | 'ios';
22
-
23
- export interface Options {
24
- /**
25
- * Only get native files from the given platforms. Default is `['android', 'ios']`.
26
- */
27
- platforms?: Platform[];
28
-
29
- /**
30
- * I/O concurrent limit. Default is the number of CPU core.
31
- */
32
- concurrentIoLimit?: number;
33
-
34
- /**
35
- * The algorithm passing to `crypto.createHash()`. Default is `'sha1'`.
36
- */
37
- hashAlgorithm?: string;
38
-
39
- /**
40
- * Excludes directories from hashing. This supported pattern is as `glob()`.
41
- * Default is `['android/build', 'android/app/build', 'android/app/.cxx', 'ios/Pods']`.
42
- * @deprecated Use `ignorePaths` instead.
43
- */
44
- dirExcludes?: string[];
45
-
46
- /**
47
- * Ignore files and directories from hashing. This supported pattern is as `glob()`.
48
- *
49
- * Please note that the pattern matching is slightly different from gitignore. For example, we don't support partial matching where `build` does not match `android/build`. You should use `'**' + '/build'` instead.
50
- * @see [minimatch implementations](https://github.com/isaacs/minimatch#comparisons-to-other-fnmatchglob-implementations) for more reference.
51
- *
52
- * Besides this `ignorePaths`, fingerprint comes with implicit default ignorePaths defined in `Options.DEFAULT_IGNORE_PATHS`.
53
- * If you want to override the default ignorePaths, use `!` prefix.
54
- */
55
- ignorePaths?: string[];
56
-
57
- /**
58
- * Additional sources for hashing.
59
- */
60
- extraSources?: HashSource[];
61
- }
62
-
63
- //#region internal types
64
-
65
- export interface NormalizedOptions extends Options {
66
- platforms: NonNullable<Options['platforms']>;
67
- concurrentIoLimit: NonNullable<Options['concurrentIoLimit']>;
68
- hashAlgorithm: NonNullable<Options['hashAlgorithm']>;
69
- ignorePaths: NonNullable<Options['ignorePaths']>;
70
- }
71
-
72
- export interface HashSourceFile {
73
- type: 'file';
74
- filePath: string;
75
-
76
- /**
77
- * Reasons of this source coming from
78
- */
79
- reasons: string[];
80
- }
81
-
82
- export interface HashSourceDir {
83
- type: 'dir';
84
- filePath: string;
85
-
86
- /**
87
- * Reasons of this source coming from
88
- */
89
- reasons: string[];
90
- }
91
-
92
- export interface HashSourceContents {
93
- type: 'contents';
94
- id: string;
95
- contents: string | Buffer;
96
-
97
- /**
98
- * Reasons of this source coming from
99
- */
100
- reasons: string[];
101
- }
102
-
103
- export type HashSource = HashSourceFile | HashSourceDir | HashSourceContents;
104
-
105
- export interface HashResult {
106
- id: string;
107
- hex: string;
108
- }
109
-
110
- //#endregion
package/src/Options.ts DELETED
@@ -1,81 +0,0 @@
1
- import fs from 'fs/promises';
2
- import os from 'os';
3
- import path from 'path';
4
-
5
- import type { NormalizedOptions, Options } from './Fingerprint.types';
6
-
7
- export const FINGERPRINT_IGNORE_FILENAME = '.fingerprintignore';
8
-
9
- export const DEFAULT_IGNORE_PATHS = [
10
- FINGERPRINT_IGNORE_FILENAME,
11
- '**/android/build/**/*',
12
- '**/android/app/build/**/*',
13
- '**/android/app/.cxx/**/*',
14
- '**/ios/Pods/**/*',
15
-
16
- // Ignore all expo configs because we will read expo config in a HashSourceContents already
17
- 'app.config.ts',
18
- 'app.config.js',
19
- 'app.config.json',
20
- 'app.json',
21
-
22
- // Ignore default javascript files when calling `getConfig()`
23
- '**/node_modules/@babel/**/*',
24
- '**/node_modules/@expo/**/*',
25
- '**/node_modules/@jridgewell/**/*',
26
- '**/node_modules/expo/config.js',
27
- '**/node_modules/expo/config-plugins.js',
28
- `**/node_modules/{${[
29
- 'debug',
30
- 'escape-string-regexp',
31
- 'getenv',
32
- 'graceful-fs',
33
- 'has-flag',
34
- 'imurmurhash',
35
- 'js-tokens',
36
- 'json5',
37
- 'lines-and-columns',
38
- 'require-from-string',
39
- 'resolve-from',
40
- 'signal-exit',
41
- 'sucrase',
42
- 'supports-color',
43
- 'ts-interface-checker',
44
- 'write-file-atomic',
45
- ].join(',')}}/**/*`,
46
- ];
47
-
48
- export async function normalizeOptionsAsync(
49
- projectRoot: string,
50
- options?: Options
51
- ): Promise<NormalizedOptions> {
52
- return {
53
- ...options,
54
- platforms: options?.platforms ?? ['android', 'ios'],
55
- concurrentIoLimit: options?.concurrentIoLimit ?? os.cpus().length,
56
- hashAlgorithm: options?.hashAlgorithm ?? 'sha1',
57
- ignorePaths: await collectIgnorePathsAsync(projectRoot, options),
58
- };
59
- }
60
-
61
- async function collectIgnorePathsAsync(projectRoot: string, options?: Options): Promise<string[]> {
62
- const ignorePaths = [
63
- ...DEFAULT_IGNORE_PATHS,
64
- ...(options?.ignorePaths ?? []),
65
- ...(options?.dirExcludes?.map((dirExclude) => `${dirExclude}/**/*`) ?? []),
66
- ];
67
-
68
- const fingerprintIgnorePath = path.join(projectRoot, FINGERPRINT_IGNORE_FILENAME);
69
- try {
70
- const fingerprintIgnore = await fs.readFile(fingerprintIgnorePath, 'utf8');
71
- const fingerprintIgnoreLines = fingerprintIgnore.split('\n');
72
- for (const line of fingerprintIgnoreLines) {
73
- const trimmedLine = line.trim();
74
- if (trimmedLine) {
75
- ignorePaths.push(trimmedLine);
76
- }
77
- }
78
- } catch {}
79
-
80
- return ignorePaths;
81
- }