"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const config_1 = require("@expo/config");
const chalk_1 = __importDefault(require("chalk"));
const deep_diff_1 = __importDefault(require("deep-diff"));
const fs_1 = __importDefault(require("fs"));
const paths_1 = require("./paths");
// https://stackoverflow.com/a/51319962/4047926
function colorizeKeys(json) {
if (typeof json !== 'string') {
json = JSON.stringify(json, undefined, 2);
}
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
if (/--pop/.test(match)) {
// Bacon: If a key is prefixed with --pop it'll be colored red
return chalk_1.default.red.bold(match.substring(0, match.length - 7) + '":');
}
else if (/--push/.test(match)) {
// Bacon: If a key is prefixed with --push it'll be colored green
return chalk_1.default.green.bold(match.substring(0, match.length - 8) + '":');
}
else if (/^"/.test(match)) {
if (/:$/.test(match)) {
return chalk_1.default.magenta(match);
}
else {
return chalk_1.default.blueBright(match);
}
}
else if (/true|false/.test(match)) {
return chalk_1.default.cyanBright(match);
}
else if (/null/.test(match)) {
return chalk_1.default.cyan(match);
}
return chalk_1.default.green(match);
});
}
function logHeader(title) {
console.log(chalk_1.default.hidden('<details><summary>\n') +
chalk_1.default.bgGreen.black(`[${title}]\n`) +
chalk_1.default.hidden('</summary>\n'));
}
function logMdHelper(...messages) {
console.log(chalk_1.default.hidden(...messages));
}
function logFooter() {
logMdHelper('</details>');
}
// Log the main risky parts of webpack.config
function logWebpackConfigComponents(webpackConfig) {
logHeader('Webpack Info');
const { mode, resolve: { alias = {} } = {}, entry, devtool, context, devServer: { https, hot, contentBase } = {}, } = webpackConfig;
// console.log('WEBPACK', JSON.stringify(webpackConfig, null, 2));
logMdHelper('```json');
console.log(colorizeKeys({
mode,
devtool,
entry,
context,
https,
hot,
contentBase,
alias,
}));
logMdHelper('```');
logFooter();
}
function logStaticsAsync(env) {
return __awaiter(this, void 0, void 0, function* () {
logHeader('Statics Info');
const paths = env.locations || (yield paths_1.getPathsAsync(env.projectRoot));
// Detect if the default template files aren't being used.
const { template: statics = {} } = paths;
const expectedLocation = 'webpack-config/web-default/';
for (const key of Object.keys(statics)) {
const filePath = statics[key];
if (typeof filePath !== 'string')
continue;
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
let message = chalk_1.default.reset(`- **${key}**: `) + chalk_1.default.blue(`\`${fileName}\``) + ' : ';
if (filePath.includes(expectedLocation)) {
message += chalk_1.default.bgGreen.black(`\`${filePath}\``);
}
else {
message += chalk_1.default.bgRed.black(`\`${filePath}\``);
}
console.log(message);
}
logFooter();
});
}
function logEnvironment(_a) {
var { config } = _a, env = __rest(_a, ["config"]);
logHeader('Environment Info');
logMdHelper('```json');
console.log(colorizeKeys(env));
logMdHelper('```');
logFooter();
}
function setDeepValue(pathComponents, object, value) {
if (!pathComponents.length) {
return;
}
const key = pathComponents.shift();
if (!key)
return;
if (!(key in object)) {
if (pathComponents.length)
object[key] = {};
else {
if (value.kind === 'N') {
object[key] = value.lhs;
}
else {
if ('rhs' in value)
object[`${key}--push`] = value.rhs;
if ('lhs' in value)
object[`${key}--pop`] = value.lhs;
}
}
}
setDeepValue(pathComponents, object[key], value);
}
function logAutoConfigValuesAsync(env) {
return __awaiter(this, void 0, void 0, function* () {
const locations = env.locations || (yield paths_1.getPathsAsync(env.projectRoot));
const { exp: config } = config_1.readConfigJson(env.projectRoot);
const standardConfig = config_1.ensurePWAConfig({}, locations.absolute, {
templateIcon: locations.template.get('icon.png'),
});
const pwaConfig = config_1.ensurePWAConfig(config, locations.absolute, {
templateIcon: locations.template.get('icon.png'),
});
// @ts-ignore
const nonStandard = deep_diff_1.default(standardConfig, pwaConfig);
let obj = {};
for (const diff of nonStandard) {
// console.log(chalk.bold(diff.path.join('/') + ': ') + chalk.bgRed(JSON.stringify(diff.rhs, null, 2)));
// TODO: Bacon: add support for array updates: https://www.npmjs.com/package/deep-diff#differences
if (diff.kind !== 'A') {
setDeepValue(diff.path, obj, diff);
}
}
logHeader('App.json');
logMdHelper('```json');
// TODO: Bacon: Diff block
console.log(colorizeKeys(obj));
logMdHelper('```');
logFooter();
});
}
function reportAsync(webpackConfig, env) {
return __awaiter(this, void 0, void 0, function* () {
console.log(chalk_1.default.bold('\n\nStart Copy\n\n'));
logWebpackConfigComponents(webpackConfig);
logEnvironment(env);
yield logStaticsAsync(env);
yield logAutoConfigValuesAsync(env);
const locations = env.locations || (yield paths_1.getPathsAsync(env.projectRoot));
yield testBabelPreset(locations);
console.log(chalk_1.default.bold('\nEnd Copy\n\n'));
});
}
exports.reportAsync = reportAsync;
function testBabelPreset(locations) {
return __awaiter(this, void 0, void 0, function* () {
logHeader('Babel Preset');
const babelrc = locations.absolute('.babelrc');
const babelConfig = locations.absolute('babel.config.js');
const printPassed = (message, ...messages) => console.log(chalk_1.default.bgGreen.black(`- [✔︎ ${message}]`, ...messages));
const printWarning = (message, ...messages) => console.log(chalk_1.default.bgYellow.black(`- [${message}]`, ...messages));
const printFailed = (message, ...messages) => console.log(chalk_1.default.bgRed.black(`- [x ${message}]`, ...messages));
if (fs_1.default.existsSync(babelrc)) {
printFailed('Using `.babelrc`', 'Please upgrade to Babel 7, and replace `.babelrc` with `babel.config.js`');
}
else {
printPassed('Not using .babelrc', 'Expo web runs best with Babel 7+');
}
const printFailedToParse = (...messages) => printWarning(`Expo CLI cannot parse your babel.config.js at ${babelConfig}.`, ...messages);
function testBabelConfig(config, isFunction) {
const preferred = 'It should be returning an object with `{ "presets: ["babel-preset-expo"]" }`.';
if (!config) {
if (isFunction) {
printWarning('`babel.config.js` is exporting a function that evaluates to a null object', preferred);
}
else {
printWarning('`babel.config.js` is exporting a `null` object', preferred);
}
return;
}
else if (!Array.isArray(config.presets)) {
const missingKey = ' without the "presets" key';
if (isFunction) {
printWarning('`babel.config.js` is exporting a function that evaluates to an object' + missingKey, preferred);
}
else {
printWarning('`babel.config.js` is exporting an object' + missingKey, preferred);
}
return;
}
const isExpo = (preset) => preset === 'expo' || preset === 'babel-preset-expo';
const hasExpoPreset = (() => {
for (const preset of config.presets) {
if ((typeof preset === 'string' && isExpo(preset)) ||
(Array.isArray(preset) && isExpo(preset[0]))) {
return true;
}
}
return false;
})();
if (hasExpoPreset) {
printPassed('Using `babel-preset-expo`', 'Tree-shaking should work as expected.');
}
else {
printWarning('Not using `babel-preset-expo`', `This is highly recommended as it'll greatly improve tree-shaking in most cases.`, `\nRun \`yarn add babel-preset-expo\` and add it to the "presets" array of your \`babel.config.js\`.`);
}
}
if (fs_1.default.existsSync(babelConfig)) {
const configObjectOrFunction = require(require.resolve(babelConfig));
if (isFunction(configObjectOrFunction)) {
try {
const results = yield configObjectOrFunction({ cache() { } });
testBabelConfig(results, true);
}
catch (error) {
printFailedToParse(`Is it exporting something other than an object or function?`, `If it's exporting a function ensure that function returns a valid object containing the "presets" key.`, `If it's exporting an object ensure it contains the "presets" key.`);
}
}
else {
testBabelConfig(configObjectOrFunction);
}
}
logFooter();
});
}
function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
//# sourceMappingURL=Diagnosis.js.map