@callstack/brownfield-cli 6.1.1 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/brownfield/commands/packageIos.d.ts.map +1 -1
- package/dist/brownfield/commands/packageIos.js +2 -0
- package/dist/brownfield/utils/createLocalSpmPackage.d.ts +4 -1
- package/dist/brownfield/utils/createLocalSpmPackage.d.ts.map +1 -1
- package/dist/brownfield/utils/createLocalSpmPackage.js +67 -13
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/schema.json +24 -0
- package/src/brownfield/commands/packageIos.ts +2 -0
- package/src/brownfield/utils/createLocalSpmPackage.ts +110 -11
- package/src/types.ts +23 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @callstack/brownfield-cli
|
|
2
2
|
|
|
3
|
+
## 6.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#514](https://github.com/callstack/react-native-brownfield/pull/514) [`6517ec5`](https://github.com/callstack/react-native-brownfield/commit/6517ec5666269007f10c28efb7a748beba476998) Thanks [@DanielPotorCK](https://github.com/DanielPotorCK)! - Allow `ios.extraSpmXcframeworks` in brownfield config so `package:ios --add-spm-package` can include project-declared XCFrameworks as additional SPM binary targets.
|
|
8
|
+
|
|
3
9
|
## 6.1.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageIos.d.ts","sourceRoot":"","sources":["../../../src/brownfield/commands/packageIos.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAU5C,OAAO,EAGL,YAAY,EACb,MAAM,uBAAuB,CAAC;AAgD/B,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,GAAG,OAAO,GACtB,OAAO,CAET;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAE7E;AAcD,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"packageIos.d.ts","sourceRoot":"","sources":["../../../src/brownfield/commands/packageIos.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAU5C,OAAO,EAGL,YAAY,EACb,MAAM,uBAAuB,CAAC;AAgD/B,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,GAAG,OAAO,GACtB,OAAO,CAET;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAE7E;AAcD,eAAO,MAAM,iBAAiB,SAoX3B,CAAC;AAEJ,qGAAqG;AACrG,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,oBAEnE;AAED,eAAO,MAAM,iBAAiB,cAG7B,CAAC"}
|
|
@@ -290,6 +290,8 @@ export const packageIosCommand = curryOptions(new Command('package:ios').descrip
|
|
|
290
290
|
packageDir,
|
|
291
291
|
frameworkName: frameworkName ?? undefined,
|
|
292
292
|
usePrebuiltExpo: options.usePrebuiltExpo,
|
|
293
|
+
projectRoot,
|
|
294
|
+
extraSpmXcframeworks: options.extraSpmXcframeworks ?? [],
|
|
293
295
|
});
|
|
294
296
|
logger.success(`Local SPM package manifest created at ${colorLink(relativeToCwd(packageManifestPath))}`);
|
|
295
297
|
logger.info(`Add the local package folder in Xcode: ${colorLink(relativeToCwd(packageDir))}`);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import type { ExtraSpmXcframework } from '../../types.js';
|
|
1
2
|
type CreateLocalSpmPackageOptions = {
|
|
2
3
|
packageDir: string;
|
|
3
4
|
frameworkName?: string;
|
|
4
5
|
usePrebuiltExpo?: boolean;
|
|
6
|
+
projectRoot?: string;
|
|
7
|
+
extraSpmXcframeworks?: ExtraSpmXcframework[];
|
|
5
8
|
};
|
|
6
9
|
type CreateLocalSpmPackageResult = {
|
|
7
10
|
packageManifestPath: string;
|
|
8
11
|
};
|
|
9
|
-
export declare function createLocalSpmPackage({ packageDir, frameworkName, usePrebuiltExpo, }: CreateLocalSpmPackageOptions): CreateLocalSpmPackageResult;
|
|
12
|
+
export declare function createLocalSpmPackage({ packageDir, frameworkName, usePrebuiltExpo, projectRoot, extraSpmXcframeworks, }: CreateLocalSpmPackageOptions): CreateLocalSpmPackageResult;
|
|
10
13
|
export {};
|
|
11
14
|
//# sourceMappingURL=createLocalSpmPackage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createLocalSpmPackage.d.ts","sourceRoot":"","sources":["../../../src/brownfield/utils/createLocalSpmPackage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createLocalSpmPackage.d.ts","sourceRoot":"","sources":["../../../src/brownfield/utils/createLocalSpmPackage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAU1D,KAAK,4BAA4B,GAAG;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC9C,CAAC;AAEF,KAAK,2BAA2B,GAAG;IACjC,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAwOF,wBAAgB,qBAAqB,CAAC,EACpC,UAAU,EACV,aAAa,EACb,eAAsB,EACtB,WAA2B,EAC3B,oBAAyB,GAC1B,EAAE,4BAA4B,GAAG,2BAA2B,CA2D5D"}
|
|
@@ -12,6 +12,8 @@ const RESERVED_FRAMEWORK_NAMES = new Set([
|
|
|
12
12
|
'ReactNativeDependencies',
|
|
13
13
|
...ALL_EXPO_SUPPORT_XCFRAMEWORK_NAMES,
|
|
14
14
|
]);
|
|
15
|
+
const SWIFT_TARGET_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
16
|
+
const RESERVED_FRAMEWORK_NAME_KEYS = new Set([...RESERVED_FRAMEWORK_NAMES].map((name) => name.toLowerCase()));
|
|
15
17
|
function requireXcframework(packageDir, name) {
|
|
16
18
|
const xcframeworkPath = path.join(packageDir, `${name}.xcframework`);
|
|
17
19
|
if (!fs.existsSync(xcframeworkPath)) {
|
|
@@ -28,7 +30,7 @@ function requireHermesXcframework(packageDir) {
|
|
|
28
30
|
return (optionalXcframework(packageDir, 'hermesvm') ??
|
|
29
31
|
requireXcframework(packageDir, 'hermes'));
|
|
30
32
|
}
|
|
31
|
-
function resolveAppFrameworkName(packageDir, explicitFrameworkName) {
|
|
33
|
+
function resolveAppFrameworkName(packageDir, reservedFrameworkNames, explicitFrameworkName) {
|
|
32
34
|
if (explicitFrameworkName) {
|
|
33
35
|
return requireXcframework(packageDir, explicitFrameworkName);
|
|
34
36
|
}
|
|
@@ -36,7 +38,7 @@ function resolveAppFrameworkName(packageDir, explicitFrameworkName) {
|
|
|
36
38
|
.readdirSync(packageDir, { withFileTypes: true })
|
|
37
39
|
.filter((entry) => entry.isDirectory() &&
|
|
38
40
|
entry.name.endsWith('.xcframework') &&
|
|
39
|
-
!
|
|
41
|
+
!reservedFrameworkNames.has(path.basename(entry.name, '.xcframework')))
|
|
40
42
|
.map((entry) => path.basename(entry.name, '.xcframework'))
|
|
41
43
|
.sort();
|
|
42
44
|
if (candidates.length === 1 && candidates[0]) {
|
|
@@ -47,6 +49,45 @@ function resolveAppFrameworkName(packageDir, explicitFrameworkName) {
|
|
|
47
49
|
}
|
|
48
50
|
throw new Error(`Found multiple packaged app XCFramework candidates (${candidates.join(', ')}). Pass --scheme explicitly when packaging.`);
|
|
49
51
|
}
|
|
52
|
+
function resolveExtraSpmXcframeworkPath(projectRoot, entry) {
|
|
53
|
+
return path.isAbsolute(entry.path)
|
|
54
|
+
? entry.path
|
|
55
|
+
: path.resolve(projectRoot, entry.path);
|
|
56
|
+
}
|
|
57
|
+
function validateExtraSpmXcframeworks(extraSpmXcframeworks, frameworkName) {
|
|
58
|
+
const nameKeys = new Set();
|
|
59
|
+
for (const entry of extraSpmXcframeworks) {
|
|
60
|
+
if (!SWIFT_TARGET_NAME_PATTERN.test(entry.name)) {
|
|
61
|
+
throw new Error(`Invalid extra SPM XCFramework name "${entry.name}". Names must start with a letter or underscore and contain only letters, numbers, and underscores.`);
|
|
62
|
+
}
|
|
63
|
+
const nameKey = entry.name.toLowerCase();
|
|
64
|
+
if (RESERVED_FRAMEWORK_NAME_KEYS.has(nameKey) ||
|
|
65
|
+
nameKey === frameworkName?.toLowerCase()) {
|
|
66
|
+
throw new Error(`Extra SPM XCFramework name "${entry.name}" conflicts with a generated package target.`);
|
|
67
|
+
}
|
|
68
|
+
if (nameKeys.has(nameKey)) {
|
|
69
|
+
throw new Error(`Duplicate extra SPM XCFramework name: ${entry.name}`);
|
|
70
|
+
}
|
|
71
|
+
nameKeys.add(nameKey);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function stageExtraSpmXcframeworks({ packageDir, projectRoot, extraSpmXcframeworks, }) {
|
|
75
|
+
const stagedNames = [];
|
|
76
|
+
for (const entry of extraSpmXcframeworks) {
|
|
77
|
+
const sourcePath = resolveExtraSpmXcframeworkPath(projectRoot, entry);
|
|
78
|
+
if (!fs.existsSync(sourcePath)) {
|
|
79
|
+
throw new Error(`Missing extra SPM XCFramework "${entry.name}" at ${entry.path}`);
|
|
80
|
+
}
|
|
81
|
+
const destinationPath = path.join(packageDir, `${entry.name}.xcframework`);
|
|
82
|
+
fs.rmSync(destinationPath, { recursive: true, force: true });
|
|
83
|
+
fs.cpSync(fs.realpathSync(sourcePath), destinationPath, {
|
|
84
|
+
recursive: true,
|
|
85
|
+
verbatimSymlinks: true,
|
|
86
|
+
});
|
|
87
|
+
stagedNames.push(entry.name);
|
|
88
|
+
}
|
|
89
|
+
return stagedNames;
|
|
90
|
+
}
|
|
50
91
|
function renderPackageSwift({ packageName, libraryName, targetNames, }) {
|
|
51
92
|
const binaryTargets = targetNames
|
|
52
93
|
.map((targetName) => ` .binaryTarget(name: "${targetName}", path: "./${SPM_ARTIFACTS_DIR_NAME}/${targetName}.xcframework")`)
|
|
@@ -107,19 +148,32 @@ If Xcode builds your host app but the simulator installation fails, check the ho
|
|
|
107
148
|
This folder is generated by \`brownfield package:ios --add-spm-package\`. Re-run that command whenever the packaged XCFrameworks change so this package stays in sync.
|
|
108
149
|
`;
|
|
109
150
|
}
|
|
110
|
-
export function createLocalSpmPackage({ packageDir, frameworkName, usePrebuiltExpo = true, }) {
|
|
111
|
-
|
|
151
|
+
export function createLocalSpmPackage({ packageDir, frameworkName, usePrebuiltExpo = true, projectRoot = process.cwd(), extraSpmXcframeworks = [], }) {
|
|
152
|
+
validateExtraSpmXcframeworks(extraSpmXcframeworks, frameworkName);
|
|
153
|
+
const reservedFrameworkNames = new Set([
|
|
154
|
+
...RESERVED_FRAMEWORK_NAMES,
|
|
155
|
+
...extraSpmXcframeworks.map((entry) => entry.name),
|
|
156
|
+
]);
|
|
157
|
+
const extraTargetNames = stageExtraSpmXcframeworks({
|
|
158
|
+
packageDir,
|
|
159
|
+
projectRoot,
|
|
160
|
+
extraSpmXcframeworks,
|
|
161
|
+
});
|
|
162
|
+
const resolvedFrameworkName = resolveAppFrameworkName(packageDir, reservedFrameworkNames, frameworkName);
|
|
112
163
|
const expoSupportXcframeworkNames = getExpoSupportXcframeworkNames(usePrebuiltExpo);
|
|
113
164
|
const targetNames = [
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
165
|
+
...new Set([
|
|
166
|
+
resolvedFrameworkName,
|
|
167
|
+
requireHermesXcframework(packageDir),
|
|
168
|
+
requireXcframework(packageDir, 'ReactBrownfield'),
|
|
169
|
+
optionalXcframework(packageDir, 'Brownie'),
|
|
170
|
+
optionalXcframework(packageDir, 'BrownfieldNavigation'),
|
|
171
|
+
...expoSupportXcframeworkNames.map((expoFrameworkName) => optionalXcframework(packageDir, expoFrameworkName)),
|
|
172
|
+
optionalXcframework(packageDir, 'React'),
|
|
173
|
+
optionalXcframework(packageDir, 'ReactNativeDependencies'),
|
|
174
|
+
...extraTargetNames,
|
|
175
|
+
].filter((targetName) => targetName !== null)),
|
|
176
|
+
];
|
|
123
177
|
const packageManifestPath = path.join(packageDir, 'Package.swift');
|
|
124
178
|
const readmePath = path.join(packageDir, 'README.md');
|
|
125
179
|
prepareLocalSpmArtifacts({
|
package/dist/types.d.ts
CHANGED
|
@@ -20,6 +20,21 @@ export type BrownieConfig = {
|
|
|
20
20
|
*/
|
|
21
21
|
kotlinPackageName?: string;
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Extra XCFramework declared for inclusion as a binary target in the
|
|
25
|
+
* local SPM package generated by `package:ios --add-spm-package`.
|
|
26
|
+
*/
|
|
27
|
+
export type ExtraSpmXcframework = {
|
|
28
|
+
/**
|
|
29
|
+
* Binary target / module name used in Package.swift.
|
|
30
|
+
* @pattern ^[A-Za-z_][A-Za-z0-9_]*$
|
|
31
|
+
*/
|
|
32
|
+
name: string;
|
|
33
|
+
/**
|
|
34
|
+
* Path to the XCFramework directory, absolute or relative to the project root.
|
|
35
|
+
*/
|
|
36
|
+
path: string;
|
|
37
|
+
};
|
|
23
38
|
export type PackageIosOptions = Omit<AppleBuildFlags, 'archive' | 'local'> & {
|
|
24
39
|
/** Set when `--use-prebuilt-rn-core` is passed; omitted when the flag is absent (Rock applies RN version defaults). */
|
|
25
40
|
usePrebuiltRnCore?: boolean;
|
|
@@ -27,6 +42,11 @@ export type PackageIosOptions = Omit<AppleBuildFlags, 'archive' | 'local'> & {
|
|
|
27
42
|
usePrebuiltExpo?: boolean;
|
|
28
43
|
/** When set, generate a local Swift Package Manager manifest next to the packaged XCFramework outputs. */
|
|
29
44
|
addSpmPackage?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Additional XCFrameworks copied into the generated local SPM package as
|
|
47
|
+
* binary targets. Only consumed when `--add-spm-package` is set. Defaults to [].
|
|
48
|
+
*/
|
|
49
|
+
extraSpmXcframeworks?: ExtraSpmXcframework[];
|
|
30
50
|
};
|
|
31
51
|
export type BrownfieldPackageAndroidOptions = BrownfieldCommonOptions & Partial<PackageAarFlags>;
|
|
32
52
|
export type BrownfieldPublishAndroidOptions = BrownfieldCommonOptions & Partial<PublishLocalAarFlags>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,eAAe,EAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAErF,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE1C,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAAC;IAC5C;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG;IAC3E,uHAAuH;IACvH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,sHAAsH;IACtH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,0GAA0G;IAC1G,aAAa,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -183,6 +183,13 @@
|
|
|
183
183
|
},
|
|
184
184
|
"type": "array"
|
|
185
185
|
},
|
|
186
|
+
"extraSpmXcframeworks": {
|
|
187
|
+
"description": "Additional XCFrameworks copied into the generated local SPM package as binary targets. Only consumed when `--add-spm-package` is set. Defaults to [].",
|
|
188
|
+
"items": {
|
|
189
|
+
"$ref": "#/definitions/ExtraSpmXcframework"
|
|
190
|
+
},
|
|
191
|
+
"type": "array"
|
|
192
|
+
},
|
|
186
193
|
"installPods": {
|
|
187
194
|
"description": "Whether to install CocoaPods.",
|
|
188
195
|
"type": "boolean"
|
|
@@ -223,6 +230,23 @@
|
|
|
223
230
|
}
|
|
224
231
|
},
|
|
225
232
|
"type": "object"
|
|
233
|
+
},
|
|
234
|
+
"ExtraSpmXcframework": {
|
|
235
|
+
"additionalProperties": false,
|
|
236
|
+
"description": "Extra XCFramework declared for inclusion as a binary target in the local SPM package generated by `package:ios --add-spm-package`.",
|
|
237
|
+
"properties": {
|
|
238
|
+
"name": {
|
|
239
|
+
"description": "Binary target / module name used in Package.swift.",
|
|
240
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
|
|
241
|
+
"type": "string"
|
|
242
|
+
},
|
|
243
|
+
"path": {
|
|
244
|
+
"description": "Path to the XCFramework directory, absolute or relative to the project root.",
|
|
245
|
+
"type": "string"
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"required": ["name", "path"],
|
|
249
|
+
"type": "object"
|
|
226
250
|
}
|
|
227
251
|
}
|
|
228
252
|
}
|
|
@@ -449,6 +449,8 @@ export const packageIosCommand = curryOptions(
|
|
|
449
449
|
packageDir,
|
|
450
450
|
frameworkName: frameworkName ?? undefined,
|
|
451
451
|
usePrebuiltExpo: options.usePrebuiltExpo,
|
|
452
|
+
projectRoot,
|
|
453
|
+
extraSpmXcframeworks: options.extraSpmXcframeworks ?? [],
|
|
452
454
|
});
|
|
453
455
|
|
|
454
456
|
logger.success(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
import type { ExtraSpmXcframework } from '../../types.js';
|
|
4
5
|
import {
|
|
5
6
|
prepareLocalSpmArtifacts,
|
|
6
7
|
SPM_ARTIFACTS_DIR_NAME,
|
|
@@ -14,6 +15,8 @@ type CreateLocalSpmPackageOptions = {
|
|
|
14
15
|
packageDir: string;
|
|
15
16
|
frameworkName?: string;
|
|
16
17
|
usePrebuiltExpo?: boolean;
|
|
18
|
+
projectRoot?: string;
|
|
19
|
+
extraSpmXcframeworks?: ExtraSpmXcframework[];
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
type CreateLocalSpmPackageResult = {
|
|
@@ -31,6 +34,11 @@ const RESERVED_FRAMEWORK_NAMES = new Set([
|
|
|
31
34
|
...ALL_EXPO_SUPPORT_XCFRAMEWORK_NAMES,
|
|
32
35
|
]);
|
|
33
36
|
|
|
37
|
+
const SWIFT_TARGET_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
38
|
+
const RESERVED_FRAMEWORK_NAME_KEYS = new Set(
|
|
39
|
+
[...RESERVED_FRAMEWORK_NAMES].map((name) => name.toLowerCase())
|
|
40
|
+
);
|
|
41
|
+
|
|
34
42
|
function requireXcframework(packageDir: string, name: string) {
|
|
35
43
|
const xcframeworkPath = path.join(packageDir, `${name}.xcframework`);
|
|
36
44
|
|
|
@@ -56,6 +64,7 @@ function requireHermesXcframework(packageDir: string) {
|
|
|
56
64
|
|
|
57
65
|
function resolveAppFrameworkName(
|
|
58
66
|
packageDir: string,
|
|
67
|
+
reservedFrameworkNames: Set<string>,
|
|
59
68
|
explicitFrameworkName?: string
|
|
60
69
|
) {
|
|
61
70
|
if (explicitFrameworkName) {
|
|
@@ -68,7 +77,7 @@ function resolveAppFrameworkName(
|
|
|
68
77
|
(entry) =>
|
|
69
78
|
entry.isDirectory() &&
|
|
70
79
|
entry.name.endsWith('.xcframework') &&
|
|
71
|
-
!
|
|
80
|
+
!reservedFrameworkNames.has(path.basename(entry.name, '.xcframework'))
|
|
72
81
|
)
|
|
73
82
|
.map((entry) => path.basename(entry.name, '.xcframework'))
|
|
74
83
|
.sort();
|
|
@@ -88,6 +97,78 @@ function resolveAppFrameworkName(
|
|
|
88
97
|
);
|
|
89
98
|
}
|
|
90
99
|
|
|
100
|
+
function resolveExtraSpmXcframeworkPath(
|
|
101
|
+
projectRoot: string,
|
|
102
|
+
entry: ExtraSpmXcframework
|
|
103
|
+
) {
|
|
104
|
+
return path.isAbsolute(entry.path)
|
|
105
|
+
? entry.path
|
|
106
|
+
: path.resolve(projectRoot, entry.path);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function validateExtraSpmXcframeworks(
|
|
110
|
+
extraSpmXcframeworks: ExtraSpmXcframework[],
|
|
111
|
+
frameworkName?: string
|
|
112
|
+
) {
|
|
113
|
+
const nameKeys = new Set<string>();
|
|
114
|
+
|
|
115
|
+
for (const entry of extraSpmXcframeworks) {
|
|
116
|
+
if (!SWIFT_TARGET_NAME_PATTERN.test(entry.name)) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Invalid extra SPM XCFramework name "${entry.name}". Names must start with a letter or underscore and contain only letters, numbers, and underscores.`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const nameKey = entry.name.toLowerCase();
|
|
123
|
+
if (
|
|
124
|
+
RESERVED_FRAMEWORK_NAME_KEYS.has(nameKey) ||
|
|
125
|
+
nameKey === frameworkName?.toLowerCase()
|
|
126
|
+
) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Extra SPM XCFramework name "${entry.name}" conflicts with a generated package target.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (nameKeys.has(nameKey)) {
|
|
133
|
+
throw new Error(`Duplicate extra SPM XCFramework name: ${entry.name}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
nameKeys.add(nameKey);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function stageExtraSpmXcframeworks({
|
|
141
|
+
packageDir,
|
|
142
|
+
projectRoot,
|
|
143
|
+
extraSpmXcframeworks,
|
|
144
|
+
}: {
|
|
145
|
+
packageDir: string;
|
|
146
|
+
projectRoot: string;
|
|
147
|
+
extraSpmXcframeworks: ExtraSpmXcframework[];
|
|
148
|
+
}) {
|
|
149
|
+
const stagedNames: string[] = [];
|
|
150
|
+
|
|
151
|
+
for (const entry of extraSpmXcframeworks) {
|
|
152
|
+
const sourcePath = resolveExtraSpmXcframeworkPath(projectRoot, entry);
|
|
153
|
+
|
|
154
|
+
if (!fs.existsSync(sourcePath)) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`Missing extra SPM XCFramework "${entry.name}" at ${entry.path}`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const destinationPath = path.join(packageDir, `${entry.name}.xcframework`);
|
|
161
|
+
fs.rmSync(destinationPath, { recursive: true, force: true });
|
|
162
|
+
fs.cpSync(fs.realpathSync(sourcePath), destinationPath, {
|
|
163
|
+
recursive: true,
|
|
164
|
+
verbatimSymlinks: true,
|
|
165
|
+
});
|
|
166
|
+
stagedNames.push(entry.name);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return stagedNames;
|
|
170
|
+
}
|
|
171
|
+
|
|
91
172
|
function renderPackageSwift({
|
|
92
173
|
packageName,
|
|
93
174
|
libraryName,
|
|
@@ -176,25 +257,43 @@ export function createLocalSpmPackage({
|
|
|
176
257
|
packageDir,
|
|
177
258
|
frameworkName,
|
|
178
259
|
usePrebuiltExpo = true,
|
|
260
|
+
projectRoot = process.cwd(),
|
|
261
|
+
extraSpmXcframeworks = [],
|
|
179
262
|
}: CreateLocalSpmPackageOptions): CreateLocalSpmPackageResult {
|
|
263
|
+
validateExtraSpmXcframeworks(extraSpmXcframeworks, frameworkName);
|
|
264
|
+
const reservedFrameworkNames = new Set([
|
|
265
|
+
...RESERVED_FRAMEWORK_NAMES,
|
|
266
|
+
...extraSpmXcframeworks.map((entry) => entry.name),
|
|
267
|
+
]);
|
|
268
|
+
const extraTargetNames = stageExtraSpmXcframeworks({
|
|
269
|
+
packageDir,
|
|
270
|
+
projectRoot,
|
|
271
|
+
extraSpmXcframeworks,
|
|
272
|
+
});
|
|
180
273
|
const resolvedFrameworkName = resolveAppFrameworkName(
|
|
181
274
|
packageDir,
|
|
275
|
+
reservedFrameworkNames,
|
|
182
276
|
frameworkName
|
|
183
277
|
);
|
|
184
278
|
const expoSupportXcframeworkNames =
|
|
185
279
|
getExpoSupportXcframeworkNames(usePrebuiltExpo);
|
|
186
280
|
const targetNames = [
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
281
|
+
...new Set(
|
|
282
|
+
[
|
|
283
|
+
resolvedFrameworkName,
|
|
284
|
+
requireHermesXcframework(packageDir),
|
|
285
|
+
requireXcframework(packageDir, 'ReactBrownfield'),
|
|
286
|
+
optionalXcframework(packageDir, 'Brownie'),
|
|
287
|
+
optionalXcframework(packageDir, 'BrownfieldNavigation'),
|
|
288
|
+
...expoSupportXcframeworkNames.map((expoFrameworkName) =>
|
|
289
|
+
optionalXcframework(packageDir, expoFrameworkName)
|
|
290
|
+
),
|
|
291
|
+
optionalXcframework(packageDir, 'React'),
|
|
292
|
+
optionalXcframework(packageDir, 'ReactNativeDependencies'),
|
|
293
|
+
...extraTargetNames,
|
|
294
|
+
].filter((targetName): targetName is string => targetName !== null)
|
|
194
295
|
),
|
|
195
|
-
|
|
196
|
-
optionalXcframework(packageDir, 'ReactNativeDependencies'),
|
|
197
|
-
].filter((targetName): targetName is string => targetName !== null);
|
|
296
|
+
];
|
|
198
297
|
|
|
199
298
|
const packageManifestPath = path.join(packageDir, 'Package.swift');
|
|
200
299
|
const readmePath = path.join(packageDir, 'README.md');
|
package/src/types.ts
CHANGED
|
@@ -29,6 +29,23 @@ export type BrownieConfig = {
|
|
|
29
29
|
kotlinPackageName?: string;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Extra XCFramework declared for inclusion as a binary target in the
|
|
34
|
+
* local SPM package generated by `package:ios --add-spm-package`.
|
|
35
|
+
*/
|
|
36
|
+
export type ExtraSpmXcframework = {
|
|
37
|
+
/**
|
|
38
|
+
* Binary target / module name used in Package.swift.
|
|
39
|
+
* @pattern ^[A-Za-z_][A-Za-z0-9_]*$
|
|
40
|
+
*/
|
|
41
|
+
name: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Path to the XCFramework directory, absolute or relative to the project root.
|
|
45
|
+
*/
|
|
46
|
+
path: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
32
49
|
export type PackageIosOptions = Omit<AppleBuildFlags, 'archive' | 'local'> & {
|
|
33
50
|
/** Set when `--use-prebuilt-rn-core` is passed; omitted when the flag is absent (Rock applies RN version defaults). */
|
|
34
51
|
usePrebuiltRnCore?: boolean;
|
|
@@ -38,6 +55,12 @@ export type PackageIosOptions = Omit<AppleBuildFlags, 'archive' | 'local'> & {
|
|
|
38
55
|
|
|
39
56
|
/** When set, generate a local Swift Package Manager manifest next to the packaged XCFramework outputs. */
|
|
40
57
|
addSpmPackage?: boolean;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Additional XCFrameworks copied into the generated local SPM package as
|
|
61
|
+
* binary targets. Only consumed when `--add-spm-package` is set. Defaults to [].
|
|
62
|
+
*/
|
|
63
|
+
extraSpmXcframeworks?: ExtraSpmXcframework[];
|
|
41
64
|
};
|
|
42
65
|
|
|
43
66
|
export type BrownfieldPackageAndroidOptions = BrownfieldCommonOptions &
|