@rnmapbox/maps 10.1.35 → 10.1.36

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.
@@ -0,0 +1 @@
1
+ module.exports = require('./plugin/build/withMapbox');
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Taken from @expo/config-plugins
3
+ *
4
+ * Sourcecode: https://github.com/expo/expo/blob/59ece3cb1d5a7aaea42f4c7fe9d1f4f825b338f8/packages/@expo/config-plugins/src/utils/generateCode.ts
5
+ * LICENSE: https://github.com/expo/expo/blob/59ece3cb1d5a7aaea42f4c7fe9d1f4f825b338f8/packages/@expo/config-plugins/LICENSE
6
+ */
7
+ export type MergeResults = {
8
+ contents: string;
9
+ didClear: boolean;
10
+ didMerge: boolean;
11
+ };
12
+ /**
13
+ * Merge the contents of two files together and add a generated header.
14
+ *
15
+ * @param src contents of the original file
16
+ * @param newSrc new contents to merge into the original file
17
+ * @param identifier used to update and remove merges
18
+ * @param anchor regex to where the merge should begin
19
+ * @param offset line offset to start merging at (<1 for behind the anchor)
20
+ * @param comment comment style `//` or `#`
21
+ */
22
+ export declare function mergeContents({ src, newSrc, tag, anchor, offset, comment, }: {
23
+ src: string;
24
+ newSrc: string;
25
+ tag: string;
26
+ anchor: string | RegExp;
27
+ offset: number;
28
+ comment: string;
29
+ }): MergeResults;
30
+ export declare function removeContents({ src, tag, }: {
31
+ src: string;
32
+ tag: string;
33
+ }): MergeResults;
34
+ /**
35
+ * Removes the generated section from a file, returns null when nothing can be removed.
36
+ * This sways heavily towards not removing lines unless it's certain that modifications were not made manually.
37
+ *
38
+ * @param src
39
+ */
40
+ export declare function removeGeneratedContents(src: string, tag: string): string | null;
41
+ export declare function createGeneratedHeaderComment(contents: string, tag: string, comment: string): string;
42
+ export declare function createHash(src: string): string;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /**
3
+ * Taken from @expo/config-plugins
4
+ *
5
+ * Sourcecode: https://github.com/expo/expo/blob/59ece3cb1d5a7aaea42f4c7fe9d1f4f825b338f8/packages/@expo/config-plugins/src/utils/generateCode.ts
6
+ * LICENSE: https://github.com/expo/expo/blob/59ece3cb1d5a7aaea42f4c7fe9d1f4f825b338f8/packages/@expo/config-plugins/LICENSE
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createHash = exports.createGeneratedHeaderComment = exports.removeGeneratedContents = exports.removeContents = exports.mergeContents = void 0;
13
+ /**
14
+ * Get line indexes for the generated section of a file.
15
+ *
16
+ * @param src
17
+ */
18
+ const crypto_1 = __importDefault(require("crypto"));
19
+ function getGeneratedSectionIndexes(src, tag) {
20
+ const contents = src.split('\n');
21
+ const start = contents.findIndex((line) => line.includes(`@generated begin ${tag}`));
22
+ const end = contents.findIndex((line) => line.includes(`@generated end ${tag}`));
23
+ return { contents, start, end };
24
+ }
25
+ /**
26
+ * Merge the contents of two files together and add a generated header.
27
+ *
28
+ * @param src contents of the original file
29
+ * @param newSrc new contents to merge into the original file
30
+ * @param identifier used to update and remove merges
31
+ * @param anchor regex to where the merge should begin
32
+ * @param offset line offset to start merging at (<1 for behind the anchor)
33
+ * @param comment comment style `//` or `#`
34
+ */
35
+ function mergeContents({ src, newSrc, tag, anchor, offset, comment, }) {
36
+ const header = createGeneratedHeaderComment(newSrc, tag, comment);
37
+ if (!src.includes(header)) {
38
+ // Ensure the old generated contents are removed.
39
+ const sanitizedTarget = removeGeneratedContents(src, tag);
40
+ return {
41
+ contents: addLines(sanitizedTarget ?? src, anchor, offset, [
42
+ header,
43
+ ...newSrc.split('\n'),
44
+ `${comment} @generated end ${tag}`,
45
+ ]),
46
+ didMerge: true,
47
+ didClear: !!sanitizedTarget,
48
+ };
49
+ }
50
+ return { contents: src, didClear: false, didMerge: false };
51
+ }
52
+ exports.mergeContents = mergeContents;
53
+ function removeContents({ src, tag, }) {
54
+ // Ensure the old generated contents are removed.
55
+ const sanitizedTarget = removeGeneratedContents(src, tag);
56
+ return {
57
+ contents: sanitizedTarget ?? src,
58
+ didMerge: false,
59
+ didClear: !!sanitizedTarget,
60
+ };
61
+ }
62
+ exports.removeContents = removeContents;
63
+ function addLines(content, find, offset, toAdd) {
64
+ const lines = content.split('\n');
65
+ let lineIndex = lines.findIndex((line) => line.match(find));
66
+ if (lineIndex < 0) {
67
+ const error = new Error(`Failed to match "${find}" in contents:\n${content}`);
68
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
69
+ // @ts-ignore
70
+ error.code = 'ERR_NO_MATCH';
71
+ throw error;
72
+ }
73
+ for (const newLine of toAdd) {
74
+ lines.splice(lineIndex + offset, 0, newLine);
75
+ lineIndex++;
76
+ }
77
+ return lines.join('\n');
78
+ }
79
+ /**
80
+ * Removes the generated section from a file, returns null when nothing can be removed.
81
+ * This sways heavily towards not removing lines unless it's certain that modifications were not made manually.
82
+ *
83
+ * @param src
84
+ */
85
+ function removeGeneratedContents(src, tag) {
86
+ const { contents, start, end } = getGeneratedSectionIndexes(src, tag);
87
+ if (start > -1 && end > -1 && start < end) {
88
+ contents.splice(start, end - start + 1);
89
+ // TODO: We could in theory check that the contents we're removing match the hash used in the header,
90
+ // this would ensure that we don't accidentally remove lines that someone added or removed from the generated section.
91
+ return contents.join('\n');
92
+ }
93
+ return null;
94
+ }
95
+ exports.removeGeneratedContents = removeGeneratedContents;
96
+ function createGeneratedHeaderComment(contents, tag, comment) {
97
+ const hashKey = createHash(contents);
98
+ // Everything after the `${tag} ` is unversioned and can be freely modified without breaking changes.
99
+ return `${comment} @generated begin ${tag} - expo prebuild (DO NOT MODIFY) ${hashKey}`;
100
+ }
101
+ exports.createGeneratedHeaderComment = createGeneratedHeaderComment;
102
+ function createHash(src) {
103
+ // this doesn't need to be secure, the shorter the better.
104
+ const hash = crypto_1.default.createHash('sha1').update(src).digest('hex');
105
+ return `sync-${hash}`;
106
+ }
107
+ exports.createHash = createHash;
@@ -0,0 +1,19 @@
1
+ import { ConfigPlugin } from 'expo/config-plugins';
2
+ type InstallerBlockName = 'pre' | 'post';
3
+ export type MapboxPlugProps = {
4
+ /**
5
+ * @deprecated
6
+ */
7
+ RNMapboxMapsImpl?: 'mapbox';
8
+ RNMapboxMapsVersion?: string;
9
+ RNMapboxMapsDownloadToken?: string;
10
+ RNMapboxMapsUseV11?: boolean;
11
+ };
12
+ export declare const addInstallerBlock: (src: string, blockName: InstallerBlockName) => string;
13
+ export declare const addConstantBlock: (src: string, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsDownloadToken, RNMapboxMapsUseV11, }: MapboxPlugProps) => string;
14
+ export declare const applyCocoaPodsModifications: (contents: string, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsDownloadToken, RNMapboxMapsUseV11, }: MapboxPlugProps) => string;
15
+ export declare const addMapboxInstallerBlock: (src: string, blockName: InstallerBlockName) => string;
16
+ export declare const addMapboxMavenRepo: (src: string) => string;
17
+ declare const _default: ConfigPlugin<MapboxPlugProps>;
18
+ export default _default;
19
+ export { addMapboxMavenRepo as _addMapboxMavenRepo, };
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports._addMapboxMavenRepo = exports.addMapboxMavenRepo = exports.addMapboxInstallerBlock = exports.applyCocoaPodsModifications = exports.addConstantBlock = exports.addInstallerBlock = void 0;
7
+ const fs_1 = require("fs");
8
+ const path_1 = __importDefault(require("path"));
9
+ const config_plugins_1 = require("expo/config-plugins");
10
+ const generateCode_1 = require("./generateCode");
11
+ let pkg = {
12
+ name: '@rnmapbox/maps',
13
+ };
14
+ try {
15
+ pkg = require('@rnmapbox/maps/package.json');
16
+ }
17
+ catch {
18
+ // empty catch block
19
+ }
20
+ const addInstallerBlock = (src, blockName) => {
21
+ const matchBlock = new RegExp(`${blockName}_install do \\|installer\\|`);
22
+ const tag = `${blockName}_installer`;
23
+ for (const line of src.split('\n')) {
24
+ const contents = line.trim();
25
+ // Ignore comments
26
+ if (!contents.startsWith('#')) {
27
+ // Prevent adding the block if it exists outside of comments.
28
+ if (contents.match(matchBlock)) {
29
+ // This helps to still allow revisions, since we enabled the block previously.
30
+ // Only continue if the generated block exists...
31
+ const modified = (0, generateCode_1.removeGeneratedContents)(src, tag);
32
+ if (!modified) {
33
+ return src;
34
+ }
35
+ }
36
+ }
37
+ }
38
+ return (0, generateCode_1.mergeContents)({
39
+ tag,
40
+ src,
41
+ newSrc: [` ${blockName}_install do |installer|`, ' end'].join('\n'),
42
+ anchor: /use_react_native/,
43
+ // We can't go after the use_react_native block because it might have parameters, causing it to be multi-line (see react-native template).
44
+ offset: 0,
45
+ comment: '#',
46
+ }).contents;
47
+ };
48
+ exports.addInstallerBlock = addInstallerBlock;
49
+ const addConstantBlock = (src, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsDownloadToken, RNMapboxMapsUseV11, }) => {
50
+ const tag = `@rnmapbox/maps-rnmapboxmapsimpl`;
51
+ if (RNMapboxMapsVersion == null &&
52
+ RNMapboxMapsDownloadToken == null &&
53
+ RNMapboxMapsUseV11 == null) {
54
+ const modified = (0, generateCode_1.removeGeneratedContents)(src, tag);
55
+ if (!modified) {
56
+ return src;
57
+ }
58
+ else {
59
+ return modified;
60
+ }
61
+ }
62
+ const newSrc = [];
63
+ if (RNMapboxMapsDownloadToken) {
64
+ newSrc.push(`$RNMapboxMapsDownloadToken = '${RNMapboxMapsDownloadToken}'`);
65
+ }
66
+ if (RNMapboxMapsImpl) {
67
+ newSrc.push(`$RNMapboxMapsImpl = '${RNMapboxMapsImpl}'`);
68
+ }
69
+ if (RNMapboxMapsVersion) {
70
+ newSrc.push(`$RNMapboxMapsVersion = '${RNMapboxMapsVersion}'`);
71
+ }
72
+ if (RNMapboxMapsUseV11) {
73
+ newSrc.push(`$RNMapboxMapsUseV11 = true`);
74
+ }
75
+ return (0, generateCode_1.mergeContents)({
76
+ tag,
77
+ src,
78
+ newSrc: newSrc.join('\n'),
79
+ anchor: /target .+ do/,
80
+ // We can't go after the use_react_native block because it might have parameters, causing it to be multi-line (see react-native template).
81
+ offset: 0,
82
+ comment: '#',
83
+ }).contents;
84
+ };
85
+ exports.addConstantBlock = addConstantBlock;
86
+ // Only the preinstaller block is required, the post installer block is
87
+ // used for spm (swift package manager) which Expo doesn't currently support.
88
+ const applyCocoaPodsModifications = (contents, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsDownloadToken, RNMapboxMapsUseV11, }) => {
89
+ // Ensure installer blocks exist
90
+ let src = (0, exports.addConstantBlock)(contents, {
91
+ RNMapboxMapsImpl,
92
+ RNMapboxMapsVersion,
93
+ RNMapboxMapsDownloadToken,
94
+ RNMapboxMapsUseV11,
95
+ });
96
+ src = (0, exports.addInstallerBlock)(src, 'pre');
97
+ src = (0, exports.addInstallerBlock)(src, 'post');
98
+ src = (0, exports.addMapboxInstallerBlock)(src, 'pre');
99
+ src = (0, exports.addMapboxInstallerBlock)(src, 'post');
100
+ return src;
101
+ };
102
+ exports.applyCocoaPodsModifications = applyCocoaPodsModifications;
103
+ const addMapboxInstallerBlock = (src, blockName) => (0, generateCode_1.mergeContents)({
104
+ tag: `@rnmapbox/maps-${blockName}_installer`,
105
+ src,
106
+ newSrc: ` $RNMapboxMaps.${blockName}_install(installer)`,
107
+ anchor: new RegExp(`^\\s*${blockName}_install do \\|installer\\|`),
108
+ offset: 1,
109
+ comment: '#',
110
+ }).contents;
111
+ exports.addMapboxInstallerBlock = addMapboxInstallerBlock;
112
+ /**
113
+ * Dangerously adds the custom installer hooks to the Podfile.
114
+ * In the future this should be removed in favor of some custom hooks provided by Expo autolinking.
115
+ *
116
+ * https://github.com/rnmapbox/maps/blob/main/ios/install.md#react-native--0600
117
+ */
118
+ const withCocoaPodsInstallerBlocks = (config, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsDownloadToken, RNMapboxMapsUseV11, }) => (0, config_plugins_1.withDangerousMod)(config, [
119
+ 'ios',
120
+ async (exportedConfig) => {
121
+ const file = path_1.default.join(exportedConfig.modRequest.platformProjectRoot, 'Podfile');
122
+ const contents = await fs_1.promises.readFile(file, 'utf8');
123
+ await fs_1.promises.writeFile(file, (0, exports.applyCocoaPodsModifications)(contents, {
124
+ RNMapboxMapsImpl,
125
+ RNMapboxMapsVersion,
126
+ RNMapboxMapsDownloadToken,
127
+ RNMapboxMapsUseV11,
128
+ }), 'utf-8');
129
+ return exportedConfig;
130
+ },
131
+ ]);
132
+ const withAndroidPropertiesDownloadToken = (config, { RNMapboxMapsDownloadToken }) => {
133
+ const key = 'MAPBOX_DOWNLOADS_TOKEN';
134
+ if (RNMapboxMapsDownloadToken) {
135
+ return (0, config_plugins_1.withGradleProperties)(config, (exportedConfig) => {
136
+ exportedConfig.modResults = exportedConfig.modResults.filter((item) => !(item.type === 'property' && item.key === key));
137
+ exportedConfig.modResults.push({
138
+ type: 'property',
139
+ key,
140
+ value: RNMapboxMapsDownloadToken,
141
+ });
142
+ return exportedConfig;
143
+ });
144
+ }
145
+ return config;
146
+ };
147
+ const withAndroidPropertiesImpl2 = (config, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsUseV11 }) => {
148
+ const keyValues = {
149
+ expoRNMapboxMapsImpl: RNMapboxMapsImpl,
150
+ expoRNMapboxMapsVersion: RNMapboxMapsVersion,
151
+ expoRNMapboxMapsUseV11: RNMapboxMapsUseV11,
152
+ };
153
+ const keys = Object.keys(keyValues);
154
+ const values = Object.values(keyValues);
155
+ if (values.filter((v) => v).length > 0) {
156
+ return (0, config_plugins_1.withGradleProperties)(config, (exportedConfig) => {
157
+ exportedConfig.modResults = exportedConfig.modResults.filter((item) => !(item.type === 'property' && keys.includes(item.key)));
158
+ keys.forEach((key) => {
159
+ const value = keyValues[key];
160
+ if (value != null) {
161
+ exportedConfig.modResults.push({
162
+ type: 'property',
163
+ key: key,
164
+ value: value.toString(),
165
+ });
166
+ }
167
+ });
168
+ return exportedConfig;
169
+ });
170
+ }
171
+ return config;
172
+ };
173
+ const withAndroidProperties = (config, { RNMapboxMapsImpl, RNMapboxMapsDownloadToken, RNMapboxMapsVersion, RNMapboxMapsUseV11, }) => {
174
+ config = withAndroidPropertiesDownloadToken(config, {
175
+ RNMapboxMapsDownloadToken,
176
+ });
177
+ config = withAndroidPropertiesImpl2(config, {
178
+ RNMapboxMapsImpl,
179
+ RNMapboxMapsVersion,
180
+ RNMapboxMapsUseV11,
181
+ });
182
+ return config;
183
+ };
184
+ const addLibCppFilter = (appBuildGradle) => {
185
+ if (appBuildGradle.includes("pickFirst 'lib/x86/libc++_shared.so'")) {
186
+ return appBuildGradle;
187
+ }
188
+ return (0, generateCode_1.mergeContents)({
189
+ tag: `@rnmapbox/maps-libcpp`,
190
+ src: appBuildGradle,
191
+ newSrc: `packagingOptions {
192
+ pickFirst 'lib/x86/libc++_shared.so'
193
+ pickFirst 'lib/x86_64/libc++_shared.so'
194
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
195
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
196
+ }`,
197
+ anchor: new RegExp(`^\\s*android\\s*{`),
198
+ offset: 1,
199
+ comment: '//',
200
+ }).contents;
201
+ };
202
+ // Because we need the package to be added AFTER the React and Google maven packages, we create a new allprojects.
203
+ // It's ok to have multiple allprojects.repositories, so we create a new one since it's cheaper than tokenizing
204
+ // the existing block to find the correct place to insert our mapbox maven.
205
+ const gradleMaven = `
206
+ allprojects {
207
+ repositories {
208
+ maven {
209
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
210
+ authentication { basic(BasicAuthentication) }
211
+ credentials {
212
+ username = 'mapbox'
213
+ password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
214
+ }
215
+ }
216
+ }
217
+ }
218
+ `;
219
+ // Fork of config-plugins mergeContents, but appends the contents to the end of the file.
220
+ const appendContents = ({ src, newSrc, tag, comment, }) => {
221
+ const header = (0, generateCode_1.createGeneratedHeaderComment)(newSrc, tag, comment);
222
+ if (!src.includes(header)) {
223
+ // Ensure the old generated contents are removed.
224
+ const sanitizedTarget = (0, generateCode_1.removeGeneratedContents)(src, tag);
225
+ const contentsToAdd = [
226
+ // @something
227
+ header,
228
+ // contents
229
+ newSrc,
230
+ // @end
231
+ `${comment} @generated end ${tag}`,
232
+ ].join('\n');
233
+ return {
234
+ contents: sanitizedTarget ?? src + contentsToAdd,
235
+ didMerge: true,
236
+ didClear: !!sanitizedTarget,
237
+ };
238
+ }
239
+ return { contents: src, didClear: false, didMerge: false };
240
+ };
241
+ const addMapboxMavenRepo = (src) => appendContents({
242
+ tag: '@rnmapbox/maps-v2-maven',
243
+ src,
244
+ newSrc: gradleMaven,
245
+ comment: '//',
246
+ }).contents;
247
+ exports.addMapboxMavenRepo = addMapboxMavenRepo;
248
+ exports._addMapboxMavenRepo = exports.addMapboxMavenRepo;
249
+ const withAndroidAppGradle = (config) => (0, config_plugins_1.withAppBuildGradle)(config, ({ modResults, ...exportedConfig }) => {
250
+ if (modResults.language !== 'groovy') {
251
+ config_plugins_1.WarningAggregator.addWarningAndroid('withMapbox', `Cannot automatically configure app build.gradle if it's not groovy`);
252
+ return { modResults, ...exportedConfig };
253
+ }
254
+ modResults.contents = addLibCppFilter(modResults.contents);
255
+ return { modResults, ...exportedConfig };
256
+ });
257
+ const withAndroidProjectGradle = (config) => (0, config_plugins_1.withProjectBuildGradle)(config, ({ modResults, ...exportedConfig }) => {
258
+ if (modResults.language !== 'groovy') {
259
+ config_plugins_1.WarningAggregator.addWarningAndroid('withMapbox', `Cannot automatically configure app build.gradle if it's not groovy`);
260
+ return { modResults, ...exportedConfig };
261
+ }
262
+ modResults.contents = (0, exports.addMapboxMavenRepo)(modResults.contents);
263
+ return { modResults, ...exportedConfig };
264
+ });
265
+ const withMapboxAndroid = (config, { RNMapboxMapsImpl, RNMapboxMapsDownloadToken, RNMapboxMapsVersion, RNMapboxMapsUseV11, }) => {
266
+ config = withAndroidProperties(config, {
267
+ RNMapboxMapsImpl,
268
+ RNMapboxMapsDownloadToken,
269
+ RNMapboxMapsVersion,
270
+ RNMapboxMapsUseV11,
271
+ });
272
+ config = withAndroidProjectGradle(config, { RNMapboxMapsImpl });
273
+ config = withAndroidAppGradle(config, { RNMapboxMapsImpl });
274
+ return config;
275
+ };
276
+ const withMapbox = (config, { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsDownloadToken, RNMapboxMapsUseV11, }) => {
277
+ config = withMapboxAndroid(config, {
278
+ RNMapboxMapsImpl,
279
+ RNMapboxMapsVersion,
280
+ RNMapboxMapsUseV11,
281
+ RNMapboxMapsDownloadToken,
282
+ });
283
+ config = withCocoaPodsInstallerBlocks(config, {
284
+ RNMapboxMapsImpl,
285
+ RNMapboxMapsVersion,
286
+ RNMapboxMapsDownloadToken,
287
+ RNMapboxMapsUseV11,
288
+ });
289
+ return config;
290
+ };
291
+ exports.default = (0, config_plugins_1.createRunOncePlugin)(withMapbox, pkg.name, pkg.version);
@@ -0,0 +1,56 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ const rootDir = path.resolve(__dirname, '..');
5
+ const destDir = path.resolve(rootDir, 'lib/commonjs');
6
+ const pluginDir = path.resolve(rootDir, 'plugin');
7
+ const appPluginFile = path.resolve(rootDir, 'app.plugin.js');
8
+
9
+ function copyFileSync(source: string, target: string) {
10
+ let targetFile = target;
11
+
12
+ // If target is a directory, a new file with the same name will be created
13
+ if (fs.existsSync(target)) {
14
+ if (fs.lstatSync(target).isDirectory()) {
15
+ targetFile = path.join(target, path.basename(source));
16
+ }
17
+ }
18
+
19
+ fs.writeFileSync(targetFile, fs.readFileSync(source));
20
+ }
21
+
22
+ function copyFolderRecursiveSync(source: string, target: string) {
23
+ let files = [];
24
+
25
+ // Check if folder needs to be created or integrated
26
+ const targetFolder = path.join(target, path.basename(source));
27
+ if (!fs.existsSync(targetFolder)) {
28
+ fs.mkdirSync(targetFolder);
29
+ }
30
+
31
+ // Copy
32
+ if (fs.lstatSync(source).isDirectory()) {
33
+ files = fs.readdirSync(source);
34
+ files.forEach((file) => {
35
+ const curSource = path.join(source, file);
36
+ if (fs.lstatSync(curSource).isDirectory()) {
37
+ copyFolderRecursiveSync(curSource, targetFolder);
38
+ } else {
39
+ copyFileSync(curSource, targetFolder);
40
+ }
41
+ });
42
+ }
43
+ }
44
+
45
+ // Ensure destination directory exists
46
+ if (!fs.existsSync(destDir)) {
47
+ fs.mkdirSync(destDir, { recursive: true });
48
+ }
49
+
50
+ // Copy app.plugin.js
51
+ copyFileSync(appPluginFile, destDir);
52
+
53
+ // Copy plugin folder
54
+ copyFolderRecursiveSync(pluginDir, destDir);
55
+
56
+ console.log('Files copied successfully.');
@@ -0,0 +1,110 @@
1
+ # Expo Installation
2
+
3
+ > :warning: This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/).
4
+
5
+ First install the package with [`expo`](https://docs.expo.io/workflow/expo-cli/#expo-install), [`yarn`or `npm`](../README.md#step-1---install-package).
6
+
7
+ Install the latest release:
8
+ ```sh
9
+ expo install @rnmapbox/maps
10
+ ```
11
+
12
+ ## Plugin Configuration
13
+
14
+ After installing this package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.{json,config.js,config.ts}`:
15
+
16
+ ```json
17
+ {
18
+ "expo": {
19
+ "plugins": [
20
+ [
21
+ "@rnmapbox/maps",
22
+ {
23
+ "RNMapboxMapsVersion": "11.8.0"
24
+ }
25
+ ]
26
+ ]
27
+ }
28
+ }
29
+ ```
30
+
31
+ You'll need to provide `RNMapboxMapsDownloadToken` as well. This secret token requires the `DOWNLOADS:READ` scope. You can refer to the [iOS guide](https://docs.mapbox.com/ios/maps/guides/install/#configure-credentials), which explains how to configure this token under the section `Configure your secret token`.
32
+
33
+ ```json
34
+ {
35
+ "expo": {
36
+ "plugins": [
37
+ [
38
+ "@rnmapbox/maps",
39
+ {
40
+ "RNMapboxMapsDownloadToken": "sk.ey...qg"
41
+ }
42
+ ]
43
+ ]
44
+ }
45
+ }
46
+ ```
47
+
48
+ If you want to show the user's current location on the map with the [UserLocation](../docs/UserLocation.md) component, you can use the [expo-location](https://docs.expo.dev/versions/latest/sdk/location/) plugin to configure the required `NSLocationWhenInUseUsageDescription` property. Install the plugin with `npx expo install expo-location` and add its config plugin to the plugins array of your `app.{json,config.js,config.ts}`:
49
+
50
+ ```json
51
+ {
52
+ "expo": {
53
+ "plugins": [
54
+ [
55
+ "expo-location",
56
+ {
57
+ "locationWhenInUsePermission": "Show current location on map."
58
+ }
59
+ ]
60
+ ]
61
+ }
62
+ }
63
+ ```
64
+
65
+ Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide.
66
+
67
+ ### Advanced Configuration
68
+
69
+ It's possible to overwrite the native SDK version with `RNMapboxMapsVersion`:
70
+
71
+ ```json
72
+ {
73
+ "expo": {
74
+ "plugins": [
75
+ [
76
+ "@rnmapbox/maps",
77
+ {
78
+ "RNMapboxMapsVersion": "10.16.2",
79
+ "RNMapboxMapsDownloadToken": "sk.ey...qg"
80
+ }
81
+ ]
82
+ ]
83
+ }
84
+ }
85
+ ```
86
+
87
+ To use V11 just set the version to a 11 version, see [the ios guide](/ios/install.md):
88
+
89
+ ```json
90
+ {
91
+ "expo": {
92
+ "plugins": [
93
+ [
94
+ "@rnmapbox/maps",
95
+ {
96
+ "RNMapboxMapsVersion": "11.8.0",
97
+ "RNMapboxMapsDownloadToken": "sk.ey...qg",
98
+ }
99
+ ]
100
+ ]
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## Manual Setup
106
+
107
+ For bare workflow projects, you can follow the manual setup guides:
108
+
109
+ - [iOS](/ios/install.md)
110
+ - [Android](/android/install.md)
@@ -0,0 +1 @@
1
+ module.exports = require('expo-module-scripts/jest-preset-plugin');
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Taken from @expo/config-plugins
3
+ *
4
+ * Sourcecode: https://github.com/expo/expo/blob/59ece3cb1d5a7aaea42f4c7fe9d1f4f825b338f8/packages/@expo/config-plugins/src/utils/generateCode.ts
5
+ * LICENSE: https://github.com/expo/expo/blob/59ece3cb1d5a7aaea42f4c7fe9d1f4f825b338f8/packages/@expo/config-plugins/LICENSE
6
+ */
7
+
8
+ /**
9
+ * Get line indexes for the generated section of a file.
10
+ *
11
+ * @param src
12
+ */
13
+ import crypto from 'crypto';
14
+
15
+ function getGeneratedSectionIndexes(
16
+ src: string,
17
+ tag: string,
18
+ ): { contents: string[]; start: number; end: number } {
19
+ const contents = src.split('\n');
20
+ const start = contents.findIndex((line) =>
21
+ line.includes(`@generated begin ${tag}`),
22
+ );
23
+ const end = contents.findIndex((line) =>
24
+ line.includes(`@generated end ${tag}`),
25
+ );
26
+
27
+ return { contents, start, end };
28
+ }
29
+
30
+ export type MergeResults = {
31
+ contents: string;
32
+ didClear: boolean;
33
+ didMerge: boolean;
34
+ };
35
+
36
+ /**
37
+ * Merge the contents of two files together and add a generated header.
38
+ *
39
+ * @param src contents of the original file
40
+ * @param newSrc new contents to merge into the original file
41
+ * @param identifier used to update and remove merges
42
+ * @param anchor regex to where the merge should begin
43
+ * @param offset line offset to start merging at (<1 for behind the anchor)
44
+ * @param comment comment style `//` or `#`
45
+ */
46
+ export function mergeContents({
47
+ src,
48
+ newSrc,
49
+ tag,
50
+ anchor,
51
+ offset,
52
+ comment,
53
+ }: {
54
+ src: string;
55
+ newSrc: string;
56
+ tag: string;
57
+ anchor: string | RegExp;
58
+ offset: number;
59
+ comment: string;
60
+ }): MergeResults {
61
+ const header = createGeneratedHeaderComment(newSrc, tag, comment);
62
+ if (!src.includes(header)) {
63
+ // Ensure the old generated contents are removed.
64
+ const sanitizedTarget = removeGeneratedContents(src, tag);
65
+ return {
66
+ contents: addLines(sanitizedTarget ?? src, anchor, offset, [
67
+ header,
68
+ ...newSrc.split('\n'),
69
+ `${comment} @generated end ${tag}`,
70
+ ]),
71
+ didMerge: true,
72
+ didClear: !!sanitizedTarget,
73
+ };
74
+ }
75
+ return { contents: src, didClear: false, didMerge: false };
76
+ }
77
+
78
+ export function removeContents({
79
+ src,
80
+ tag,
81
+ }: {
82
+ src: string;
83
+ tag: string;
84
+ }): MergeResults {
85
+ // Ensure the old generated contents are removed.
86
+ const sanitizedTarget = removeGeneratedContents(src, tag);
87
+ return {
88
+ contents: sanitizedTarget ?? src,
89
+ didMerge: false,
90
+ didClear: !!sanitizedTarget,
91
+ };
92
+ }
93
+
94
+ function addLines(
95
+ content: string,
96
+ find: string | RegExp,
97
+ offset: number,
98
+ toAdd: string[],
99
+ ) {
100
+ const lines = content.split('\n');
101
+
102
+ let lineIndex = lines.findIndex((line) => line.match(find));
103
+ if (lineIndex < 0) {
104
+ const error = new Error(
105
+ `Failed to match "${find}" in contents:\n${content}`,
106
+ );
107
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
108
+ // @ts-ignore
109
+ error.code = 'ERR_NO_MATCH';
110
+ throw error;
111
+ }
112
+ for (const newLine of toAdd) {
113
+ lines.splice(lineIndex + offset, 0, newLine);
114
+ lineIndex++;
115
+ }
116
+
117
+ return lines.join('\n');
118
+ }
119
+
120
+ /**
121
+ * Removes the generated section from a file, returns null when nothing can be removed.
122
+ * This sways heavily towards not removing lines unless it's certain that modifications were not made manually.
123
+ *
124
+ * @param src
125
+ */
126
+ export function removeGeneratedContents(
127
+ src: string,
128
+ tag: string,
129
+ ): string | null {
130
+ const { contents, start, end } = getGeneratedSectionIndexes(src, tag);
131
+ if (start > -1 && end > -1 && start < end) {
132
+ contents.splice(start, end - start + 1);
133
+ // TODO: We could in theory check that the contents we're removing match the hash used in the header,
134
+ // this would ensure that we don't accidentally remove lines that someone added or removed from the generated section.
135
+ return contents.join('\n');
136
+ }
137
+ return null;
138
+ }
139
+
140
+ export function createGeneratedHeaderComment(
141
+ contents: string,
142
+ tag: string,
143
+ comment: string,
144
+ ): string {
145
+ const hashKey = createHash(contents);
146
+
147
+ // Everything after the `${tag} ` is unversioned and can be freely modified without breaking changes.
148
+ return `${comment} @generated begin ${tag} - expo prebuild (DO NOT MODIFY) ${hashKey}`;
149
+ }
150
+
151
+ export function createHash(src: string): string {
152
+ // this doesn't need to be secure, the shorter the better.
153
+ const hash = crypto.createHash('sha1').update(src).digest('hex');
154
+ return `sync-${hash}`;
155
+ }
@@ -0,0 +1,466 @@
1
+ import { promises } from 'fs';
2
+ import path from 'path';
3
+
4
+ import {
5
+ ConfigPlugin,
6
+ createRunOncePlugin,
7
+ withDangerousMod,
8
+ withGradleProperties,
9
+ WarningAggregator,
10
+ withProjectBuildGradle,
11
+ withAppBuildGradle,
12
+ } from 'expo/config-plugins';
13
+
14
+ import {
15
+ mergeContents,
16
+ createGeneratedHeaderComment,
17
+ removeGeneratedContents,
18
+ MergeResults,
19
+ } from './generateCode';
20
+
21
+ let pkg: { name: string; version?: string } = {
22
+ name: '@rnmapbox/maps',
23
+ };
24
+ try {
25
+ pkg = require('@rnmapbox/maps/package.json');
26
+ } catch {
27
+ // empty catch block
28
+ }
29
+
30
+ type InstallerBlockName = 'pre' | 'post';
31
+
32
+ export type MapboxPlugProps = {
33
+ /**
34
+ * @deprecated
35
+ */
36
+ RNMapboxMapsImpl?: 'mapbox';
37
+
38
+ RNMapboxMapsVersion?: string;
39
+
40
+ RNMapboxMapsDownloadToken?: string;
41
+
42
+ RNMapboxMapsUseV11?: boolean;
43
+ };
44
+
45
+ export const addInstallerBlock = (
46
+ src: string,
47
+ blockName: InstallerBlockName,
48
+ ): string => {
49
+ const matchBlock = new RegExp(`${blockName}_install do \\|installer\\|`);
50
+ const tag = `${blockName}_installer`;
51
+
52
+ for (const line of src.split('\n')) {
53
+ const contents = line.trim();
54
+ // Ignore comments
55
+ if (!contents.startsWith('#')) {
56
+ // Prevent adding the block if it exists outside of comments.
57
+ if (contents.match(matchBlock)) {
58
+ // This helps to still allow revisions, since we enabled the block previously.
59
+ // Only continue if the generated block exists...
60
+ const modified = removeGeneratedContents(src, tag);
61
+ if (!modified) {
62
+ return src;
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ return mergeContents({
69
+ tag,
70
+ src,
71
+ newSrc: [` ${blockName}_install do |installer|`, ' end'].join('\n'),
72
+ anchor: /use_react_native/,
73
+ // We can't go after the use_react_native block because it might have parameters, causing it to be multi-line (see react-native template).
74
+ offset: 0,
75
+ comment: '#',
76
+ }).contents;
77
+ };
78
+
79
+ export const addConstantBlock = (
80
+ src: string,
81
+ {
82
+ RNMapboxMapsImpl,
83
+ RNMapboxMapsVersion,
84
+ RNMapboxMapsDownloadToken,
85
+ RNMapboxMapsUseV11,
86
+ }: MapboxPlugProps,
87
+ ): string => {
88
+ const tag = `@rnmapbox/maps-rnmapboxmapsimpl`;
89
+
90
+ if (
91
+ RNMapboxMapsVersion == null &&
92
+ RNMapboxMapsDownloadToken == null &&
93
+ RNMapboxMapsUseV11 == null
94
+ ) {
95
+ const modified = removeGeneratedContents(src, tag);
96
+ if (!modified) {
97
+ return src;
98
+ } else {
99
+ return modified;
100
+ }
101
+ }
102
+
103
+ const newSrc = [];
104
+
105
+ if (RNMapboxMapsDownloadToken) {
106
+ newSrc.push(`$RNMapboxMapsDownloadToken = '${RNMapboxMapsDownloadToken}'`);
107
+ }
108
+
109
+ if (RNMapboxMapsImpl) {
110
+ newSrc.push(`$RNMapboxMapsImpl = '${RNMapboxMapsImpl}'`);
111
+ }
112
+
113
+ if (RNMapboxMapsVersion) {
114
+ newSrc.push(`$RNMapboxMapsVersion = '${RNMapboxMapsVersion}'`);
115
+ }
116
+
117
+ if (RNMapboxMapsUseV11) {
118
+ newSrc.push(`$RNMapboxMapsUseV11 = true`);
119
+ }
120
+
121
+ return mergeContents({
122
+ tag,
123
+ src,
124
+ newSrc: newSrc.join('\n'),
125
+ anchor: /target .+ do/,
126
+ // We can't go after the use_react_native block because it might have parameters, causing it to be multi-line (see react-native template).
127
+ offset: 0,
128
+ comment: '#',
129
+ }).contents;
130
+ };
131
+
132
+ // Only the preinstaller block is required, the post installer block is
133
+ // used for spm (swift package manager) which Expo doesn't currently support.
134
+ export const applyCocoaPodsModifications = (
135
+ contents: string,
136
+ {
137
+ RNMapboxMapsImpl,
138
+ RNMapboxMapsVersion,
139
+ RNMapboxMapsDownloadToken,
140
+ RNMapboxMapsUseV11,
141
+ }: MapboxPlugProps,
142
+ ): string => {
143
+ // Ensure installer blocks exist
144
+ let src = addConstantBlock(contents, {
145
+ RNMapboxMapsImpl,
146
+ RNMapboxMapsVersion,
147
+ RNMapboxMapsDownloadToken,
148
+ RNMapboxMapsUseV11,
149
+ });
150
+ src = addInstallerBlock(src, 'pre');
151
+ src = addInstallerBlock(src, 'post');
152
+ src = addMapboxInstallerBlock(src, 'pre');
153
+ src = addMapboxInstallerBlock(src, 'post');
154
+
155
+ return src;
156
+ };
157
+
158
+ export const addMapboxInstallerBlock = (
159
+ src: string,
160
+ blockName: InstallerBlockName,
161
+ ): string =>
162
+ mergeContents({
163
+ tag: `@rnmapbox/maps-${blockName}_installer`,
164
+ src,
165
+ newSrc: ` $RNMapboxMaps.${blockName}_install(installer)`,
166
+ anchor: new RegExp(`^\\s*${blockName}_install do \\|installer\\|`),
167
+ offset: 1,
168
+ comment: '#',
169
+ }).contents;
170
+
171
+ /**
172
+ * Dangerously adds the custom installer hooks to the Podfile.
173
+ * In the future this should be removed in favor of some custom hooks provided by Expo autolinking.
174
+ *
175
+ * https://github.com/rnmapbox/maps/blob/main/ios/install.md#react-native--0600
176
+ */
177
+ const withCocoaPodsInstallerBlocks: ConfigPlugin<MapboxPlugProps> = (
178
+ config,
179
+ {
180
+ RNMapboxMapsImpl,
181
+ RNMapboxMapsVersion,
182
+ RNMapboxMapsDownloadToken,
183
+ RNMapboxMapsUseV11,
184
+ },
185
+ ) =>
186
+ withDangerousMod(config, [
187
+ 'ios',
188
+ async (exportedConfig) => {
189
+ const file = path.join(
190
+ exportedConfig.modRequest.platformProjectRoot,
191
+ 'Podfile',
192
+ );
193
+
194
+ const contents = await promises.readFile(file, 'utf8');
195
+ await promises.writeFile(
196
+ file,
197
+ applyCocoaPodsModifications(contents, {
198
+ RNMapboxMapsImpl,
199
+ RNMapboxMapsVersion,
200
+ RNMapboxMapsDownloadToken,
201
+ RNMapboxMapsUseV11,
202
+ }),
203
+ 'utf-8',
204
+ );
205
+
206
+ return exportedConfig;
207
+ },
208
+ ]);
209
+
210
+ const withAndroidPropertiesDownloadToken: ConfigPlugin<MapboxPlugProps> = (
211
+ config,
212
+ { RNMapboxMapsDownloadToken },
213
+ ) => {
214
+ const key = 'MAPBOX_DOWNLOADS_TOKEN';
215
+
216
+ if (RNMapboxMapsDownloadToken) {
217
+ return withGradleProperties(config, (exportedConfig) => {
218
+ exportedConfig.modResults = exportedConfig.modResults.filter(
219
+ (item) => !(item.type === 'property' && item.key === key),
220
+ );
221
+ exportedConfig.modResults.push({
222
+ type: 'property',
223
+ key,
224
+ value: RNMapboxMapsDownloadToken,
225
+ });
226
+
227
+ return exportedConfig;
228
+ });
229
+ }
230
+
231
+ return config;
232
+ };
233
+
234
+ const withAndroidPropertiesImpl2: ConfigPlugin<MapboxPlugProps> = (
235
+ config,
236
+ { RNMapboxMapsImpl, RNMapboxMapsVersion, RNMapboxMapsUseV11 },
237
+ ) => {
238
+ const keyValues = {
239
+ expoRNMapboxMapsImpl: RNMapboxMapsImpl,
240
+ expoRNMapboxMapsVersion: RNMapboxMapsVersion,
241
+ expoRNMapboxMapsUseV11: RNMapboxMapsUseV11,
242
+ } as const;
243
+ type Keys = keyof typeof keyValues;
244
+ const keys = Object.keys(keyValues) as Keys[];
245
+ const values = Object.values(keyValues);
246
+
247
+ if (values.filter((v) => v).length > 0) {
248
+ return withGradleProperties(config, (exportedConfig) => {
249
+ exportedConfig.modResults = exportedConfig.modResults.filter(
250
+ (item) =>
251
+ !(item.type === 'property' && (keys as string[]).includes(item.key)),
252
+ );
253
+ keys.forEach((key) => {
254
+ const value = keyValues[key];
255
+ if (value != null) {
256
+ exportedConfig.modResults.push({
257
+ type: 'property',
258
+ key: key,
259
+ value: value.toString(),
260
+ });
261
+ }
262
+ });
263
+
264
+ return exportedConfig;
265
+ });
266
+ }
267
+
268
+ return config;
269
+ };
270
+
271
+ const withAndroidProperties: ConfigPlugin<MapboxPlugProps> = (
272
+ config,
273
+ {
274
+ RNMapboxMapsImpl,
275
+ RNMapboxMapsDownloadToken,
276
+ RNMapboxMapsVersion,
277
+ RNMapboxMapsUseV11,
278
+ },
279
+ ) => {
280
+ config = withAndroidPropertiesDownloadToken(config, {
281
+ RNMapboxMapsDownloadToken,
282
+ });
283
+ config = withAndroidPropertiesImpl2(config, {
284
+ RNMapboxMapsImpl,
285
+ RNMapboxMapsVersion,
286
+ RNMapboxMapsUseV11,
287
+ });
288
+
289
+ return config;
290
+ };
291
+
292
+ const addLibCppFilter = (appBuildGradle: string): string => {
293
+ if (appBuildGradle.includes("pickFirst 'lib/x86/libc++_shared.so'")) {
294
+ return appBuildGradle;
295
+ }
296
+
297
+ return mergeContents({
298
+ tag: `@rnmapbox/maps-libcpp`,
299
+ src: appBuildGradle,
300
+ newSrc: `packagingOptions {
301
+ pickFirst 'lib/x86/libc++_shared.so'
302
+ pickFirst 'lib/x86_64/libc++_shared.so'
303
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
304
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
305
+ }`,
306
+ anchor: new RegExp(`^\\s*android\\s*{`),
307
+ offset: 1,
308
+ comment: '//',
309
+ }).contents;
310
+ };
311
+
312
+ // Because we need the package to be added AFTER the React and Google maven packages, we create a new allprojects.
313
+ // It's ok to have multiple allprojects.repositories, so we create a new one since it's cheaper than tokenizing
314
+ // the existing block to find the correct place to insert our mapbox maven.
315
+ const gradleMaven = `
316
+ allprojects {
317
+ repositories {
318
+ maven {
319
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
320
+ authentication { basic(BasicAuthentication) }
321
+ credentials {
322
+ username = 'mapbox'
323
+ password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
324
+ }
325
+ }
326
+ }
327
+ }
328
+ `;
329
+
330
+ // Fork of config-plugins mergeContents, but appends the contents to the end of the file.
331
+ const appendContents = ({
332
+ src,
333
+ newSrc,
334
+ tag,
335
+ comment,
336
+ }: {
337
+ src: string;
338
+ newSrc: string;
339
+ tag: string;
340
+ comment: string;
341
+ }): MergeResults => {
342
+ const header = createGeneratedHeaderComment(newSrc, tag, comment);
343
+
344
+ if (!src.includes(header)) {
345
+ // Ensure the old generated contents are removed.
346
+ const sanitizedTarget = removeGeneratedContents(src, tag);
347
+ const contentsToAdd = [
348
+ // @something
349
+ header,
350
+ // contents
351
+ newSrc,
352
+ // @end
353
+ `${comment} @generated end ${tag}`,
354
+ ].join('\n');
355
+
356
+ return {
357
+ contents: sanitizedTarget ?? src + contentsToAdd,
358
+ didMerge: true,
359
+ didClear: !!sanitizedTarget,
360
+ };
361
+ }
362
+
363
+ return { contents: src, didClear: false, didMerge: false };
364
+ };
365
+
366
+ export const addMapboxMavenRepo = (src: string): string =>
367
+ appendContents({
368
+ tag: '@rnmapbox/maps-v2-maven',
369
+ src,
370
+ newSrc: gradleMaven,
371
+ comment: '//',
372
+ }).contents;
373
+
374
+ const withAndroidAppGradle: ConfigPlugin<MapboxPlugProps> = (config) =>
375
+ withAppBuildGradle(config, ({ modResults, ...exportedConfig }) => {
376
+ if (modResults.language !== 'groovy') {
377
+ WarningAggregator.addWarningAndroid(
378
+ 'withMapbox',
379
+ `Cannot automatically configure app build.gradle if it's not groovy`,
380
+ );
381
+
382
+ return { modResults, ...exportedConfig };
383
+ }
384
+
385
+ modResults.contents = addLibCppFilter(modResults.contents);
386
+
387
+ return { modResults, ...exportedConfig };
388
+ });
389
+
390
+ const withAndroidProjectGradle: ConfigPlugin<MapboxPlugProps> = (config) =>
391
+ withProjectBuildGradle(config, ({ modResults, ...exportedConfig }) => {
392
+ if (modResults.language !== 'groovy') {
393
+ WarningAggregator.addWarningAndroid(
394
+ 'withMapbox',
395
+ `Cannot automatically configure app build.gradle if it's not groovy`,
396
+ );
397
+
398
+ return { modResults, ...exportedConfig };
399
+ }
400
+
401
+ modResults.contents = addMapboxMavenRepo(modResults.contents);
402
+
403
+ return { modResults, ...exportedConfig };
404
+ });
405
+
406
+ const withMapboxAndroid: ConfigPlugin<MapboxPlugProps> = (
407
+ config,
408
+ {
409
+ RNMapboxMapsImpl,
410
+ RNMapboxMapsDownloadToken,
411
+ RNMapboxMapsVersion,
412
+ RNMapboxMapsUseV11,
413
+ },
414
+ ) => {
415
+ config = withAndroidProperties(config, {
416
+ RNMapboxMapsImpl,
417
+ RNMapboxMapsDownloadToken,
418
+ RNMapboxMapsVersion,
419
+ RNMapboxMapsUseV11,
420
+ });
421
+ config = withAndroidProjectGradle(config, { RNMapboxMapsImpl });
422
+ config = withAndroidAppGradle(config, { RNMapboxMapsImpl });
423
+
424
+ return config;
425
+ };
426
+
427
+ const withMapbox: ConfigPlugin<MapboxPlugProps> = (
428
+ config,
429
+ {
430
+ RNMapboxMapsImpl,
431
+ RNMapboxMapsVersion,
432
+ RNMapboxMapsDownloadToken,
433
+ RNMapboxMapsUseV11,
434
+ },
435
+ ) => {
436
+ config = withMapboxAndroid(config, {
437
+ RNMapboxMapsImpl,
438
+ RNMapboxMapsVersion,
439
+ RNMapboxMapsUseV11,
440
+ RNMapboxMapsDownloadToken,
441
+ });
442
+ config = withCocoaPodsInstallerBlocks(config, {
443
+ RNMapboxMapsImpl,
444
+ RNMapboxMapsVersion,
445
+ RNMapboxMapsDownloadToken,
446
+ RNMapboxMapsUseV11,
447
+ });
448
+
449
+ return config;
450
+ };
451
+
452
+ export default createRunOncePlugin(withMapbox, pkg.name, pkg.version);
453
+
454
+ // TODO: export internal functions for testing purposes
455
+ export {
456
+ // the following methods accept a string and return a string
457
+ addMapboxMavenRepo as _addMapboxMavenRepo,
458
+ // addLibCppFilter as _addLibCppFilter,
459
+ // Following methods accept a config object
460
+ // withAndroidProperties as _withAndroidProperties,
461
+ // withAndroidPropertiesDownloadToken as _withAndroidPropertiesDownloadToken,
462
+ // withAndroidPropertiesImpl2 as _withAndroidPropertiesImpl2,
463
+ // withAndroidAppGradle as _withAndroidAppGradle,
464
+ // withAndroidProjectGradle as _withAndroidProjectGradle,
465
+ // withMapboxAndroid as _withMapboxAndroid,
466
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "compilerOptions": {
3
+ },
4
+ "include": ["./copy-plugin.ts"],
5
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "expo-module-scripts/tsconfig.plugin",
3
+ "compilerOptions": {
4
+ "outDir": "build",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["./src"],
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rnmapbox/maps",
3
3
  "description": "A Mapbox react native module for creating custom maps",
4
- "version": "10.1.35",
4
+ "version": "10.1.36",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -53,7 +53,8 @@
53
53
  "build:examples.json": "cd example; jest __tests__/dumpExamplesJson.ts",
54
54
  "lint:plugin": "yarn eslint plugin/src/*",
55
55
  "build": "yarn bob build",
56
- "prepare": "yarn bob build"
56
+ "prepare": "yarn bob build",
57
+ "build:copy-plugin": "yarn ts-node plugin/copy-plugin.ts"
57
58
  },
58
59
  "peerDependencies": {
59
60
  "expo": ">=47.0.0",
@@ -121,9 +122,9 @@
121
122
  "react-docgen": "rnmapbox/react-docgen#rnmapbox-dist-react-docgen-v6",
122
123
  "to-fast-properties": "3.0.1",
123
124
  "react-native": "0.76.7",
124
- "react-native-builder-bob": "^0.36.0",
125
+ "react-native-builder-bob": "^0.37.0",
125
126
  "react-test-renderer": "18.3.1",
126
- "ts-node": "10.9.1",
127
+ "ts-node": "10.9.2",
127
128
  "typescript": "5.1.3",
128
129
  "@mdx-js/mdx": "^3.0.0",
129
130
  "@types/react": "^18.3.1",
@@ -140,15 +141,6 @@
140
141
  "lint-staged": {
141
142
  "*.{js,jsx,ts,tsx}": "eslint --fix"
142
143
  },
143
- "react-native-builder-bob": {
144
- "source": "src",
145
- "output": "lib",
146
- "targets": [
147
- "commonjs",
148
- "module",
149
- "typescript"
150
- ]
151
- },
152
144
  "eslintIgnore": [
153
145
  "node_modules/",
154
146
  "lib/"
@@ -0,0 +1,56 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ const rootDir = path.resolve(__dirname, '..');
5
+ const destDir = path.resolve(rootDir, 'lib/commonjs');
6
+ const pluginDir = path.resolve(rootDir, 'plugin');
7
+ const appPluginFile = path.resolve(rootDir, 'app.plugin.js');
8
+
9
+ function copyFileSync(source: string, target: string) {
10
+ let targetFile = target;
11
+
12
+ // If target is a directory, a new file with the same name will be created
13
+ if (fs.existsSync(target)) {
14
+ if (fs.lstatSync(target).isDirectory()) {
15
+ targetFile = path.join(target, path.basename(source));
16
+ }
17
+ }
18
+
19
+ fs.writeFileSync(targetFile, fs.readFileSync(source));
20
+ }
21
+
22
+ function copyFolderRecursiveSync(source: string, target: string) {
23
+ let files = [];
24
+
25
+ // Check if folder needs to be created or integrated
26
+ const targetFolder = path.join(target, path.basename(source));
27
+ if (!fs.existsSync(targetFolder)) {
28
+ fs.mkdirSync(targetFolder);
29
+ }
30
+
31
+ // Copy
32
+ if (fs.lstatSync(source).isDirectory()) {
33
+ files = fs.readdirSync(source);
34
+ files.forEach((file) => {
35
+ const curSource = path.join(source, file);
36
+ if (fs.lstatSync(curSource).isDirectory()) {
37
+ copyFolderRecursiveSync(curSource, targetFolder);
38
+ } else {
39
+ copyFileSync(curSource, targetFolder);
40
+ }
41
+ });
42
+ }
43
+ }
44
+
45
+ // Ensure destination directory exists
46
+ if (!fs.existsSync(destDir)) {
47
+ fs.mkdirSync(destDir, { recursive: true });
48
+ }
49
+
50
+ // Copy app.plugin.js
51
+ copyFileSync(appPluginFile, destDir);
52
+
53
+ // Copy plugin folder
54
+ copyFolderRecursiveSync(pluginDir, destDir);
55
+
56
+ console.log('Files copied successfully.');
@@ -0,0 +1,5 @@
1
+ {
2
+ "compilerOptions": {
3
+ },
4
+ "include": ["./copy-plugin.ts"],
5
+ }