bitmovin-player-react-native
Version:
Official React Native bindings for Bitmovin's mobile Player SDKs.
237 lines (214 loc) • 7.72 kB
text/typescript
import {
ConfigPlugin,
withAppBuildGradle,
WarningAggregator,
} from 'expo/config-plugins';
export type PluginProps = {
spacing?: string;
dependencies?: string[];
};
const DEFAULT_SPACING = ' ';
const defaultProps: PluginProps = {
spacing: DEFAULT_SPACING,
dependencies: [],
};
const CORE_LIBRARY_DESUGARING_DEPENDENCY =
"coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'";
const CORE_LIBRARY_DESUGARING_ARTIFACT = 'com.android.tools:desugar_jdk_libs';
const hasCoreLibraryDesugaringEnabled = (contents: string) =>
/^\s*(?:set)?CoreLibraryDesugaringEnabled\b.*?\btrue\b/m.test(contents);
const escapeRegExp = (value: string) =>
value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const hasGradleDependencyDeclaration = (
contents: string,
dependency: string,
configuration?: string,
allowVersionSuffix = false
) => {
const dependencyPattern = escapeRegExp(dependency);
const configurationPattern = configuration
? escapeRegExp(configuration)
: '[A-Za-z_][\\w.-]*';
const versionSuffixPattern = allowVersionSuffix ? `(?::[^'"]*)?` : '';
const declarationPattern = new RegExp(
`^${configurationPattern}\\s*(?:\\(\\s*)?['"]${dependencyPattern}${versionSuffixPattern}['"]`
);
let nestedBlockDepth = 0;
return contents.split('\n').some((line) => {
const trimmedLine = line.trim();
if (trimmedLine.startsWith('//')) {
return false;
}
if (/^dependencies\s*\{$/.test(trimmedLine)) {
return false;
}
const isTopLevelDependency =
nestedBlockDepth === 0 && declarationPattern.test(trimmedLine);
const openBlockCount = (trimmedLine.match(/\{/g) || []).length;
const closeBlockCount = (trimmedLine.match(/\}/g) || []).length;
nestedBlockDepth += openBlockCount - closeBlockCount;
return isTopLevelDependency;
});
};
// Matches any pinned version of the desugaring artifact so an existing
// declaration is never duplicated, even when it pins a different version.
const hasCoreLibraryDesugaringDependency = (contents: string) =>
hasGradleDependencyDeclaration(
contents,
CORE_LIBRARY_DESUGARING_ARTIFACT,
'coreLibraryDesugaring',
true
);
const replaceDisabledCoreLibraryDesugaringSettings = (contents: string) =>
contents
.replace(
/^(\s*)setCoreLibraryDesugaringEnabled\s*\(\s*false\s*\)/gm,
'$1setCoreLibraryDesugaringEnabled(true)'
)
.replace(
/^(\s*)coreLibraryDesugaringEnabled(\s*=\s*)false\b/gm,
'$1coreLibraryDesugaringEnabled$2true'
)
.replace(
/^(\s*)coreLibraryDesugaringEnabled(\s+)false\b/gm,
'$1coreLibraryDesugaringEnabled$2true'
);
const ensureCoreLibraryDesugaringCompileOptions = (
contents: string,
spacing: string,
androidBlockStart: number,
androidPosition: number
) => {
const androidBlock = contents.slice(androidBlockStart, androidPosition);
const updatedAndroidBlock =
replaceDisabledCoreLibraryDesugaringSettings(androidBlock);
const updatedContents = [
contents.slice(0, androidBlockStart),
updatedAndroidBlock,
contents.slice(androidPosition),
].join('');
const updatedAndroidPosition =
androidPosition + updatedAndroidBlock.length - androidBlock.length;
if (hasCoreLibraryDesugaringEnabled(updatedAndroidBlock)) {
return updatedContents;
}
const compileOptionsRelativeStart = updatedAndroidBlock.search(
/^[^\S\r\n]*compileOptions\s*\{$/m
);
if (compileOptionsRelativeStart === -1) {
const compileOptions = [
`${spacing}compileOptions {`,
`${spacing}${spacing}setCoreLibraryDesugaringEnabled(true)`,
`${spacing}}`,
'',
].join('\n');
return [
updatedContents.slice(0, updatedAndroidPosition),
compileOptions,
updatedContents.slice(updatedAndroidPosition),
].join('');
}
const compileOptionsStart = androidBlockStart + compileOptionsRelativeStart;
const compileOptionsLineEnd =
updatedContents.indexOf('\n', compileOptionsStart) + 1;
return [
updatedContents.slice(0, compileOptionsLineEnd),
`${spacing}${spacing}setCoreLibraryDesugaringEnabled(true)\n`,
updatedContents.slice(compileOptionsLineEnd),
].join('');
};
const withAppGradleDependencies: ConfigPlugin<PluginProps> = (
config,
props: PluginProps
) => {
const combinedProps = { ...defaultProps, ...(props || {}) };
const spacing = combinedProps.spacing || DEFAULT_SPACING;
config = withAppBuildGradle(config, (config) => {
if (config.modResults.language !== 'groovy') {
WarningAggregator.addWarningAndroid(
'withAppGradleDependencies',
`Cannot automatically configure app/build.gradle if it's not groovy`
);
return config;
}
const androidBlockStart =
config.modResults.contents.search(/^android \{$/m);
if (androidBlockStart === -1) {
WarningAggregator.addWarningAndroid(
'withAppGradleDependencies',
`Cannot configure app/build.gradle as no android block start was found`
);
return config;
}
const fromAndroid = config.modResults.contents.substring(androidBlockStart);
const androidBlockEnd = fromAndroid.search(/^\}$/m);
if (androidBlockEnd === -1) {
WarningAggregator.addWarningAndroid(
'withAppGradleDependencies',
`Cannot configure app/build.gradle as no android block end was found`
);
return config;
}
const dependenciesBlockStart =
config.modResults.contents.search(/^dependencies \{$/m);
if (dependenciesBlockStart === -1) {
WarningAggregator.addWarningAndroid(
'withAppGradleDependencies',
`Cannot configure app/build.gradle as no dependency block start was found`
);
return config;
}
const fromDependencies = config.modResults.contents.substring(
dependenciesBlockStart
);
const dependenciesBlockEnd = fromDependencies.search(/^\}$/m);
if (dependenciesBlockEnd === -1) {
WarningAggregator.addWarningAndroid(
'withAppGradleDependencies',
`Cannot configure app/build.gradle as no dependency block end was found`
);
return config;
}
const androidPosition = androidBlockStart + androidBlockEnd;
config.modResults.contents = ensureCoreLibraryDesugaringCompileOptions(
config.modResults.contents,
spacing,
androidBlockStart,
androidPosition
);
const updatedDependenciesBlockStart =
config.modResults.contents.search(/^dependencies \{$/m);
const updatedFromDependencies = config.modResults.contents.substring(
updatedDependenciesBlockStart
);
const updatedDependenciesBlockEnd = updatedFromDependencies.search(/^\}$/m);
const position =
updatedDependenciesBlockStart + updatedDependenciesBlockEnd;
const dependenciesBlock = config.modResults.contents.slice(
updatedDependenciesBlockStart,
position
);
const dependencyDeclarations = [
...(!hasCoreLibraryDesugaringDependency(dependenciesBlock)
? [`${spacing}${CORE_LIBRARY_DESUGARING_DEPENDENCY}`]
: []),
...Array.from(new Set(combinedProps.dependencies))
.filter(
(dependency) =>
!hasGradleDependencyDeclaration(dependenciesBlock, dependency)
)
.map((dependency) => `${spacing}implementation '${dependency}'`),
];
if (dependencyDeclarations.length === 0) {
return config;
}
config.modResults.contents = [
config.modResults.contents.slice(0, position),
`\n${dependencyDeclarations.join('\n')}\n`,
config.modResults.contents.slice(position),
].join('');
return config;
});
return config;
};
export default withAppGradleDependencies;