Skip to content

Commit

Permalink
feat(task): add main activity task support
Browse files Browse the repository at this point in the history
close #8
  • Loading branch information
Murat committed Mar 24, 2024
1 parent 31ca994 commit a9da787
Show file tree
Hide file tree
Showing 10 changed files with 1,070 additions and 19 deletions.
716 changes: 716 additions & 0 deletions src/__tests__/unit/tasks/mainActivityTask.spec.ts

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/__tests__/unit/utils/runTask.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const mocks = {
main_application: {
runTask: jest.fn(),
},
main_activity: {
runTask: jest.fn(),
},
xcode: {
runTask: jest.fn(),
},
Expand All @@ -38,6 +41,7 @@ jest.mock('../../../tasks/plistTask', () => mocks.plist);
jest.mock('../../../tasks/buildGradleTask', () => mocks.build_gradle);
jest.mock('../../../tasks/settingsGradleTask', () => mocks.settings_gradle);
jest.mock('../../../tasks/mainApplicationTask', () => mocks.main_application);
jest.mock('../../../tasks/mainActivityTask', () => mocks.main_activity);
jest.mock('../../../tasks/xcode/xcodeTask', () => mocks.xcode);
jest.mock('../../../tasks/androidManifestTask', () => mocks.android_manifest);
jest.mock('../../../tasks/podFileTask', () => mocks.podfile);
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const Constants = {
SETTINGS_GRADLE_FILE_NAME: 'settings.gradle',
MAIN_APPLICATION_JAVA_FILE_NAME: 'MainApplication.java',
MAIN_APPLICATION_KT_FILE_NAME: 'MainApplication.kt',
MAIN_ACTIVITY_JAVA_FILE_NAME: 'MainActivity.java',
MAIN_ACTIVITY_KT_FILE_NAME: 'MainActivity.kt',
POD_FILE_NAME: 'Podfile',
GITIGNORE_FILE_NAME: '.gitignore',
XCODEPROJ_EXT: '.xcodeproj',
Expand Down
41 changes: 41 additions & 0 deletions src/schema/integrate.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,44 @@
],
"type": "object"
},
"MainActivityTaskType": {
"additionalProperties": false,
"properties": {
"actions": {
"items": {
"$ref": "#/definitions/ContentModifierType<string>"
},
"type": "array"
},
"label": {
"type": "string"
},
"lang": {
"$ref": "#/definitions/AndroidCodeType"
},
"name": {
"type": "string"
},
"postInfo": {
"$ref": "#/definitions/TextOrTitleMessage"
},
"preInfo": {
"$ref": "#/definitions/TextOrTitleMessage"
},
"type": {
"const": "main_activity",
"type": "string"
},
"when": {
"$ref": "#/definitions/AnyObject"
}
},
"required": [
"actions",
"type"
],
"type": "object"
},
"MainApplicationTaskType": {
"additionalProperties": false,
"properties": {
Expand Down Expand Up @@ -553,6 +591,9 @@
{
"$ref": "#/definitions/MainApplicationTaskType"
},
{
"$ref": "#/definitions/MainActivityTaskType"
},
{
"$ref": "#/definitions/AndroidManifestTaskType"
},
Expand Down
41 changes: 41 additions & 0 deletions src/schema/upgrade.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,44 @@
],
"type": "object"
},
"MainActivityTaskType": {
"additionalProperties": false,
"properties": {
"actions": {
"items": {
"$ref": "#/definitions/ContentModifierType<string>"
},
"type": "array"
},
"label": {
"type": "string"
},
"lang": {
"$ref": "#/definitions/AndroidCodeType"
},
"name": {
"type": "string"
},
"postInfo": {
"$ref": "#/definitions/TextOrTitleMessage"
},
"preInfo": {
"$ref": "#/definitions/TextOrTitleMessage"
},
"type": {
"const": "main_activity",
"type": "string"
},
"when": {
"$ref": "#/definitions/AnyObject"
}
},
"required": [
"actions",
"type"
],
"type": "object"
},
"MainApplicationTaskType": {
"additionalProperties": false,
"properties": {
Expand Down Expand Up @@ -553,6 +591,9 @@
{
"$ref": "#/definitions/MainApplicationTaskType"
},
{
"$ref": "#/definitions/MainActivityTaskType"
},
{
"$ref": "#/definitions/AndroidManifestTaskType"
},
Expand Down
190 changes: 190 additions & 0 deletions src/tasks/mainActivityTask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import fs from 'fs';
import { globSync } from 'glob';
import { Constants } from '../constants';
import {
AndroidCodeType,
BlockContentType,
MainActivityTaskType,
} from '../types/mod.types';
import { applyContentModification } from '../utils/applyContentModification';
import { findClosingTagIndex } from '../utils/findClosingTagIndex';
import { getErrMessage } from '../utils/getErrMessage';
import { getProjectPath } from '../utils/getProjectPath';
import { satisfies } from '../utils/satisfies';
import { setState } from '../utils/setState';
import { stringSplice } from '../utils/stringSplice';
import { variables } from '../variables';

export async function mainActivityTask(args: {
configPath: string;
packageName: string;
content: string;
task: MainActivityTaskType;
}): Promise<string> {
let { content } = args;
const { task, configPath, packageName } = args;

for (const action of task.actions) {
variables.set('CONTENT', content);
if (action.when && !satisfies(variables.getStore(), action.when)) {
setState(action.name, {
state: 'skipped',
reason: 'when',
error: false,
});
continue;
}

setState(action.name, {
state: 'progress',
error: false,
});
try {
content = await applyContentModification({
action,
findOrCreateBlock,
configPath,
packageName,
content,
indentation: 2,
});

setState(action.name, {
state: 'done',
error: false,
});
} catch (e) {
setState(action.name, {
state: 'error',
reason: getErrMessage(e),
error: true,
});
throw e;
}
}

return content;
}

function findOrCreateBlock(
content: string,
block: string
): {
blockContent: BlockContentType;
content: string;
} {
let blockContent = {
start: 0,
end: content.length,
match: content,
space: '',
justCreated: false,
};

const blockPath = block.split('.');
let contentOffset = 0;

for (let i = 0; i < blockPath.length; i++) {
const matcherRegex = new RegExp(`^((\\s+)?)${blockPath[i]}\\s+\\{`, 'ms');
let blockStart = matcherRegex.exec(blockContent.match);

const justCreated = !blockStart;
if (!blockStart) {
const blockName = blockPath[i];
// create block in block
const space = ' '.repeat(2 * i);
const previousSpace = ' '.repeat(Math.max(0, 2 * (i - 1)));
const newBlock = `${space}${blockName} {}`;
const codeToInsert = `
${newBlock}
${previousSpace}`;
const contentLengthBeforeInsert = content.length;
content = stringSplice(content, blockContent.end, 0, codeToInsert);
if (codeToInsert.length && contentLengthBeforeInsert < content.length) {
blockContent.match += codeToInsert;
blockContent.end += codeToInsert.length;
blockStart = matcherRegex.exec(blockContent.match);
}
}
if (!blockStart) {
throw new Error('block could not be inserted, something wrong?');
}

const blockEndIndex = findClosingTagIndex(
content,
contentOffset + blockStart.index + blockStart[0].length
);
const blockBody = content.substring(
contentOffset + blockStart.index + blockStart[0].length,
blockEndIndex
);
blockContent = {
start: contentOffset + blockStart.index + blockStart[0].length,
end: blockEndIndex,
match: blockBody,
justCreated,
space: ' '.repeat(2 * i),
};
contentOffset += blockStart.index + blockStart[0].length;
}

return {
blockContent,
content,
};
}

function getMainActivityPath(lang?: AndroidCodeType) {
const projectPath = getProjectPath();

const mainActivityPath = globSync(
[
projectPath,
'android',
'app',
'src',
'main',
'java',
'**',
lang === 'kotlin'
? Constants.MAIN_ACTIVITY_KT_FILE_NAME
: Constants.MAIN_ACTIVITY_JAVA_FILE_NAME,
].join('/'),
{ nodir: true }
)[0];
if (!mainActivityPath)
throw new Error(
`MainActivity.${lang === 'kotlin' ? 'kt' : 'java'} file not found`
);
return mainActivityPath;
}

function readMainActivityContent(lang?: AndroidCodeType) {
const mainActivityPath = getMainActivityPath(lang);
return fs.readFileSync(mainActivityPath, 'utf-8');
}

function writeAppDelegateContent(
content: string,
lang?: AndroidCodeType
): void {
const mainActivityPath = getMainActivityPath(lang);
return fs.writeFileSync(mainActivityPath, content, 'utf-8');
}

export async function runTask(args: {
configPath: string;
packageName: string;
task: MainActivityTaskType;
}): Promise<void> {
let content = readMainActivityContent(args.task.lang);

content = await mainActivityTask({
...args,
content,
});

writeAppDelegateContent(content, args.task.lang);
}

export const summary = 'MainActivity modification';
9 changes: 9 additions & 0 deletions src/types/mod.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ export type MainApplicationTaskType = ModTaskBase &

export type AndroidCodeType = 'java' | 'kotlin';

// main activity

export type MainActivityTaskType = ModTaskBase &
ActionsType<ContentModifierType> & {
type: 'main_activity';
lang?: AndroidCodeType;
};

// android manifest task

export type AndroidManifestTaskType = ModTaskBase &
Expand Down Expand Up @@ -397,6 +405,7 @@ export type ModTask =
| BuildGradleTaskType
| SettingsGradleTaskType
| MainApplicationTaskType
| MainActivityTaskType
| AndroidManifestTaskType
| StringsXmlTaskType
| NotificationServiceTaskType
Expand Down
2 changes: 2 additions & 0 deletions src/utils/taskManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as prompt from '../tasks/promptTask';
import * as notification_service from '../tasks/notificationServiceTask';
import * as notification_view_controller from '../tasks/notificationViewControllerTask';
import * as main_application from '../tasks/mainApplicationTask';
import * as main_activity from '../tasks/mainActivityTask';
import * as settings_gradle from '../tasks/settingsGradleTask';
import * as shell from '../tasks/shellTask';
import { ModTask } from '../types/mod.types';
Expand All @@ -30,6 +31,7 @@ const task: Record<string, TaskExports> = {
notification_service,
notification_view_controller,
main_application,
main_activity,
settings_gradle,
strings_xml,
shell,
Expand Down
Loading

0 comments on commit a9da787

Please sign in to comment.