Skip to content

cli-kit

The cli-kit package furnishes a comprehensive array of utilities essential for the creation and manipulation of native code within iOS and Android projects. It offers specialized file parsers and file system APIs, facilitating seamless expansion of native functionalities beyond the foundational framework of a React Native project.

Add @brandingbrand/code-cli-kit as a development dependency to your React Native project.

Terminal window
yarn add --dev @brandingbrand/code-cli-kit

Your package.json should now be updated, @brandingbrand/code-cli-kit should be listed as a devDependency.

package.json
{
"name": "my-awesome-app",
"version": "1.0.0",
"author": "Your Name <email@example.com>",
"dependencies": {
"react": "^18.2.0",
"react-native": "~0.72.0"
},
"devDependencies": {
"@brandingbrand/code-cli-kit": "13.0.0"
}
}

The modules provided by the cli-kit package are also leveraged by the @brandingbrand/code-cli package for the purpose of native code management. This collaboration ensures efficient utilization of only the essential exposed modules, with emphasis on detailing those of utmost importance.

The parsers module within cli-kit is tasked with the parsing and composition of domain-specific files into a structured object format, facilitating convenient manipulation in accordance with project requirements. Noteworthy available parsers include those for UTF-8, XML, Property List (plist), and Old-Style ASCII Property Lists (pbxproj).

The UTF-8 parser is designed to interpret generic files into a manipulable string format. Typical scenarios involve handling source code and configuration files such as MainActivity.{java|kt}, MainApplication.{java|kt}, AppDelegate.mm, AppDelegate.h, build.gradle, podfile, and similar items. Presently, there are no parsers available specifically for these types of files. However, it’s worth noting that this situation might evolve in the future, particularly for configuration files, should further parsers, grammars, and lexers be developed.

The exposed module for parsing UTF-8 files is withUTF8. It can be used with the following options.

type: withUTF8(filePath: string, callback(content: string): string): Promise<Void>

type: string

required

The path of the file relative to the project root to be parsed.

type: function (content: string): string

required

A callback function is implemented to accept the parsed file as a string and anticipates a manipulated string to be returned as its output.

Below is an illustrative example demonstrating the utilization of the UTF-8 parser to parse the build.gradle file and subsequently update the compileSdkVersion:

build-gradle-transform.ts
import { path, withUTF8 } from "@brandingbrand/code-cli-kit";
// config supplied by @brandingbrand/cli
withUTF8(path.android.buildGradle, (content: string) => {
return content.replace(
content,
/(compileSdkVersion\s*=\s*)[\d]+/m,
`$1${config.android.gradle.projectGradle.compileSdkVersion}`,
);
});

The XML parser serves to decipher XML-formatted files into a manipulatable object tailored to meet the specific requirements of your project. Noteworthy XML files parsed within the @brandingbrand/cli framework include AndroidManifest.xml, colors.xml, strings.xml, styles.xml, among others. At present, this parser harnesses the capabilities of the fast-xml-parser package to accomplish its tasks efficiently.

The exposed module for parsing XML files is withXML. It can be used with the following options.

type: function withXML<T>(path: string, options: X2jOptions, callback: (xml: T): void): Promise<Void>

type: string

required

The path of the XML file relative to the project root to be parsed.

type: X2jOptions

required

The options on how to parse/write and format the XML object and file.

type: function<T>(content: T): void

required

A callback function is implemented to accept the parsed file as a generic object, with the expectation that no explicit return value is necessary, as the object is mutable by nature.

Below is an illustrative example demonstrating the utilization of the XML parser to parse the colors.xml file and subsequently add a color:

colors-xml-transform.ts
import { path, withXML } from "@brandingbrand/code-cli-kit";
// config supplied by @brandingbrand/cli
type ColorAttributes = {
name: string;
};
type Color = {
$: ColorAttributes;
_: string;
};
type ColorsElements = {
color?: Color[];
};
export type ColorsXML = {
resources: ColorsElements;
};
withXml<ColorsXML>(
path.android.colors,
{
isArray: tagName => {
if (['color'].indexOf(tagName) !== -1) {
return true;
}
return false;
},
},
(xml: ColorsXML) => {
if (!config.android.colors) return;
if (!xml.resources.color) {
xml.resources = {...xml.resources, color: []};
}
Object.entries(config.android.colors).forEach(([name, _]) =>
xml.resources.color?.push({
$: {name},
_,
}),
);
},
);

The plist parser is specifically crafted to interpret property list files into a mutable object format. Commonly, it finds application in scenarios involving the management of iOS Info.plist files.

The exposed module for parsing plist files is withPlist. It can be used with the following options.

type: function withPlist<T>(path: string, callback(content: T): T): Promise<Void>

type: string

required

The path of the file relative to the project root to be parsed.

type: function<T>(content: T): T

required

A callback function is implemented to accept the parsed plist file as a generic object, with the expectation that the mutated object will be returned as its output.

Below is an illustrative example demonstrating the utilization of the plist parser to parse the info.plist file and subsequently update the the bundle identifier and display name.

info-plist-transform.ts
import { path, withPlist } from "@brandingbrand/code-cli-kit";
// config supplied by @brandingbrand/cli
type InfoPlist = Record<string, unknown> & {
UIStatusBarHidden?: boolean;
UIStatusBarStyle?: string;
UILaunchStoryboardName?: string | 'LaunchScreen';
CFBundleShortVersionString?: string;
CFBundleVersion?: string;
CFBundleDisplayName?: string;
CFBundleIdentifier?: string;
CFBundleName?: string;
// See source code for more
};
withPlist<InfoPlist>(path.ios.infoPlist, (content: InfoPlist): InfoPlist => {
const {displayName, bundleId} = config.ios;
return mergeAndConcat<InfoPlist, InfoPlist[]>(content, {
CFBundleIdentifier: bundleId,
CFBundleDisplayName: displayName,
});
});

The pbxproj parser is meticulously crafted to interpret pbxproj files into a mutable object format. Common scenarios involving its usage include the management of project.pbxproj files, encompassing tasks such as adding source files, resource files, updating build settings, and similar project-related operations.

The exposed module for parsing UTF-8 files is withPbxproj. It can be used with the following options.

type: function withPbxproj(callback: (pbxproj: XcodeProject): void): Promise<Void>

type: function (content: XcodeProject): void

required

A callback function is established to receive the parsed file as a XcodeProject object. It expects no explicit return value, as the object is inherently mutable and intended for direct manipulation within the context of the Xcode project.

Below is an illustrative example demonstrating the utilization of the pbxproj parser to parse the project.pbxproj file and subsequently update the IPHONEOS_DEPLOYMENT_TARGET:

build-gradle-transform.ts
import { withPbxproj } from "@brandingbrand/code-cli-kit";
// config supplied by @brandingbrand/cli
withPbxproj(project => {
if (!config.ios.deploymentTarget) return;
project.addToBuildSettings(
'IPHONEOS_DEPLOYMENT_TARGET',
config.ios.deploymentTarget,
);
});

A comprehensive array of exposed library modules is available to assist in the generation of native code, complementing the functionality of the parsers. These modules offer a versatile toolkit to facilitate efficient native code development within the project ecosystem.

The fs module builds upon the foundation provided by fs/promises, addressing specific gaps to enhance functionality where necessary. Within this module, four additional functions are exposed to facilitate manipulation of native code: doesKeywordExist, doesPathExist, update, and renameAndCopyDirectory. These functions serve to augment the capabilities of file system operations, offering a comprehensive toolkit for efficient native code management.

This function examines a file to determine if a specified keyword exists within it. The keyword can be provided either as a regular expression or as a string format.

type: function doesKeywordExist(path: string, keyword: RegExp | string): Promise<boolean>

type: string

required

The path of the file relative to the project root to examine.

type: RegExp | string

required

The parameter for this function represents either a string or a regular expression that is to be checked for existence within the specified file.

Below is an illustrative example demonstrating the utilization of the doesKeywordExist lib.

import { fs } from "@brandingbrand/code-cli-kit";
// file content at ./my_file.txt
// "This is someKeyword content."
const res = await fs.doesKeywordExist(
path.project.resolve('my_file.txt'),
'someKeyword',
);
/// res will be true
const res1 = await fs.doesKeywordExist(path, /some/);
/// res1 will be true

This function determines whether the provided file path exists within the file system.

type: string

required

The path of the file relative to the project root.

Below is an illustrative example demonstrating the utilization of the doesPathExist lib.

import { fs, path } from "@brandingbrand/code-cli-kit";
// file system has a file at ./ios/app/MyFile.swift
const res = await fs.doesPathExist(
path.project.resolve('ios', 'app', 'MyFile.swift'),
);
/// res will be true

This function facilitates the updating of a text value within a file by replacing it with a new text value.

type: function update(path: string, oldText: RegExp | string, newText: string): Promise<void>

type: string

required

The path of the file relative to the project root to update.

type: RegExp | string

required

The parameter for this function represents either a string or a regular expression that is to be replaced.

type: string

required

The parameter for this function represents the string to replace the old string.

Below is an illustrative example demonstrating the utilization of the update lib.

import { fs, path } from "@brandingbrand/code-cli-kit";
// file content at ./my_file.txt
// "This is someKeyword content."
await fs.update(
path.project.resolve('my_file.txt'),
/(some)Keyword/,
`$1Example`,
);
// file updated content at ./my_file.txt
// "This is someExample content."

The guards module provides functions designed to strictly type-guard objects, aiming to restrict side-effects specifically for @brandingbrand/code-cli usage. Within Flagship Code, we extensively employ guards for various configurations, including Flagship Code configuration, build configurations, environment configurations, and plugin configurations. The exposed guard functions include defineConfig, defineBuild, defineEnv, and definePlugin.

This function type guards the flagship-code.config.ts, which serves as the base configuration for Flagship Code. For more detailed information, please refer to the Flagship Code Configuration guide.

type: function defineConfig(config: CodeConfig): CodeConfig

type: CodeConfig

required

The parameter for this function represents the Flagship Code configuration, which undergoes type-guarding and is then returned.

Below is an illustrative example demonstrating the utilization of the defineConfig guard.

flagship-code.config.ts
import { defineConfig } from "@brandingbrand/code-cli-kit";
export default defineConfig({
buildPath: './coderc/build',
envPath: './coderc/env',
pluginPath: './coderc/plugins',
preset: "@brandingbrand/code-preset-react-native",
plugins: [
'@brandingbrand/code-plugin-native-navigation',
'@brandingbrand/code-plugin-splash-screen',
'@brandingbrand/code-plugin-app-icon',
],
});

This function type guards the build.<mode>.ts, which serves as defining the build configuration. For more detailed information, please refer to the Build Configuration guide.

type: function defineBuild<T = BuildConfig>(build: (T extends BuildConfig ? BuildConfig : BuildConfig & T) | ((pkg: PackageJson) => T extends BuildConfig ? BuildConfig : BuildConfig & T)): T

type: BuildConfig

required

The parameter for this function represents the build configuration configuration, which undergoes type-guarding and is then returned.

Below is an illustrative example demonstrating the utilization of the defineBuild guard. Utilizing build.internal.ts purely as an example.

build.internal.ts
import { defineBuild } from "@brandingbrand/code-cli-kit";
export default defineBuild({
ios: {
bundleId: 'com.brandingbrand',
displayName: 'Branding Brand',
},
android: {
packageName: 'com.brandingbrand',
displayName: 'Branding Brand',
},
});
build.internal.ts
import { defineBuild } from "@brandingbrand/code-cli-kit";
export default defineBuild(pkg => ({
ios: {
bundleId: 'com.brandingbrand',
displayName: 'Branding Brand',
versioning: {
version: pkg.version,
build: 1,
},
},
android: {
packageName: 'com.brandingbrand',
displayName: 'Branding Brand',
versioning: {
version: pkg.version,
build: 1,
},
},
}));

This function type guards the env.<mode>.ts, which serves as the env configuration for your chosen ENV provider. For more detailed information, please refer to the Environment Configuration guide.

type: function defineEnv<T>(env: T): T

type: Env

required

The parameter for this function represents the environment configuration, which undergoes type-guarding and is then returned.

Below is an illustrative example demonstrating the utilization of the defineEnv guard. Utilizing env.dev.ts purely as an example.

env.dev.ts
import { defineEnv } from "@brandingbrand/code-cli-kit";
export default defineEnv<Env>({
id: 'abc12345',
domain: 'https://dev.myexampledomain.com',
});

This function type guards your plugin entry point. For more detailed information, please refer to the Plugins guide.

type: function definePlugin<T>(plugin: PluginConfig<T>): PluginConfig<T>

type: PluginConfig

required

The parameter for this function represents the plugin configuration, which undergoes type-guarding and is then returned.

Below is an illustrative example demonstrating the utilization of the definePlugin guard. Utilizing index.ts purely as an example.

index.ts
import {
definePlugin,
type BuildConfig,
type PrebuildOptions,
} from "@brandingbrand/code-cli-kit";
export default definePlugin({
ios: async function (build, options): Promise<void> {
// make iOS code changes here
},
android: async function (build, options): Promise<void> {
// make Android code changes here
},
});

The path module offers functions and constants that extend the functionality of the path module provided by Node.js. These extensions include convenient functions and constants designed to facilitate access to various aspects of your project’s path, including iOS and Android file paths.

This project enables you to resolve paths relative to your project’s root directory. Subsequent paths are constructed based on this function.

type: function (...paths: string[]): string

type: string[]

required

An array of strings representing a path relative to the root of the project.

Below is an illustrative example demonstrating the utilization of the path.project.resolve to generate the absolute path to the Podfile.

import { path } from "@brandingbrand/code-cli-kit";
const podfilePath = path.project.resolve('ios', 'Podfile');

Generates the absolute path to the iOS Podfile file.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.podfile to generate the absolute path to the Podfile.

import { path } from "@brandingbrand/code-cli-kit";
const podfilePath = path.ios.podfile;

Generates the absolute path to the iOS Info.plist file.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.infoPlist to generate the absolute path to the Info.plist.

import { path } from "@brandingbrand/code-cli-kit";
const infoPlistPath = path.ios.infoPlist;

Generates the absolute path to the iOS Gemfile.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.gemfile to generate the absolute path to the Gemfile.

import { path } from "@brandingbrand/code-cli-kit";
const gemfilePath = path.ios.gemfile;

Generates the absolute path to the iOS EnvSwitcher.m.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.envSwitcher to generate the absolute path to the EnvSwitcher.m.

import { path } from "@brandingbrand/code-cli-kit";
const envSwitcherPath = path.ios.envSwitcher;

Generates the absolute path to the iOS app.entitlements.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.entitlements to generate the absolute path to the app.entitlements.

import { path } from "@brandingbrand/code-cli-kit";
const entitlementsPath = path.ios.entitlements;

Generates the absolute path to the iOS PrivacyInfo.xcprivacy.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.privacyManifest to generate the absolute path to the PrivacyInfo.xcprivacy.

import { path } from "@brandingbrand/code-cli-kit";
const privacyManifestPath = path.ios.privacyManifest;

Generates the absolute path to the iOS NativeConstants.m.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.nativeConstants to generate the absolute path to the NativeConstants.m.

import { path } from "@brandingbrand/code-cli-kit";
const nativeConstantsPath = path.ios.nativeConstants;

Generates the absolute path to the iOS project.pbxproj.

type: string

Below is an illustrative example demonstrating the utilization of the path.ios.projectPbxProj to generate the absolute path to the project.pbxproj.

import { path } from "@brandingbrand/code-cli-kit";
const projectPbxProjPath = path.ios.projectPbxProj;

Generates the absolute path to the Android build.gradle.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.buildGradle to generate the absolute path to the build.gradle.

import { path } from "@brandingbrand/code-cli-kit";
const buildGradlePath = path.android.buildGradle;

Generates the absolute path to the Android Gemfile.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.gemfile to generate the absolute path to the Gemfile.

import { path } from "@brandingbrand/code-cli-kit";
const gemfilePath = path.android.gemfile;

Generates the absolute path to the Android gradle.properties.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.gradleProperties to generate the absolute path to the gradle.properties.

import { path } from "@brandingbrand/code-cli-kit";
const gradlePropertiesPath = path.android.gradleProperties;

Generates the absolute path to the Android app module build.gradle.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.appBuildGradle to generate the absolute path to the app module build.gradle.

import { path } from "@brandingbrand/code-cli-kit";
const appBuildGradlePath = path.android.appBuildGradle;

Generates the absolute path to the Android AndroidManifest.xml.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.androidManifest to generate the absolute path to the AndroidManifest.xml.

import { path } from "@brandingbrand/code-cli-kit";
const androidManifestPath = path.android.androidManifest;

Generates the absolute path to the Android colors.xml.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.colors to generate the absolute path to the colors.xml.

import { path } from "@brandingbrand/code-cli-kit";
const colorsPath = path.android.colors;

Generates the absolute path to the Android network_security_config.xml.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.networkSecurityConfig to generate the absolute path to the network_security_config.xml.

import { path } from "@brandingbrand/code-cli-kit";
const networkSecurityConfigPath = path.android.networkSecurityConfig;

Generates the absolute path to the Android strings.xml.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.strings to generate the absolute path to the strings.xml.

import { path } from "@brandingbrand/code-cli-kit";
const stringsPath = path.android.strings;

Generates the absolute path to the Android styles.xml.

type: string

Below is an illustrative example demonstrating the utilization of the path.android.styles to generate the absolute path to the styles.xml.

import { path } from "@brandingbrand/code-cli-kit";
const stylesPath = path.android.styles;

Generates the absolute path to the Android MainApplication.java.

type: function (config: BuildConfig): string

type: BuildConfig

required

The build configuration consumed by Flagship Code represented by build.<mode>.ts.

Below is an illustrative example demonstrating the utilization of the path.android.mainApplication to generate the absolute path to the MainApplication.java.

import { path } from "@brandingbrand/code-cli-kit";
// config aggregated from @brandingbrand/cli
const mainApplicationPath = path.android.mainApplication(config);

Generates the absolute path to the Android MainActivity.java.

type: function (config: BuildConfig): string

type: BuildConfig

required

The build configuration consumed by Flagship Code represented by build.<mode>.ts.

Below is an illustrative example demonstrating the utilization of the path.android.mainActivity to generate the absolute path to the MainActivity.java.

import { path } from "@brandingbrand/code-cli-kit";
// config aggregated from @brandingbrand/cli
const mainActivityPath = path.android.mainActivity(config);

Generates the absolute path to the Android EnvSwitcher.java.

type: function (config: BuildConfig): string

type: BuildConfig

required

The build configuration consumed by Flagship Code represented by build.<mode>.ts.

Below is an illustrative example demonstrating the utilization of the path.android.envSwitcher to generate the absolute path to the EnvSwitcher.java.

import { path } from "@brandingbrand/code-cli-kit";
// config aggregated from @brandingbrand/cli
const envSwitcherPath = path.android.envSwitcher(config);

Generates the absolute path to the Android NativeConstants.java.

type: function (config: BuildConfig): string

type: BuildConfig

required

The build configuration consumed by Flagship Code represented by build.<mode>.ts.

Below is an illustrative example demonstrating the utilization of the path.android.nativeConstants to generate the absolute path to the NativeConstants.java.

import { path } from "@brandingbrand/code-cli-kit";
// config aggregated from @brandingbrand/cli
const nativeConstantsPath = path.android.nativeConstants(config);

A comprehensive suite of string-related utility functions facilitating efficient error handling and warning notifications.

Safely replaces and old string or regular expression statement with a new string.

type: function (content: string, oldText: RegExp | string, newText: string): string

type: string

required

A string that contains text to be replaced.

type: string | RegExp

required

A string or regular expression statement to represent text that needs to be replaced.

type: string

required

A string of text that will replace the old text.

Below is an illustrative example demonstrating the utilization of the replace to update a string.

import { string } from "@brandingbrand/code-cli-kit";
const originalContent = 'Hello, world!';
const newText = replace(originalContent, /world/i, 'there');
console.log(newText);
// Output: "Hello, there!"