react-native-integrate
Version:
Automate integration of additional code into React Native projects
287 lines (285 loc) • 12.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.summary = void 0;
exports.appDelegateTask = appDelegateTask;
exports.runTask = runTask;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const constants_1 = require("../constants");
const applyContentModification_1 = require("../utils/applyContentModification");
const findClosingTagIndex_1 = require("../utils/findClosingTagIndex");
const getErrMessage_1 = require("../utils/getErrMessage");
const getIosProjectPath_1 = require("../utils/getIosProjectPath");
const setState_1 = require("../utils/setState");
const stringSplice_1 = require("../utils/stringSplice");
const variables_1 = require("../variables");
const checkCondition_1 = require("../utils/checkCondition");
async function appDelegateTask(args) {
let { content } = args;
const { task, configPath, packageName } = args;
for (const action of task.actions) {
variables_1.variables.set('CONTENT', content);
if (action.when && !(0, checkCondition_1.checkCondition)(action.when)) {
(0, setState_1.setState)(action.name, {
state: 'skipped',
reason: 'when',
});
continue;
}
(0, setState_1.setState)(action.name, {
state: 'progress',
});
try {
content = await (0, applyContentModification_1.applyContentModification)({
action,
findOrCreateBlock: findOrCreateBlock(task.lang),
configPath,
packageName,
content,
indentation: 2,
});
(0, setState_1.setState)(action.name, {
state: 'done',
});
}
catch (e) {
(0, setState_1.setState)(action.name, {
state: 'error',
reason: (0, getErrMessage_1.getErrMessage)(e),
});
throw e;
}
}
return content;
}
const findOrCreateBlock = (lang) => {
const _lang = lang || 'objc';
return (content, block) => {
let blockContent = {
start: 0,
end: content.length,
match: content,
space: '',
justCreated: false,
};
const blockDefinition = blockDefinitions[_lang][block];
if (!blockDefinition)
throw new Error(`Invalid block: ${block}`);
const { regex, makeNewMethod } = blockDefinition;
let blockStart = regex.exec(content);
const justCreated = !blockStart;
if (!blockStart) {
const newMethod = makeNewMethod();
content = appendNewMethod(content, newMethod, _lang);
blockStart = regex.exec(content);
}
if (!blockStart) {
throw new Error('block could not be inserted, something wrong?');
}
const blockEndIndex = (0, findClosingTagIndex_1.findClosingTagIndex)(content, blockStart.index + blockStart[0].length);
const blockBody = content.substring(blockStart.index + blockStart[0].length, blockEndIndex);
blockContent = {
start: blockStart.index + blockStart[0].length,
end: blockEndIndex,
match: blockBody,
justCreated,
space: _lang === 'swift' ? ' '.repeat(2) : '',
};
return {
blockContent,
content,
};
};
};
const blockDefinitions = {
objc: {
didFinishLaunchingWithOptions: {
regex: /didFinishLaunchingWithOptions.*?\{/s,
makeNewMethod: () => {
throw new Error('didFinishLaunchingWithOptions not implemented, something is wrong?');
},
},
applicationDidBecomeActive: {
regex: /applicationDidBecomeActive.*?\{/s,
makeNewMethod: () => {
return '- (void)applicationDidBecomeActive:(UIApplication *)application {}';
},
},
applicationWillResignActive: {
regex: /applicationWillResignActive.*?\{/s,
makeNewMethod: () => {
return '- (void)applicationWillResignActive:(UIApplication *)application {}';
},
},
applicationDidEnterBackground: {
regex: /applicationDidEnterBackground.*?\{/s,
makeNewMethod: () => {
return '- (void)applicationDidEnterBackground:(UIApplication *)application {}';
},
},
applicationWillEnterForeground: {
regex: /applicationWillEnterForeground.*?\{/s,
makeNewMethod: () => {
return '- (void)applicationWillEnterForeground:(UIApplication *)application {}';
},
},
applicationWillTerminate: {
regex: /applicationWillTerminate.*?\{/s,
makeNewMethod: () => {
return '- (void)applicationWillTerminate:(UIApplication *)application {}';
},
},
openURL: {
regex: /openURL:.*?options:.*?\{/s,
makeNewMethod: () => {
// noinspection SpellCheckingInspection
return '- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {}';
},
},
restorationHandler: {
regex: /continueUserActivity:.*?restorationHandler:.*?\{/s,
makeNewMethod: () => {
return '- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler {}';
},
},
didRegisterForRemoteNotificationsWithDeviceToken: {
regex: /didRegisterForRemoteNotificationsWithDeviceToken.*?\{/s,
makeNewMethod: () => {
return '- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {}';
},
},
didFailToRegisterForRemoteNotificationsWithError: {
regex: /didFailToRegisterForRemoteNotificationsWithError.*?\{/s,
makeNewMethod: () => {
return '- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {}';
},
},
didReceiveRemoteNotification: {
regex: /didReceiveRemoteNotification((?!fetchCompletionHandler).)*?\{/s,
makeNewMethod: () => {
return '- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {}';
},
},
fetchCompletionHandler: {
regex: /didReceiveRemoteNotification:.*?fetchCompletionHandler:.*?\{/s,
makeNewMethod: () => {
return '- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {}';
},
},
},
swift: {
didFinishLaunchingWithOptions: {
regex: /func application\(.*?didFinishLaunchingWithOptions.*?\{/s,
makeNewMethod: () => {
throw new Error('didFinishLaunchingWithOptions not implemented, something is wrong?');
},
},
applicationDidBecomeActive: {
regex: /func application\(.*?didBecomeActive.*?\{/s,
makeNewMethod: () => {
return 'func applicationDidBecomeActive(_ application: UIApplication) {}';
},
},
applicationWillResignActive: {
regex: /func application\(.*?willResignActive.*?\{/s,
makeNewMethod: () => {
return 'func applicationWillResignActive(_ application: UIApplication) {}';
},
},
applicationDidEnterBackground: {
regex: /func application\(.*?didEnterBackground.*?\{/s,
makeNewMethod: () => {
return 'func applicationDidEnterBackground(_ application: UIApplication) {}';
},
},
applicationWillEnterForeground: {
regex: /func application\(.*?willEnterForeground.*?\{/s,
makeNewMethod: () => {
return 'func applicationWillEnterForeground(_ application: UIApplication) {}';
},
},
applicationWillTerminate: {
regex: /func application\(.*?willTerminate.*?\{/s,
makeNewMethod: () => {
return 'func applicationWillTerminate(_ application: UIApplication) {}';
},
},
openURL: {
regex: /func application\(.*?open url:.*?\{/s,
makeNewMethod: () => {
return 'func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { return true }';
},
},
restorationHandler: {
regex: /func application\(.*?continue userActivity:.*?\{/s,
makeNewMethod: () => {
return 'func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { return true }';
},
},
didRegisterForRemoteNotificationsWithDeviceToken: {
regex: /func application\(.*?didRegisterForRemoteNotificationsWithDeviceToken.*?\{/s,
makeNewMethod: () => {
return 'func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {}';
},
},
didFailToRegisterForRemoteNotificationsWithError: {
regex: /func application\(.*?didFailToRegisterForRemoteNotificationsWithError.*?\{/s,
makeNewMethod: () => {
return 'func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {}';
},
},
didReceiveRemoteNotification: {
regex: /func application\(.*?didReceiveRemoteNotification.*?\{/s,
makeNewMethod: () => {
return 'func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {}';
},
},
fetchCompletionHandler: {
regex: /func application\(.*?didReceiveRemoteNotification.*?completionHandler.*?\{/s,
makeNewMethod: () => {
return 'func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {}';
},
},
},
};
function appendNewMethod(content, newMethod, lang) {
const appDelegateMatch = lang === 'objc'
? /@implementation AppDelegate.*?@end/s.exec(content)
: /class AppDelegate:.*\}/s.exec(content);
if (!appDelegateMatch)
throw new Error('Could not find @implementation AppDelegate');
const codeToInsert = `${newMethod}
`;
return (0, stringSplice_1.stringSplice)(content, appDelegateMatch.index +
appDelegateMatch[0].length -
(lang === 'objc' ? 4 : 1), 0, codeToInsert);
}
function getAppDelegatePath(lang) {
const iosProjectPath = (0, getIosProjectPath_1.getIosProjectPath)();
const appDelegatePath = path_1.default.join(iosProjectPath, lang === 'swift'
? constants_1.Constants.APP_DELEGATE_SWIFT_FILE_NAME
: constants_1.Constants.APP_DELEGATE_MM_FILE_NAME);
if (!fs_1.default.existsSync(appDelegatePath))
throw new Error(`AppDelegate file not found at ${appDelegatePath}`);
return appDelegatePath;
}
function readAppDelegateContent(lang) {
const appDelegatePath = getAppDelegatePath(lang);
return fs_1.default.readFileSync(appDelegatePath, 'utf-8');
}
function writeAppDelegateContent(content, lang) {
const appDelegatePath = getAppDelegatePath(lang);
return fs_1.default.writeFileSync(appDelegatePath, content, 'utf-8');
}
async function runTask(args) {
let content = readAppDelegateContent(args.task.lang);
content = await appDelegateTask({
...args,
content,
});
writeAppDelegateContent(content, args.task.lang);
}
exports.summary = 'AppDelegate modification';