byCedric/semantic-release-expo

View on GitHub
src/expo.ts

Summary

Maintainability
A
0 mins
Test Coverage
import detectIndent from 'detect-indent';
import detectNewline from 'detect-newline';
import { readFile, writeJson } from 'fs-extra';
import { Context } from './types';

/**
 * A manifest-light definition to use for typehinting.
 *
 * @todo Replace with `@types/expo` when react-native and node console issue is resolved
 */
export interface Manifest {
    name: string;
    version?: string;
    platforms?: string[];
    android?: { versionCode: string | number };
    ios?: { buildNumber: string };
    [propName: string]: any;
}

/**
 * A small manifest description object to include filenames.
 * This is required when reading mulitple manifests to keep track of the filenames.
 */
export interface ManifestMeta {
    filename: string;
    content: string;
    manifest: Manifest;
}

/**
 * The name of the default Expo manifest file.
 */
export const MANIFEST_FILE = 'app.json';

/**
 * The default indentation to use when no indentation is found.
 */
export const DEFAULT_INDENT = '  ';

/**
 * The default newline character to use when no existing was detected.
 */
export const DEFAULT_NEWLINE = '\n';

/**
 * Log information about the manifest which is related to the error.
 */
export function logManifestFromError(context: Context, error: any) {
    if (error && error.expo) {
        context.logger.log('Error encountered for %s manifest %s', 'Expo', error.expo);
    }
}

/**
 * Read the Expo manifest content and return the parsed JSON.
 */
export async function readManifest(filename: string): Promise<ManifestMeta> {
    try {
        const content = await readFile(filename, 'utf8');
        const manifest = JSON.parse(content).expo;

        return { filename, content, manifest };
    } catch (error) {
        error.expo = filename;
        throw error;
    }
}

/**
 * Read a list of Expo mannifest files and return the parsed JSON.
 */
export async function readManifests(filenames: string[]): Promise<ManifestMeta[]> {
    return await Promise.all(filenames.map(readManifest));
}

/**
 * Write new content to the Expo manifest file, keeping indentation intact.
 */
export async function writeManifest(meta: ManifestMeta, manifest: Manifest) {
    const { indent } = detectIndent(meta.content) || { indent: DEFAULT_INDENT };
    const newline = detectNewline(meta.content) || DEFAULT_NEWLINE;

    await writeJson(meta.filename, { expo: manifest }, { spaces: indent, EOL: newline });
}

/**
 * Get the platforms from a loaded manifest.
 * This will fallback to the default from Expo itself.
 */
export function getPlatforms(manifest: Manifest) {
    return manifest.platforms || ['android', 'ios'];
}

/**
 * Get the platform settings for Android, if available.
 */
export function getAndroidPlatform(manifest: Manifest) {
    return manifest.android || { versionCode: 0 };
}

/**
 * Get the platform settings for iOS, if available.
 */
export function getIosPlatform(manifest: Manifest) {
    return manifest.ios || { buildNumber: '' };
}