Skip to content

Commit

Permalink
feat(cli): support TS/JS config files (#3756)
Browse files Browse the repository at this point in the history
  • Loading branch information
imhoffd committed Nov 9, 2020
1 parent d71e6d5 commit a52775f
Show file tree
Hide file tree
Showing 11 changed files with 554 additions and 81 deletions.
6 changes: 4 additions & 2 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"engines": {
"node": ">=10.3.0"
},
"main": "./dist/index.js",
"main": "dist/index.js",
"types": "dist/declarations.d.ts",
"scripts": {
"build": "npm run clean && npm run assets && tsc",
"clean": "rimraf ./dist",
Expand All @@ -23,7 +24,8 @@
"files": [
"assets/",
"bin/",
"dist/"
"dist/**/*.js",
"dist/declarations.d.ts"
],
"keywords": [
"ionic",
Expand Down
8 changes: 4 additions & 4 deletions cli/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { setTimeout } from 'timers';
import xml2js from 'xml2js';

import c from './colors';
import type { Config, PackageJson, ExternalConfig } from './definitions';
import type { Config, ExternalConfig, PackageJson } from './definitions';
import { output, logger } from './log';

export type CheckFunction = () => Promise<string | null>;
Expand All @@ -34,7 +34,7 @@ export async function checkWebDir(config: Config): Promise<string | null> {
`Please create it and make sure it has an ${c.strong(
'index.html',
)} file. You can change the path of this directory in ${c.strong(
'capacitor.config.json',
config.app.extConfigName,
)} (${c.input(
'webDir',
)} option). You may need to compile the web assets for your app (typically ${c.input(
Expand Down Expand Up @@ -87,15 +87,15 @@ export async function checkAppConfig(config: Config): Promise<string | null> {
if (!config.app.appId) {
return (
`Missing ${c.input('appId')} for new platform.\n` +
`Please add it in capacitor.config.json or run ${c.input(
`Please add it in ${config.app.extConfigName} or run ${c.input(
'npx cap init',
)}.`
);
}
if (!config.app.appName) {
return (
`Missing ${c.input('appName')} for new platform.\n` +
`Please add it in capacitor.config.json or run ${c.input(
`Please add it in ${config.app.extConfigName} or run ${c.input(
'npx cap init',
)}.`
);
Expand Down
133 changes: 97 additions & 36 deletions cli/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,36 @@ import { pathExists, readJSON } from '@ionic/utils-fs';
import Debug from 'debug';
import { dirname, join, resolve } from 'path';

import { runCommand } from './common';
import c from './colors';
import { logFatal, resolveNode, runCommand } from './common';
import type {
AndroidConfig,
AppConfig,
CLIConfig,
Config,
ExternalConfig,
CLIConfig,
AndroidConfig,
IOSConfig,
PackageJson,
WebConfig,
} from './definitions';
import { OS } from './definitions';
import { tryFn } from './util/fn';
import { requireTS } from './util/node';

const debug = Debug('capacitor:config');

export const EXTERNAL_CONFIG_FILE = 'capacitor.config.json';

export async function loadConfig(): Promise<Config> {
const appRootDir = process.cwd();
const cliRootDir = dirname(__dirname);
const extConfig = await loadExternalConfig(
resolve(appRootDir, EXTERNAL_CONFIG_FILE),
);
const conf = await loadExtConfig(appRootDir);

const appId = extConfig.appId ?? '';
const appName = extConfig.appName ?? '';
const webDir = extConfig.webDir ?? 'www';
const appId = conf.extConfig.appId ?? '';
const appName = conf.extConfig.appName ?? '';
const webDir = conf.extConfig.webDir ?? 'www';
const cli = await loadCLIConfig(cliRootDir);

const config = {
android: await loadAndroidConfig(appRootDir, extConfig, cli),
ios: await loadIOSConfig(appRootDir, extConfig, cli),
const config: Config = {
android: await loadAndroidConfig(appRootDir, conf.extConfig, cli),
ios: await loadIOSConfig(appRootDir, conf.extConfig, cli),
web: await loadWebConfig(appRootDir, webDir),
cli,
app: {
Expand All @@ -41,14 +40,12 @@ export async function loadConfig(): Promise<Config> {
appName,
webDir,
webDirAbs: resolve(appRootDir, webDir),
package: (await readPackageJSON(resolve(appRootDir, 'package.json'))) ?? {
package: (await tryFn(readJSON, resolve(appRootDir, 'package.json'))) ?? {
name: appName,
version: '1.0.0',
},
extConfigName: EXTERNAL_CONFIG_FILE,
extConfigFilePath: resolve(appRootDir, EXTERNAL_CONFIG_FILE),
extConfig,
bundledWebRuntime: extConfig.bundledWebRuntime ?? false,
...conf,
bundledWebRuntime: conf.extConfig.bundledWebRuntime ?? false,
},
};

Expand All @@ -57,6 +54,86 @@ export async function loadConfig(): Promise<Config> {
return config;
}

type ExtConfigPairs = Pick<
AppConfig,
'extConfigType' | 'extConfigName' | 'extConfigFilePath' | 'extConfig'
>;

async function loadExtConfigTS(
rootDir: string,
extConfigName: string,
extConfigFilePath: string,
): Promise<ExtConfigPairs> {
try {
const tsPath = resolveNode(rootDir, 'typescript');

if (!tsPath) {
logFatal(
'Could not find installation of TypeScript.\n' +
`To use ${c.strong(
extConfigName,
)} files, you must install TypeScript in your project, e.g. w/ ${c.input(
'npm install -D typescript',
)}`,
);
}

const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires

return {
extConfigType: 'ts',
extConfigName,
extConfigFilePath: extConfigFilePath,
extConfig: requireTS(ts, extConfigFilePath) as any,
};
} catch (e) {
logFatal(`Parsing ${c.strong(extConfigName)} failed.\n\n${e.stack ?? e}`);
}
}

async function loadExtConfigJS(
rootDir: string,
extConfigName: string,
extConfigFilePath: string,
): Promise<ExtConfigPairs> {
try {
return {
extConfigType: 'js',
extConfigName,
extConfigFilePath: extConfigFilePath,
extConfig: require(extConfigFilePath),
};
} catch (e) {
logFatal(`Parsing ${c.strong(extConfigName)} failed.\n\n${e.stack ?? e}`);
}
}

async function loadExtConfig(rootDir: string): Promise<ExtConfigPairs> {
const extConfigNameTS = 'capacitor.config.ts';
const extConfigFilePathTS = resolve(rootDir, extConfigNameTS);

if (await pathExists(extConfigFilePathTS)) {
return loadExtConfigTS(rootDir, extConfigNameTS, extConfigFilePathTS);
}

const extConfigNameJS = 'capacitor.config.js';
const extConfigFilePathJS = resolve(rootDir, extConfigNameJS);

if (await pathExists(extConfigFilePathJS)) {
return loadExtConfigJS(rootDir, extConfigNameJS, extConfigFilePathJS);
}

const extConfigName = 'capacitor.config.json';
const extConfigFilePath = resolve(rootDir, extConfigName);

return {
extConfigType: 'json',
extConfigName,
extConfigFilePath: extConfigFilePath,
extConfig: (await tryFn(readJSON, extConfigFilePath)) ?? {},
};
}

async function loadCLIConfig(rootDir: string): Promise<CLIConfig> {
const assetsName = 'assets';

Expand Down Expand Up @@ -202,19 +279,3 @@ async function determineAndroidStudioPath(os: OS): Promise<string> {

return '';
}

async function loadExternalConfig(p: string): Promise<ExternalConfig> {
try {
return await readJSON(p);
} catch (e) {
return {};
}
}

async function readPackageJSON(p: string): Promise<PackageJson | null> {
try {
return await readJSON(p);
} catch (e) {
return null;
}
}
5 changes: 2 additions & 3 deletions cli/src/cordova.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ export async function getCordovaPreferences(config: Config): Promise<any> {
const answers = await logPrompt(
`${c.strong(
`Cordova preferences can be automatically ported to ${c.strong(
'capacitor.config.json',
config.app.extConfigName,
)}.`,
)}\n` +
`Keep in mind: Not all values can be automatically migrated from ${c.strong(
Expand All @@ -550,8 +550,7 @@ export async function getCordovaPreferences(config: Config): Promise<any> {
{
type: 'confirm',
name: 'confirm',
message:
'capacitor.config.json already contains Cordova preferences. Overwrite?',
message: `${config.app.extConfigName} already contains Cordova preferences. Overwrite?`,
},
],
{ onCancel: () => process.exit(1) },
Expand Down
Loading

0 comments on commit a52775f

Please sign in to comment.