diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index 78b0cf2e7d..bd7ef1be68 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -26,4 +26,4 @@ jobs: - name: Run tests run: yarn test - name: Initialize react native app - run: yarn workspace @brandingbrand/code-example prebuild --build internal --env prod --platform android --verbose + run: yarn workspace @brandingbrand/code-example prebuild --build internal --platform android --app-env-initial prod --app-env-dir ./coderc/env --verbose diff --git a/apps/example/.flagshipappenvrc b/apps/example/.flagshipappenvrc index b9651e550f..25dbc637e1 100644 --- a/apps/example/.flagshipappenvrc +++ b/apps/example/.flagshipappenvrc @@ -1,4 +1,5 @@ { "hiddenEnvs": [], + "singleEnv": false, "dir": "./coderc/env" } diff --git a/apps/example/coderc/plugins/plugin-env/src/index.ts b/apps/example/coderc/plugins/plugin-env/src/index.ts index d6d65a3463..fa266712eb 100644 --- a/apps/example/coderc/plugins/plugin-env/src/index.ts +++ b/apps/example/coderc/plugins/plugin-env/src/index.ts @@ -1,49 +1,120 @@ -/** - * Defines a plugin for @brandingbrand/code-cli-kit. - * @module Plugin - */ - import { definePlugin, + fs, + path, withInfoPlist, withStrings, } from '@brandingbrand/code-cli-kit'; /** - * Defines a plugin with functions for both iOS and Android platforms. - * @alias module:Plugin - * @param {Object} build - The build configuration object. - * @param {Object} options - The options object. + * Custom error for missing required options. + */ +class MissingOptionError extends Error { + constructor(optionName: string) { + super(`MissingOptionError: missing ${optionName} variable`); + this.name = 'MissingOptionError'; + } +} + +/** + * Custom error for when a specified directory does not exist. + */ +class DirectoryNotFoundError extends Error { + constructor(directoryPath: string) { + super( + `DirectoryNotFoundError: The directory "${directoryPath}" does not exist.`, + ); + this.name = 'DirectoryNotFoundError'; + } +} + +/** + * Custom error for when a specified file does not exist. + */ +class FileNotFoundError extends Error { + constructor(filePath: string) { + super(`FileNotFoundError: The file "${filePath}" does not exist.`); + this.name = 'FileNotFoundError'; + } +} + +/** + * Type definition for the plugin options. + */ +interface PluginOptions { + appEnvInitial: string; + appEnvDir: string; + appEnvHide?: string[]; + release: boolean; +} + +/** + * Helper function to validate required options. + */ +async function validateOptions(options: PluginOptions) { + if (!options.appEnvInitial) { + throw new MissingOptionError('appEnvInitial'); + } + if (!options.appEnvDir) { + throw new MissingOptionError('appEnvDir'); + } + + const absoluteAppEnvDir = path.resolve(process.cwd(), options.appEnvDir); + if (!(await fs.doesPathExist(absoluteAppEnvDir))) { + throw new DirectoryNotFoundError(absoluteAppEnvDir); + } + + const absoluteInitialAppEnvPath = path.resolve( + process.cwd(), + options.appEnvDir, + `env.${options.appEnvInitial}.ts`, + ); + if (!(await fs.doesPathExist(absoluteInitialAppEnvPath))) { + throw new FileNotFoundError(absoluteInitialAppEnvPath); + } +} + +/** + * Helper function to write the environment configuration file. + */ +async function writeEnvConfig(options: PluginOptions) { + const configPath = path.join(process.cwd(), '.flagshipappenvrc'); + const configData = { + hiddenEnvs: options.appEnvHide || [], + singleEnv: options.release, + dir: options.appEnvDir, + }; + + await fs.writeFile(configPath, JSON.stringify(configData, null, 2) + '\n'); +} + +/** + * Defines a plugin for both iOS and Android platforms. */ export default definePlugin({ - /** - * Function to be executed for iOS platform. - * @param {Object} _build - The build configuration object for iOS. - * @param {Object} _options - The options object for iOS. - * @returns {Promise} A promise that resolves when the process completes. - */ - ios: async function (_build: object, _options: object): Promise { - await withInfoPlist(plist => { - return { - ...plist, - FlagshipEnv: 'prod', - FlagshipDevMenu: true, - }; - }); + ios: async (_build: object, options: any): Promise => { + await validateOptions(options); + + await withInfoPlist(plist => ({ + ...plist, + FlagshipEnv: options.appEnvInitial, + FlagshipDevMenu: options.release, + })); + + await writeEnvConfig(options); }, - /** - * Function to be executed for Android platform. - * @param {Object} _build - The build configuration object for Android. - * @param {Object} _options - The options object for Android. - * @returns {Promise} A promise that resolves when the process completes. - */ - android: async function (_build: object, _options: object): Promise { - return withStrings(xml => { - xml.resources.string?.push({$: {name: 'flagship_env'}, _: 'prod'}); - xml.resources.string?.push({$: {name: 'flagship_dev_menu'}, _: 'true'}); + android: async (_build: object, options: any): Promise => { + await validateOptions(options); + await withStrings(xml => { + xml.resources.string?.push( + {$: {name: 'flagship_env'}, _: options.appEnvInitial}, + {$: {name: 'flagship_dev_menu'}, _: `${options.release}`}, + ); return xml; }); + + await writeEnvConfig(options); }, }); diff --git a/packages/app-env/.flagshipcoderc.json b/packages/app-env/.flagshipcoderc.json new file mode 100644 index 0000000000..8079e92c1d --- /dev/null +++ b/packages/app-env/.flagshipcoderc.json @@ -0,0 +1,22 @@ +{ + "options": [ + { + "flags": "--app-env-initial ", + "description": "Specifies the initial environment to be used when the application starts (e.g., 'development', 'staging', or 'production').", + "required": true, + "example": "--app-env-initial development" + }, + { + "flags": "--app-env-dir ", + "description": "Defines the directory path where environment configuration files are stored (relative or absolute path).", + "required": true, + "example": "--app-env-dir ./config/environments" + }, + { + "flags": "--app-env-hide ", + "description": "Specifies one or more environments to hide from selection or visibility (comma-separated list).", + "required": false, + "example": "--app-env-hide staging,test" + } + ] +} diff --git a/packages/cli/__tests__/common_fixtures/package.json b/packages/cli/__tests__/common_fixtures/package.json new file mode 100644 index 0000000000..ed33f8baa7 --- /dev/null +++ b/packages/cli/__tests__/common_fixtures/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@brandingbrand/fsapp": "11.0.0" + } +} diff --git a/packages/cli/__tests__/env-switcher-java.ts b/packages/cli/__tests__/env-switcher-java.ts index fd62fb381d..8b61ea8201 100644 --- a/packages/cli/__tests__/env-switcher-java.ts +++ b/packages/cli/__tests__/env-switcher-java.ts @@ -1,5 +1,5 @@ /** - * @jest-environment-options {"requireTemplate": true} + * @jest-environment-options {"requireTemplate": true, "fixtures": "common_fixtures"} */ /// diff --git a/packages/cli/__tests__/env-switcher-m.ts b/packages/cli/__tests__/env-switcher-m.ts index 0c723fef80..3bfc7a1a28 100644 --- a/packages/cli/__tests__/env-switcher-m.ts +++ b/packages/cli/__tests__/env-switcher-m.ts @@ -1,5 +1,5 @@ /** - * @jest-environment-options {"requireTemplate": true} + * @jest-environment-options {"requireTemplate": true, "fixtures": "common_fixtures"} */ /// diff --git a/packages/cli/__tests__/main-application-java.ts b/packages/cli/__tests__/main-application-java.ts index afb926cb01..7b7e313ce8 100644 --- a/packages/cli/__tests__/main-application-java.ts +++ b/packages/cli/__tests__/main-application-java.ts @@ -1,5 +1,5 @@ /** - * @jest-environment-options {"requireTemplate": true} + * @jest-environment-options {"requireTemplate": true, "fixtures": "project-pbxproj_fixtures"} */ /// diff --git a/packages/cli/__tests__/native-constants-java.ts b/packages/cli/__tests__/native-constants-java.ts index 97786214b1..2fe9008b1b 100644 --- a/packages/cli/__tests__/native-constants-java.ts +++ b/packages/cli/__tests__/native-constants-java.ts @@ -1,5 +1,5 @@ /** - * @jest-environment-options {"requireTemplate": true} + * @jest-environment-options {"requireTemplate": true, "fixtures": "common_fixtures"} */ /// diff --git a/packages/cli/__tests__/native-constants-m.ts b/packages/cli/__tests__/native-constants-m.ts index c9f4dabb2e..885e9e5440 100644 --- a/packages/cli/__tests__/native-constants-m.ts +++ b/packages/cli/__tests__/native-constants-m.ts @@ -1,5 +1,5 @@ /** - * @jest-environment-options {"requireTemplate": true} + * @jest-environment-options {"requireTemplate": true, "fixtures": "common_fixtures"} */ /// diff --git a/packages/cli/__tests__/project-pbxproj_fixtures/package.json b/packages/cli/__tests__/project-pbxproj_fixtures/package.json new file mode 100644 index 0000000000..ed33f8baa7 --- /dev/null +++ b/packages/cli/__tests__/project-pbxproj_fixtures/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@brandingbrand/fsapp": "11.0.0" + } +} diff --git a/packages/cli/package.json b/packages/cli/package.json index 72f2f56fe5..6b42a83fd7 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -30,7 +30,9 @@ "detect-package-manager": "^3.0.1", "esbuild": "^0.20.0", "execa": "^9.3.0", + "find-node-modules": "^2.1.3", "fp-ts": "^2.16.2", + "glob": "^11.0.0", "ink": "^4.4.1", "ink-spinner": "^5.0.0", "io-ts": "^2.2.21", @@ -57,9 +59,11 @@ "@repo/typescript-config": "*", "@types/ansi-align": "3.0.5", "@types/eslint": "^8.56.1", + "@types/find-node-modules": "^2.1.2", "@types/node": "^20.10.6", "@types/npmcli__package-json": "^4.0.4", "@types/react": "18.2.6", + "ajv": "^8.17.1", "react": "^18.2.0", "type-fest": "^4.10.2", "typescript": "^5.3.3" diff --git a/packages/cli/schema.json b/packages/cli/schema.json new file mode 100644 index 0000000000..4b49ef8254 --- /dev/null +++ b/packages/cli/schema.json @@ -0,0 +1,74 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Flagship Code Commands Configuration", + "description": "Schema for defining custom commander options in flagship-code.commands.json", + "type": "object", + "properties": { + "options": { + "type": "array", + "description": "An array of custom options to be dynamically added to commander commands", + "items": { + "type": "object", + "properties": { + "flags": { + "type": "string", + "description": "The flag syntax for the option, following commander conventions (e.g., '--flag ').", + "pattern": "^--[a-zA-Z0-9\\-_]+(\\s<[a-zA-Z0-9\\-_]+>|\\s\\[[a-zA-Z0-9\\-_]+\\])?$", + "examples": [ + "--custom-flag ", + "--enable-feature", + "--mode [type]" + ], + "minLength": 2 + }, + "description": { + "type": "string", + "description": "A brief description of the option, including the expected value format or type.", + "minLength": 1, + "examples": [ + "Specifies the initial environment to use, e.g., 'development', 'staging', or 'production'.", + "Defines the path to the environments directory.", + "A comma-separated list of environments to hide." + ] + }, + "example": { + "type": "string", + "description": "A concrete example showing how to use the option.", + "examples": [ + "--app-env-initial development", + "--app-env-dir ./config/environments", + "--app-env-hide staging,test" + ] + }, + "defaultValue": { + "description": "The default value for the option if it is not specified by the user.", + "anyOf": [ + {"type": "string"}, + {"type": "number"}, + {"type": "boolean"}, + {"type": "null"} + ] + }, + "choices": { + "type": "array", + "description": "Restrict the option's possible values to a predefined set.", + "items": { + "type": "string" + }, + "uniqueItems": true, + "examples": [["debug", "release", "test"]] + }, + "required": { + "type": "boolean", + "description": "Indicates whether the option is mandatory.", + "default": false + } + }, + "required": ["flags", "description"], + "additionalProperties": false + } + } + }, + "required": ["options"], + "additionalProperties": false +} diff --git a/packages/cli/src/actions/template.ts b/packages/cli/src/actions/template.ts index 6ddab3a666..b0de39f144 100644 --- a/packages/cli/src/actions/template.ts +++ b/packages/cli/src/actions/template.ts @@ -9,7 +9,14 @@ import { getReactNativeVersion, } from '@brandingbrand/code-cli-kit'; -import {config, defineAction, isGenerateCommand} from '@/lib'; +import { + FSAPP_DEPENDENCY, + config, + defineAction, + isGenerateCommand, + hasDependency, + matchesFilePatterns, +} from '@/lib'; /** * Define an action to initialize a project template. @@ -29,6 +36,38 @@ export default defineAction(async () => { `react-native-${reactNativeVersion}`, ); + /** + * Filters files during a copy operation to exclude specific native files if the `fsapp` dependency is not installed. + * + * The function checks if the current project does not have the `fsapp` dependency and matches the source file + * against a predefined set of patterns. If both conditions are true, the file is excluded. + * + * @param src - The source file path being processed. + * @returns `false` if the file should be excluded; otherwise, `true`. + * + * @example + * ```typescript + * const shouldCopy = filter('/path/to/ios/EnvSwitcher.java'); + * console.log(shouldCopy); // true or false depending on the presence of 'fsapp' and file match + * ``` + */ + const fileFilter = (src: string): boolean => { + if ( + !hasDependency(process.cwd(), FSAPP_DEPENDENCY) && + matchesFilePatterns(src, [ + 'EnvSwitcher.java', + 'EnvSwitcher.m', + 'NativeConstants.java', + 'NativeConstants.m', + 'EnvSwitcherPackage.java', + 'NativeConstantsPackage.java', + ]) + ) { + return false; + } + return true; + }; + // If the generate cli command was executed copy the plugin template only // WARNING: Consider moving this in future. if (isGenerateCommand()) { @@ -138,7 +177,7 @@ export default defineAction(async () => { return false; } - return true; + return fileFilter(path); }, }) .catch(e => { diff --git a/packages/cli/src/cmds/prebuild.tsx b/packages/cli/src/cmds/prebuild.tsx index ebb7aee795..c10e8e8523 100644 --- a/packages/cli/src/cmds/prebuild.tsx +++ b/packages/cli/src/cmds/prebuild.tsx @@ -14,6 +14,7 @@ import { FLAGSHIP_CODE_TITLE, } from '@/lib'; import {Status} from '@/components/Status'; +import {registerCustomOptions} from '@/lib/commands'; /** * Defines a command for the "prebuild" operation using the "commander" library. @@ -30,78 +31,82 @@ import {Status} from '@/components/Status'; * * @see {@link https://www.npmjs.com/package/commander | commander} - Command-line framework for Node.js. */ -program - .command('prebuild') - .description( - 'Ephemeral native code generation for a specific build, environment, and platform.', - ) - .requiredOption('-b, --build [build]', 'Build configuration.') - .requiredOption('-e, --env [env]', 'Initial environment.') - .addOption( - new Option( - '-p, --platform [platform]', - 'ios, android, or native (ios & android) code generation.', +registerCustomOptions( + program + .command('prebuild') + .description( + 'Ephemeral native code generation for a specific build, environment, and platform.', ) - .choices(['ios', 'android', 'native']) - .default('native'), - ) - .addOption( - new Option( - '-l --log-level [logLevel]', - 'debug, log, info, warn, error log levels.', + .requiredOption('-b, --build [build]', 'Build configuration.') + .option('-e, --env [env]', 'Initial environment.') + .addOption( + new Option( + '-p, --platform [platform]', + 'ios, android, or native (ios & android) code generation.', + ) + .choices(['ios', 'android', 'native']) + .default('native'), ) - .choices(['debug', 'log', 'info', 'warn', 'error']) - .default('info'), - ) - .option('-r, --release', 'Bundle only specified environment.', false) - .option('--verbose', 'Show stdout.', false) - .action(async (options: PrebuildOptions) => { - /** - * Update the configuration options with the provided options and command type. - */ - config.options = {...options, command: 'prebuild'}; - - const {render} = await import('ink'); - - await new Promise(res => { + .addOption( + new Option( + '-l --log-level [logLevel]', + 'debug, log, info, warn, error log levels.', + ) + .choices(['debug', 'log', 'info', 'warn', 'error']) + .default('info'), + ) + .option('-r, --release', 'Bundle only specified environment.', false) + .option('--verbose', 'Show stdout.', false) + .action(async (options: PrebuildOptions) => { /** - * Render the Reporter component to display progress. + * Update the configuration options with the provided options and command type. */ - const {unmount} = render(, {stdout: process.stderr}); + config.options = {...options, command: 'prebuild'}; + + const {render} = await import('ink'); - global.unmount = unmount; - }); + await new Promise(res => { + /** + * Render the Reporter component to display progress. + */ + const {unmount} = render(, { + stdout: process.stderr, + }); - logger.setLogLevel(logger.getLogLevelFromString(options.logLevel)); + global.unmount = unmount; + }); - if (!options.verbose) { - logger.pause(); - } + logger.setLogLevel(logger.getLogLevelFromString(options.logLevel)); - process.stdout.write(FLAGSHIP_CODE_LOGO + '\n\n'); - process.stdout.write( - ansiAlign([FLAGSHIP_CODE_TITLE, FLAGSHIP_CODE_DESCRIPTION]).join('\n') + - '\n\n', - ); + if (!options.verbose) { + logger.pause(); + } - logger.printCmdOptions(options, 'prebuild'); + process.stdout.write(FLAGSHIP_CODE_LOGO + '\n\n'); + process.stdout.write( + ansiAlign([FLAGSHIP_CODE_TITLE, FLAGSHIP_CODE_DESCRIPTION]).join('\n') + + '\n\n', + ); - FlagshipCodeManager.shared - .addAction(actions.info) - .addAction(actions.clean) - .addAction(actions.config) - .addAction(actions.template) - .addAction(actions.env) - .addAction(actions.transformers) - .addAction(actions.plugins) - .addAction(actions.packagers); + logger.printCmdOptions(options, 'prebuild'); - await FlagshipCodeManager.shared.run(); + FlagshipCodeManager.shared + .addAction(actions.info) + .addAction(actions.clean) + .addAction(actions.config) + .addAction(actions.template) + .addAction(actions.env) + .addAction(actions.transformers) + .addAction(actions.plugins) + .addAction(actions.packagers); - /** - * Resume logging with console.log and process.stdout - */ - logger.resume(); + await FlagshipCodeManager.shared.run(); + + /** + * Resume logging with console.log and process.stdout + */ + logger.resume(); - global.unmount?.(); - }); + global.unmount?.(); + }), +); diff --git a/packages/cli/src/lib/commands.ts b/packages/cli/src/lib/commands.ts new file mode 100644 index 0000000000..9e738ca4ac --- /dev/null +++ b/packages/cli/src/lib/commands.ts @@ -0,0 +1,159 @@ +import fs from 'fs'; +import {cwd} from 'process'; + +import {Command, Option} from 'commander'; +import {glob} from 'glob'; +import findNodeModules from 'find-node-modules'; +import Ajv from 'ajv'; + +import schema from '../../schema.json'; + +const ajv = new Ajv(); + +/** + * Interface for the configuration options in the JSON file. + */ +interface CommandOption { + /** + * The flag syntax for the option, e.g., `--flag ` or `--flag [value]`. + */ + flags: string; + /** + * A description of the option, shown in the CLI help output. + */ + description: string; + /** + * The default value for the option if it is not provided by the user. + */ + defaultValue?: string | number | boolean | null; + /** + * A list of valid values for the option, if applicable. + */ + choices?: string[]; + /** + * Whether the option is mandatory. + */ + required?: boolean; +} + +/** + * Interface for the structure of the flagship-code.commands.json file. + */ +interface ConfigFile { + /** + * A list of command options to dynamically add to the CLI. + */ + options: CommandOption[]; +} + +/** + * The name of the configuration file to search for in node_modules directories. + * + * This file contains CLI configuration options defined by plugins or packages + * and is used to dynamically extend the functionality of the CLI. + */ +const CONFIG_FILE_NAME = '.flagshipcoderc.json'; + +/** + * Find all flagship-code.commands.json files in node_modules + */ +function findConfigFiles() { + const nodeModulesPaths = findNodeModules({cwd: cwd(), relative: false}).map( + it => `${it}/**/${CONFIG_FILE_NAME}`, + ); + + return glob.sync(nodeModulesPaths, { + nodir: true, // Ensure we only get files + }); +} + +/** + * Reads and parses a single JSON configuration file. + * + * @param configPath - Path to the configuration file. + * @returns Parsed configuration or null if invalid. + */ +function parseConfigFile(configPath: string): ConfigFile | null { + const fileContents = fs.readFileSync(configPath, 'utf8'); + const json = JSON.parse(fileContents) as ConfigFile; + + const validate = ajv.compile(schema); + const valid = validate(json); + + if (!valid) + throw Error( + `ValidationError: ${CONFIG_FILE_NAME} does not conform to the json schema.`, + ); + + return json; +} + +/** + * Loads and aggregates all JSON configuration files matching the glob pattern. + * + * @returns Aggregated configuration object. + */ +function loadConfigFiles(): ConfigFile { + const configFiles = findConfigFiles(); + + const aggregatedOptions: CommandOption[] = []; + + if (configFiles.length === 0) { + return {options: []}; + } + + configFiles.forEach(configPath => { + const parsedConfig = parseConfigFile(configPath); + if (parsedConfig?.options) { + aggregatedOptions.push(...parsedConfig.options); + } + }); + + return {options: aggregatedOptions}; +} + +/** + * Custom argument parser to validate input against choices. + * + * @param value - The input value. + * @param choices - The allowed choices. + * @returns The validated value. + * @throws Error if the value is not in the allowed choices. + */ +function validateChoice(value: string, choices: string[]): string { + if (!choices.includes(value)) { + throw new Error( + `Invalid value '${value}'. Allowed choices are: ${choices.join(', ')}`, + ); + } + return value; +} + +/** + * Dynamically registers custom options from the configuration file to a given Commander command. + * + * @param command - The Commander command to which options will be added. + */ +export function registerCustomOptions(command: Command): void { + const config = loadConfigFiles(); + + config.options.forEach(opt => { + const option = new Option(opt.flags, opt.description); + + if (opt.defaultValue !== undefined) { + option.default(opt.defaultValue); + } + + if (opt.required) { + option.makeOptionMandatory(); + } + + if (opt.choices) { + option.argParser((value: string, previous: unknown) => + validateChoice(value, opt.choices ?? []), + ); + } + + command.addOption(option); + }); +} diff --git a/packages/cli/src/lib/constants.ts b/packages/cli/src/lib/constants.ts index cae9b36a14..24ff0a43cd 100644 --- a/packages/cli/src/lib/constants.ts +++ b/packages/cli/src/lib/constants.ts @@ -19,6 +19,9 @@ export const REACT_NATIVE_VERSION_RANGE = '^0.72.0 || ^0.73.0'; */ export const REACT_VERSION_RANGE = '^18.0.0'; +/** + * ASCII art logo for Flagship Code, styled in blue using Chalk. + */ export const FLAGSHIP_CODE_LOGO = chalk.blue` ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒▒ @@ -41,9 +44,40 @@ export const FLAGSHIP_CODE_LOGO = chalk.blue` ▒▒▒▒ `; +/** + * Title string for Flagship Code, styled with bold blue and white Chalk text. + * Displays the current version of the package. + * + * Example output: + * ``` + * Flagship Code v1.0.0 + * ``` + */ export const FLAGSHIP_CODE_TITLE = chalk.bold .blue`Flagship Code ${chalk.bold.white`v${pkg.version}`}`; +/** + * Short description for Flagship Code, styled with dim Chalk text. + * Highlights key features such as configurability and extensibility. + * + * Example output: + * ``` + * Configurable - Extensible - Toolkit + * ``` + */ export const FLAGSHIP_CODE_DESCRIPTION = chalk.dim`Configurable - Extensible - Toolkit`; +/** + * Label for Flagship Code commands, styled with a blue background and white text. + * + * Example output: + * ``` + * ▸ flagship-code + * ``` + */ export const FLAGSHIP_CODE_LABEL = chalk.bgBlueBright.white` ▸ flagship-code `; + +/** + * The package name for the `fsapp` dependency from Branding Brand. + */ +export const FSAPP_DEPENDENCY = '@brandingbrand/fsapp'; diff --git a/packages/cli/src/lib/dependencies.ts b/packages/cli/src/lib/dependencies.ts new file mode 100644 index 0000000000..540ccb4d34 --- /dev/null +++ b/packages/cli/src/lib/dependencies.ts @@ -0,0 +1,35 @@ +import {existsSync} from 'fs'; +import path from 'path'; + +/** + * Checks if the specified dependency exists in the project's dependencies or devDependencies. + * @param projectPath - The path to the project's root directory. + * @param dependencyName - The name of the dependency to check. + * @returns True if the dependency is installed, otherwise false. + */ +export function hasDependency( + projectPath: string, + dependencyName: string, +): boolean { + const packageJsonPath = path.resolve(projectPath, 'package.json'); + if (!existsSync(packageJsonPath)) return false; + + const packageJson = require(packageJsonPath); + return Boolean( + packageJson.dependencies?.[dependencyName] || + packageJson.devDependencies?.[dependencyName], + ); +} + +/** + * Determines if the given file path matches any of the specified patterns. + * @param filePath - The path to the file. + * @param patterns - An array of strings representing file name patterns to match. + * @returns True if the file path matches any of the patterns, otherwise false. + */ +export function matchesFilePatterns( + filePath: string, + patterns: string[], +): boolean { + return patterns.some(pattern => filePath.includes(pattern)); +} diff --git a/packages/cli/src/lib/index.ts b/packages/cli/src/lib/index.ts index c8a5cfa53f..670d7acdd4 100644 --- a/packages/cli/src/lib/index.ts +++ b/packages/cli/src/lib/index.ts @@ -38,3 +38,10 @@ export * from './constants'; * @module lib/profiles */ export * from './profiles'; + +/** + * Dependency helper functions + * + * @module lib/dependencies + */ +export * from './dependencies'; diff --git a/packages/cli/src/transformers/transformers-0.72/android/env-switcher-java.ts b/packages/cli/src/transformers/transformers-0.72/android/env-switcher-java.ts index 4af84c488a..541abf1ef2 100644 --- a/packages/cli/src/transformers/transformers-0.72/android/env-switcher-java.ts +++ b/packages/cli/src/transformers/transformers-0.72/android/env-switcher-java.ts @@ -6,7 +6,12 @@ import { string, } from '@brandingbrand/code-cli-kit'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the Android project's "EnvSwitcher.java" file. @@ -59,6 +64,8 @@ export default defineTransformer>({ config: BuildConfig, options: PrebuildOptions, ): Promise { + if (!hasDependency(process.cwd(), FSAPP_DEPENDENCY)) return; + return withUTF8(path.android.envSwitcher(config), (content: string) => { return this.transforms.reduce((acc, curr) => { return curr(acc, config, options); diff --git a/packages/cli/src/transformers/transformers-0.72/android/main-application-java.ts b/packages/cli/src/transformers/transformers-0.72/android/main-application-java.ts index ba2d999101..b0a849c78d 100644 --- a/packages/cli/src/transformers/transformers-0.72/android/main-application-java.ts +++ b/packages/cli/src/transformers/transformers-0.72/android/main-application-java.ts @@ -6,7 +6,12 @@ import { string, } from '@brandingbrand/code-cli-kit'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the Android project's "MainApplication.java" file. @@ -42,6 +47,8 @@ export default defineTransformer>({ config: BuildConfig, options: PrebuildOptions, ): string => { + if (!hasDependency(process.cwd(), FSAPP_DEPENDENCY)) return content; + return string.replace( content, /(new PackageList.*\s+)/m, diff --git a/packages/cli/src/transformers/transformers-0.72/android/native-constants-java.ts b/packages/cli/src/transformers/transformers-0.72/android/native-constants-java.ts index c9737bf395..0774f46b79 100644 --- a/packages/cli/src/transformers/transformers-0.72/android/native-constants-java.ts +++ b/packages/cli/src/transformers/transformers-0.72/android/native-constants-java.ts @@ -6,7 +6,12 @@ import { string, } from '@brandingbrand/code-cli-kit'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the Android project's "NativeConstants.java" file. @@ -59,6 +64,8 @@ export default defineTransformer>({ config: BuildConfig, options: PrebuildOptions, ): Promise { + if (!hasDependency(process.cwd(), FSAPP_DEPENDENCY)) return; + return withUTF8(path.android.nativeConstants(config), (content: string) => { return this.transforms.reduce((acc, curr) => { return curr(acc, config, options); diff --git a/packages/cli/src/transformers/transformers-0.72/ios/env-switcher-m.ts b/packages/cli/src/transformers/transformers-0.72/ios/env-switcher-m.ts index f9649e4ec7..9c949c27c7 100644 --- a/packages/cli/src/transformers/transformers-0.72/ios/env-switcher-m.ts +++ b/packages/cli/src/transformers/transformers-0.72/ios/env-switcher-m.ts @@ -6,7 +6,12 @@ import { string, } from '@brandingbrand/code-cli-kit'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the iOS project's "EnvSwitcher.m" file. @@ -59,6 +64,8 @@ export default defineTransformer>({ config: BuildConfig, options: PrebuildOptions, ): Promise { + if (!hasDependency(process.cwd(), FSAPP_DEPENDENCY)) return; + return withUTF8(path.ios.envSwitcher, (content: string) => { return this.transforms.reduce((acc, curr) => { return curr(acc, config, options); diff --git a/packages/cli/src/transformers/transformers-0.72/ios/native-constants-m.ts b/packages/cli/src/transformers/transformers-0.72/ios/native-constants-m.ts index 0a904c31ac..6f2b671699 100644 --- a/packages/cli/src/transformers/transformers-0.72/ios/native-constants-m.ts +++ b/packages/cli/src/transformers/transformers-0.72/ios/native-constants-m.ts @@ -6,7 +6,12 @@ import { string, } from '@brandingbrand/code-cli-kit'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the iOS project's "NativeConstants.m" file. @@ -59,6 +64,8 @@ export default defineTransformer>({ config: BuildConfig, options: PrebuildOptions, ): Promise { + if (!hasDependency(process.cwd(), FSAPP_DEPENDENCY)) return; + return withUTF8(path.ios.nativeConstants, (content: string) => { return this.transforms.reduce((acc, curr) => { return curr(acc, config, options); diff --git a/packages/cli/src/transformers/transformers-0.72/ios/project-pbxproj.ts b/packages/cli/src/transformers/transformers-0.72/ios/project-pbxproj.ts index e74d46a64d..6463d16df2 100644 --- a/packages/cli/src/transformers/transformers-0.72/ios/project-pbxproj.ts +++ b/packages/cli/src/transformers/transformers-0.72/ios/project-pbxproj.ts @@ -8,7 +8,12 @@ import { } from '@brandingbrand/code-cli-kit'; import type {XcodeProject, PBXFile} from 'xcode'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the iOS project's "project.pbxproj" file. @@ -56,9 +61,12 @@ export default defineTransformer>({ // These files exist as extras and need to be added to pbxproj file as // source files or header files + if (hasDependency(process.cwd(), FSAPP_DEPENDENCY)) { + project.addSourceFile('app/EnvSwitcher.m', opt, groupKey); + project.addSourceFile('app/NativeConstants.m', opt, groupKey); + } + project.addSourceFile('app/app.swift', opt, groupKey); - project.addSourceFile('app/EnvSwitcher.m', opt, groupKey); - project.addSourceFile('app/NativeConstants.m', opt, groupKey); project.addHeaderFile('app/app-Bridging-Header.h', opt, groupKey); // Add the PrivacyInfo.xcprivacy privacy manifest for React Native base usage diff --git a/packages/cli/src/transformers/transformers-0.73/ios/project-pbxproj.ts b/packages/cli/src/transformers/transformers-0.73/ios/project-pbxproj.ts index ac342a8d09..dfe130fb28 100644 --- a/packages/cli/src/transformers/transformers-0.73/ios/project-pbxproj.ts +++ b/packages/cli/src/transformers/transformers-0.73/ios/project-pbxproj.ts @@ -8,7 +8,12 @@ import { } from '@brandingbrand/code-cli-kit'; import type {XcodeProject, PBXFile} from 'xcode'; -import {Transforms, defineTransformer} from '@/lib'; +import { + FSAPP_DEPENDENCY, + Transforms, + defineTransformer, + hasDependency, +} from '@/lib'; /** * Defines a transformer for the iOS project's "project.pbxproj" file. @@ -56,9 +61,12 @@ export default defineTransformer>({ // These files exist as extras and need to be added to pbxproj file as // source files or header files + if (hasDependency(process.cwd(), FSAPP_DEPENDENCY)) { + project.addSourceFile('app/EnvSwitcher.m', opt, groupKey); + project.addSourceFile('app/NativeConstants.m', opt, groupKey); + } + project.addSourceFile('app/app.swift', opt, groupKey); - project.addSourceFile('app/EnvSwitcher.m', opt, groupKey); - project.addSourceFile('app/NativeConstants.m', opt, groupKey); project.addHeaderFile('app/app-Bridging-Header.h', opt, groupKey); // PrivacyInfo.xcprivacy is already included in the React Native 0.73 template from diff --git a/yarn.lock b/yarn.lock index 7d2dbe8fac..669cbfd70f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3797,6 +3797,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== +"@types/find-node-modules@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/find-node-modules/-/find-node-modules-2.1.2.tgz#db621fe8c634337c62178ef48cd48f7339e431f1" + integrity sha512-5hRcqDclY6MTkHXJBc5q79z5luG+IJRlGR01wluMVMM9lYogYc2sfclXTVU5Edp0Ja4viIOCDI1lXhFRlsNTKA== + "@types/fs-extra@^11.0.4": version "11.0.4" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.4.tgz#e16a863bb8843fba8c5004362b5a73e17becca45" @@ -4346,6 +4351,16 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + anser@^1.4.9: version "1.4.10" resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" @@ -5745,6 +5760,11 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q== + detect-indent@^6.0.0, detect-indent@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" @@ -6646,6 +6666,13 @@ expand-template@^2.0.3: resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw== + dependencies: + homedir-polyfill "^1.0.1" + expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -6729,6 +6756,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241" + integrity sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw== + fast-xml-parser@^4.0.12, fast-xml-parser@^4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f" @@ -6807,6 +6839,14 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" +find-node-modules@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/find-node-modules/-/find-node-modules-2.1.3.tgz#3c976cff2ca29ee94b4f9eafc613987fc4c0ee44" + integrity sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg== + dependencies: + findup-sync "^4.0.0" + merge "^2.1.1" + find-up-simple@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/find-up-simple/-/find-up-simple-1.0.0.tgz#21d035fde9fdbd56c8f4d2f63f32fd93a1cfc368" @@ -6843,6 +6883,16 @@ find-yarn-workspace-root2@1.2.16: micromatch "^4.0.2" pkg-dir "^4.2.0" +findup-sync@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0" + integrity sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^4.0.2" + resolve-dir "^1.0.1" + flat-cache@^3.0.4: version "3.2.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" @@ -7131,6 +7181,18 @@ glob@^10.2.2: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" +glob@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e" + integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^4.0.1" + minimatch "^10.0.0" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -7143,6 +7205,26 @@ glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg== + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -7613,6 +7695,13 @@ hoist-non-react-statics@3.x.x: dependencies: react-is "^16.7.0" +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -7782,16 +7871,16 @@ inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@^1.3.4, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + ini@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.3.tgz#4c359675a6071a46985eb39b14e4a2c0ec98a795" integrity sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg== -ini@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - ink-spinner@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/ink-spinner/-/ink-spinner-5.0.0.tgz#32ec318ef8ebb0ace8f595451f8e93280623429f" @@ -8237,7 +8326,7 @@ is-what@^4.1.8: resolved "https://registry.yarnpkg.com/is-what/-/is-what-4.1.16.tgz#1ad860a19da8b4895ad5495da3182ce2acdd7a6f" integrity sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A== -is-windows@^1.0.0: +is-windows@^1.0.0, is-windows@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== @@ -8368,6 +8457,13 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jackspeak@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015" + integrity sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw== + dependencies: + "@isaacs/cliui" "^8.0.2" + jake@^10.8.5: version "10.8.7" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" @@ -8847,6 +8943,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -9116,6 +9217,11 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^11.0.0: + version "11.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39" + integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA== + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -9475,6 +9581,11 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +merge@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-2.1.1.tgz#59ef4bf7e0b3e879186436e8481c06a6c162ca98" + integrity sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w== + metro-babel-transformer@0.80.9: version "0.80.9" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.80.9.tgz#7051ba377b7d2140abd23f4846bbbb1e81fea99b" @@ -10106,6 +10217,13 @@ minimatch@9.0.3, minimatch@^9.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -10796,6 +10914,11 @@ parse-ms@^4.0.0: resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-4.0.0.tgz#c0c058edd47c2a590151a718990533fd62803df4" integrity sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw== +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== + parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -10869,6 +10992,14 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + path-to-regexp@^8.1.0: version "8.2.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4" @@ -11737,6 +11868,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -11754,6 +11890,14 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg== + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -13948,7 +14092,7 @@ which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.1" -which@^1.2.9: +which@^1.2.14, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==