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.
- package/README.md +271 -0
- package/dist/android/android-generator.d.ts +3 -0
- package/dist/android/android-generator.d.ts.map +1 -0
- package/dist/android/android-generator.js +154 -0
- package/dist/android/android-generator.js.map +1 -0
- package/dist/android/gradle-parser.d.ts +32 -0
- package/dist/android/gradle-parser.d.ts.map +1 -0
- package/dist/android/gradle-parser.js +107 -0
- package/dist/android/gradle-parser.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +227 -0
- package/dist/cli.js.map +1 -0
- package/dist/generators/ci-generator.d.ts +3 -0
- package/dist/generators/ci-generator.d.ts.map +1 -0
- package/dist/generators/ci-generator.js +130 -0
- package/dist/generators/ci-generator.js.map +1 -0
- package/dist/generators/js-env-generator.d.ts +3 -0
- package/dist/generators/js-env-generator.d.ts.map +1 -0
- package/dist/generators/js-env-generator.js +191 -0
- package/dist/generators/js-env-generator.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/ios/ios-generator.d.ts +3 -0
- package/dist/ios/ios-generator.d.ts.map +1 -0
- package/dist/ios/ios-generator.js +180 -0
- package/dist/ios/ios-generator.js.map +1 -0
- package/dist/ios/xcode-patcher.d.ts +14 -0
- package/dist/ios/xcode-patcher.d.ts.map +1 -0
- package/dist/ios/xcode-patcher.js +76 -0
- package/dist/ios/xcode-patcher.js.map +1 -0
- package/dist/types/index.d.ts +61 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/config-loader.d.ts +16 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +231 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/file-utils.d.ts +29 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +93 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/validator.d.ts +3 -0
- package/dist/utils/validator.d.ts.map +1 -0
- package/dist/utils/validator.js +91 -0
- package/dist/utils/validator.js.map +1 -0
- package/package.json +40 -24
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// src/ios/ios-generator.ts
|
|
2
|
+
// Generates iOS xcconfig files, schemes, and patches Info.plist per environment.
|
|
3
|
+
// For Xcode project (pbxproj) manipulation, delegates to xcode-patcher.ts.
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { backup, logDry, normalizeEnvName, findFirst } from '../utils/file-utils.js';
|
|
8
|
+
import { patchXcodeProject } from './xcode-patcher.js';
|
|
9
|
+
export async function generateIos(ctx) {
|
|
10
|
+
const result = {
|
|
11
|
+
success: false,
|
|
12
|
+
filesModified: [],
|
|
13
|
+
filesCreated: [],
|
|
14
|
+
commands: [],
|
|
15
|
+
warnings: [],
|
|
16
|
+
errors: [],
|
|
17
|
+
};
|
|
18
|
+
const iosDir = path.join(ctx.projectRoot, 'ios');
|
|
19
|
+
if (!fs.existsSync(iosDir)) {
|
|
20
|
+
result.errors.push('ios/ directory not found. Are you in a React Native project?');
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
// Find the .xcodeproj
|
|
24
|
+
const xcodeprojDir = findFirst(iosDir, (f) => f.endsWith('.xcodeproj'));
|
|
25
|
+
if (!xcodeprojDir) {
|
|
26
|
+
result.errors.push('No .xcodeproj found in ios/. Ensure you have run `pod install`.');
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const pbxprojPath = path.join(xcodeprojDir, 'project.pbxproj');
|
|
30
|
+
const appName = ctx.config.appName;
|
|
31
|
+
// Backup pbxproj
|
|
32
|
+
if (ctx.config.enableRollback && !ctx.dryRun) {
|
|
33
|
+
await backup(pbxprojPath);
|
|
34
|
+
}
|
|
35
|
+
// ── Step 1: Create xcconfig files per environment ─────────────────────────
|
|
36
|
+
const xcconfigDir = path.join(iosDir, 'Configs');
|
|
37
|
+
if (!ctx.dryRun) {
|
|
38
|
+
await fs.ensureDir(xcconfigDir);
|
|
39
|
+
}
|
|
40
|
+
for (const env of ctx.config.environments) {
|
|
41
|
+
const envKey = normalizeEnvName(env.name);
|
|
42
|
+
const xcconfigContent = buildXcconfig(env.bundleId, env.appName, env.apiUrl, env.variables ?? {}, env.xconfigExtras ?? {});
|
|
43
|
+
const xcconfigPath = path.join(xcconfigDir, `${appName}-${capitalize(envKey)}.xcconfig`);
|
|
44
|
+
const relPath = `ios/Configs/${appName}-${capitalize(envKey)}.xcconfig`;
|
|
45
|
+
if (ctx.dryRun) {
|
|
46
|
+
logDry(`Would create: ${relPath}`);
|
|
47
|
+
logDry(xcconfigContent);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
fs.writeFileSync(xcconfigPath, xcconfigContent, 'utf-8');
|
|
51
|
+
result.filesCreated.push(relPath);
|
|
52
|
+
console.log(chalk.green(` ✔ Created ${relPath}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// ── Step 2: Create scheme files per environment ───────────────────────────
|
|
56
|
+
const schemesDir = path.join(xcodeprojDir, 'xcshareddata', 'xcschemes');
|
|
57
|
+
if (!ctx.dryRun) {
|
|
58
|
+
await fs.ensureDir(schemesDir);
|
|
59
|
+
}
|
|
60
|
+
for (const env of ctx.config.environments) {
|
|
61
|
+
const envKey = normalizeEnvName(env.name);
|
|
62
|
+
const schemeName = `${appName}-${capitalize(envKey)}`;
|
|
63
|
+
const schemeContent = buildSchemeXml(appName, schemeName, envKey);
|
|
64
|
+
const schemePath = path.join(schemesDir, `${schemeName}.xcscheme`);
|
|
65
|
+
const relPath = `ios/${path.basename(xcodeprojDir)}/xcshareddata/xcschemes/${schemeName}.xcscheme`;
|
|
66
|
+
if (ctx.dryRun) {
|
|
67
|
+
logDry(`Would create scheme: ${relPath}`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Idempotent: only write if not exists or force
|
|
71
|
+
if (!fs.existsSync(schemePath)) {
|
|
72
|
+
fs.writeFileSync(schemePath, schemeContent, 'utf-8');
|
|
73
|
+
result.filesCreated.push(relPath);
|
|
74
|
+
console.log(chalk.green(` ✔ Created scheme ${schemeName}`));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
result.warnings.push(`Scheme already exists, skipping: ${schemeName}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Build commands
|
|
81
|
+
result.commands.push({
|
|
82
|
+
platform: 'ios',
|
|
83
|
+
environment: env.name,
|
|
84
|
+
command: `react-native run-ios --scheme ${schemeName}`,
|
|
85
|
+
description: `Run iOS ${env.name}`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// ── Step 3: Patch the Xcode project (pbxproj) ────────────────────────────
|
|
89
|
+
// This adds build configurations and xcconfig references.
|
|
90
|
+
if (!ctx.dryRun) {
|
|
91
|
+
try {
|
|
92
|
+
await patchXcodeProject(pbxprojPath, ctx.config, xcconfigDir);
|
|
93
|
+
result.filesModified.push(pbxprojPath.replace(ctx.projectRoot + '/', ''));
|
|
94
|
+
console.log(chalk.green(' ✔ Patched Xcode project (pbxproj)'));
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
98
|
+
result.warnings.push(`pbxproj patch failed (manual review may be needed): ${msg}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
logDry('Would patch: ' + pbxprojPath.replace(ctx.projectRoot + '/', ''));
|
|
103
|
+
}
|
|
104
|
+
result.success = true;
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
// ── Builder functions ────────────────────────────────────────────────────────
|
|
108
|
+
function buildXcconfig(bundleId, appName, apiUrl, variables, extras) {
|
|
109
|
+
const customVars = Object.entries(variables)
|
|
110
|
+
.map(([k, v]) => `${k.toUpperCase()} = ${v}`)
|
|
111
|
+
.join('\n');
|
|
112
|
+
const extraVars = Object.entries(extras)
|
|
113
|
+
.map(([k, v]) => `${k} = ${v}`)
|
|
114
|
+
.join('\n');
|
|
115
|
+
return `// rn-env-setup: auto-generated — do not edit manually
|
|
116
|
+
|
|
117
|
+
PRODUCT_BUNDLE_IDENTIFIER = ${bundleId}
|
|
118
|
+
PRODUCT_NAME = ${appName}
|
|
119
|
+
API_URL = ${apiUrl}
|
|
120
|
+
${customVars}
|
|
121
|
+
${extraVars}
|
|
122
|
+
`.trim() + '\n';
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Minimal shared scheme XML. Xcode will augment this on first open.
|
|
126
|
+
* References the target by name — patchXcodeProject wires up the target GUIDs.
|
|
127
|
+
*/
|
|
128
|
+
function buildSchemeXml(baseName, schemeName, envKey) {
|
|
129
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
130
|
+
<Scheme
|
|
131
|
+
LastUpgradeVersion = "1500"
|
|
132
|
+
version = "1.7">
|
|
133
|
+
<BuildAction
|
|
134
|
+
parallelizeBuildables = "YES"
|
|
135
|
+
buildImplicitDependencies = "YES">
|
|
136
|
+
<BuildActionEntries>
|
|
137
|
+
<BuildActionEntry
|
|
138
|
+
buildForTesting = "YES"
|
|
139
|
+
buildForRunning = "YES"
|
|
140
|
+
buildForProfiling = "YES"
|
|
141
|
+
buildForArchiving = "YES"
|
|
142
|
+
buildForAnalyzing = "YES">
|
|
143
|
+
<BuildableReference
|
|
144
|
+
BuildableIdentifier = "primary"
|
|
145
|
+
BlueprintIdentifier = ""
|
|
146
|
+
BuildableName = "${schemeName}.app"
|
|
147
|
+
BlueprintName = "${schemeName}"
|
|
148
|
+
ReferencedContainer = "container:${baseName}.xcodeproj">
|
|
149
|
+
</BuildableReference>
|
|
150
|
+
</BuildActionEntry>
|
|
151
|
+
</BuildActionEntries>
|
|
152
|
+
</BuildAction>
|
|
153
|
+
<LaunchAction
|
|
154
|
+
buildConfiguration = "${capitalize(envKey)}"
|
|
155
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
156
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
157
|
+
launchStyle = "0"
|
|
158
|
+
useCustomWorkingDirectory = "NO"
|
|
159
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
160
|
+
debugDocumentVersioning = "YES"
|
|
161
|
+
debugServiceExtension = "internal"
|
|
162
|
+
allowLocationSimulation = "YES">
|
|
163
|
+
<BuildableProductRunnable
|
|
164
|
+
runnableDebuggingMode = "0">
|
|
165
|
+
<BuildableReference
|
|
166
|
+
BuildableIdentifier = "primary"
|
|
167
|
+
BlueprintIdentifier = ""
|
|
168
|
+
BuildableName = "${schemeName}.app"
|
|
169
|
+
BlueprintName = "${schemeName}"
|
|
170
|
+
ReferencedContainer = "container:${baseName}.xcodeproj">
|
|
171
|
+
</BuildableReference>
|
|
172
|
+
</BuildableProductRunnable>
|
|
173
|
+
</LaunchAction>
|
|
174
|
+
</Scheme>
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
function capitalize(s) {
|
|
178
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=ios-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ios-generator.js","sourceRoot":"","sources":["../../src/ios/ios-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ProjectConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Patch the .pbxproj file to:
|
|
4
|
+
* 1. Add a new XCBuildConfiguration for each environment (Debug + Release variants).
|
|
5
|
+
* 2. Point each configuration to the corresponding xcconfig file.
|
|
6
|
+
* 3. Add the configuration to the XCConfigurationList.
|
|
7
|
+
*
|
|
8
|
+
* NOTE: Full target duplication (creating new PBXNativeTarget entries) is complex
|
|
9
|
+
* and project-specific. This patcher handles build configurations which is the
|
|
10
|
+
* minimum required for xcconfig-based multi-env setups. For target duplication,
|
|
11
|
+
* see the README guide for manual steps or use the --full-targets flag (future).
|
|
12
|
+
*/
|
|
13
|
+
export declare function patchXcodeProject(pbxprojPath: string, config: ProjectConfig, xcconfigDir: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=xcode-patcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode-patcher.d.ts","sourceRoot":"","sources":["../../src/ios/xcode-patcher.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CA8Df"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// src/ios/xcode-patcher.ts
|
|
2
|
+
// Safely patches project.pbxproj using the `xcode` npm package.
|
|
3
|
+
// Adds build configurations and maps them to xcconfig files.
|
|
4
|
+
// Idempotent: checks for existing configurations before adding.
|
|
5
|
+
import xcode from 'xcode';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { normalizeEnvName } from '../utils/file-utils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Patch the .pbxproj file to:
|
|
11
|
+
* 1. Add a new XCBuildConfiguration for each environment (Debug + Release variants).
|
|
12
|
+
* 2. Point each configuration to the corresponding xcconfig file.
|
|
13
|
+
* 3. Add the configuration to the XCConfigurationList.
|
|
14
|
+
*
|
|
15
|
+
* NOTE: Full target duplication (creating new PBXNativeTarget entries) is complex
|
|
16
|
+
* and project-specific. This patcher handles build configurations which is the
|
|
17
|
+
* minimum required for xcconfig-based multi-env setups. For target duplication,
|
|
18
|
+
* see the README guide for manual steps or use the --full-targets flag (future).
|
|
19
|
+
*/
|
|
20
|
+
export async function patchXcodeProject(pbxprojPath, config, xcconfigDir) {
|
|
21
|
+
const proj = xcode.project(pbxprojPath);
|
|
22
|
+
// Parse is synchronous but wrapped in callback-style — promisify it
|
|
23
|
+
await new Promise((resolve, reject) => {
|
|
24
|
+
proj.parse((err) => {
|
|
25
|
+
if (err)
|
|
26
|
+
reject(err);
|
|
27
|
+
else
|
|
28
|
+
resolve();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
const pbxBuildConfigSection = proj.pbxXCBuildConfigurationSection();
|
|
32
|
+
for (const env of config.environments) {
|
|
33
|
+
const envKey = normalizeEnvName(env.name);
|
|
34
|
+
const configName = capitalize(envKey);
|
|
35
|
+
// Check if this build configuration already exists (idempotency)
|
|
36
|
+
const exists = Object.values(pbxBuildConfigSection).some((entry) => typeof entry === 'object' &&
|
|
37
|
+
entry !== null &&
|
|
38
|
+
entry.name === configName);
|
|
39
|
+
if (exists) {
|
|
40
|
+
console.log(` ⚠ Build configuration "${configName}" already exists, skipping`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// xcconfig relative path from the .xcodeproj
|
|
44
|
+
const xcconfigFilename = `${config.appName}-${configName}.xcconfig`;
|
|
45
|
+
const xcconfigRelPath = path.join('Configs', xcconfigFilename);
|
|
46
|
+
// Add the build configuration (Debug-based settings)
|
|
47
|
+
const guid = proj.generateUuid();
|
|
48
|
+
pbxBuildConfigSection[guid] = {
|
|
49
|
+
isa: 'XCBuildConfiguration',
|
|
50
|
+
name: configName,
|
|
51
|
+
buildSettings: {
|
|
52
|
+
// These will be overridden by the xcconfig
|
|
53
|
+
PRODUCT_BUNDLE_IDENTIFIER: `"${env.bundleId}"`,
|
|
54
|
+
PRODUCT_NAME: `"$(TARGET_NAME)"`,
|
|
55
|
+
// Reference to xcconfig for this environment
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
// Add the xcconfig file reference
|
|
59
|
+
try {
|
|
60
|
+
proj.addFile(xcconfigRelPath, proj.getFirstGroup().uuid, {
|
|
61
|
+
lastKnownFileType: 'text.xcconfig',
|
|
62
|
+
explicitFileType: 'text.xcconfig',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// File reference may already exist
|
|
67
|
+
}
|
|
68
|
+
console.log(` ✔ Added build configuration: ${configName}`);
|
|
69
|
+
}
|
|
70
|
+
// Write patched pbxproj back to disk
|
|
71
|
+
fs.writeFileSync(pbxprojPath, proj.writeSync(), 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
function capitalize(s) {
|
|
74
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=xcode-patcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode-patcher.js","sourceRoot":"","sources":["../../src/ios/xcode-patcher.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,gEAAgE;AAChE,6DAA6D;AAC7D,gEAAgE;AAEhE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,MAAqB,EACrB,WAAmB;IAEnB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAExC,oEAAoE;IACpE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,IAAI,CAAC,KAAK,CAAC,CAAC,GAAiB,EAAE,EAAE;YAC/B,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;gBAChB,OAAO,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,qBAAqB,GAAG,IAAI,CAAC,8BAA8B,EAAE,CAAC;IAEpE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAEtC,iEAAiE;QACjE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,IAAI,CACtD,CAAC,KAAc,EAAE,EAAE,CACjB,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACb,KAAiC,CAAC,IAAI,KAAK,UAAU,CACzD,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,8BAA8B,UAAU,4BAA4B,CAAC,CAAC;YAClF,SAAS;QACX,CAAC;QAED,6CAA6C;QAC7C,MAAM,gBAAgB,GAAG,GAAG,MAAM,CAAC,OAAO,IAAI,UAAU,WAAW,CAAC;QACpE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;QAE/D,qDAAqD;QACrD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,qBAAqB,CAAC,IAAI,CAAC,GAAG;YAC5B,GAAG,EAAE,sBAAsB;YAC3B,IAAI,EAAE,UAAU;YAChB,aAAa,EAAE;gBACb,2CAA2C;gBAC3C,yBAAyB,EAAE,IAAI,GAAG,CAAC,QAAQ,GAAG;gBAC9C,YAAY,EAAE,kBAAkB;gBAChC,6CAA6C;aAC9C;SACF,CAAC;QAEF,kCAAkC;QAClC,IAAI,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,aAAa,EAAG,CAAC,IAAI,EAAE;gBACxD,iBAAiB,EAAE,eAAe;gBAClC,gBAAgB,EAAE,eAAe;aAClC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,oCAAoC,UAAU,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,qCAAqC;IACrC,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface EnvironmentConfig {
|
|
2
|
+
/** Internal key: dev | staging | prod | any custom name */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Display name shown in the app launcher */
|
|
5
|
+
appName: string;
|
|
6
|
+
/** Android applicationId / iOS CFBundleIdentifier */
|
|
7
|
+
bundleId: string;
|
|
8
|
+
/** Base API URL injected as BuildConfig / .xcconfig */
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
/** Path to the app icon image (relative to project root) */
|
|
11
|
+
logo?: string;
|
|
12
|
+
/** Arbitrary key-value variables injected into native build configs & JS layer */
|
|
13
|
+
variables?: Record<string, string | boolean | number>;
|
|
14
|
+
/** Optional: version name suffix for Android (e.g. "-dev") */
|
|
15
|
+
versionNameSuffix?: string;
|
|
16
|
+
/** Optional: custom xcconfig values for iOS */
|
|
17
|
+
xconfigExtras?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export interface ProjectConfig {
|
|
20
|
+
/** Human-readable app name (no spaces recommended for scheme names) */
|
|
21
|
+
appName: string;
|
|
22
|
+
/** Base package name, e.g. com.myapp */
|
|
23
|
+
packageName: string;
|
|
24
|
+
/** All environments to generate */
|
|
25
|
+
environments: EnvironmentConfig[];
|
|
26
|
+
/** If true, generate src/env.ts with typed exports */
|
|
27
|
+
generateJsEnv?: boolean;
|
|
28
|
+
/** Integration: 'react-native-config' | 'dotenv' | 'custom' | 'none' */
|
|
29
|
+
jsEnvStrategy?: 'react-native-config' | 'dotenv' | 'custom' | 'none';
|
|
30
|
+
/** If true, generate CI snippet files (GitHub Actions, Bitrise, etc.) */
|
|
31
|
+
generateCiSnippets?: boolean;
|
|
32
|
+
/** Rollback: store a backup of original files before modification */
|
|
33
|
+
enableRollback?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface GeneratorContext {
|
|
36
|
+
config: ProjectConfig;
|
|
37
|
+
projectRoot: string;
|
|
38
|
+
dryRun: boolean;
|
|
39
|
+
verbose: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface GenerationResult {
|
|
42
|
+
success: boolean;
|
|
43
|
+
filesModified: string[];
|
|
44
|
+
filesCreated: string[];
|
|
45
|
+
commands: BuildCommand[];
|
|
46
|
+
warnings: string[];
|
|
47
|
+
errors: string[];
|
|
48
|
+
}
|
|
49
|
+
export interface BuildCommand {
|
|
50
|
+
platform: 'android' | 'ios';
|
|
51
|
+
environment: string;
|
|
52
|
+
buildType?: 'debug' | 'release';
|
|
53
|
+
command: string;
|
|
54
|
+
description: string;
|
|
55
|
+
}
|
|
56
|
+
export interface ValidationResult {
|
|
57
|
+
valid: boolean;
|
|
58
|
+
errors: string[];
|
|
59
|
+
warnings: string[];
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;IACtD,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+CAA+C;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,sDAAsD;IACtD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wEAAwE;IACxE,aAAa,CAAC,EAAE,qBAAqB,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrE,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,4CAA4C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ProjectConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Attempt to find a config file in the project root.
|
|
4
|
+
* Returns the file path if found, null otherwise.
|
|
5
|
+
*/
|
|
6
|
+
export declare function findConfigFile(projectRoot: string): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Load and parse a config file (YAML or JSON).
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadConfigFile(filePath: string): ProjectConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Run interactive prompts to gather config from the user.
|
|
13
|
+
* Used when no config file is found and user runs `init`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function promptForConfig(): Promise<ProjectConfig>;
|
|
16
|
+
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAqB,MAAM,mBAAmB,CAAC;AAQrE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAe9D;AAwDD;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,CAgJ9D"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// src/config-loader.ts
|
|
2
|
+
// Loads ProjectConfig from YAML/JSON file or interactive inquirer prompts
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
const CONFIG_FILE_NAMES = [
|
|
9
|
+
'rn-env.yaml',
|
|
10
|
+
'rn-env.yml',
|
|
11
|
+
'rn-env.json',
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Attempt to find a config file in the project root.
|
|
15
|
+
* Returns the file path if found, null otherwise.
|
|
16
|
+
*/
|
|
17
|
+
export function findConfigFile(projectRoot) {
|
|
18
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
19
|
+
const filePath = path.join(projectRoot, name);
|
|
20
|
+
if (fs.existsSync(filePath)) {
|
|
21
|
+
return filePath;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load and parse a config file (YAML or JSON).
|
|
28
|
+
*/
|
|
29
|
+
export function loadConfigFile(filePath) {
|
|
30
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
31
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
32
|
+
let parsed;
|
|
33
|
+
if (ext === '.json') {
|
|
34
|
+
parsed = JSON.parse(raw);
|
|
35
|
+
}
|
|
36
|
+
else if (ext === '.yaml' || ext === '.yml') {
|
|
37
|
+
parsed = yaml.load(raw);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
throw new Error(`Unsupported config file format: ${ext}`);
|
|
41
|
+
}
|
|
42
|
+
return validateAndNormalizeConfig(parsed);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Validate parsed config object and apply defaults.
|
|
46
|
+
*/
|
|
47
|
+
function validateAndNormalizeConfig(raw) {
|
|
48
|
+
if (!raw || typeof raw !== 'object') {
|
|
49
|
+
throw new Error('Config file must be a YAML/JSON object');
|
|
50
|
+
}
|
|
51
|
+
const obj = raw;
|
|
52
|
+
if (!obj.appName || typeof obj.appName !== 'string') {
|
|
53
|
+
throw new Error('Config must have a string "appName"');
|
|
54
|
+
}
|
|
55
|
+
if (!obj.packageName || typeof obj.packageName !== 'string') {
|
|
56
|
+
throw new Error('Config must have a string "packageName"');
|
|
57
|
+
}
|
|
58
|
+
if (!Array.isArray(obj.environments) || obj.environments.length === 0) {
|
|
59
|
+
throw new Error('Config must have at least one environment in "environments"');
|
|
60
|
+
}
|
|
61
|
+
const environments = obj.environments.map((env, i) => {
|
|
62
|
+
if (!env || typeof env !== 'object') {
|
|
63
|
+
throw new Error(`Environment at index ${i} must be an object`);
|
|
64
|
+
}
|
|
65
|
+
const e = env;
|
|
66
|
+
if (!e.name || typeof e.name !== 'string')
|
|
67
|
+
throw new Error(`Environment[${i}] missing "name"`);
|
|
68
|
+
if (!e.appName || typeof e.appName !== 'string')
|
|
69
|
+
throw new Error(`Environment[${i}] missing "appName"`);
|
|
70
|
+
if (!e.bundleId || typeof e.bundleId !== 'string')
|
|
71
|
+
throw new Error(`Environment[${i}] missing "bundleId"`);
|
|
72
|
+
if (!e.apiUrl || typeof e.apiUrl !== 'string')
|
|
73
|
+
throw new Error(`Environment[${i}] missing "apiUrl"`);
|
|
74
|
+
return {
|
|
75
|
+
name: e.name,
|
|
76
|
+
appName: e.appName,
|
|
77
|
+
bundleId: e.bundleId,
|
|
78
|
+
apiUrl: e.apiUrl,
|
|
79
|
+
logo: e.logo ?? undefined,
|
|
80
|
+
variables: e.variables ?? {},
|
|
81
|
+
versionNameSuffix: e.versionNameSuffix ?? undefined,
|
|
82
|
+
xconfigExtras: e.xconfigExtras ?? {},
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
appName: obj.appName,
|
|
87
|
+
packageName: obj.packageName,
|
|
88
|
+
environments,
|
|
89
|
+
generateJsEnv: obj.generateJsEnv ?? true,
|
|
90
|
+
jsEnvStrategy: obj.jsEnvStrategy ?? 'react-native-config',
|
|
91
|
+
generateCiSnippets: obj.generateCiSnippets ?? false,
|
|
92
|
+
enableRollback: obj.enableRollback ?? true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Run interactive prompts to gather config from the user.
|
|
97
|
+
* Used when no config file is found and user runs `init`.
|
|
98
|
+
*/
|
|
99
|
+
export async function promptForConfig() {
|
|
100
|
+
console.log(chalk.cyan('\n🔧 rn-env-setup — Interactive Setup\n'));
|
|
101
|
+
const { appName, packageName, envCount } = await inquirer.prompt([
|
|
102
|
+
{
|
|
103
|
+
type: 'input',
|
|
104
|
+
name: 'appName',
|
|
105
|
+
message: 'App base name (e.g. MyApp):',
|
|
106
|
+
validate: (v) => v.trim().length > 0 || 'Required',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
type: 'input',
|
|
110
|
+
name: 'packageName',
|
|
111
|
+
message: 'Base package / bundle ID (e.g. com.myapp):',
|
|
112
|
+
validate: (v) => /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(v.trim()) || 'Must be a valid package name',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'number',
|
|
116
|
+
name: 'envCount',
|
|
117
|
+
message: 'How many environments?',
|
|
118
|
+
default: 3,
|
|
119
|
+
validate: (v) => v >= 1 || 'At least one environment required',
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
const environments = [];
|
|
123
|
+
for (let i = 0; i < envCount; i++) {
|
|
124
|
+
console.log(chalk.yellow(`\n Environment ${i + 1} of ${envCount}`));
|
|
125
|
+
const env = await inquirer.prompt([
|
|
126
|
+
{
|
|
127
|
+
type: 'input',
|
|
128
|
+
name: 'name',
|
|
129
|
+
message: ' Environment name (e.g. dev, staging, prod):',
|
|
130
|
+
default: ['dev', 'staging', 'prod'][i] ?? `env${i + 1}`,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
type: 'input',
|
|
134
|
+
name: 'appName',
|
|
135
|
+
message: ' Display name for this environment:',
|
|
136
|
+
default: (answers) => `${appName} ${capitalize(answers.name)}`,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: 'input',
|
|
140
|
+
name: 'bundleId',
|
|
141
|
+
message: ' Bundle ID / Application ID:',
|
|
142
|
+
default: (answers) => answers.name === 'prod' ? packageName : `${packageName}.${answers.name}`,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'input',
|
|
146
|
+
name: 'apiUrl',
|
|
147
|
+
message: ' API base URL:',
|
|
148
|
+
validate: (v) => v.startsWith('http') || 'Must start with http/https',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
type: 'input',
|
|
152
|
+
name: 'logo',
|
|
153
|
+
message: ' App icon path (leave blank to skip):',
|
|
154
|
+
default: '',
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
const { addVariables } = await inquirer.prompt([
|
|
158
|
+
{
|
|
159
|
+
type: 'confirm',
|
|
160
|
+
name: 'addVariables',
|
|
161
|
+
message: ' Add custom variables for this environment?',
|
|
162
|
+
default: false,
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
165
|
+
const variables = {};
|
|
166
|
+
if (addVariables) {
|
|
167
|
+
let addMore = true;
|
|
168
|
+
while (addMore) {
|
|
169
|
+
const { key, value } = await inquirer.prompt([
|
|
170
|
+
{ type: 'input', name: 'key', message: ' Variable name:' },
|
|
171
|
+
{ type: 'input', name: 'value', message: ' Variable value:' },
|
|
172
|
+
]);
|
|
173
|
+
variables[key] = value;
|
|
174
|
+
const { more } = await inquirer.prompt([
|
|
175
|
+
{ type: 'confirm', name: 'more', message: ' Add another variable?', default: false },
|
|
176
|
+
]);
|
|
177
|
+
addMore = more;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
environments.push({ ...env, logo: env.logo || undefined, variables });
|
|
181
|
+
}
|
|
182
|
+
const envGenerationAnswers = await inquirer.prompt([
|
|
183
|
+
{
|
|
184
|
+
type: 'confirm',
|
|
185
|
+
name: 'generateJsEnv',
|
|
186
|
+
message: 'Generate a JS/TS environment file (env.ts)?',
|
|
187
|
+
default: true,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'list',
|
|
191
|
+
name: 'jsEnvStrategy',
|
|
192
|
+
message: 'JS env integration strategy:',
|
|
193
|
+
choices: ['react-native-config', 'dotenv', 'custom', 'none'],
|
|
194
|
+
when: (a) => a.generateJsEnv,
|
|
195
|
+
default: 'react-native-config',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'confirm',
|
|
199
|
+
name: 'generateCiSnippets',
|
|
200
|
+
message: 'Generate CI/CD snippets (GitHub Actions, Bitrise)?',
|
|
201
|
+
default: false,
|
|
202
|
+
},
|
|
203
|
+
]);
|
|
204
|
+
const generateJsEnv = Boolean(envGenerationAnswers.generateJsEnv);
|
|
205
|
+
const generateCiSnippets = Boolean(envGenerationAnswers.generateCiSnippets);
|
|
206
|
+
const strategyAnswer = envGenerationAnswers.jsEnvStrategy;
|
|
207
|
+
const normalizedJsEnvStrategy = strategyAnswer === 'react-native-config' ||
|
|
208
|
+
strategyAnswer === 'dotenv' ||
|
|
209
|
+
strategyAnswer === 'custom' ||
|
|
210
|
+
strategyAnswer === 'none'
|
|
211
|
+
? strategyAnswer
|
|
212
|
+
: 'none';
|
|
213
|
+
const config = {
|
|
214
|
+
appName,
|
|
215
|
+
packageName,
|
|
216
|
+
environments,
|
|
217
|
+
generateJsEnv,
|
|
218
|
+
jsEnvStrategy: normalizedJsEnvStrategy,
|
|
219
|
+
generateCiSnippets,
|
|
220
|
+
enableRollback: true,
|
|
221
|
+
};
|
|
222
|
+
// Save the config to disk so it can be re-used
|
|
223
|
+
const outPath = path.join(process.cwd(), 'rn-env.yaml');
|
|
224
|
+
fs.writeFileSync(outPath, yaml.dump(config), 'utf-8');
|
|
225
|
+
console.log(chalk.green(`\n✅ Config saved to ${outPath}`));
|
|
226
|
+
return config;
|
|
227
|
+
}
|
|
228
|
+
function capitalize(s) {
|
|
229
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=config-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"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"}
|