1#!/usr/bin/env node 2'use strict'; 3 4const fs = require('fs'); 5const glob = require('glob'); 6const path = require('path'); 7 8function replaceAll(current, replacement, content) { 9 const regexp = new RegExp(escapeRegExp('${' + current + '}'), 'g'); 10 return content.replace(regexp, replacement); 11} 12 13function escapeRegExp(string) { 14 return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 15} 16 17function removeUnapplicableSections(name, content) { 18 const opener = `<!--- remove for ${name} --->`; 19 const closer = `<!--- end remove for ${name} --->`; 20 let nextContent = content; 21 22 while (nextContent.includes(opener)) { 23 const openIndex = nextContent.indexOf(opener); 24 let closeIndex = nextContent.indexOf(closer); 25 if (!closeIndex) { 26 console.warn(`Can't find section closer for ${name}`); 27 closeIndex = openIndex + opener.length; 28 } 29 const section = nextContent.substring(openIndex, closeIndex + closer.length); 30 nextContent = nextContent.replace(section, ''); 31 } 32 return nextContent; 33} 34 35function removeOptionals(content) { 36 const regexp = new RegExp(escapeRegExp('<!---') + '.*' + escapeRegExp('--->') + '\n', 'g'); 37 return content.replace(regexp, ''); 38} 39 40const DEFAULT_HOMEPAGE = 'https://docs.expo.dev/versions/latest/'; 41 42function generateREADME() { 43 const template = path.join(__dirname, '..', 'templates', 'README.md'); 44 let readme = fs.readFileSync(template, 'utf8'); 45 const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8')); 46 const packageName = pkg.name; 47 const homepage = pkg.homepage || DEFAULT_HOMEPAGE; 48 const description = pkg.description || 'Put a description of your Unimodule here'; 49 50 // This isn't really accurate, but these all behave the same as far as READMEs go 51 const isInterface = packageName.endsWith('-interface') || packageName.endsWith('-provider'); 52 53 const isAndroid = fs.existsSync(path.join(process.cwd(), 'android')); 54 const isIOS = fs.existsSync(path.join(process.cwd(), 'ios')); 55 56 // Search in docs/versions/unversioned/sdk/*.md - can't find it? Ask what it should be and initialize for them 57 readme = replaceAll('packageName', packageName, readme); 58 readme = replaceAll('description', description, readme); 59 60 if (isIOS) { 61 const podspecs = glob.sync('{ios/**/,}*.podspec'); 62 const podspecPath = podspecs[0]; 63 const podName = (() => { 64 const parts = podspecPath.split('/'); 65 return parts[parts.length - 1].replace('.podspec', ''); 66 })(); 67 68 readme = replaceAll('podName', podName, readme); 69 } else { 70 readme = removeUnapplicableSections('no-ios', readme); 71 } 72 73 if (isInterface) { 74 readme = removeUnapplicableSections('interfaces', readme); 75 } else { 76 let docName; 77 if (homepage === DEFAULT_HOMEPAGE || homepage.startsWith('https://github.com')) { 78 docName = packageName.replace('expo-', ''); 79 console.warn( 80 `Tried to guess the docs homepage for ${packageName}; add it under the "homepage" entry in package.json` 81 ); 82 } else { 83 docName = (() => { 84 const parts = homepage.split('/'); 85 // Handle both with and without trailing slash 86 let name = parts[parts.length - 1]; 87 if (name === '') { 88 name = parts[parts.length - 2]; 89 } 90 return name; 91 })(); 92 } 93 readme = replaceAll('docName', docName, readme); 94 if (isAndroid) { 95 const androidPackages = glob.sync('android/src/**/*Package.{java,kt}'); 96 let androidPackage; 97 let androidPackagePath = 'expo.modules.yourModule.YourPackage'; 98 let androidPackageName = 'YourPackage'; 99 if (!androidPackages) { 100 console.warn( 101 `No Android package classes found, using: ${androidPackageName} - be sure to update this` 102 ); 103 } else { 104 androidPackage = androidPackages[0]; 105 if (androidPackages.length > 1) { 106 console.warn('Found multiple packages, which one should we use?'); 107 androidPackage = androidPackages[0]; 108 } 109 110 if (androidPackage) { 111 // From: android/src/main/java/expo/modules/localization/LocalizationPackage.java' 112 // To: expo.modules.localization.LocalizationPackage 113 androidPackagePath = androidPackage 114 .split('/java/')[1] 115 .replace(/\//g, '.') 116 .replace('.java', ''); 117 androidPackageName = (() => { 118 const parts = androidPackagePath.split('.'); 119 return parts[parts.length - 1]; 120 })(); 121 122 readme = replaceAll('androidPackageName', androidPackageName, readme); 123 } else { 124 readme = removeUnapplicableSections('no-package', readme); 125 } 126 } 127 128 readme = replaceAll('androidPackagePath', androidPackagePath, readme); 129 } else { 130 readme = removeUnapplicableSections('no-android', readme); 131 } 132 } 133 return removeOptionals(readme); 134} 135 136const readme = generateREADME(); 137const readmePath = path.join(process.cwd(), 'README.md'); 138if (fs.existsSync(readmePath)) { 139 console.log('expo-module-scripts: README.md exists, not updating'); 140} else { 141 fs.writeFileSync(readmePath, readme, { encoding: 'utf8' }); 142} 143