1import { ExpoConfig } from '@expo/config-types';
2
3import { ConfigPlugin } from '../Plugin.types';
4import { createStringsXmlPlugin, withSettingsGradle } from '../plugins/android-plugins';
5import { addWarningAndroid } from '../utils/warnings';
6import { buildResourceItem, ResourceXML } from './Resources';
7import { removeStringItem, setStringItem } from './Strings';
8
9/**
10 * Sanitize a name, this should be used for files and gradle names.
11 * - `[/, \, :, <, >, ", ?, *, |]` are not allowed
12 * https://docs.gradle.org/4.2/release-notes.html#path-separator-characters-in-names-are-deprecated
13 *
14 * @param name
15 */
16export function sanitizeNameForGradle(name: string): string {
17  // Remove escape characters which are valid in XML names but not in gradle.
18  name = name.replace(/[\n\r\t]/g, '');
19
20  // Gradle disallows these:
21  // The project name 'My-Special �� Co/ol_Project' must not contain any of the following characters: [/, \, :, <, >, ", ?, *, |]. Set the 'rootProject.name' or adjust the 'include' statement (see https://docs.gradle.org/6.2/dsl/org.gradle.api.initialization.Settings.html#org.gradle.api.initialization.Settings:include(java.lang.String[]) for more details).
22  return name.replace(/(\/|\\|:|<|>|"|\?|\*|\|)/g, '');
23}
24
25export const withName = createStringsXmlPlugin(applyNameFromConfig, 'withName');
26
27export const withNameSettingsGradle: ConfigPlugin = (config) => {
28  return withSettingsGradle(config, (config) => {
29    if (config.modResults.language === 'groovy') {
30      config.modResults.contents = applyNameSettingsGradle(config, config.modResults.contents);
31    } else {
32      addWarningAndroid(
33        'name',
34        `Cannot automatically configure settings.gradle if it's not groovy`
35      );
36    }
37    return config;
38  });
39};
40
41export function getName(config: Pick<ExpoConfig, 'name'>) {
42  return typeof config.name === 'string' ? config.name : null;
43}
44
45function applyNameFromConfig(
46  config: Pick<ExpoConfig, 'name'>,
47  stringsJSON: ResourceXML
48): ResourceXML {
49  const name = getName(config);
50  if (name) {
51    return setStringItem([buildResourceItem({ name: 'app_name', value: name })], stringsJSON);
52  }
53  return removeStringItem('app_name', stringsJSON);
54}
55
56/**
57 * Regex a name change -- fragile.
58 *
59 * @param config
60 * @param settingsGradle
61 */
62export function applyNameSettingsGradle(config: Pick<ExpoConfig, 'name'>, settingsGradle: string) {
63  const name = sanitizeNameForGradle(getName(config) ?? '');
64
65  // Select rootProject.name = '***' and replace the contents between the quotes.
66  return settingsGradle.replace(
67    /rootProject.name\s?=\s?(["'])(?:(?=(\\?))\2.)*?\1/g,
68    `rootProject.name = '${name.replace(/'/g, "\\'")}'`
69  );
70}
71