react-native-bootsplash 5.3.0 → 5.4.1

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/src/generate.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  import murmurhash from "@emotion/hash";
2
+ import { IOSConfig } from "@expo/config-plugins";
3
+ import plist from "@expo/plist";
4
+ import { findProjectRoot } from "@react-native-community/cli-tools";
2
5
  import {
3
6
  AndroidProjectConfig,
4
- CommandFunction,
5
7
  IOSProjectConfig,
6
8
  } from "@react-native-community/cli-types";
7
9
  import detectIndent from "detect-indent";
8
- import fs from "fs-extra";
10
+ import fs from "fs";
9
11
  import { parse as parseHtml } from "node-html-parser";
10
12
  import path from "path";
11
13
  import pc from "picocolors";
@@ -103,6 +105,43 @@ const getStoryboard = ({
103
105
  `;
104
106
  };
105
107
 
108
+ export const addFileToXcodeProject = (filePath: string) => {
109
+ const projectRoot = findProjectRoot(workingPath);
110
+
111
+ const pbxprojectPath = IOSConfig.Paths.getPBXProjectPath(projectRoot);
112
+ const project = IOSConfig.XcodeUtils.getPbxproj(projectRoot);
113
+ const xcodeProjectPath = IOSConfig.Paths.getXcodeProjectPath(projectRoot);
114
+
115
+ IOSConfig.XcodeUtils.addResourceFileToGroup({
116
+ filepath: filePath,
117
+ groupName: path.parse(xcodeProjectPath).name,
118
+ project,
119
+ isBuildFile: true,
120
+ });
121
+
122
+ hfs.write(pbxprojectPath, project.writeSync());
123
+ logWrite(pbxprojectPath);
124
+ };
125
+
126
+ // Freely inspired by https://github.com/humanwhocodes/humanfs
127
+ export const hfs = {
128
+ buffer: (path: string) => fs.readFileSync(path),
129
+ exists: (path: string) => fs.existsSync(path),
130
+ json: (path: string) => JSON.parse(fs.readFileSync(path, "utf-8")) as unknown,
131
+ readDir: (path: string) => fs.readdirSync(path, "utf-8"),
132
+ realPath: (path: string) => fs.realpathSync(path, "utf-8"),
133
+ rm: (path: string) => fs.rmSync(path, { force: true }),
134
+ text: (path: string) => fs.readFileSync(path, "utf-8"),
135
+
136
+ ensureDir: (dir: string) => {
137
+ fs.mkdirSync(dir, { recursive: true });
138
+ },
139
+ write: (file: string, data: string) => {
140
+ const trimmed = data.trim();
141
+ fs.writeFileSync(file, trimmed === "" ? trimmed : trimmed + "\n", "utf-8");
142
+ },
143
+ };
144
+
106
145
  export const log = {
107
146
  error: (text: string) => console.log(pc.red(`❌ ${text}`)),
108
147
  text: (text: string) => console.log(text),
@@ -121,12 +160,12 @@ export const logWrite = (
121
160
  );
122
161
 
123
162
  export const writeJson = (file: string, json: object) => {
124
- fs.writeFileSync(file, JSON.stringify(json, null, 2) + "\n", "utf-8");
163
+ hfs.write(file, JSON.stringify(json, null, 2));
125
164
  logWrite(file);
126
165
  };
127
166
 
128
167
  export const readXml = (file: string) => {
129
- const xml = fs.readFileSync(file, "utf-8");
168
+ const xml = hfs.text(file);
130
169
  const { indent } = detectIndent(xml);
131
170
 
132
171
  const formatOptions: XMLFormatterOptions = {
@@ -150,12 +189,12 @@ export const writeXml = (
150
189
  ...options,
151
190
  });
152
191
 
153
- fs.writeFileSync(file, formatted + "\n", "utf-8");
192
+ hfs.write(file, formatted);
154
193
  logWrite(file);
155
194
  };
156
195
 
157
196
  export const readHtml = (file: string) => {
158
- const html = fs.readFileSync(file, "utf-8");
197
+ const html = hfs.text(file);
159
198
  const { type, amount } = detectIndent(html);
160
199
 
161
200
  const formatOptions: PrettierOptions = {
@@ -179,15 +218,16 @@ export const writeHtml = async (
179
218
  ...options,
180
219
  });
181
220
 
182
- fs.writeFileSync(file, formatted, "utf-8");
221
+ hfs.write(file, formatted);
183
222
  logWrite(file);
184
223
  };
185
224
 
186
225
  export const cleanIOSAssets = (dir: string, prefix: string) => {
187
- fs.readdirSync(dir, "utf-8")
226
+ hfs
227
+ .readDir(dir)
188
228
  .filter((file) => file.startsWith(prefix) && file.endsWith(".png"))
189
229
  .map((file) => path.join(dir, file))
190
- .forEach((file) => fs.rmSync(file, { force: true }));
230
+ .forEach((file) => hfs.rm(file));
191
231
  };
192
232
 
193
233
  export const getIOSAssetFileName = async ({
@@ -249,7 +289,7 @@ const getAndroidResPath = (
249
289
  "res",
250
290
  );
251
291
 
252
- if (!fs.existsSync(androidResPath)) {
292
+ if (!hfs.exists(androidResPath)) {
253
293
  log.warn(
254
294
  `No ${path.relative(
255
295
  workingPath,
@@ -283,7 +323,7 @@ const getIOSProjectPath = (ios: IOSProjectConfig): string | undefined => {
283
323
  .resolve(ios.sourceDir, ios.xcodeProject.name)
284
324
  .replace(/\.(xcodeproj|xcworkspace)$/, "");
285
325
 
286
- if (!fs.existsSync(iosProjectPath)) {
326
+ if (!hfs.exists(iosProjectPath)) {
287
327
  log.warn(
288
328
  `No ${path.relative(
289
329
  workingPath,
@@ -298,7 +338,7 @@ const getIOSProjectPath = (ios: IOSProjectConfig): string | undefined => {
298
338
  const getHtmlTemplatePath = (html: string): string | undefined => {
299
339
  const htmlTemplatePath = path.resolve(workingPath, html);
300
340
 
301
- if (!fs.existsSync(htmlTemplatePath)) {
341
+ if (!hfs.exists(htmlTemplatePath)) {
302
342
  log.warn(
303
343
  `No ${path.relative(
304
344
  workingPath,
@@ -347,7 +387,19 @@ const requireAddon = ():
347
387
  }
348
388
  };
349
389
 
350
- export const generate: CommandFunction<{
390
+ export const generate = async ({
391
+ android,
392
+ ios,
393
+ platforms,
394
+ html,
395
+ flavor,
396
+ licenseKey,
397
+ ...args
398
+ }: {
399
+ android?: AndroidProjectConfig;
400
+ ios?: IOSProjectConfig;
401
+
402
+ logo: string;
351
403
  platforms: string[];
352
404
  background: string;
353
405
  logoWidth: number;
@@ -361,11 +413,7 @@ export const generate: CommandFunction<{
361
413
  darkBackground?: string;
362
414
  darkLogo?: string;
363
415
  darkBrand?: string;
364
- }> = async (
365
- [argsLogo],
366
- { project: { android, ios } },
367
- { platforms, html, flavor, licenseKey, ...args },
368
- ) => {
416
+ }) => {
369
417
  const [nodeStringVersion = ""] = process.versions.node.split(".");
370
418
  const nodeVersion = parseInt(nodeStringVersion, 10);
371
419
 
@@ -374,12 +422,7 @@ export const generate: CommandFunction<{
374
422
  process.exit(1);
375
423
  }
376
424
 
377
- if (argsLogo == null) {
378
- log.error("Missing required argument 'logo'");
379
- process.exit(1);
380
- }
381
-
382
- const logoPath = path.resolve(workingPath, argsLogo);
425
+ const logoPath = path.resolve(workingPath, args.logo);
383
426
 
384
427
  const darkLogoPath =
385
428
  args.darkLogo != null
@@ -498,12 +541,12 @@ export const generate: CommandFunction<{
498
541
  log.title("🤖", "Android");
499
542
 
500
543
  const valuesPath = path.resolve(androidResPath, "values");
501
- fs.ensureDirSync(valuesPath);
544
+ hfs.ensureDir(valuesPath);
502
545
 
503
546
  const colorsXmlPath = path.resolve(valuesPath, "colors.xml");
504
547
  const colorsXmlEntry = `<color name="bootsplash_background">${background.hex}</color>`;
505
548
 
506
- if (fs.existsSync(colorsXmlPath)) {
549
+ if (hfs.exists(colorsXmlPath)) {
507
550
  const { root, formatOptions } = readXml(colorsXmlPath);
508
551
  const nextColor = parseHtml(colorsXmlEntry);
509
552
  const prevColor = root.querySelector(
@@ -534,7 +577,7 @@ export const generate: CommandFunction<{
534
577
  `drawable-${suffix}`,
535
578
  );
536
579
 
537
- fs.ensureDirSync(drawableDirPath);
580
+ hfs.ensureDir(drawableDirPath);
538
581
 
539
582
  // https://developer.android.com/develop/ui/views/launch/splash-screen#dimensions
540
583
  const canvasSize = 288 * ratio;
@@ -594,13 +637,39 @@ export const generate: CommandFunction<{
594
637
  { whiteSpaceAtEndOfSelfclosingTag: false },
595
638
  );
596
639
 
640
+ addFileToXcodeProject(
641
+ path.join(path.basename(iosProjectPath), "BootSplash.storyboard"),
642
+ );
643
+
644
+ const infoPlistPath = path.join(iosProjectPath, "Info.plist");
645
+
646
+ const infoPlist = plist.parse(hfs.text(infoPlistPath)) as Record<
647
+ string,
648
+ unknown
649
+ >;
650
+
651
+ infoPlist["UILaunchStoryboardName"] = "BootSplash.storyboard";
652
+
653
+ const formatted = formatXml(plist.build(infoPlist), {
654
+ collapseContent: true,
655
+ forceSelfClosingEmptyTag: false,
656
+ indentation: "\t",
657
+ lineSeparator: "\n",
658
+ whiteSpaceAtEndOfSelfclosingTag: false,
659
+ })
660
+ .replace(/<string\/>/gm, "<string></string>")
661
+ .replace(/^\t/gm, "");
662
+
663
+ hfs.write(infoPlistPath, formatted);
664
+ logWrite(infoPlistPath);
665
+
597
666
  const imageSetPath = path.resolve(
598
667
  iosProjectPath,
599
668
  "Images.xcassets",
600
669
  "BootSplashLogo.imageset",
601
670
  );
602
671
 
603
- fs.ensureDirSync(imageSetPath);
672
+ hfs.ensureDir(imageSetPath);
604
673
  cleanIOSAssets(imageSetPath, "bootsplash_logo");
605
674
 
606
675
  const logoFileName = await getIOSAssetFileName({
@@ -665,7 +734,7 @@ export const generate: CommandFunction<{
665
734
 
666
735
  const base64 = (
667
736
  format === "svg"
668
- ? fs.readFileSync(logoPath)
737
+ ? hfs.buffer(logoPath)
669
738
  : await logo
670
739
  .clone()
671
740
  .resize(Math.round(logoWidth * 2))
@@ -723,7 +792,7 @@ export const generate: CommandFunction<{
723
792
  if (assetsOutputPath != null) {
724
793
  log.title("📄", "Assets");
725
794
 
726
- fs.ensureDirSync(assetsOutputPath);
795
+ hfs.ensureDir(assetsOutputPath);
727
796
 
728
797
  writeJson(path.resolve(assetsOutputPath, "bootsplash_manifest.json"), {
729
798
  background: background.hex,