react-native-config-ultimate 0.0.1

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/android/build.gradle +180 -0
  4. package/android/rncu.gradle +132 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/reactnativeultimateconfig/UltimateConfigModule.java +56 -0
  7. package/android/src/main/java/com/reactnativeultimateconfig/UltimateConfigPackage.java +53 -0
  8. package/bin.js +5 -0
  9. package/index.js +9 -0
  10. package/index.ts +18 -0
  11. package/ios/ConfigValues.h +1 -0
  12. package/ios/UltimateConfig.h +12 -0
  13. package/ios/UltimateConfig.mm +27 -0
  14. package/ios/UltimateConfig.xcodeproj/project.pbxproj +274 -0
  15. package/override.js +1 -0
  16. package/package.json +110 -0
  17. package/react-native-config-ultimate.podspec +41 -0
  18. package/src/NativeUltimateConfig.js +4 -0
  19. package/src/NativeUltimateConfig.ts +15 -0
  20. package/src/bin.spec.ts +36 -0
  21. package/src/cli.js +177 -0
  22. package/src/cli.spec.ts +224 -0
  23. package/src/cli.ts +166 -0
  24. package/src/flatten.js +22 -0
  25. package/src/flatten.spec.ts +16 -0
  26. package/src/flatten.ts +26 -0
  27. package/src/load-env.js +107 -0
  28. package/src/load-env.spec.ts +163 -0
  29. package/src/load-env.ts +84 -0
  30. package/src/main.js +34 -0
  31. package/src/main.spec.ts +171 -0
  32. package/src/main.ts +39 -0
  33. package/src/render-env.js +110 -0
  34. package/src/render-env.ts +115 -0
  35. package/src/resolve-env.js +12 -0
  36. package/src/resolve-env.spec.ts +25 -0
  37. package/src/resolve-env.ts +45 -0
  38. package/src/templates/ConfigValues.h.handlebars +24 -0
  39. package/src/templates/index.d.ts.handlebars +18 -0
  40. package/src/templates/index.web.js.handlebars +1 -0
  41. package/src/templates/override.js.handlebars +16 -0
  42. package/src/templates/rncu.xcconfig.handlebars +4 -0
  43. package/src/templates/rncu.yaml.handlebars +7 -0
  44. package/src/validate-env.js +53 -0
  45. package/src/validate-env.spec.ts +164 -0
  46. package/src/validate-env.ts +68 -0
  47. package/src/write-env.js +99 -0
  48. package/src/write-env.spec.ts +105 -0
  49. package/src/write-env.ts +67 -0
@@ -0,0 +1,274 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 46;
7
+ objects = {
8
+
9
+ /* Begin PBXBuildFile section */
10
+ 5E555C0D2413F4C50049A1A2 /* UltimateConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* UltimateConfig.m */; };
11
+ /* End PBXBuildFile section */
12
+
13
+ /* Begin PBXCopyFilesBuildPhase section */
14
+ 58B511D91A9E6C8500147676 /* CopyFiles */ = {
15
+ isa = PBXCopyFilesBuildPhase;
16
+ buildActionMask = 2147483647;
17
+ dstPath = "include/$(PRODUCT_NAME)";
18
+ dstSubfolderSpec = 16;
19
+ files = (
20
+ );
21
+ runOnlyForDeploymentPostprocessing = 0;
22
+ };
23
+ /* End PBXCopyFilesBuildPhase section */
24
+
25
+ /* Begin PBXFileReference section */
26
+ 134814201AA4EA6300B7C361 /* libUltimateConfig.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libUltimateConfig.a; sourceTree = BUILT_PRODUCTS_DIR; };
27
+ B3E7B5881CC2AC0600A0062D /* UltimateConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UltimateConfig.h; sourceTree = "<group>"; };
28
+ B3E7B5891CC2AC0600A0062D /* UltimateConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UltimateConfig.m; sourceTree = "<group>"; };
29
+ /* End PBXFileReference section */
30
+
31
+ /* Begin PBXFrameworksBuildPhase section */
32
+ 58B511D81A9E6C8500147676 /* Frameworks */ = {
33
+ isa = PBXFrameworksBuildPhase;
34
+ buildActionMask = 2147483647;
35
+ files = (
36
+ );
37
+ runOnlyForDeploymentPostprocessing = 0;
38
+ };
39
+ /* End PBXFrameworksBuildPhase section */
40
+
41
+ /* Begin PBXGroup section */
42
+ 134814211AA4EA7D00B7C361 /* Products */ = {
43
+ isa = PBXGroup;
44
+ children = (
45
+ 134814201AA4EA6300B7C361 /* libUltimateConfig.a */,
46
+ );
47
+ name = Products;
48
+ sourceTree = "<group>";
49
+ };
50
+ 58B511D21A9E6C8500147676 = {
51
+ isa = PBXGroup;
52
+ children = (
53
+ B3E7B5881CC2AC0600A0062D /* UltimateConfig.h */,
54
+ B3E7B5891CC2AC0600A0062D /* UltimateConfig.m */,
55
+ 134814211AA4EA7D00B7C361 /* Products */,
56
+ );
57
+ sourceTree = "<group>";
58
+ };
59
+ /* End PBXGroup section */
60
+
61
+ /* Begin PBXNativeTarget section */
62
+ 58B511DA1A9E6C8500147676 /* UltimateConfig */ = {
63
+ isa = PBXNativeTarget;
64
+ buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "UltimateConfig" */;
65
+ buildPhases = (
66
+ 58B511D71A9E6C8500147676 /* Sources */,
67
+ 58B511D81A9E6C8500147676 /* Frameworks */,
68
+ 58B511D91A9E6C8500147676 /* CopyFiles */,
69
+ );
70
+ buildRules = (
71
+ );
72
+ dependencies = (
73
+ );
74
+ name = UltimateConfig;
75
+ productName = RCTDataManager;
76
+ productReference = 134814201AA4EA6300B7C361 /* libUltimateConfig.a */;
77
+ productType = "com.apple.product-type.library.static";
78
+ };
79
+ /* End PBXNativeTarget section */
80
+
81
+ /* Begin PBXProject section */
82
+ 58B511D31A9E6C8500147676 /* Project object */ = {
83
+ isa = PBXProject;
84
+ attributes = {
85
+ LastUpgradeCheck = 0920;
86
+ ORGANIZATIONNAME = Facebook;
87
+ TargetAttributes = {
88
+ 58B511DA1A9E6C8500147676 = {
89
+ CreatedOnToolsVersion = 6.1.1;
90
+ };
91
+ };
92
+ };
93
+ buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "UltimateConfig" */;
94
+ compatibilityVersion = "Xcode 3.2";
95
+ developmentRegion = English;
96
+ hasScannedForEncodings = 0;
97
+ knownRegions = (
98
+ English,
99
+ en,
100
+ );
101
+ mainGroup = 58B511D21A9E6C8500147676;
102
+ productRefGroup = 58B511D21A9E6C8500147676;
103
+ projectDirPath = "";
104
+ projectRoot = "";
105
+ targets = (
106
+ 58B511DA1A9E6C8500147676 /* UltimateConfig */,
107
+ );
108
+ };
109
+ /* End PBXProject section */
110
+
111
+ /* Begin PBXSourcesBuildPhase section */
112
+ 58B511D71A9E6C8500147676 /* Sources */ = {
113
+ isa = PBXSourcesBuildPhase;
114
+ buildActionMask = 2147483647;
115
+ files = (
116
+ B3E7B58A1CC2AC0600A0062D /* UltimateConfig.m in Sources */,
117
+ );
118
+ runOnlyForDeploymentPostprocessing = 0;
119
+ };
120
+ /* End PBXSourcesBuildPhase section */
121
+
122
+ /* Begin XCBuildConfiguration section */
123
+ 58B511ED1A9E6C8500147676 /* Debug */ = {
124
+ isa = XCBuildConfiguration;
125
+ buildSettings = {
126
+ ALWAYS_SEARCH_USER_PATHS = NO;
127
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
128
+ CLANG_CXX_LIBRARY = "libc++";
129
+ CLANG_ENABLE_MODULES = YES;
130
+ CLANG_ENABLE_OBJC_ARC = YES;
131
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
132
+ CLANG_WARN_BOOL_CONVERSION = YES;
133
+ CLANG_WARN_COMMA = YES;
134
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
135
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
136
+ CLANG_WARN_EMPTY_BODY = YES;
137
+ CLANG_WARN_ENUM_CONVERSION = YES;
138
+ CLANG_WARN_INFINITE_RECURSION = YES;
139
+ CLANG_WARN_INT_CONVERSION = YES;
140
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
141
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
142
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
143
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
144
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
145
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
146
+ CLANG_WARN_UNREACHABLE_CODE = YES;
147
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
148
+ COPY_PHASE_STRIP = NO;
149
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
150
+ ENABLE_TESTABILITY = YES;
151
+ "EXCLUDED_ARCHS[sdk=*]" = arm64;
152
+ GCC_C_LANGUAGE_STANDARD = gnu99;
153
+ GCC_DYNAMIC_NO_PIC = NO;
154
+ GCC_NO_COMMON_BLOCKS = YES;
155
+ GCC_OPTIMIZATION_LEVEL = 0;
156
+ GCC_PREPROCESSOR_DEFINITIONS = (
157
+ "DEBUG=1",
158
+ "$(inherited)",
159
+ );
160
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
161
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
162
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
163
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
164
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
165
+ GCC_WARN_UNUSED_FUNCTION = YES;
166
+ GCC_WARN_UNUSED_VARIABLE = YES;
167
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
168
+ MTL_ENABLE_DEBUG_INFO = YES;
169
+ ONLY_ACTIVE_ARCH = YES;
170
+ SDKROOT = iphoneos;
171
+ };
172
+ name = Debug;
173
+ };
174
+ 58B511EE1A9E6C8500147676 /* Release */ = {
175
+ isa = XCBuildConfiguration;
176
+ buildSettings = {
177
+ ALWAYS_SEARCH_USER_PATHS = NO;
178
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
179
+ CLANG_CXX_LIBRARY = "libc++";
180
+ CLANG_ENABLE_MODULES = YES;
181
+ CLANG_ENABLE_OBJC_ARC = YES;
182
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
183
+ CLANG_WARN_BOOL_CONVERSION = YES;
184
+ CLANG_WARN_COMMA = YES;
185
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
186
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
187
+ CLANG_WARN_EMPTY_BODY = YES;
188
+ CLANG_WARN_ENUM_CONVERSION = YES;
189
+ CLANG_WARN_INFINITE_RECURSION = YES;
190
+ CLANG_WARN_INT_CONVERSION = YES;
191
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
192
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
193
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
194
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
195
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
196
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
197
+ CLANG_WARN_UNREACHABLE_CODE = YES;
198
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
199
+ COPY_PHASE_STRIP = YES;
200
+ ENABLE_NS_ASSERTIONS = NO;
201
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
202
+ "EXCLUDED_ARCHS[sdk=*]" = arm64;
203
+ GCC_C_LANGUAGE_STANDARD = gnu99;
204
+ GCC_NO_COMMON_BLOCKS = YES;
205
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
206
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
207
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
208
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
209
+ GCC_WARN_UNUSED_FUNCTION = YES;
210
+ GCC_WARN_UNUSED_VARIABLE = YES;
211
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
212
+ MTL_ENABLE_DEBUG_INFO = NO;
213
+ SDKROOT = iphoneos;
214
+ VALIDATE_PRODUCT = YES;
215
+ };
216
+ name = Release;
217
+ };
218
+ 58B511F01A9E6C8500147676 /* Debug */ = {
219
+ isa = XCBuildConfiguration;
220
+ buildSettings = {
221
+ HEADER_SEARCH_PATHS = (
222
+ "$(inherited)",
223
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
224
+ "$(SRCROOT)/../../../React/**",
225
+ "$(SRCROOT)/../../react-native/React/**",
226
+ );
227
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
228
+ OTHER_LDFLAGS = "-ObjC";
229
+ PRODUCT_NAME = UltimateConfig;
230
+ SKIP_INSTALL = YES;
231
+ };
232
+ name = Debug;
233
+ };
234
+ 58B511F11A9E6C8500147676 /* Release */ = {
235
+ isa = XCBuildConfiguration;
236
+ buildSettings = {
237
+ HEADER_SEARCH_PATHS = (
238
+ "$(inherited)",
239
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
240
+ "$(SRCROOT)/../../../React/**",
241
+ "$(SRCROOT)/../../react-native/React/**",
242
+ );
243
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
244
+ OTHER_LDFLAGS = "-ObjC";
245
+ PRODUCT_NAME = UltimateConfig;
246
+ SKIP_INSTALL = YES;
247
+ };
248
+ name = Release;
249
+ };
250
+ /* End XCBuildConfiguration section */
251
+
252
+ /* Begin XCConfigurationList section */
253
+ 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "UltimateConfig" */ = {
254
+ isa = XCConfigurationList;
255
+ buildConfigurations = (
256
+ 58B511ED1A9E6C8500147676 /* Debug */,
257
+ 58B511EE1A9E6C8500147676 /* Release */,
258
+ );
259
+ defaultConfigurationIsVisible = 0;
260
+ defaultConfigurationName = Release;
261
+ };
262
+ 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "UltimateConfig" */ = {
263
+ isa = XCConfigurationList;
264
+ buildConfigurations = (
265
+ 58B511F01A9E6C8500147676 /* Debug */,
266
+ 58B511F11A9E6C8500147676 /* Release */,
267
+ );
268
+ defaultConfigurationIsVisible = 0;
269
+ defaultConfigurationName = Release;
270
+ };
271
+ /* End XCConfigurationList section */
272
+ };
273
+ rootObject = 58B511D31A9E6C8500147676 /* Project object */;
274
+ }
package/override.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = {};
package/package.json ADDED
@@ -0,0 +1,110 @@
1
+ {
2
+ "name": "react-native-config-ultimate",
3
+ "title": "React Native Config Ultimate",
4
+ "version": "0.0.1",
5
+ "description": "Config that works. A community-maintained fork of react-native-ultimate-config.",
6
+ "main": "index.js",
7
+ "react-native": "index.js",
8
+ "browser": "index.web.js",
9
+ "types": "index.d.ts",
10
+ "files": [
11
+ "src/*.js",
12
+ "src/*.ts",
13
+ "src/templates",
14
+ "index.js",
15
+ "index.ts",
16
+ "override.js",
17
+ "ios/UltimateConfig.{h,mm}",
18
+ "ios/ConfigValues.h",
19
+ "ios/UltimateConfig.xcodeproj/project.pbxproj",
20
+ "android/src",
21
+ "android/build.gradle",
22
+ "android/rncu.gradle",
23
+ "react-native-config-ultimate.podspec"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "typecheck": "tsc --noEmit",
28
+ "pretest": "tsc",
29
+ "test": "jest",
30
+ "prepack": "echo '#error \"invoke bin.js with env file before compiling native project\"' > ios/ConfigValues.h && echo 'module.exports = {};' > override.js",
31
+ "lint": "eslint src/**/*.ts index.ts --max-warnings=0",
32
+ "format": "prettier --write src/**/*.ts index.ts"
33
+ },
34
+ "bin": {
35
+ "rncu": "./bin.js"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/javier545dev/react-native-config-ultimate.git"
40
+ },
41
+ "homepage": "https://github.com/javier545dev/react-native-config-ultimate#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/javier545dev/react-native-config-ultimate/issues"
44
+ },
45
+ "keywords": [
46
+ "react-native",
47
+ "ios",
48
+ "android",
49
+ "12factor",
50
+ "12factorapp",
51
+ "dotenv",
52
+ "env",
53
+ "environment",
54
+ "config",
55
+ "xcconfig",
56
+ "gradle",
57
+ "objective-c",
58
+ "java",
59
+ "typescript"
60
+ ],
61
+ "author": {
62
+ "name": "Javier Fuentes",
63
+ "email": "javierfuentes545@gmail.com"
64
+ },
65
+ "contributors": [
66
+ {
67
+ "name": "Max Komarychev",
68
+ "email": "maxkomarychev@gmail.com",
69
+ "url": "https://github.com/maxkomarychev"
70
+ }
71
+ ],
72
+ "license": "MIT",
73
+ "peerDependencies": {
74
+ "react-native": ">=0.60.0-rc.0 <1.0.x"
75
+ },
76
+ "devDependencies": {
77
+ "@types/jest": "^29.5.0",
78
+ "@types/js-yaml": "^4.0.9",
79
+ "@types/node": "^20.0.0",
80
+ "@types/yargs": "^17.0.35",
81
+ "@typescript-eslint/eslint-plugin": "^8.20.0",
82
+ "@typescript-eslint/parser": "^8.20.0",
83
+ "eslint": "^9.17.0",
84
+ "jest": "^29.7.0",
85
+ "prettier": "^3.4.2",
86
+ "react": "^19.0.0",
87
+ "react-native": "0.79.5",
88
+ "ts-jest": "^29.2.0",
89
+ "typescript": "^5.5.4"
90
+ },
91
+ "engines": {
92
+ "node": ">= 18.0.0"
93
+ },
94
+ "dependencies": {
95
+ "chokidar": "4.0.3",
96
+ "dotenv": "16.6.1",
97
+ "dotenv-expand": "^12.0.3",
98
+ "handlebars": "^4.7.7",
99
+ "js-yaml": "^4",
100
+ "yargs": "^17"
101
+ },
102
+ "codegenConfig": {
103
+ "name": "RNUltimateConfigSpec",
104
+ "type": "modules",
105
+ "jsSrcsDir": "src",
106
+ "android": {
107
+ "javaPackageName": "com.reactnativeultimateconfig"
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,41 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "react-native-config-ultimate"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.description = <<-DESC
11
+ react-native-config-ultimate
12
+ A community-maintained fork of react-native-ultimate-config
13
+ by Max Komarychev. Adds New Architecture (TurboModules),
14
+ multi-env merging, dotenv expansion, schema validation,
15
+ and CLI watch mode.
16
+ DESC
17
+ s.homepage = "https://github.com/javier545dev/react-native-config-ultimate"
18
+ s.license = "MIT"
19
+ s.authors = { "Javier Fuentes" => "javierfuentes545@gmail.com" }
20
+ s.platforms = { :ios => "11.0" }
21
+ s.source = { :git => "https://github.com/javier545dev/react-native-config-ultimate.git", :tag => "#{s.version}" }
22
+
23
+ s.source_files = "ios/**/*.{h,m,mm}"
24
+
25
+ s.dependency "React-Core"
26
+
27
+ # Don't install the dependencies when we run `pod install` in the old architecture.
28
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
29
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
30
+ s.pod_target_xcconfig = {
31
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
32
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
33
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
34
+ }
35
+ s.dependency "React-Codegen"
36
+ s.dependency "RCT-Folly"
37
+ s.dependency "RCTRequired"
38
+ s.dependency "RCTTypeSafety"
39
+ s.dependency "ReactCommon/turbomodule/core"
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_native_1 = require("react-native");
4
+ exports.default = react_native_1.TurboModuleRegistry.get('UltimateConfig');
@@ -0,0 +1,15 @@
1
+ /**
2
+ * TurboModule spec for react-native-ultimate-config
3
+ * This file is read by React Native Codegen to generate native bindings.
4
+ * Do not rename or move this file - Codegen relies on the "Native" prefix.
5
+ */
6
+ import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
7
+ import { TurboModuleRegistry } from 'react-native';
8
+
9
+ export type ConfigValue = string | number | boolean;
10
+
11
+ export interface Spec extends TurboModule {
12
+ readonly getConstants: () => Record<string, ConfigValue>;
13
+ }
14
+
15
+ export default TurboModuleRegistry.get<Spec>('UltimateConfig');
@@ -0,0 +1,36 @@
1
+ import cp from 'child_process';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
5
+ const { files_to_assert } = require('./main.spec') as { files_to_assert: string[] };
6
+
7
+ describe.each`
8
+ extension | env_test_content
9
+ ${''} | ${'hello=world'}
10
+ ${'.yaml'} | ${'hello: world'}
11
+ ${'.yml'} | ${'hello: world'}
12
+ `('test codegen', ({ extension, env_test_content }: { extension: string; env_test_content: string }) => {
13
+ let project_root: string;
14
+ beforeAll(() => {
15
+ project_root = path.join(process.cwd(), fs.mkdtempSync('rncu-jest'));
16
+ for (const file_path of files_to_assert) {
17
+ const { dir } = path.parse(file_path);
18
+ const folder = path.join(project_root, dir);
19
+ fs.mkdirSync(folder, { recursive: true });
20
+ }
21
+ });
22
+ afterAll(() => {
23
+ fs.rmSync(project_root, { recursive: true, force: true });
24
+ });
25
+ it.each(files_to_assert.map((k) => [k]))(
26
+ 'creates file at path %s',
27
+ (file_path) => {
28
+ const env_file_path = path.join(project_root, `.env${extension}`);
29
+ fs.writeFileSync(env_file_path, env_test_content);
30
+ cp.execFileSync(path.join(process.cwd(), 'bin.js'), [env_file_path], {
31
+ cwd: project_root,
32
+ });
33
+ expect(fs.existsSync(path.join(project_root, file_path as string))).toEqual(true);
34
+ }
35
+ );
36
+ });
package/src/cli.js ADDED
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.default = cli;
40
+ const yargs_1 = __importDefault(require("yargs"));
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const chokidar_1 = require("chokidar");
44
+ const main_1 = __importDefault(require("./main"));
45
+ /**
46
+ * Load the RC file fresh on every call (clears require cache so
47
+ * changes to .rncurc.js are picked up during --watch mode).
48
+ */
49
+ function load_rc(rc_file) {
50
+ if (!fs.existsSync(rc_file))
51
+ return undefined;
52
+ delete require.cache[require.resolve(rc_file)];
53
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
54
+ return require(rc_file);
55
+ }
56
+ function log(msg) {
57
+ process.stdout.write(`[rncu] ${msg}\n`);
58
+ }
59
+ function log_err(msg) {
60
+ process.stderr.write(`[rncu] ✗ ${msg}\n`);
61
+ }
62
+ async function cli() {
63
+ const argv = await (0, yargs_1.default)(process.argv.slice(2))
64
+ .option('projectRoot', {
65
+ type: 'string',
66
+ default: process.cwd(),
67
+ description: 'Root directory of the React Native project',
68
+ })
69
+ .option('libRoot', {
70
+ type: 'string',
71
+ description: 'Root directory of react-native-config-ultimate ' +
72
+ '(defaults to <projectRoot>/node_modules/react-native-config-ultimate)',
73
+ })
74
+ .option('watch', {
75
+ alias: 'w',
76
+ type: 'boolean',
77
+ default: false,
78
+ description: 'Watch env file(s) for changes and regenerate automatically. ' +
79
+ 'Note: changes to native vars (iOS xcconfig, Android BuildConfig) ' +
80
+ 'still require a full native rebuild.',
81
+ })
82
+ .usage('Usage: $0 <env-file> [env-file2 ...] [options]')
83
+ .help()
84
+ .parseAsync();
85
+ const project_root = argv.projectRoot;
86
+ /**
87
+ * Resolve the library root directory.
88
+ *
89
+ * Priority:
90
+ * 1. --libRoot flag (explicit override)
91
+ * 2. Conventional path <projectRoot>/node_modules/react-native-config-ultimate
92
+ * — used when the directory exists (standard install, or bin.spec.ts integration test).
93
+ * 3. require.resolve() — handles npm workspaces hoisting, pnpm, Yarn PnP,
94
+ * and any layout where the package is hoisted above projectRoot.
95
+ * 4. Fall back to conventional path even if it doesn't exist yet
96
+ * (write-env.ts will create the directories on first run).
97
+ */
98
+ const lib_root = (() => {
99
+ if (argv.libRoot)
100
+ return argv.libRoot;
101
+ const conventional = path.join(project_root, 'node_modules', 'react-native-config-ultimate');
102
+ // If the directory already exists at the conventional location, use it.
103
+ // This handles standard installs and the integration test temp-dir setup.
104
+ if (fs.existsSync(conventional))
105
+ return conventional;
106
+ // Otherwise, try require.resolve to handle hoisted workspaces.
107
+ try {
108
+ const pkg_json = require.resolve('react-native-config-ultimate/package.json', { paths: [project_root] });
109
+ return path.dirname(pkg_json);
110
+ }
111
+ catch (_a) {
112
+ // Last resort: return the conventional path and let write-env create it.
113
+ return conventional;
114
+ }
115
+ })();
116
+ // Accept one or more positional env file paths.
117
+ // Multiple files are merged left-to-right (last file wins for conflicting keys).
118
+ const env_files = argv._.map(String);
119
+ // Validate env files exist before running anything.
120
+ const missing_files = env_files.filter((f) => !fs.existsSync(f));
121
+ if (missing_files.length > 0) {
122
+ for (const f of missing_files) {
123
+ log_err(`env file not found: ${f}`);
124
+ }
125
+ process.exit(1);
126
+ }
127
+ const rc_file = path.resolve(project_root, '.rncurc.js');
128
+ // Helper: run the full pipeline once, returning duration in ms.
129
+ // Never throws — errors are caught and logged so watch mode stays alive.
130
+ async function run(changed_path) {
131
+ if (changed_path) {
132
+ log(`${changed_path} changed → regenerating...`);
133
+ }
134
+ const start = Date.now();
135
+ try {
136
+ const rc = load_rc(rc_file);
137
+ await (0, main_1.default)(project_root, lib_root, env_files, rc);
138
+ if (changed_path) {
139
+ log(`✓ done in ${Date.now() - start}ms`);
140
+ }
141
+ }
142
+ catch (err) {
143
+ log_err(err instanceof Error ? err.message : String(err));
144
+ }
145
+ }
146
+ // Initial run (always runs, throws on error in non-watch mode).
147
+ if (!argv.watch) {
148
+ const rc = load_rc(rc_file);
149
+ await (0, main_1.default)(project_root, lib_root, env_files, rc);
150
+ return;
151
+ }
152
+ // --watch mode ────────────────────────────────────────────────────────────
153
+ // Initial run (errors are caught — we still want to start watching).
154
+ await run();
155
+ // Files to watch: env files + RC file (if it exists).
156
+ const files_to_watch = [
157
+ ...env_files,
158
+ ...(fs.existsSync(rc_file) ? [rc_file] : []),
159
+ ];
160
+ const watcher = (0, chokidar_1.watch)(files_to_watch, {
161
+ ignoreInitial: true,
162
+ persistent: true,
163
+ });
164
+ log(`watching: ${files_to_watch.join(', ')}\n` +
165
+ `[rncu] ⚠ native vars (xcconfig/BuildConfig) require a full rebuild to take effect`);
166
+ watcher.on('change', (p) => void run(p));
167
+ watcher.on('add', (p) => void run(p));
168
+ // Keep the process alive (chokidar persistent:true already does this,
169
+ // but stdin.resume makes it explicit and survives edge cases).
170
+ process.stdin.resume();
171
+ // Graceful shutdown on Ctrl+C.
172
+ process.on('SIGINT', () => {
173
+ process.stdout.write('\n');
174
+ log('stopping...');
175
+ void watcher.close().then(() => process.exit(0));
176
+ });
177
+ }