@webority/mobile-tools 0.5.0 → 0.6.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/lib/prebuild.js +1 -1
- package/package.json +1 -1
package/lib/prebuild.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{copyFileSync,existsSync,readFileSync,rmSync,writeFileSync}from"node:fs";import path from"node:path";import{applicationId,COMPILED_FILE,ENVIRONMENTS,gradleAppId,lastCompiledEnvironment,loadAppSettings,loadToolsConfig,resolveIosProjectName}from"./config.js";import{capture}from"./exec.js";import{otaNativeSettings,rewriteAndroidManifestOta,rewriteExpoPlistOta}from"./otaNative.js";import{fail,say}from"./output.js";import{findOnPath}from"./platform.js";const eolOf=e=>e.includes("\r\n")?"\r\n":"\n";export const rewriteGradleProperties=(e,t)=>{const o=eolOf(e),i=e.split(o),
|
|
1
|
+
import{copyFileSync,existsSync,readFileSync,rmSync,writeFileSync}from"node:fs";import path from"node:path";import{applicationId,COMPILED_FILE,ENVIRONMENTS,gradleAppId,lastCompiledEnvironment,loadAppSettings,loadToolsConfig,resolveIosProjectName}from"./config.js";import{capture}from"./exec.js";import{otaNativeSettings,rewriteAndroidManifestOta,rewriteExpoPlistOta}from"./otaNative.js";import{fail,say}from"./output.js";import{findOnPath}from"./platform.js";const eolOf=e=>e.includes("\r\n")?"\r\n":"\n";export const rewriteGradleProperties=(e,t)=>{const o=eolOf(e),i=e.split(o),n=new Map(Object.entries(t)),r=i.map(e=>{const t=/^\s*([A-Za-z0-9_.-]+)\s*[=:]/.exec(e);if(t&&n.has(t[1])){const e=t[1],o=n.get(e);return n.delete(e),`${e}=${o}`}return e});if(0===n.size)return r.join(o);const s=[...n].map(([e,t])=>`${e}=${t}`);return r.length>1&&""===r[r.length-1]?r.splice(r.length-1,0,...s):1===r.length&&""===r[0]?r.splice(0,1,...s):r.push(...s),r.join(o)};const pbxValue=e=>/^[A-Za-z0-9._/-]+$/.test(e)?e:`"${e.replace(/"/g,'\\"')}"`;export const rewritePbxproj=(e,t,o={})=>{let i=e;for(const[e,n]of Object.entries(t)){const t=new RegExp(`(\\s)${e} = [^;\\n]*;`,"g");t.test(i)||fail(`${e} not found in project.pbxproj`);const r=o.quote?.includes(e)?`"${n.replace(/"/g,'\\"')}"`:pbxValue(n);i=i.replace(t,(t,o)=>`${o}${e} = ${r};`)}return i};const escapeXml=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");export const rewriteInfoPlistDisplayName=(e,t)=>{const o=/(<key>CFBundleDisplayName<\/key>\s*<string>)[^<]*(<\/string>)/;return o.test(e)||fail("CFBundleDisplayName not found in Info.plist"),e.replace(o,(e,o,i)=>`${o}${escapeXml(t)}${i}`)};const ANDROID_MANIFEST="android/app/src/main/AndroidManifest.xml",expoPlistPath=e=>`ios/${e}/Supporting/Expo.plist`;export const prebuildOutputs=(e,t=!1)=>{const o=[COMPILED_FILE,"android/gradle.properties"];return t&&o.push(ANDROID_MANIFEST),e&&(o.push(`ios/${e}/Info.plist`,`ios/${e}.xcodeproj/project.pbxproj`,`ios/${e}/GoogleService-Info.plist`),t&&o.push(expoPlistPath(e))),o};export const buildCommit=(e,t)=>{const o=findOnPath("git",process.env,process.platform);if(!o)return"nogit";const i=capture({file:o,args:["rev-parse","--short","HEAD"]},e);if(0!==i.status)return"nogit";const n=capture({file:o,args:["status","--porcelain","--",".",...t.map(e=>`:(exclude)${e}`)]},e);return 0!==n.status?fail(`git status failed in ${e}: ${n.stderr.trim()}`):""===n.stdout.trim()?i.stdout.trim():`${i.stdout.trim()}-dirty`};const writeIfChanged=(e,t)=>(!existsSync(e)||readFileSync(e,"utf8")!==t)&&(writeFileSync(e,t,"utf8"),!0),report=(e,t,o)=>{say(`prebuild: ${o?"wrote":"unchanged"} ${path.relative(e,t)}`)};export const usesFirebase=e=>{const t=path.join(e,"package.json");if(!existsSync(t))return!1;const o=JSON.parse(readFileSync(t,"utf8"));return Boolean(o.dependencies?.["@react-native-firebase/app"])};export const checkNdkHook=e=>{const t=path.join(e,"android","build.gradle");if(!existsSync(t))return;const o=readFileSync(t,"utf8");/withId\(\s*["']com\.android\.library["']\s*\)/.test(o)&&/\.ndkVersion\s*=\s*rootProject\.ext\.ndkVersion/.test(o)||fail('android/build.gradle does not hand the app NDK to library modules; add after apply plugin "com.facebook.react.rootproject": subprojects { project -> project.plugins.withId("com.android.library") { project.android.ndkVersion = rootProject.ext.ndkVersion } }')};export const stampAndroid=(e,t,o,i)=>{const n=path.join(e,"android","gradle.properties");existsSync(n)||fail(`android/gradle.properties not found in ${e}`),usesFirebase(e)&&!existsSync(path.join(e,"android","app","google-services.json"))&&fail("android/app/google-services.json is missing; the app uses @react-native-firebase, whose Gradle plugin needs it"),checkNdkHook(e);const r=rewriteGradleProperties(readFileSync(n,"utf8"),{APP_NAME:String(t.APP_NAME),APP_ID:gradleAppId(t.APP_ID,o,i.flavors),VERSION_DISPLAY:String(t.VERSION_DISPLAY),VERSION_INTERNAL:String(t.VERSION_INTERNAL)});report(e,n,writeIfChanged(n,r));const s=otaNativeSettings(e,t,o,"android");if(s){const t=path.join(e,ANDROID_MANIFEST);existsSync(t)||fail(`${ANDROID_MANIFEST} not found: expo-updates reads its settings from it`),report(e,t,writeIfChanged(t,rewriteAndroidManifestOta(readFileSync(t,"utf8"),s)))}};export const stampIos=(e,t,o,i,n)=>{const r=path.join(e,"ios",n),s=path.join(r,"Info.plist"),a=path.join(e,"ios",`${n}.xcodeproj`,"project.pbxproj");for(const t of[s,a])existsSync(t)||fail(`${path.relative(e,t)} not found: check "iosProjectName"`);const p=`AppIcon-${o}`,c=path.join(r,"Images.xcassets"),l=existsSync(path.join(c,`${p}.appiconset`)),d=ENVIRONMENTS.filter(e=>e!==o&&existsSync(path.join(c,`AppIcon-${e}.appiconset`)));!l&&d.length>0&&fail(`ios/${n}/Images.xcassets has AppIcon-${d[0]} but no ${p}: run mobile-tools icons`),report(e,s,writeIfChanged(s,rewriteInfoPlistDisplayName(readFileSync(s,"utf8"),String(t.APP_NAME))));const f={PRODUCT_BUNDLE_IDENTIFIER:applicationId(t.APP_ID,o),MARKETING_VERSION:String(t.VERSION_DISPLAY),CURRENT_PROJECT_VERSION:String(t.VERSION_INTERNAL)};l&&(f.ASSETCATALOG_COMPILER_APPICON_NAME=p),report(e,a,writeIfChanged(a,rewritePbxproj(readFileSync(a,"utf8"),f,{quote:["PRODUCT_BUNDLE_IDENTIFIER"]}))),l||say("prebuild: no AppIcon-<Env> sets, app icon left as the project sets it");const u=path.join(r,"GoogleService-Info.plist"),I=path.join(e,i.firebasePlistDir,`GoogleService-Info.${o}.plist`);if(!existsSync(I)&&usesFirebase(e)&&fail(`${path.relative(e,I)} is missing; the app uses @react-native-firebase, and an iOS build without it reports no crashes`),existsSync(I)){const t=!existsSync(u)||!readFileSync(I).equals(readFileSync(u));t&©FileSync(I,u),report(e,u,t)}else existsSync(u)&&(rmSync(u),say(`prebuild: removed ${path.relative(e,u)}, no ${path.relative(e,I)}`));const S=otaNativeSettings(e,t,o,"ios");if(S){const t=path.join(e,expoPlistPath(n));existsSync(t)||fail(`${expoPlistPath(n)} not found: add it to the Xcode project for expo-updates`),report(e,t,writeIfChanged(t,rewriteExpoPlistOta(readFileSync(t,"utf8"),S)))}};export const prebuild=e=>{const{appRoot:t,sameEnv:o,platform:i}=e;o&&e.env&&fail("pass --env or --same-env, not both",2);const n=o?lastCompiledEnvironment(t):e.env;if(!n)return fail("prebuild needs --env <Development|Staging|Production> or --same-env",2);const r=loadToolsConfig(t),s=resolveIosProjectName(t,r),a=loadAppSettings(t,n),p={...a,COMMIT:buildCommit(t,prebuildOutputs(s,Boolean(a.OTA_UPDATE_BASE_URL))),BUILD_TIME:(new Date).toISOString()};writeFileSync(path.join(t,COMPILED_FILE),`${JSON.stringify(p,null,2)}\n`,"utf8"),say(`prebuild: wrote ${COMPILED_FILE} (${n}, ${p.COMMIT})`);const c=existsSync(path.join(t,"android"));if(("android"===i||!i&&c)&&stampAndroid(t,p,n,r),"ios"===i||!i&&s){if(!s)return fail(`no ios/ folder in ${t}`);stampIos(t,p,n,r,s)}return p};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/mobile-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Dev-time CLI for Webority React Native apps: one prebuild, a dependency guard, a device-aware run, per-environment launcher icons and over-the-air deploys, the same on Windows and macOS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|