import assert from 'assert' ; import findUp from 'find-up' ; import * as path from 'path' ; import resolveFrom from 'resolve-from' ; import { ConfigPlugin , StaticPlugin } from '../Plugin.types' ; import { PluginError } from './errors' ; import { fileExists } from './modules' ; export const pluginFileName = 'app.plugin.js' ; function findUpPackageJson ( root ) { const packageJson = findUp . sync ( 'package.json' , { cwd : root } ) ; assert ( packageJson , `No package.json found for module "${ root }"` ) ; return packageJson ; } export function resolvePluginForModule ( projectRoot , modulePath ) { const resolved = resolveFrom . silent ( projectRoot , modulePath ) ; if ( ! resolved ) { throw new PluginError ( `Failed to resolve plugin for module "${ modulePath }" relative to "${ projectRoot }"` , 'PLUGIN_NOT_FOUND' ) ; } if ( moduleNameIsDirectFileReference ( modulePath ) ) { return { isPluginFile : false , filePath : resolved } ; } return findUpPlugin ( resolved ) ; } function pathIsFilePath ( name ) { return ! ! name . match ( /^(\.|~\/|\/)/g ) ; } export function moduleNameIsDirectFileReference ( name ) { if ( pathIsFilePath ( name ) ) { return true ; } const slashCount = name . split ( path . sep ) ?. length ; if ( name . startsWith ( '@' ) ) { return slashCount > 2 ; } return slashCount > 1 ; } function resolveExpoPluginFile ( root ) { const pluginModuleFile = resolveFrom . silent ( root , `./${ pluginFileName }` ) ; if ( pluginModuleFile && fileExists ( pluginModuleFile ) ) { return pluginModuleFile ; } return null ; } function findUpPlugin ( root ) { const packageJson = findUpPackageJson ( root ) ; const moduleRoot = path . dirname ( packageJson ) ; const pluginFile = resolveExpoPluginFile ( moduleRoot ) ; return { filePath : pluginFile ?? root , isPluginFile : ! ! pluginFile } ; } export function normalizeStaticPlugin ( plugin ) { if ( Array . isArray ( plugin ) ) { assert ( plugin . length > 0 && plugin . length < 3 , `Wrong number of arguments provided for static config plugin, expected either 1 or 2, got ${ plugin . length }` ) ; return plugin ; } return [ plugin , undefined ] ; } export function assertInternalProjectRoot ( projectRoot ? ) { assert ( projectRoot , `Unexpected: Config \`_internal.projectRoot\` isn't defined by expo-cli, this is a bug.` ) ; } export function resolveConfigPluginFunction ( projectRoot , pluginReference ) { const { plugin } = resolveConfigPluginFunctionWithInfo ( projectRoot , pluginReference ) ; return plugin ; } export function resolveConfigPluginFunctionWithInfo ( projectRoot , pluginReference ) { const { filePath : pluginFile , isPluginFile } = resolvePluginForModule ( projectRoot , pluginReference ) ; let result ; try { result = requirePluginFile ( pluginFile ) ; } catch ( error ) { if ( error instanceof SyntaxError ) { const learnMoreLink = `Learn more: https://docs.expo.dev/guides/config-plugins/#creating-a-plugin` ; if ( ! isPluginFile && ! moduleNameIsDirectFileReference ( pluginReference ) ) { const pluginError = new PluginError ( `Package "${ pluginReference }" does not contain a valid config plugin.\n${ learnMoreLink }\n\n${ error . message }` , 'INVALID_PLUGIN_IMPORT' ) ; pluginError . stack = error . stack ; throw pluginError ; } } throw error ; } const plugin = resolveConfigPluginExport ( { plugin : result , pluginFile , pluginReference , isPluginFile } ) ; return { plugin , pluginFile , pluginReference , isPluginFile } ; } param props . plugin param props . pluginFile param props . pluginReference param props . isPluginFile export function resolveConfigPluginExport ( { plugin , pluginFile , pluginReference , isPluginFile , } ) { if ( plugin . default != null ) { plugin = plugin . default ; } if ( typeof plugin !== 'function' ) { const learnMoreLink = `Learn more: https://docs.expo.dev/guides/config-plugins/#creating-a-plugin` ; if ( ! isPluginFile && ! moduleNameIsDirectFileReference ( pluginReference ) ) { throw new PluginError ( `Package "${ pluginReference }" does not contain a valid config plugin. Module must export a function from file: ${ pluginFile }\n${ learnMoreLink }` , 'INVALID_PLUGIN_TYPE' ) ; } throw new PluginError ( `Plugin "${ pluginReference }" must export a function from file: ${ pluginFile }. ${ learnMoreLink }` , 'INVALID_PLUGIN_TYPE' ) ; } return plugin ; } function requirePluginFile ( filePath ) { try { return require ( filePath ) ; } catch ( error ) { throw error ; } }