rn-env-setup 1.0.0 → 1.1.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.
Files changed (50) hide show
  1. package/README.md +271 -0
  2. package/dist/android/android-generator.d.ts +3 -0
  3. package/dist/android/android-generator.d.ts.map +1 -0
  4. package/dist/android/android-generator.js +154 -0
  5. package/dist/android/android-generator.js.map +1 -0
  6. package/dist/android/gradle-parser.d.ts +32 -0
  7. package/dist/android/gradle-parser.d.ts.map +1 -0
  8. package/dist/android/gradle-parser.js +107 -0
  9. package/dist/android/gradle-parser.js.map +1 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +227 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/generators/ci-generator.d.ts +3 -0
  15. package/dist/generators/ci-generator.d.ts.map +1 -0
  16. package/dist/generators/ci-generator.js +130 -0
  17. package/dist/generators/ci-generator.js.map +1 -0
  18. package/dist/generators/js-env-generator.d.ts +3 -0
  19. package/dist/generators/js-env-generator.d.ts.map +1 -0
  20. package/dist/generators/js-env-generator.js +191 -0
  21. package/dist/generators/js-env-generator.js.map +1 -0
  22. package/dist/index.d.ts +11 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +11 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/ios/ios-generator.d.ts +3 -0
  27. package/dist/ios/ios-generator.d.ts.map +1 -0
  28. package/dist/ios/ios-generator.js +180 -0
  29. package/dist/ios/ios-generator.js.map +1 -0
  30. package/dist/ios/xcode-patcher.d.ts +14 -0
  31. package/dist/ios/xcode-patcher.d.ts.map +1 -0
  32. package/dist/ios/xcode-patcher.js +76 -0
  33. package/dist/ios/xcode-patcher.js.map +1 -0
  34. package/dist/types/index.d.ts +61 -0
  35. package/dist/types/index.d.ts.map +1 -0
  36. package/dist/types/index.js +4 -0
  37. package/dist/types/index.js.map +1 -0
  38. package/dist/utils/config-loader.d.ts +16 -0
  39. package/dist/utils/config-loader.d.ts.map +1 -0
  40. package/dist/utils/config-loader.js +231 -0
  41. package/dist/utils/config-loader.js.map +1 -0
  42. package/dist/utils/file-utils.d.ts +29 -0
  43. package/dist/utils/file-utils.d.ts.map +1 -0
  44. package/dist/utils/file-utils.js +93 -0
  45. package/dist/utils/file-utils.js.map +1 -0
  46. package/dist/utils/validator.d.ts +3 -0
  47. package/dist/utils/validator.d.ts.map +1 -0
  48. package/dist/utils/validator.js +91 -0
  49. package/dist/utils/validator.js.map +1 -0
  50. package/package.json +40 -24
package/README.md ADDED
@@ -0,0 +1,271 @@
1
+ # rn-env-setup
2
+
3
+ > One command to configure Android product flavors, iOS xcconfig + schemes, and JS env files for multi-environment React Native CI.
4
+
5
+ ---
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g rn-env-setup
11
+ # or use without installing:
12
+ npx rn-env-setup init
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Quick Start
18
+
19
+ ### Option A — Interactive (no config file needed)
20
+
21
+ ```bash
22
+ cd your-rn-project
23
+ npx rn-env-setup init # prompts for all details, saves rn-env.yaml
24
+ npx rn-env-setup generate # applies everything
25
+ ```
26
+
27
+ ### Option B — Config file (CI-friendly)
28
+
29
+ 1. Create `rn-env.yaml` in your project root (see example below).
30
+ 2. Run:
31
+
32
+ ```bash
33
+ npx rn-env-setup validate # check for errors first
34
+ npx rn-env-setup generate # apply
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Config File (`rn-env.yaml`)
40
+
41
+ ```yaml
42
+ appName: MyApp
43
+ packageName: com.myapp
44
+ jsEnvStrategy: react-native-config # react-native-config | dotenv | custom | none
45
+ generateJsEnv: true
46
+ generateCiSnippets: false
47
+ enableRollback: true
48
+
49
+ environments:
50
+ - name: dev
51
+ appName: MyApp Dev
52
+ bundleId: com.myapp.dev
53
+ apiUrl: https://dev.api.example.com
54
+ logo: ./assets/icons/dev.png
55
+ variables:
56
+ ENABLE_LOGS: true
57
+ FEATURE_NEW_UI: true
58
+
59
+ - name: staging
60
+ appName: MyApp Staging
61
+ bundleId: com.myapp.staging
62
+ apiUrl: https://staging.api.example.com
63
+
64
+ - name: prod
65
+ appName: MyApp
66
+ bundleId: com.myapp
67
+ apiUrl: https://api.example.com
68
+ ```
69
+
70
+ ---
71
+
72
+ ## CLI Commands
73
+
74
+ | Command | Description |
75
+ |---|---|
76
+ | `rn-env-setup init` | Interactive setup, saves `rn-env.yaml` |
77
+ | `rn-env-setup generate` | Apply config to Android + iOS + JS layer |
78
+ | `rn-env-setup generate --dry-run` | Preview changes without writing files |
79
+ | `rn-env-setup generate --android-only` | Skip iOS generation |
80
+ | `rn-env-setup generate --ios-only` | Skip Android generation |
81
+ | `rn-env-setup generate --config path/to/rn-env.yaml` | Use a specific config file |
82
+ | `rn-env-setup validate` | Validate config without generating |
83
+ | `rn-env-setup rollback` | Restore original files from backups |
84
+
85
+ ---
86
+
87
+ ## What Gets Generated
88
+
89
+ ### Android
90
+
91
+ - **`android/app/build.gradle`** — `flavorDimensions` + `productFlavors` block injected or updated. Includes:
92
+ - `applicationId` per flavor
93
+ - `resValue "string", "app_name"` per flavor
94
+ - `buildConfigField "String", "API_URL"` per flavor
95
+ - All custom `variables` as `buildConfigField` entries
96
+
97
+ - **`android/app/src/{env}/res/values/strings.xml`** — App name override per flavor
98
+
99
+ - **`android/app/src/{env}/res/mipmap-*/ic_launcher.png`** — App icon copied from `logo` path
100
+
101
+ **Build commands output:**
102
+ ```bash
103
+ react-native run-android --variant=devDebug
104
+ react-native run-android --variant=stagingRelease
105
+ cd android && ./gradlew assembleProdRelease
106
+ ```
107
+
108
+ ### iOS
109
+
110
+ - **`ios/Configs/MyApp-Dev.xcconfig`** — Per-environment xcconfig with:
111
+ - `PRODUCT_BUNDLE_IDENTIFIER`
112
+ - `PRODUCT_NAME`
113
+ - `API_URL`
114
+ - All custom variables
115
+
116
+ - **`ios/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp-Dev.xcscheme`** — Shared scheme per environment
117
+
118
+ - **`project.pbxproj`** — Build configurations added and wired to xcconfig files
119
+
120
+ **Build commands output:**
121
+ ```bash
122
+ react-native run-ios --scheme MyApp-Dev
123
+ react-native run-ios --scheme MyApp-Staging
124
+ xcodebuild -scheme MyApp-Prod -configuration Prod archive
125
+ ```
126
+
127
+ ### JS Layer
128
+
129
+ **`react-native-config` strategy** → generates `.env.dev`, `.env.staging`, `.env.prod` + `src/env.d.ts`
130
+
131
+ ```bash
132
+ # Usage
133
+ ENVFILE=.env.dev react-native run-android
134
+ ENVFILE=.env.staging react-native run-ios
135
+ ```
136
+
137
+ **`custom` strategy** → generates `src/env.ts` with all environments baked in as a typed module:
138
+
139
+ ```typescript
140
+ import Config from './env';
141
+
142
+ console.log(Config.API_URL); // https://dev.api.example.com
143
+ console.log(Config.ENABLE_LOGS); // true
144
+ ```
145
+
146
+ ---
147
+
148
+ ## CI/CD Integration
149
+
150
+ Set `generateCiSnippets: true` in your config to generate:
151
+ - `.github/workflows/rn-multi-env.yml` — GitHub Actions workflow with one job per environment per platform
152
+ - `bitrise-rn-env.yml` — Bitrise workflow snippets
153
+
154
+ ### Using in CI (no interactive prompts)
155
+
156
+ ```yaml
157
+ # .github/workflows/build.yml
158
+ - name: Generate env config
159
+ run: npx rn-env-setup generate --config rn-env.yaml
160
+ ```
161
+
162
+ The tool is fully non-interactive when a config file exists — safe for all CI environments.
163
+
164
+ ---
165
+
166
+ ## Idempotency
167
+
168
+ `rn-env-setup generate` is safe to run multiple times:
169
+
170
+ - **`build.gradle`**: The injected block is wrapped in marker comments. Re-running replaces only the marked block, leaving all other Gradle configuration untouched.
171
+ - **Xcconfig files**: Overwritten on each run (content is deterministic).
172
+ - **Scheme files**: Skipped if already exist (add `--force` to overwrite).
173
+ - **Source set directories**: Created with `ensureDir` — no-op if present.
174
+ - **Backups**: Only created once per file — won't overwrite an existing backup.
175
+
176
+ ---
177
+
178
+ ## Rollback
179
+
180
+ If generation fails or produces unexpected results:
181
+
182
+ ```bash
183
+ npx rn-env-setup rollback
184
+ ```
185
+
186
+ This restores `.rn-env-backup` copies of `build.gradle` and `project.pbxproj`.
187
+
188
+ ---
189
+
190
+ ## Architecture
191
+
192
+ ```
193
+ src/
194
+ ├── cli.ts # commander entry point: init, generate, validate, rollback
195
+ ├── index.ts # package entrypoint exports for programmatic usage
196
+
197
+ ├── android/
198
+ │ ├── android-generator.ts # Orchestrates Android: gradle + source sets + icons
199
+ │ └── gradle-parser.ts # Safe bracket-balanced build.gradle manipulation
200
+
201
+ ├── ios/
202
+ │ ├── ios-generator.ts # Orchestrates iOS: xcconfig + schemes + pbxproj
203
+ │ └── xcode-patcher.ts # pbxproj manipulation via `xcode` npm package
204
+
205
+ ├── generators/
206
+ │ ├── js-env-generator.ts # .env files / typed env.ts for JS layer
207
+ │ └── ci-generator.ts # GitHub Actions + Bitrise CI snippets
208
+
209
+ ├── types/
210
+ │ ├── index.ts # ProjectConfig, EnvironmentConfig, GenerationResult types
211
+ │ └── xcode.d.ts # Local declaration shim for xcode package
212
+
213
+ └── utils/
214
+ ├── config-loader.ts # YAML/JSON loader + inquirer interactive prompts
215
+ ├── file-utils.ts # backup, rollback, logDry, normalizeEnvName, findFirst
216
+ └── validator.ts # Pre-flight validation: duplicates, paths, bundle IDs
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Gradle Modification Strategy
222
+
223
+ The tool uses **marker-comment-based block replacement** — not regex on the whole file:
224
+
225
+ 1. On first run: locates the `android { }` block using bracket counting, appends the `productFlavors` block before the closing brace.
226
+ 2. On subsequent runs: finds `// ── rn-env-setup: auto-generated` and `// ── end rn-env-setup` markers and replaces only what's between them.
227
+
228
+ This means your other Gradle configuration (signing, dependencies, build types) is **never touched**.
229
+
230
+ ---
231
+
232
+ ## Edge Cases Handled
233
+
234
+ | Case | Handling |
235
+ |---|---|
236
+ | Duplicate environment names | Validation error before generation |
237
+ | Duplicate bundle IDs | Validation error before generation |
238
+ | Missing logo file | Warning, generation continues |
239
+ | Existing productFlavors (not ours) | Warning, replaced by ours |
240
+ | No `.xcodeproj` found | iOS generation skipped with warning |
241
+ | Generation fails mid-way | Rollback restores all backed-up files |
242
+ | Config file not found | Clear error: run `init` first |
243
+
244
+ ---
245
+
246
+ ## Roadmap / Plugin System
247
+
248
+ Future versions will support a plugin API for custom generators:
249
+
250
+ ```typescript
251
+ // rn-env-plugin-firebase.ts (planned)
252
+ export const plugin: RnEnvPlugin = {
253
+ name: 'firebase',
254
+ onGenerate: async (ctx, env) => {
255
+ // Copy google-services.json per flavor
256
+ },
257
+ };
258
+ ```
259
+
260
+ Planned features:
261
+ - `--full-targets` flag for full iOS target duplication
262
+ - White-label / multi-brand support (overlapping environments)
263
+ - OTA / EAS Update channel injection
264
+ - Fastlane lane generation
265
+ - Firebase multi-app configuration
266
+
267
+ ---
268
+
269
+ ## License
270
+
271
+ MIT
@@ -0,0 +1,3 @@
1
+ import { GeneratorContext, GenerationResult } from '../types/index.js';
2
+ export declare function generateAndroid(ctx: GeneratorContext): Promise<GenerationResult>;
3
+ //# sourceMappingURL=android-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"android-generator.d.ts","sourceRoot":"","sources":["../../src/android/android-generator.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAMvE,wBAAsB,eAAe,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgHtF"}
@@ -0,0 +1,154 @@
1
+ // src/android/android-generator.ts
2
+ // Generates Android product flavors, source sets, and app icon directories
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import chalk from 'chalk';
6
+ import { backup, logDry, normalizeEnvName } from '../utils/file-utils.js';
7
+ import { injectFlavorBlock } from './gradle-parser.js';
8
+ const GRADLE_PATH = 'android/app/build.gradle';
9
+ export async function generateAndroid(ctx) {
10
+ const result = {
11
+ success: false,
12
+ filesModified: [],
13
+ filesCreated: [],
14
+ commands: [],
15
+ warnings: [],
16
+ errors: [],
17
+ };
18
+ const gradlePath = path.join(ctx.projectRoot, GRADLE_PATH);
19
+ if (!fs.existsSync(gradlePath)) {
20
+ result.errors.push(`build.gradle not found at ${gradlePath}. Are you in a React Native project?`);
21
+ return result;
22
+ }
23
+ // ── Step 1: Backup original build.gradle ──────────────────────────────────
24
+ if (ctx.config.enableRollback && !ctx.dryRun) {
25
+ await backup(gradlePath);
26
+ }
27
+ // ── Step 2: Read and parse the gradle file ────────────────────────────────
28
+ const gradleContent = fs.readFileSync(gradlePath, 'utf-8');
29
+ // ── Step 3: Build the flavorDimensions + productFlavors block ─────────────
30
+ const flavorBlock = buildFlavorBlock(ctx);
31
+ // ── Step 4: Inject or replace the productFlavors block ───────────────────
32
+ const { content: newGradle, injected } = injectFlavorBlock(gradleContent, flavorBlock);
33
+ if (ctx.dryRun) {
34
+ logDry(`Would modify: ${GRADLE_PATH}`);
35
+ logDry('Generated productFlavors:\n' + flavorBlock);
36
+ }
37
+ else {
38
+ fs.writeFileSync(gradlePath, newGradle, 'utf-8');
39
+ result.filesModified.push(GRADLE_PATH);
40
+ console.log(chalk.green(` ✔ ${injected ? 'Updated' : 'Injected'} productFlavors in ${GRADLE_PATH}`));
41
+ }
42
+ // ── Step 5: Create source sets and icon directories per flavor ────────────
43
+ for (const env of ctx.config.environments) {
44
+ const envKey = normalizeEnvName(env.name);
45
+ // Source set directories
46
+ const srcDirs = [
47
+ `android/app/src/${envKey}/res/values`,
48
+ `android/app/src/${envKey}/res/mipmap-hdpi`,
49
+ `android/app/src/${envKey}/res/mipmap-mdpi`,
50
+ `android/app/src/${envKey}/res/mipmap-xhdpi`,
51
+ `android/app/src/${envKey}/res/mipmap-xxhdpi`,
52
+ `android/app/src/${envKey}/res/mipmap-xxxhdpi`,
53
+ ];
54
+ for (const dir of srcDirs) {
55
+ const fullDir = path.join(ctx.projectRoot, dir);
56
+ if (ctx.dryRun) {
57
+ logDry(`Would create directory: ${dir}`);
58
+ }
59
+ else {
60
+ await fs.ensureDir(fullDir);
61
+ result.filesCreated.push(dir);
62
+ }
63
+ }
64
+ // strings.xml for this flavor (app name override)
65
+ const stringsXml = buildStringsXml(env.appName);
66
+ const stringsPath = `android/app/src/${envKey}/res/values/strings.xml`;
67
+ const fullStringsPath = path.join(ctx.projectRoot, stringsPath);
68
+ if (ctx.dryRun) {
69
+ logDry(`Would create: ${stringsPath}`);
70
+ }
71
+ else {
72
+ fs.writeFileSync(fullStringsPath, stringsXml, 'utf-8');
73
+ result.filesCreated.push(stringsPath);
74
+ console.log(chalk.green(` ✔ Created ${stringsPath}`));
75
+ }
76
+ // Copy logo if specified
77
+ if (env.logo) {
78
+ const logoSrc = path.join(ctx.projectRoot, env.logo);
79
+ if (fs.existsSync(logoSrc)) {
80
+ const logoDest = path.join(ctx.projectRoot, `android/app/src/${envKey}/res/mipmap-xxxhdpi/ic_launcher.png`);
81
+ if (ctx.dryRun) {
82
+ logDry(`Would copy logo: ${env.logo} → android/app/src/${envKey}/res/mipmap-xxxhdpi/ic_launcher.png`);
83
+ }
84
+ else {
85
+ await fs.copy(logoSrc, logoDest, { overwrite: true });
86
+ result.filesCreated.push(logoDest);
87
+ console.log(chalk.green(` ✔ Copied logo for ${envKey}`));
88
+ }
89
+ }
90
+ else {
91
+ result.warnings.push(`Logo not found for ${envKey}: ${env.logo}`);
92
+ }
93
+ }
94
+ // ── Build commands ─────────────────────────────────────────────────────
95
+ for (const buildType of ['debug', 'release']) {
96
+ const variant = `${envKey}${capitalize(buildType)}`;
97
+ result.commands.push({
98
+ platform: 'android',
99
+ environment: env.name,
100
+ buildType,
101
+ command: `react-native run-android --variant=${variant}`,
102
+ description: `Run Android ${env.name} (${buildType})`,
103
+ });
104
+ }
105
+ }
106
+ result.success = true;
107
+ return result;
108
+ }
109
+ // ── Gradle builders ──────────────────────────────────────────────────────────
110
+ function buildFlavorBlock(ctx) {
111
+ const { config } = ctx;
112
+ const flavorDimension = 'environment';
113
+ const flavorsCode = config.environments
114
+ .map((env) => {
115
+ const envKey = normalizeEnvName(env.name);
116
+ const customVars = Object.entries(env.variables ?? {})
117
+ .map(([k, v]) => {
118
+ const type = typeof v === 'boolean' ? 'boolean' : typeof v === 'number' ? 'int' : 'String';
119
+ const quotedVal = type === 'String' ? `\\"${v}\\"` : String(v);
120
+ return ` buildConfigField "${type}", "${k.toUpperCase()}", "${quotedVal}"`;
121
+ })
122
+ .join('\n');
123
+ const suffix = env.versionNameSuffix ?? (env.name !== 'prod' ? `-${env.name}` : '');
124
+ return `
125
+ ${envKey} {
126
+ dimension "${flavorDimension}"
127
+ applicationId "${env.bundleId}"
128
+ versionNameSuffix "${suffix}"
129
+ resValue "string", "app_name", "${env.appName}"
130
+ buildConfigField "String", "API_URL", "\\"${env.apiUrl}\\""
131
+ ${customVars ? customVars + '\n' : ''} }`;
132
+ })
133
+ .join('\n');
134
+ return `
135
+ // ── rn-env-setup: auto-generated — do not edit manually ──
136
+ flavorDimensions "${flavorDimension}"
137
+ productFlavors {${flavorsCode}
138
+ }
139
+ // ── end rn-env-setup ──`;
140
+ }
141
+ function buildStringsXml(appName) {
142
+ return `<?xml version="1.0" encoding="utf-8"?>
143
+ <resources>
144
+ <string name="app_name">${escapeXml(appName)}</string>
145
+ </resources>
146
+ `;
147
+ }
148
+ function escapeXml(str) {
149
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
150
+ }
151
+ function capitalize(s) {
152
+ return s.charAt(0).toUpperCase() + s.slice(1);
153
+ }
154
+ //# sourceMappingURL=android-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"android-generator.js","sourceRoot":"","sources":["../../src/android/android-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export interface GradleInjectResult {
2
+ content: string;
3
+ injected: boolean;
4
+ }
5
+ /**
6
+ * Inject or replace the productFlavors block in build.gradle content.
7
+ *
8
+ * Strategy:
9
+ * 1. If our marker comments exist → replace the entire block between them (idempotent).
10
+ * 2. Else if an `android {` block exists → append inside it before the closing brace.
11
+ * 3. Else throw — we can't safely modify an unrecognized file.
12
+ */
13
+ export declare function injectFlavorBlock(content: string, flavorBlock: string): GradleInjectResult;
14
+ /**
15
+ * Find the start/end character indices of a top-level named block, e.g. `android { ... }`.
16
+ * Uses bracket counting so it handles nested blocks correctly.
17
+ */
18
+ export declare function findTopLevelBlock(content: string, blockName: string): {
19
+ start: number;
20
+ end: number;
21
+ } | null;
22
+ /**
23
+ * Check if a specific flavor name is already declared in the file.
24
+ * Used for idempotency reporting.
25
+ */
26
+ export declare function hasExistingFlavor(content: string, flavorName: string): boolean;
27
+ /**
28
+ * Parse all declared applicationId values from productFlavors.
29
+ * Used to detect duplicate bundle ID conflicts before generation.
30
+ */
31
+ export declare function parseExistingApplicationIds(content: string): string[];
32
+ //# sourceMappingURL=gradle-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gradle-parser.d.ts","sourceRoot":"","sources":["../../src/android/gradle-parser.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAKD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,kBAAkB,CA6C1F;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqBvC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAK9E;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQrE"}
@@ -0,0 +1,107 @@
1
+ // src/android/gradle-parser.ts
2
+ // Safe, idempotent Gradle file manipulation using bracket-balanced block replacement.
3
+ // Never uses regex on the full file — only finds and replaces the specific block.
4
+ const BLOCK_START_MARKER = '// ── rn-env-setup: auto-generated — do not edit manually ──';
5
+ const BLOCK_END_MARKER = '// ── end rn-env-setup ──';
6
+ /**
7
+ * Inject or replace the productFlavors block in build.gradle content.
8
+ *
9
+ * Strategy:
10
+ * 1. If our marker comments exist → replace the entire block between them (idempotent).
11
+ * 2. Else if an `android {` block exists → append inside it before the closing brace.
12
+ * 3. Else throw — we can't safely modify an unrecognized file.
13
+ */
14
+ export function injectFlavorBlock(content, flavorBlock) {
15
+ // Case 1: Already has our markers — safe replace
16
+ const startIdx = content.indexOf(BLOCK_START_MARKER);
17
+ const endIdx = content.indexOf(BLOCK_END_MARKER);
18
+ if (startIdx !== -1 && endIdx !== -1) {
19
+ const before = content.substring(0, startIdx);
20
+ const after = content.substring(endIdx + BLOCK_END_MARKER.length);
21
+ return {
22
+ content: before + flavorBlock.trim() + after,
23
+ injected: true,
24
+ };
25
+ }
26
+ // Case 2: Remove any user-written productFlavors block (replace with ours)
27
+ // Find the `android {` block and locate/replace productFlavors inside it
28
+ const androidBlockRange = findTopLevelBlock(content, 'android');
29
+ if (!androidBlockRange) {
30
+ throw new Error('Could not find `android { }` block in build.gradle. Please ensure your build.gradle has a standard Android block.');
31
+ }
32
+ let androidContent = content.substring(androidBlockRange.start, androidBlockRange.end);
33
+ // Remove any existing productFlavors + flavorDimensions lines
34
+ const existingFlavorsRange = findTopLevelBlock(androidContent, 'productFlavors');
35
+ if (existingFlavorsRange) {
36
+ // Also strip the flavorDimensions line before it
37
+ androidContent =
38
+ androidContent.substring(0, existingFlavorsRange.start).replace(/\s*flavorDimensions[^\n]+\n/, '\n') +
39
+ androidContent.substring(existingFlavorsRange.end);
40
+ }
41
+ // Inject before the closing brace of the android block
42
+ const trimmed = androidContent.trimEnd();
43
+ const newAndroidContent = trimmed.slice(0, -1) + '\n' + indent(flavorBlock, 4) + '\n}\n';
44
+ return {
45
+ content: content.substring(0, androidBlockRange.start) +
46
+ newAndroidContent +
47
+ content.substring(androidBlockRange.end),
48
+ injected: false,
49
+ };
50
+ }
51
+ /**
52
+ * Find the start/end character indices of a top-level named block, e.g. `android { ... }`.
53
+ * Uses bracket counting so it handles nested blocks correctly.
54
+ */
55
+ export function findTopLevelBlock(content, blockName) {
56
+ // Match `blockName {` or `blockName(...) {`
57
+ const regex = new RegExp(`\\b${blockName}\\s*(?:\\([^)]*\\)\\s*)?\\{`);
58
+ const match = regex.exec(content);
59
+ if (!match)
60
+ return null;
61
+ let depth = 0;
62
+ let i = match.index;
63
+ // Walk forward, counting braces
64
+ for (; i < content.length; i++) {
65
+ if (content[i] === '{')
66
+ depth++;
67
+ else if (content[i] === '}') {
68
+ depth--;
69
+ if (depth === 0) {
70
+ return { start: match.index, end: i + 1 };
71
+ }
72
+ }
73
+ }
74
+ return null; // Unbalanced braces
75
+ }
76
+ /**
77
+ * Check if a specific flavor name is already declared in the file.
78
+ * Used for idempotency reporting.
79
+ */
80
+ export function hasExistingFlavor(content, flavorName) {
81
+ const flavorsRange = findTopLevelBlock(content, 'productFlavors');
82
+ if (!flavorsRange)
83
+ return false;
84
+ const flavorsBlock = content.substring(flavorsRange.start, flavorsRange.end);
85
+ return new RegExp(`\\b${flavorName}\\s*\\{`).test(flavorsBlock);
86
+ }
87
+ /**
88
+ * Parse all declared applicationId values from productFlavors.
89
+ * Used to detect duplicate bundle ID conflicts before generation.
90
+ */
91
+ export function parseExistingApplicationIds(content) {
92
+ const ids = [];
93
+ const regex = /applicationId\s+"([^"]+)"/g;
94
+ let match;
95
+ while ((match = regex.exec(content)) !== null) {
96
+ ids.push(match[1]);
97
+ }
98
+ return ids;
99
+ }
100
+ function indent(text, spaces) {
101
+ const pad = ' '.repeat(spaces);
102
+ return text
103
+ .split('\n')
104
+ .map((line) => (line.trim() ? pad + line : line))
105
+ .join('\n');
106
+ }
107
+ //# sourceMappingURL=gradle-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gradle-parser.js","sourceRoot":"","sources":["../../src/android/gradle-parser.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}