18864b1cdSBrent Vatne#!/usr/bin/env node 28864b1cdSBrent Vatne'use strict'; 38864b1cdSBrent Vatne 48864b1cdSBrent Vatneconst fs = require('fs'); 58864b1cdSBrent Vatneconst glob = require('glob'); 6a9e9eb76SJames Ideconst path = require('path'); 78864b1cdSBrent Vatne 88864b1cdSBrent Vatnefunction replaceAll(current, replacement, content) { 9a9e9eb76SJames Ide const regexp = new RegExp(escapeRegExp('${' + current + '}'), 'g'); 108864b1cdSBrent Vatne return content.replace(regexp, replacement); 118864b1cdSBrent Vatne} 128864b1cdSBrent Vatne 138864b1cdSBrent Vatnefunction escapeRegExp(string) { 148864b1cdSBrent Vatne return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 158864b1cdSBrent Vatne} 168864b1cdSBrent Vatne 178864b1cdSBrent Vatnefunction removeUnapplicableSections(name, content) { 18a9e9eb76SJames Ide const opener = `<!--- remove for ${name} --->`; 19a9e9eb76SJames Ide const closer = `<!--- end remove for ${name} --->`; 208864b1cdSBrent Vatne let nextContent = content; 218864b1cdSBrent Vatne 228864b1cdSBrent Vatne while (nextContent.includes(opener)) { 23a9e9eb76SJames Ide const openIndex = nextContent.indexOf(opener); 248864b1cdSBrent Vatne let closeIndex = nextContent.indexOf(closer); 258864b1cdSBrent Vatne if (!closeIndex) { 268864b1cdSBrent Vatne console.warn(`Can't find section closer for ${name}`); 278864b1cdSBrent Vatne closeIndex = openIndex + opener.length; 288864b1cdSBrent Vatne } 29a9e9eb76SJames Ide const section = nextContent.substring(openIndex, closeIndex + closer.length); 308864b1cdSBrent Vatne nextContent = nextContent.replace(section, ''); 318864b1cdSBrent Vatne } 328864b1cdSBrent Vatne return nextContent; 338864b1cdSBrent Vatne} 348864b1cdSBrent Vatne 358864b1cdSBrent Vatnefunction removeOptionals(content) { 36a9e9eb76SJames Ide const regexp = new RegExp(escapeRegExp('<!---') + '.*' + escapeRegExp('--->') + '\n', 'g'); 378864b1cdSBrent Vatne return content.replace(regexp, ''); 388864b1cdSBrent Vatne} 398864b1cdSBrent Vatne 40b52e368fSJames Ideconst DEFAULT_HOMEPAGE = 'https://docs.expo.dev/versions/latest/'; 418864b1cdSBrent Vatne 428864b1cdSBrent Vatnefunction generateREADME() { 43a9e9eb76SJames Ide const template = path.join(__dirname, '..', 'templates', 'README.md'); 448864b1cdSBrent Vatne let readme = fs.readFileSync(template, 'utf8'); 45a9e9eb76SJames Ide const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8')); 46a9e9eb76SJames Ide const packageName = pkg.name; 47a9e9eb76SJames Ide const homepage = pkg.homepage || DEFAULT_HOMEPAGE; 48a9e9eb76SJames Ide const description = pkg.description || 'Put a description of your Unimodule here'; 498864b1cdSBrent Vatne 508864b1cdSBrent Vatne // This isn't really accurate, but these all behave the same as far as READMEs go 51a9e9eb76SJames Ide const isInterface = packageName.endsWith('-interface') || packageName.endsWith('-provider'); 528864b1cdSBrent Vatne 53a9e9eb76SJames Ide const isAndroid = fs.existsSync(path.join(process.cwd(), 'android')); 54a9e9eb76SJames Ide const isIOS = fs.existsSync(path.join(process.cwd(), 'ios')); 558864b1cdSBrent Vatne 568864b1cdSBrent Vatne // Search in docs/versions/unversioned/sdk/*.md - can't find it? Ask what it should be and initialize for them 578864b1cdSBrent Vatne readme = replaceAll('packageName', packageName, readme); 588864b1cdSBrent Vatne readme = replaceAll('description', description, readme); 598864b1cdSBrent Vatne 608864b1cdSBrent Vatne if (isIOS) { 61a9e9eb76SJames Ide const podspecs = glob.sync('{ios/**/,}*.podspec'); 62a9e9eb76SJames Ide const podspecPath = podspecs[0]; 63a9e9eb76SJames Ide const podName = (() => { 64a9e9eb76SJames Ide const parts = podspecPath.split('/'); 658864b1cdSBrent Vatne return parts[parts.length - 1].replace('.podspec', ''); 668864b1cdSBrent Vatne })(); 678864b1cdSBrent Vatne 688864b1cdSBrent Vatne readme = replaceAll('podName', podName, readme); 698864b1cdSBrent Vatne } else { 708864b1cdSBrent Vatne readme = removeUnapplicableSections('no-ios', readme); 718864b1cdSBrent Vatne } 728864b1cdSBrent Vatne 738864b1cdSBrent Vatne if (isInterface) { 748864b1cdSBrent Vatne readme = removeUnapplicableSections('interfaces', readme); 758864b1cdSBrent Vatne } else { 768864b1cdSBrent Vatne let docName; 778864b1cdSBrent Vatne if (homepage === DEFAULT_HOMEPAGE || homepage.startsWith('https://github.com')) { 788864b1cdSBrent Vatne docName = packageName.replace('expo-', ''); 798864b1cdSBrent Vatne console.warn( 800623af9eSJames Ide `Tried to guess the docs homepage for ${packageName}; add it under the "homepage" entry in package.json` 818864b1cdSBrent Vatne ); 828864b1cdSBrent Vatne } else { 838864b1cdSBrent Vatne docName = (() => { 84a9e9eb76SJames Ide const parts = homepage.split('/'); 858864b1cdSBrent Vatne // Handle both with and without trailing slash 868864b1cdSBrent Vatne let name = parts[parts.length - 1]; 878864b1cdSBrent Vatne if (name === '') { 888864b1cdSBrent Vatne name = parts[parts.length - 2]; 898864b1cdSBrent Vatne } 908864b1cdSBrent Vatne return name; 918864b1cdSBrent Vatne })(); 928864b1cdSBrent Vatne } 938864b1cdSBrent Vatne readme = replaceAll('docName', docName, readme); 948864b1cdSBrent Vatne if (isAndroid) { 95*748ab554SKudo Chien const androidPackages = glob.sync('android/src/**/*Package.{java,kt}'); 968864b1cdSBrent Vatne let androidPackage; 978864b1cdSBrent Vatne let androidPackagePath = 'expo.modules.yourModule.YourPackage'; 988864b1cdSBrent Vatne let androidPackageName = 'YourPackage'; 998864b1cdSBrent Vatne if (!androidPackages) { 1008864b1cdSBrent Vatne console.warn( 1018864b1cdSBrent Vatne `No Android package classes found, using: ${androidPackageName} - be sure to update this` 1028864b1cdSBrent Vatne ); 1038864b1cdSBrent Vatne } else { 1048864b1cdSBrent Vatne androidPackage = androidPackages[0]; 1058864b1cdSBrent Vatne if (androidPackages.length > 1) { 1068864b1cdSBrent Vatne console.warn('Found multiple packages, which one should we use?'); 1078864b1cdSBrent Vatne androidPackage = androidPackages[0]; 1088864b1cdSBrent Vatne } 1098864b1cdSBrent Vatne 1108864b1cdSBrent Vatne if (androidPackage) { 1118864b1cdSBrent Vatne // From: android/src/main/java/expo/modules/localization/LocalizationPackage.java' 1128864b1cdSBrent Vatne // To: expo.modules.localization.LocalizationPackage 1138864b1cdSBrent Vatne androidPackagePath = androidPackage 1148864b1cdSBrent Vatne .split('/java/')[1] 1158864b1cdSBrent Vatne .replace(/\//g, '.') 1168864b1cdSBrent Vatne .replace('.java', ''); 1178864b1cdSBrent Vatne androidPackageName = (() => { 118a9e9eb76SJames Ide const parts = androidPackagePath.split('.'); 1198864b1cdSBrent Vatne return parts[parts.length - 1]; 1208864b1cdSBrent Vatne })(); 1218864b1cdSBrent Vatne 1228864b1cdSBrent Vatne readme = replaceAll('androidPackageName', androidPackageName, readme); 1238864b1cdSBrent Vatne } else { 1248864b1cdSBrent Vatne readme = removeUnapplicableSections('no-package', readme); 1258864b1cdSBrent Vatne } 1268864b1cdSBrent Vatne } 1278864b1cdSBrent Vatne 1288864b1cdSBrent Vatne readme = replaceAll('androidPackagePath', androidPackagePath, readme); 1298864b1cdSBrent Vatne } else { 1308864b1cdSBrent Vatne readme = removeUnapplicableSections('no-android', readme); 1318864b1cdSBrent Vatne } 1328864b1cdSBrent Vatne } 1338864b1cdSBrent Vatne return removeOptionals(readme); 1348864b1cdSBrent Vatne} 1358864b1cdSBrent Vatne 136a9e9eb76SJames Ideconst readme = generateREADME(); 137a9e9eb76SJames Ideconst readmePath = path.join(process.cwd(), 'README.md'); 1388864b1cdSBrent Vatneif (fs.existsSync(readmePath)) { 1398d441c7eSStanisław Chmiela console.log('expo-module-scripts: README.md exists, not updating'); 1408864b1cdSBrent Vatne} else { 1418864b1cdSBrent Vatne fs.writeFileSync(readmePath, readme, { encoding: 'utf8' }); 1428864b1cdSBrent Vatne} 143