From c47325303d6debc34290423837a2ea024c355109 Mon Sep 17 00:00:00 2001 From: Eric Samelson Date: Thu, 5 Nov 2020 18:37:09 -0800 Subject: [PATCH 1/3] [config] add getPublicExpoConfig method and tests --- packages/config/src/Config.ts | 23 ++++++ packages/config/src/Config.types.ts | 5 ++ packages/config/src/__tests__/Config-test.js | 84 +++++++++++++++++++- 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/packages/config/src/Config.ts b/packages/config/src/Config.ts index a15a8f59d2..9af560b86f 100644 --- a/packages/config/src/Config.ts +++ b/packages/config/src/Config.ts @@ -15,6 +15,7 @@ import { Platform, ProjectConfig, ProjectTarget, + PublicExpoConfig, WriteConfigOptions, } from './Config.types'; import { ConfigError } from './Errors'; @@ -149,6 +150,28 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): return fillAndReturnConfig(staticConfig || {}, null); } +/** + * Evaluate and return the public-facing portions of the Expo config for a project. + * The resulting config should be suitable for hosting or embedding in a publicly readable location. + * + * @param projectRoot the root folder containing all of your application code + * @param options enforce criteria for a project config + */ +export function getPublicExpoConfig( + projectRoot: string, + options: GetConfigOptions = {} +): PublicExpoConfig { + const { exp } = getConfig(projectRoot, options); + delete exp.hooks; + if (exp.ios?.config) { + delete exp.ios.config; + } + if (exp.android?.config) { + delete exp.android.config; + } + return exp; +} + export function getPackageJson( projectRoot: string, config: Partial> = {} diff --git a/packages/config/src/Config.types.ts b/packages/config/src/Config.types.ts index 449386f3e9..f03f71e64e 100644 --- a/packages/config/src/Config.types.ts +++ b/packages/config/src/Config.types.ts @@ -60,6 +60,11 @@ export type HookArguments = { log: (msg: any) => void; }; +export type PublicExpoConfig = Omit & { + ios?: Omit; + android?: Omit; +}; + export type ExpoAppManifest = ExpoConfig & { sdkVersion: string; bundledAssets?: string[]; diff --git a/packages/config/src/__tests__/Config-test.js b/packages/config/src/__tests__/Config-test.js index 1a710ab032..f278028f56 100644 --- a/packages/config/src/__tests__/Config-test.js +++ b/packages/config/src/__tests__/Config-test.js @@ -1,6 +1,11 @@ import { vol } from 'memfs'; -import { getConfig, getProjectConfigDescription, readConfigJson } from '../Config'; +import { + getConfig, + getProjectConfigDescription, + getPublicExpoConfig, + readConfigJson, +} from '../Config'; jest.mock('fs'); jest.mock('resolve-from'); @@ -37,6 +42,83 @@ describe(`getProjectConfigDescription`, () => { }); }); +describe('getPublicExpoConfig', () => { + const appJsonWithPrivateData = { + name: 'testing 123', + version: '0.1.0', + slug: 'testing-123', + sdkVersion: '100.0.0', + hooks: { + postPublish: [], + }, + android: { + config: { + googleMaps: { + apiKey: 'test-key', + }, + }, + versionCode: 1, + }, + ios: { + config: { + googleMapsApiKey: 'test-key', + }, + buildNumber: '1.0', + }, + }; + + const appJsonNoPrivateData = { + name: 'testing 123', + version: '0.1.0', + slug: 'testing-123', + sdkVersion: '100.0.0', + ios: { + buildNumber: '1.0', + }, + }; + + beforeAll(() => { + const packageJson = JSON.stringify( + { + name: 'testing123', + version: '0.1.0', + description: 'fake description', + main: 'index.js', + }, + null, + 2 + ); + + vol.fromJSON({ + '/private-data/package.json': packageJson, + '/private-data/app.json': JSON.stringify({ expo: appJsonWithPrivateData }), + '/no-private-data/package.json': packageJson, + '/no-private-data/app.json': JSON.stringify({ expo: appJsonNoPrivateData }), + }); + }); + + afterAll(() => vol.reset()); + + it('removes only private data from the config', () => { + const exp = getPublicExpoConfig('/private-data'); + + expect(exp.hooks).toBeUndefined(); + + expect(exp.ios).toBeDefined(); + expect(exp.ios.buildNumber).toEqual(appJsonWithPrivateData.ios.buildNumber); + expect(exp.ios.config).toBeUndefined(); + + expect(exp.android).toBeDefined(); + expect(exp.android.versionCode).toEqual(appJsonWithPrivateData.android.versionCode); + expect(exp.android.config).toBeUndefined(); + }); + + it('does not remove properties from a config with no private data', () => { + const exp = getPublicExpoConfig('/no-private-data'); + expect(exp).toMatchObject(appJsonNoPrivateData); + }); +}); + describe('readConfigJson', () => { describe('sdkVersion', () => { beforeAll(() => { From 186c7314464d365053e90357ed8c8537c505cbac Mon Sep 17 00:00:00 2001 From: Eric Samelson Date: Mon, 9 Nov 2020 13:27:34 -0800 Subject: [PATCH 2/3] use options parameter instead of separate function, remove new type --- packages/config/src/Config.ts | 41 ++++++++------------ packages/config/src/Config.types.ts | 6 +-- packages/config/src/__tests__/Config-test.js | 13 ++----- 3 files changed, 22 insertions(+), 38 deletions(-) diff --git a/packages/config/src/Config.ts b/packages/config/src/Config.ts index 9af560b86f..a743183acf 100644 --- a/packages/config/src/Config.ts +++ b/packages/config/src/Config.ts @@ -15,7 +15,6 @@ import { Platform, ProjectConfig, ProjectTarget, - PublicExpoConfig, WriteConfigOptions, } from './Config.types'; import { ConfigError } from './Errors'; @@ -75,6 +74,8 @@ export function getConfigWithMods(projectRoot: string, options?: GetConfigOption * If a function is exported from the `app.config.js` then a partial config will be passed as an argument. * The partial config is composed from any existing app.json, and certain fields from the `package.json` like name and description. * + * If options.omitPrivateExpoConfig is true, the Expo config will include only public-facing portions. + * The resulting config should be suitable for hosting or embedding in a publicly readable location. * * **Example** * ```js @@ -109,7 +110,7 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): ); function fillAndReturnConfig(config: SplitConfigs, dynamicConfigObjectType: string | null) { - return { + const configWithDefaultValues = { ...ensureConfigHasDefaultValues( projectRoot, config.expo, @@ -122,6 +123,20 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): dynamicConfigPath: paths.dynamicConfigPath, staticConfigPath: paths.staticConfigPath, }; + + if (options.omitPrivateExpoConfig) { + if (configWithDefaultValues.exp.hooks) { + delete configWithDefaultValues.exp.hooks; + } + if (configWithDefaultValues.exp.ios?.config) { + delete configWithDefaultValues.exp.ios.config; + } + if (configWithDefaultValues.exp.android?.config) { + delete configWithDefaultValues.exp.android.config; + } + } + + return configWithDefaultValues; } // Fill in the static config @@ -150,28 +165,6 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): return fillAndReturnConfig(staticConfig || {}, null); } -/** - * Evaluate and return the public-facing portions of the Expo config for a project. - * The resulting config should be suitable for hosting or embedding in a publicly readable location. - * - * @param projectRoot the root folder containing all of your application code - * @param options enforce criteria for a project config - */ -export function getPublicExpoConfig( - projectRoot: string, - options: GetConfigOptions = {} -): PublicExpoConfig { - const { exp } = getConfig(projectRoot, options); - delete exp.hooks; - if (exp.ios?.config) { - delete exp.ios.config; - } - if (exp.android?.config) { - delete exp.android.config; - } - return exp; -} - export function getPackageJson( projectRoot: string, config: Partial> = {} diff --git a/packages/config/src/Config.types.ts b/packages/config/src/Config.types.ts index f03f71e64e..700eb44d43 100644 --- a/packages/config/src/Config.types.ts +++ b/packages/config/src/Config.types.ts @@ -60,11 +60,6 @@ export type HookArguments = { log: (msg: any) => void; }; -export type PublicExpoConfig = Omit & { - ios?: Omit; - android?: Omit; -}; - export type ExpoAppManifest = ExpoConfig & { sdkVersion: string; bundledAssets?: string[]; @@ -142,6 +137,7 @@ export type ConfigContext = { }; export type GetConfigOptions = { + omitPrivateExpoConfig?: boolean; skipSDKVersionRequirement?: boolean; strict?: boolean; }; diff --git a/packages/config/src/__tests__/Config-test.js b/packages/config/src/__tests__/Config-test.js index f278028f56..6febe0b1c0 100644 --- a/packages/config/src/__tests__/Config-test.js +++ b/packages/config/src/__tests__/Config-test.js @@ -1,11 +1,6 @@ import { vol } from 'memfs'; -import { - getConfig, - getProjectConfigDescription, - getPublicExpoConfig, - readConfigJson, -} from '../Config'; +import { getConfig, getProjectConfigDescription, readConfigJson } from '../Config'; jest.mock('fs'); jest.mock('resolve-from'); @@ -42,7 +37,7 @@ describe(`getProjectConfigDescription`, () => { }); }); -describe('getPublicExpoConfig', () => { +describe('getConfig with omitPrivateExpoConfig', () => { const appJsonWithPrivateData = { name: 'testing 123', version: '0.1.0', @@ -100,7 +95,7 @@ describe('getPublicExpoConfig', () => { afterAll(() => vol.reset()); it('removes only private data from the config', () => { - const exp = getPublicExpoConfig('/private-data'); + const { exp } = getConfig('/private-data', { omitPrivateExpoConfig: true }); expect(exp.hooks).toBeUndefined(); @@ -114,7 +109,7 @@ describe('getPublicExpoConfig', () => { }); it('does not remove properties from a config with no private data', () => { - const exp = getPublicExpoConfig('/no-private-data'); + const { exp } = getConfig('/no-private-data', { omitPrivateExpoConfig: true }); expect(exp).toMatchObject(appJsonNoPrivateData); }); }); From 788ac81dc5845f9f7856b6a91ea931f0e6c83d65 Mon Sep 17 00:00:00 2001 From: Eric Samelson Date: Mon, 9 Nov 2020 14:33:45 -0800 Subject: [PATCH 3/3] isPublicConfig, edited comment --- packages/config/src/Config.ts | 4 ++-- packages/config/src/Config.types.ts | 2 +- packages/config/src/__tests__/Config-test.js | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/config/src/Config.ts b/packages/config/src/Config.ts index a743183acf..c7cc1eca40 100644 --- a/packages/config/src/Config.ts +++ b/packages/config/src/Config.ts @@ -74,7 +74,7 @@ export function getConfigWithMods(projectRoot: string, options?: GetConfigOption * If a function is exported from the `app.config.js` then a partial config will be passed as an argument. * The partial config is composed from any existing app.json, and certain fields from the `package.json` like name and description. * - * If options.omitPrivateExpoConfig is true, the Expo config will include only public-facing portions. + * If options.isPublicConfig is true, the Expo config will include only public-facing options (omitting private keys). * The resulting config should be suitable for hosting or embedding in a publicly readable location. * * **Example** @@ -124,7 +124,7 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): staticConfigPath: paths.staticConfigPath, }; - if (options.omitPrivateExpoConfig) { + if (options.isPublicConfig) { if (configWithDefaultValues.exp.hooks) { delete configWithDefaultValues.exp.hooks; } diff --git a/packages/config/src/Config.types.ts b/packages/config/src/Config.types.ts index 700eb44d43..e92dcff3a9 100644 --- a/packages/config/src/Config.types.ts +++ b/packages/config/src/Config.types.ts @@ -137,7 +137,7 @@ export type ConfigContext = { }; export type GetConfigOptions = { - omitPrivateExpoConfig?: boolean; + isPublicConfig?: boolean; skipSDKVersionRequirement?: boolean; strict?: boolean; }; diff --git a/packages/config/src/__tests__/Config-test.js b/packages/config/src/__tests__/Config-test.js index 6febe0b1c0..b7313089b5 100644 --- a/packages/config/src/__tests__/Config-test.js +++ b/packages/config/src/__tests__/Config-test.js @@ -37,7 +37,7 @@ describe(`getProjectConfigDescription`, () => { }); }); -describe('getConfig with omitPrivateExpoConfig', () => { +describe('getConfig public config', () => { const appJsonWithPrivateData = { name: 'testing 123', version: '0.1.0', @@ -95,7 +95,7 @@ describe('getConfig with omitPrivateExpoConfig', () => { afterAll(() => vol.reset()); it('removes only private data from the config', () => { - const { exp } = getConfig('/private-data', { omitPrivateExpoConfig: true }); + const { exp } = getConfig('/private-data', { isPublicConfig: true }); expect(exp.hooks).toBeUndefined(); @@ -109,7 +109,7 @@ describe('getConfig with omitPrivateExpoConfig', () => { }); it('does not remove properties from a config with no private data', () => { - const { exp } = getConfig('/no-private-data', { omitPrivateExpoConfig: true }); + const { exp } = getConfig('/no-private-data', { isPublicConfig: true }); expect(exp).toMatchObject(appJsonNoPrivateData); }); });