@callstack/brownfield-cli 3.13.0 → 3.13.2
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 +16 -0
- package/dist/brownfield/commands/packageAndroid.d.ts.map +1 -1
- package/dist/brownfield/commands/packageAndroid.js +3 -1
- package/dist/brownfield/commands/packageIos.d.ts.map +1 -1
- package/dist/brownfield/commands/packageIos.js +4 -2
- package/dist/brownfield/commands/publishAndroid.d.ts.map +1 -1
- package/dist/brownfield/commands/publishAndroid.js +3 -1
- package/dist/brownfield/utils/project.d.ts.map +1 -1
- package/dist/brownfield/utils/project.js +20 -9
- package/dist/brownie/config.js +1 -1
- package/dist/config.d.ts +4 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -7
- package/dist/expoPluginConfig.d.ts +74 -0
- package/dist/expoPluginConfig.d.ts.map +1 -0
- package/dist/expoPluginConfig.js +103 -0
- package/dist/types.d.ts +92 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +14 -7
- package/schema.json +195 -0
- package/src/brownfield/commands/packageAndroid.ts +4 -1
- package/src/brownfield/commands/packageIos.ts +5 -3
- package/src/brownfield/commands/publishAndroid.ts +4 -1
- package/src/brownfield/utils/project.ts +33 -14
- package/src/brownie/config.ts +1 -1
- package/src/config.ts +12 -8
- package/src/expoPluginConfig.ts +195 -0
- package/src/types.ts +109 -3
package/schema.json
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$ref": "#/definitions/BrownfieldConfig",
|
|
3
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
|
+
"definitions": {
|
|
5
|
+
"BrownfieldAndroidConfig": {
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {
|
|
8
|
+
"expo": {
|
|
9
|
+
"$ref": "#/definitions/BrownfieldExpoAndroidConfig",
|
|
10
|
+
"description": "Expo config plugin options for Android Expo prebuild phase."
|
|
11
|
+
},
|
|
12
|
+
"moduleName": {
|
|
13
|
+
"description": "AAR module name.",
|
|
14
|
+
"type": "string"
|
|
15
|
+
},
|
|
16
|
+
"variant": {
|
|
17
|
+
"description": "Your app's build variant, which is constructed from build type and product flavor, e.g. 'debug' or 'freeRelease'.",
|
|
18
|
+
"type": "string"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"type": "object"
|
|
22
|
+
},
|
|
23
|
+
"BrownfieldConfig": {
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"properties": {
|
|
26
|
+
"$schema": {
|
|
27
|
+
"type": "string"
|
|
28
|
+
},
|
|
29
|
+
"android": {
|
|
30
|
+
"$ref": "#/definitions/BrownfieldAndroidConfig",
|
|
31
|
+
"description": "Brownfield Android configuration."
|
|
32
|
+
},
|
|
33
|
+
"brownie": {
|
|
34
|
+
"$ref": "#/definitions/BrownieConfig",
|
|
35
|
+
"description": "Brownie (state library) configuration."
|
|
36
|
+
},
|
|
37
|
+
"ios": {
|
|
38
|
+
"$ref": "#/definitions/BrownfieldIosConfig",
|
|
39
|
+
"description": "Brownfield iOS configuration."
|
|
40
|
+
},
|
|
41
|
+
"verbose": {
|
|
42
|
+
"description": "Enables verbose CLI logging.",
|
|
43
|
+
"type": "boolean"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"type": "object"
|
|
47
|
+
},
|
|
48
|
+
"BrownfieldExpoAndroidConfig": {
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"description": "Expo config plugin options for Android prebuild scaffolding.",
|
|
51
|
+
"properties": {
|
|
52
|
+
"artifactId": {
|
|
53
|
+
"description": "Maven artifact ID used when publishing the AAR.",
|
|
54
|
+
"type": "string"
|
|
55
|
+
},
|
|
56
|
+
"compileSdkVersion": {
|
|
57
|
+
"description": "Compile SDK version for the Android library.",
|
|
58
|
+
"type": "number"
|
|
59
|
+
},
|
|
60
|
+
"groupId": {
|
|
61
|
+
"description": "Maven group ID used when publishing the AAR.",
|
|
62
|
+
"type": "string"
|
|
63
|
+
},
|
|
64
|
+
"minSdkVersion": {
|
|
65
|
+
"description": "Minimum SDK version for the Android library.",
|
|
66
|
+
"type": "number"
|
|
67
|
+
},
|
|
68
|
+
"packageName": {
|
|
69
|
+
"description": "The package name for the Android library module.",
|
|
70
|
+
"type": "string"
|
|
71
|
+
},
|
|
72
|
+
"targetSdkVersion": {
|
|
73
|
+
"description": "Target SDK version for the Android library.",
|
|
74
|
+
"type": "number"
|
|
75
|
+
},
|
|
76
|
+
"useLocalGradlePlugin": {
|
|
77
|
+
"description": "When true, load the Brownfield Gradle plugin from `@callstack/react-native-brownfield/gradle-plugin/brownfield` via `includeBuild` instead of adding the Maven classpath dependency. Disabled by default.",
|
|
78
|
+
"type": "boolean"
|
|
79
|
+
},
|
|
80
|
+
"version": {
|
|
81
|
+
"description": "Maven version used when publishing the AAR.",
|
|
82
|
+
"type": "string"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"type": "object"
|
|
86
|
+
},
|
|
87
|
+
"BrownfieldExpoIosConfig": {
|
|
88
|
+
"additionalProperties": false,
|
|
89
|
+
"description": "Expo config plugin options for iOS prebuild scaffolding.",
|
|
90
|
+
"properties": {
|
|
91
|
+
"buildSettings": {
|
|
92
|
+
"additionalProperties": {
|
|
93
|
+
"type": ["string", "boolean", "number"]
|
|
94
|
+
},
|
|
95
|
+
"description": "Custom build settings applied when building the framework.",
|
|
96
|
+
"type": "object"
|
|
97
|
+
},
|
|
98
|
+
"bundleIdentifier": {
|
|
99
|
+
"description": "The bundle identifier for the framework.",
|
|
100
|
+
"type": "string"
|
|
101
|
+
},
|
|
102
|
+
"deploymentTarget": {
|
|
103
|
+
"description": "Minimum iOS deployment target for the generated framework.",
|
|
104
|
+
"type": "string"
|
|
105
|
+
},
|
|
106
|
+
"frameworkVersion": {
|
|
107
|
+
"description": "Framework version used for Apple build settings.",
|
|
108
|
+
"type": "string"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"type": "object"
|
|
112
|
+
},
|
|
113
|
+
"BrownfieldIosConfig": {
|
|
114
|
+
"additionalProperties": false,
|
|
115
|
+
"properties": {
|
|
116
|
+
"addSpmPackage": {
|
|
117
|
+
"description": "When set, generate a local Swift Package Manager manifest next to the packaged XCFramework outputs.",
|
|
118
|
+
"type": "boolean"
|
|
119
|
+
},
|
|
120
|
+
"buildFolder": {
|
|
121
|
+
"description": "Location for iOS build artifacts.",
|
|
122
|
+
"type": "string"
|
|
123
|
+
},
|
|
124
|
+
"configuration": {
|
|
125
|
+
"description": "Xcode scheme configuration (case sensitive).",
|
|
126
|
+
"type": "string"
|
|
127
|
+
},
|
|
128
|
+
"destination": {
|
|
129
|
+
"description": "Destination(s) for the build. You can pass multiple destinations as separate values or repeated use of the flag. Values can be either: \"simulator\", \"device\" or destinations supported by \"xcodebuild -destination\" flag, e.g. \"generic/platform=iOS\".",
|
|
130
|
+
"items": {
|
|
131
|
+
"type": "string"
|
|
132
|
+
},
|
|
133
|
+
"type": "array"
|
|
134
|
+
},
|
|
135
|
+
"expo": {
|
|
136
|
+
"$ref": "#/definitions/BrownfieldExpoIosConfig",
|
|
137
|
+
"description": "Expo config plugin options for iOS Expo prebuild phase."
|
|
138
|
+
},
|
|
139
|
+
"exportExtraParams": {
|
|
140
|
+
"description": "Custom xcodebuild export archive parameters.",
|
|
141
|
+
"items": {
|
|
142
|
+
"type": "string"
|
|
143
|
+
},
|
|
144
|
+
"type": "array"
|
|
145
|
+
},
|
|
146
|
+
"exportOptionsPlist": {
|
|
147
|
+
"description": "Export options file name for archiving (default: ExportOptions.plist).",
|
|
148
|
+
"type": "string"
|
|
149
|
+
},
|
|
150
|
+
"extraParams": {
|
|
151
|
+
"description": "Custom xcodebuild parameters.",
|
|
152
|
+
"items": {
|
|
153
|
+
"type": "string"
|
|
154
|
+
},
|
|
155
|
+
"type": "array"
|
|
156
|
+
},
|
|
157
|
+
"installPods": {
|
|
158
|
+
"description": "Whether to install CocoaPods.",
|
|
159
|
+
"type": "boolean"
|
|
160
|
+
},
|
|
161
|
+
"newArch": {
|
|
162
|
+
"description": "Whether to build in new architecture.",
|
|
163
|
+
"type": "boolean"
|
|
164
|
+
},
|
|
165
|
+
"scheme": {
|
|
166
|
+
"description": "Xcode scheme to use.",
|
|
167
|
+
"type": "string"
|
|
168
|
+
},
|
|
169
|
+
"target": {
|
|
170
|
+
"description": "Xcode target to use.",
|
|
171
|
+
"type": "string"
|
|
172
|
+
},
|
|
173
|
+
"usePrebuiltRnCore": {
|
|
174
|
+
"description": "Set when `--use-prebuilt-rn-core` is passed; omitted when the flag is absent (Rock applies RN version defaults).",
|
|
175
|
+
"type": "boolean"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"type": "object"
|
|
179
|
+
},
|
|
180
|
+
"BrownieConfig": {
|
|
181
|
+
"additionalProperties": false,
|
|
182
|
+
"properties": {
|
|
183
|
+
"kotlin": {
|
|
184
|
+
"description": "The output path to generate Kotlin Brownie store files at.",
|
|
185
|
+
"type": "string"
|
|
186
|
+
},
|
|
187
|
+
"kotlinPackageName": {
|
|
188
|
+
"description": "The package name for the Kotlin source code.",
|
|
189
|
+
"type": "string"
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"type": "object"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
curryOptions,
|
|
13
13
|
} from '../../shared/index.js';
|
|
14
14
|
import { runExpoPrebuildIfNeeded } from '../utils/expo.js';
|
|
15
|
+
import { findProjectRoot } from '../utils/paths.js';
|
|
15
16
|
import { getProjectInfo } from '../utils/project.js';
|
|
16
17
|
import { runBrownieCodegenIfApplicable } from '../../brownie/helpers/runBrownieCodegenIfApplicable.js';
|
|
17
18
|
import { runNavigationCodegenIfApplicable } from '../../navigation/helpers/runNavigationCodegenIfApplicable.js';
|
|
@@ -23,13 +24,15 @@ export const packageAndroidCommand = curryOptions(
|
|
|
23
24
|
).action(
|
|
24
25
|
actionRunner(async (cliOptions: PackageAarFlags) => {
|
|
25
26
|
const options = mergeBrownfieldConfigWithOptions(cliOptions, 'android');
|
|
27
|
+
const projectRoot = findProjectRoot();
|
|
26
28
|
|
|
27
|
-
const { projectRoot, platformConfig } = getProjectInfo('android');
|
|
28
29
|
await runExpoPrebuildIfNeeded({
|
|
29
30
|
projectRoot,
|
|
30
31
|
platform: 'android',
|
|
31
32
|
});
|
|
32
33
|
|
|
34
|
+
const { platformConfig } = getProjectInfo('android');
|
|
35
|
+
|
|
33
36
|
await runBrownieCodegenIfApplicable(projectRoot, 'kotlin');
|
|
34
37
|
await runNavigationCodegenIfApplicable(projectRoot);
|
|
35
38
|
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { Command, Option } from 'commander';
|
|
18
18
|
|
|
19
19
|
import { runExpoPrebuildIfNeeded } from '../utils/expo.js';
|
|
20
|
+
import { findProjectRoot } from '../utils/paths.js';
|
|
20
21
|
import { getProjectInfo } from '../utils/project.js';
|
|
21
22
|
import { supportsPrebuiltRNCore } from '../utils/supportsPrebuiltRNCore.js';
|
|
22
23
|
import {
|
|
@@ -97,8 +98,11 @@ export const packageIosCommand = curryOptions(
|
|
|
97
98
|
.action(
|
|
98
99
|
actionRunner(async (cliOptions: PackageIosOptions) => {
|
|
99
100
|
const options = mergeBrownfieldConfigWithOptions(cliOptions, 'ios');
|
|
101
|
+
const projectRoot = findProjectRoot();
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
await runExpoPrebuildIfNeeded({ projectRoot, platform: 'ios' });
|
|
104
|
+
|
|
105
|
+
const { platformConfig, userConfig } = getProjectInfo('ios');
|
|
102
106
|
|
|
103
107
|
const prebuiltRNCoreSupport = supportsPrebuiltRNCore({ projectRoot });
|
|
104
108
|
|
|
@@ -126,8 +130,6 @@ export const packageIosCommand = curryOptions(
|
|
|
126
130
|
throw new RockError(prebuiltRNCoreSupport.reason);
|
|
127
131
|
}
|
|
128
132
|
|
|
129
|
-
await runExpoPrebuildIfNeeded({ projectRoot, platform: 'ios' });
|
|
130
|
-
|
|
131
133
|
if (!userConfig.project.ios) {
|
|
132
134
|
throw new Error('iOS project not found.');
|
|
133
135
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ExampleUsage,
|
|
13
13
|
} from '../../shared/index.js';
|
|
14
14
|
import { getProjectInfo } from '../utils/project.js';
|
|
15
|
+
import { findProjectRoot } from '../utils/paths.js';
|
|
15
16
|
import { runExpoPrebuildIfNeeded } from '../utils/expo.js';
|
|
16
17
|
import { runBrownieCodegenIfApplicable } from '../../brownie/helpers/runBrownieCodegenIfApplicable.js';
|
|
17
18
|
import { runNavigationCodegenIfApplicable } from '../../navigation/helpers/runNavigationCodegenIfApplicable.js';
|
|
@@ -25,13 +26,15 @@ export const publishAndroidCommand = curryOptions(
|
|
|
25
26
|
).action(
|
|
26
27
|
actionRunner(async (cliOptions: PublishLocalAarFlags) => {
|
|
27
28
|
const options = mergeBrownfieldConfigWithOptions(cliOptions, 'android');
|
|
29
|
+
const projectRoot = findProjectRoot();
|
|
28
30
|
|
|
29
|
-
const { projectRoot, platformConfig } = getProjectInfo('android');
|
|
30
31
|
await runExpoPrebuildIfNeeded({
|
|
31
32
|
projectRoot,
|
|
32
33
|
platform: 'android',
|
|
33
34
|
});
|
|
34
35
|
|
|
36
|
+
const { platformConfig } = getProjectInfo('android');
|
|
37
|
+
|
|
35
38
|
await runBrownieCodegenIfApplicable(projectRoot, 'kotlin');
|
|
36
39
|
await runNavigationCodegenIfApplicable(projectRoot);
|
|
37
40
|
|
|
@@ -21,15 +21,46 @@ const cliConfig: typeof cliConfigImport =
|
|
|
21
21
|
: // @ts-expect-error: interop default
|
|
22
22
|
cliConfigImport.default;
|
|
23
23
|
|
|
24
|
+
function hasExpoAppConfig(projectRoot: string): boolean {
|
|
25
|
+
return (
|
|
26
|
+
fs.existsSync(path.join(projectRoot, 'app.json')) ||
|
|
27
|
+
fs.existsSync(path.join(projectRoot, 'app.config.js')) ||
|
|
28
|
+
fs.existsSync(path.join(projectRoot, 'app.config.ts')) ||
|
|
29
|
+
fs.existsSync(path.join(projectRoot, 'app.config.mjs'))
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function projectDependsOnExpo(projectRoot: string): boolean {
|
|
34
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
35
|
+
|
|
36
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const packageJson = JSON.parse(
|
|
41
|
+
fs.readFileSync(packageJsonPath, 'utf-8')
|
|
42
|
+
) as Record<string, Record<string, string>>;
|
|
43
|
+
|
|
44
|
+
return ['dependencies', 'peerDependencies', 'devDependencies'].some(
|
|
45
|
+
(key) => packageJson[key]?.expo
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
24
49
|
/**
|
|
25
50
|
* Gets the Expo config if the project is an Expo project
|
|
26
51
|
* @param projectRoot The project root path
|
|
27
52
|
* @returns The Expo config if the project is an Expo project, null otherwise
|
|
28
53
|
*/
|
|
29
54
|
export function getExpoConfigIfIsExpo(projectRoot: string) {
|
|
55
|
+
const hasAppConfig = hasExpoAppConfig(projectRoot);
|
|
56
|
+
|
|
30
57
|
try {
|
|
31
58
|
return getConfig(projectRoot, { skipSDKVersionRequirement: true });
|
|
32
|
-
} catch {
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (hasAppConfig) {
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
|
|
33
64
|
return null;
|
|
34
65
|
}
|
|
35
66
|
}
|
|
@@ -41,19 +72,7 @@ export function getExpoConfigIfIsExpo(projectRoot: string) {
|
|
|
41
72
|
* @returns Whether the project is an Expo project
|
|
42
73
|
*/
|
|
43
74
|
export function isExpoProject(projectRoot: string): boolean {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// additionally, it is needed to check if the project depends on Expo packages explicitly
|
|
47
|
-
// to prevent false positives in a monorepo setup
|
|
48
|
-
const rnProjectRoot = findProjectRoot();
|
|
49
|
-
const packageJsonPath = path.join(rnProjectRoot, 'package.json');
|
|
50
|
-
const dependsOnExpo =
|
|
51
|
-
fs.existsSync(packageJsonPath) &&
|
|
52
|
-
['dependencies', 'peerDependencies', 'devDependencies'].some(
|
|
53
|
-
(key) => JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))[key]?.expo
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return hasExpoConfig && dependsOnExpo;
|
|
75
|
+
return hasExpoAppConfig(projectRoot) && projectDependsOnExpo(projectRoot);
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
export function getExpoSdkMajor(projectRoot: string): number | null {
|
package/src/brownie/config.ts
CHANGED
|
@@ -108,7 +108,7 @@ export function resolveBrownieCodegenConfig({
|
|
|
108
108
|
const legacyConfig = hasLegacyConfig(projectRoot)
|
|
109
109
|
? loadConfig(projectRoot)
|
|
110
110
|
: undefined;
|
|
111
|
-
const brownfieldBrownie = loadBrownfieldConfig(projectRoot)
|
|
111
|
+
const brownfieldBrownie = loadBrownfieldConfig(projectRoot)?.brownie;
|
|
112
112
|
|
|
113
113
|
if (legacyConfig !== undefined && (brownie ?? brownfieldBrownie)) {
|
|
114
114
|
throw new Error(LEGACY_AND_NEW_BROWNIE_CONFIG_ERROR);
|
package/src/config.ts
CHANGED
|
@@ -10,13 +10,13 @@ import { findProjectRoot } from './brownfield/utils/paths.js';
|
|
|
10
10
|
import BrownfieldSchema from '../schema.json' with { type: 'json' };
|
|
11
11
|
import { logger } from '@rock-js/tools';
|
|
12
12
|
|
|
13
|
-
const CONFIG_BASE_NAME = 'brownfield';
|
|
14
|
-
const JS_CONFIG_FILE_NAME = `${CONFIG_BASE_NAME}.config.js`;
|
|
15
|
-
const JSON_CONFIG_FILE_NAME = `${CONFIG_BASE_NAME}.config.json`;
|
|
13
|
+
export const CONFIG_BASE_NAME = 'brownfield';
|
|
14
|
+
export const JS_CONFIG_FILE_NAME = `${CONFIG_BASE_NAME}.config.js`;
|
|
15
|
+
export const JSON_CONFIG_FILE_NAME = `${CONFIG_BASE_NAME}.config.json`;
|
|
16
16
|
|
|
17
17
|
const SEPARATOR = '\n● ';
|
|
18
18
|
|
|
19
|
-
const ajv = new Ajv({ allErrors: true });
|
|
19
|
+
const ajv = new Ajv({ allErrors: true, allowUnionTypes: true });
|
|
20
20
|
const validateBrownfieldConfig = ajv.compile(BrownfieldSchema);
|
|
21
21
|
|
|
22
22
|
export function validateBrownfieldCLIConfig(config: unknown): void {
|
|
@@ -29,7 +29,7 @@ export function validateBrownfieldCLIConfig(config: unknown): void {
|
|
|
29
29
|
|
|
30
30
|
export function loadBrownfieldConfig(
|
|
31
31
|
projectRoot: string = findProjectRoot()
|
|
32
|
-
): BrownfieldConfig {
|
|
32
|
+
): BrownfieldConfig | null {
|
|
33
33
|
const require = createRequire(path.join(projectRoot, 'package.json'));
|
|
34
34
|
|
|
35
35
|
const jsConfigFilePath = path.join(projectRoot, JS_CONFIG_FILE_NAME);
|
|
@@ -41,7 +41,7 @@ export function loadBrownfieldConfig(
|
|
|
41
41
|
[
|
|
42
42
|
fs.existsSync(jsConfigFilePath),
|
|
43
43
|
fs.existsSync(jsonConfigFilePath),
|
|
44
|
-
packageJson
|
|
44
|
+
CONFIG_BASE_NAME in packageJson,
|
|
45
45
|
].filter(Boolean).length > 1
|
|
46
46
|
) {
|
|
47
47
|
throw new Error('Project has multiple Brownfield configuration files');
|
|
@@ -55,7 +55,11 @@ export function loadBrownfieldConfig(
|
|
|
55
55
|
return require(jsonConfigFilePath) as BrownfieldConfig;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
if (CONFIG_BASE_NAME in packageJson) {
|
|
59
|
+
return (packageJson[CONFIG_BASE_NAME] as BrownfieldConfig) ?? {};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
type BrownfieldPlatform = 'android' | 'ios';
|
|
@@ -77,7 +81,7 @@ export function mergeBrownfieldConfigWithOptions<T extends object>(
|
|
|
77
81
|
options: T,
|
|
78
82
|
platform: BrownfieldPlatform
|
|
79
83
|
): T {
|
|
80
|
-
const reactNativeBrownfieldConfig = loadBrownfieldConfig();
|
|
84
|
+
const reactNativeBrownfieldConfig = loadBrownfieldConfig() ?? {};
|
|
81
85
|
|
|
82
86
|
validateBrownfieldCLIConfig(reactNativeBrownfieldConfig);
|
|
83
87
|
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { BrownfieldConfig } from './types.js';
|
|
2
|
+
|
|
3
|
+
export { loadBrownfieldConfig } from './config.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Legacy Expo config plugin props shape accepted via app.json plugins tuple.
|
|
7
|
+
*/
|
|
8
|
+
export type BrownfieldPluginProps = {
|
|
9
|
+
debug?: boolean;
|
|
10
|
+
ios?: {
|
|
11
|
+
frameworkName?: string;
|
|
12
|
+
bundleIdentifier?: string;
|
|
13
|
+
buildSettings?: Record<string, string | boolean | number>;
|
|
14
|
+
deploymentTarget?: string;
|
|
15
|
+
frameworkVersion?: string;
|
|
16
|
+
};
|
|
17
|
+
android?: {
|
|
18
|
+
moduleName?: string;
|
|
19
|
+
packageName?: string;
|
|
20
|
+
minSdkVersion?: number;
|
|
21
|
+
targetSdkVersion?: number;
|
|
22
|
+
compileSdkVersion?: number;
|
|
23
|
+
groupId?: string;
|
|
24
|
+
artifactId?: string;
|
|
25
|
+
version?: string;
|
|
26
|
+
useLocalGradlePlugin?: boolean;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type ResolvedBrownfieldPluginAndroidConfig = {
|
|
31
|
+
moduleName: string;
|
|
32
|
+
packageName: string;
|
|
33
|
+
minSdkVersion: number;
|
|
34
|
+
targetSdkVersion: number;
|
|
35
|
+
compileSdkVersion: number;
|
|
36
|
+
groupId: string;
|
|
37
|
+
artifactId: string;
|
|
38
|
+
version: string;
|
|
39
|
+
useLocalGradlePlugin: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type ResolvedBrownfieldPluginIosConfig = {
|
|
43
|
+
frameworkName: string;
|
|
44
|
+
bundleIdentifier: string;
|
|
45
|
+
buildSettings: Record<string, string | boolean | number>;
|
|
46
|
+
deploymentTarget: string;
|
|
47
|
+
frameworkVersion: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type ResolvedBrownfieldPluginConfig = {
|
|
51
|
+
debug: boolean;
|
|
52
|
+
ios: ResolvedBrownfieldPluginIosConfig | null;
|
|
53
|
+
android: ResolvedBrownfieldPluginAndroidConfig | null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type BrownfieldExpoConfig = {
|
|
57
|
+
ios?: {
|
|
58
|
+
bundleIdentifier?: string;
|
|
59
|
+
};
|
|
60
|
+
android?: {
|
|
61
|
+
package?: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const CONFIG_FILE_PLUGIN_OVERLAP_ERROR =
|
|
66
|
+
'Brownfield configuration is defined in both a brownfield config file and app.json plugin options. ' +
|
|
67
|
+
'Use only one source: either brownfield.config.js, brownfield.config.json, package.json#brownfield, or the plugin options in app.json.';
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Checks if the plugin props are non-empty.
|
|
71
|
+
* @param props - The plugin props to check.
|
|
72
|
+
* @returns True if the plugin props are non-empty, false otherwise.
|
|
73
|
+
*/
|
|
74
|
+
function isPluginPropsNonEmpty(props: BrownfieldPluginProps): boolean {
|
|
75
|
+
if (props.debug !== undefined) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (props.ios && Object.keys(props.ios).length > 0) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (props.android && Object.keys(props.android).length > 0) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Converts the file config to plugin props.
|
|
92
|
+
* @param fileConfig - The file config to convert to plugin props.
|
|
93
|
+
* @returns The plugin props.
|
|
94
|
+
*/
|
|
95
|
+
function fileConfigToPluginProps(
|
|
96
|
+
fileConfig: BrownfieldConfig
|
|
97
|
+
): BrownfieldPluginProps {
|
|
98
|
+
const props: BrownfieldPluginProps = {};
|
|
99
|
+
|
|
100
|
+
if (fileConfig.verbose !== undefined) {
|
|
101
|
+
props.debug = fileConfig.verbose;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (fileConfig.android) {
|
|
105
|
+
props.android = {
|
|
106
|
+
moduleName: fileConfig.android.moduleName,
|
|
107
|
+
...fileConfig.android.expo,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (fileConfig.ios) {
|
|
112
|
+
props.ios = {
|
|
113
|
+
frameworkName: fileConfig.ios.scheme,
|
|
114
|
+
...fileConfig.ios.expo,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return props;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Asserts that there is no overlap between the file config and the plugin props.
|
|
123
|
+
* @param fileConfig - The loaded file config, or null when no config source exists.
|
|
124
|
+
* @param pluginProps - The plugin props to check for overlap.
|
|
125
|
+
* @throws An error if there is overlap.
|
|
126
|
+
* @returns void
|
|
127
|
+
*/
|
|
128
|
+
export function assertNoConfigFilePluginOverlap(
|
|
129
|
+
fileConfig: BrownfieldConfig | null,
|
|
130
|
+
pluginProps: BrownfieldPluginProps
|
|
131
|
+
): void {
|
|
132
|
+
if (fileConfig === null) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (isPluginPropsNonEmpty(pluginProps)) {
|
|
137
|
+
throw new Error(CONFIG_FILE_PLUGIN_OVERLAP_ERROR);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Resolves the plugin config from the file config and the plugin props.
|
|
143
|
+
* @param pluginProps - The plugin props to resolve.
|
|
144
|
+
* @param fileConfig - The file config to resolve.
|
|
145
|
+
* @param expoConfig - The Expo plugin config to resolve.
|
|
146
|
+
* @returns The resolved plugin config.
|
|
147
|
+
*/
|
|
148
|
+
export function resolveBrownfieldPluginConfig(
|
|
149
|
+
pluginProps: BrownfieldPluginProps,
|
|
150
|
+
fileConfig: BrownfieldConfig | null,
|
|
151
|
+
expoConfig: BrownfieldExpoConfig
|
|
152
|
+
): ResolvedBrownfieldPluginConfig {
|
|
153
|
+
const effectiveProps =
|
|
154
|
+
fileConfig !== null ? fileConfigToPluginProps(fileConfig) : pluginProps;
|
|
155
|
+
|
|
156
|
+
const androidPackage = expoConfig.android?.package;
|
|
157
|
+
/**
|
|
158
|
+
* Below: android.moduleName may be provided in the fully-qualified Gradle format
|
|
159
|
+
* (e.g. :BrownfieldLib — this is shown in the CLI example usage).
|
|
160
|
+
* The Expo prebuild side expects a raw module folder/name (it later
|
|
161
|
+
* prepends : itself and uses it as a path), so a leading : is removed.
|
|
162
|
+
*/
|
|
163
|
+
const androidModuleName = (
|
|
164
|
+
effectiveProps.android?.moduleName ?? 'brownfieldlib'
|
|
165
|
+
).replace(/^:/, '');
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
debug: effectiveProps.debug ?? false,
|
|
169
|
+
ios: expoConfig.ios
|
|
170
|
+
? {
|
|
171
|
+
frameworkName: effectiveProps.ios?.frameworkName ?? 'BrownfieldLib',
|
|
172
|
+
bundleIdentifier:
|
|
173
|
+
effectiveProps.ios?.bundleIdentifier ??
|
|
174
|
+
`${expoConfig.ios.bundleIdentifier}.brownfield`,
|
|
175
|
+
buildSettings: effectiveProps.ios?.buildSettings ?? {},
|
|
176
|
+
deploymentTarget: effectiveProps.ios?.deploymentTarget ?? '15.0',
|
|
177
|
+
frameworkVersion: effectiveProps.ios?.frameworkVersion ?? '1',
|
|
178
|
+
}
|
|
179
|
+
: null,
|
|
180
|
+
android: androidPackage
|
|
181
|
+
? {
|
|
182
|
+
moduleName: androidModuleName,
|
|
183
|
+
packageName: effectiveProps.android?.packageName ?? androidPackage,
|
|
184
|
+
minSdkVersion: effectiveProps.android?.minSdkVersion ?? 24,
|
|
185
|
+
targetSdkVersion: effectiveProps.android?.targetSdkVersion ?? 35,
|
|
186
|
+
compileSdkVersion: effectiveProps.android?.compileSdkVersion ?? 35,
|
|
187
|
+
groupId: effectiveProps.android?.groupId ?? androidPackage,
|
|
188
|
+
artifactId: effectiveProps.android?.artifactId ?? androidModuleName,
|
|
189
|
+
version: effectiveProps.android?.version ?? '0.0.1-SNAPSHOT',
|
|
190
|
+
useLocalGradlePlugin:
|
|
191
|
+
effectiveProps.android?.useLocalGradlePlugin ?? false,
|
|
192
|
+
}
|
|
193
|
+
: null,
|
|
194
|
+
};
|
|
195
|
+
}
|