react-native-integrate
Version:
Automate integration of additional code into React Native projects
204 lines (203 loc) • 9.07 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.androidManifestTask = androidManifestTask;
exports.runTask = runTask;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const constants_1 = require("../constants");
const prompter_1 = require("../prompter");
const applyContentModification_1 = require("../utils/applyContentModification");
const checkCondition_1 = require("../utils/checkCondition");
const escapeRegExp_1 = require("../utils/escapeRegExp");
const findClosingTagIndex_1 = require("../utils/findClosingTagIndex");
const getErrMessage_1 = require("../utils/getErrMessage");
const getProjectPath_1 = require("../utils/getProjectPath");
const setState_1 = require("../utils/setState");
const stringSplice_1 = require("../utils/stringSplice");
const variables_1 = require("../variables");
async function androidManifestTask(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 {
const additionalModification = (args) => applyAttributeModification({ ...args, action });
content = await (0, applyContentModification_1.applyContentModification)({
action,
findOrCreateBlock,
configPath,
packageName,
content,
indentation: 0,
additionalModification,
buildComment: buildXmlComment,
});
(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;
}
function buildXmlComment(comment) {
return comment.split('\n').map(x => `<!-- ${x} -->`);
}
function applyAttributeModification(args) {
const { action, blockContent } = args;
let { content } = args;
if (action.attributes) {
if (!action.block)
throw new Error('you must set block to update attributes');
const blockDefinition = blockDefinitions[action.block];
const { regex, indentation } = blockDefinition;
const getCodeToInsert = (text, isReplacing) => {
let openingNewLine = '\n', closingNewLine = '', blockIndentation = ' '.repeat(indentation);
if (isReplacing) {
openingNewLine = '';
closingNewLine = '\n';
}
if (isReplacing) {
closingNewLine = '';
blockIndentation = '';
}
return `${openingNewLine}${isReplacing ? '' : blockIndentation}${text}${closingNewLine}`;
};
Object.entries(action.attributes).forEach(([name, value]) => {
value = (0, variables_1.transformTextInObject)(value);
const blockStart = regex.exec(content);
checkBlockStartValue(blockStart);
if (blockStart) {
// noinspection RegExpSimplifiable
const existingMatcher = new RegExp(`\\b${(0, escapeRegExp_1.escapeRegExp)(name)}="(?:\\\\.|[^\\\\"])*"([\\s]+)?`);
const existingMatch = existingMatcher.exec(blockStart[0]);
// delete
if (typeof value == 'object' && value.$delete) {
if (existingMatch) {
const start = existingMatch.index + blockStart.index, rem = existingMatch[0].length, insert = '';
content = (0, stringSplice_1.stringSplice)(content, start, rem, insert);
(0, applyContentModification_1.updateBlockContent)(blockContent, rem, insert, content);
(0, prompter_1.logMessage)(`deleted attribute ${(0, prompter_1.summarize)(name)} in ${(0, prompter_1.summarize)((0, applyContentModification_1.getBlockName)(action))}`);
}
else {
(0, prompter_1.logMessageGray)(`attribute ${(0, prompter_1.summarize)(name)} does not exist in ${(0, prompter_1.summarize)((0, applyContentModification_1.getBlockName)(action))} - skipping delete operation`);
}
}
else {
// set or replace
const codeToInsert = getCodeToInsert(`${name}="${value}"`, !!existingMatch);
if (existingMatch) {
// replace
const start = existingMatch.index + blockStart.index, rem = existingMatch[0].length, insert = codeToInsert;
content = (0, stringSplice_1.stringSplice)(content, start, rem, insert);
(0, applyContentModification_1.updateBlockContent)(blockContent, rem, insert, content);
(0, prompter_1.logMessage)(`set existing attribute in ${(0, prompter_1.summarize)((0, applyContentModification_1.getBlockName)(action))} - ${(0, prompter_1.summarize)(name)}: ${(0, prompter_1.summarize)(value)}`);
}
else {
// set
const endOfOpeningTagIndex = blockStart.index + blockStart[0].length - 1;
// noinspection UnnecessaryLocalVariableJS
const start = endOfOpeningTagIndex, rem = 0, insert = codeToInsert;
content = (0, stringSplice_1.stringSplice)(content, start, rem, insert);
(0, applyContentModification_1.updateBlockContent)(blockContent, rem, insert, content);
(0, prompter_1.logMessage)(`set new attribute in ${(0, prompter_1.summarize)((0, applyContentModification_1.getBlockName)(action))} - ${(0, prompter_1.summarize)(name)}: ${(0, prompter_1.summarize)(value)}`);
}
}
}
});
}
return content;
}
function checkBlockStartValue(value) {
if (!value) {
throw new Error('block could not be found, something wrong?');
}
}
function findOrCreateBlock(content, block) {
let blockContent = {
start: 0,
end: content.length,
match: content,
space: '',
justCreated: false,
};
const blockDefinition = blockDefinitions[block];
if (!blockDefinition)
throw new Error(`Invalid block: ${block}`);
const { regex } = blockDefinition;
const blockStart = regex.exec(content);
checkBlockStartValue(blockStart);
if (blockStart) {
const blockEndIndex = (0, findClosingTagIndex_1.findClosingTagIndex)(content, blockStart.index + blockStart[0].length, findClosingTagIndex_1.TagDefinitions.XML);
const blockBody = content.substring(blockStart.index + blockStart[0].length, blockEndIndex);
blockContent = {
start: blockStart.index + blockStart[0].length,
end: blockEndIndex,
match: blockBody,
justCreated: false,
space: ' '.repeat(blockDefinition.indentation),
};
}
return {
blockContent,
content,
};
}
const blockDefinitions = {
manifest: {
regex: /<manifest.*?>/s,
indentation: 4,
},
application: {
regex: /<application.*?>/s,
indentation: 6,
},
activity: {
regex: /<activity.*?>/s,
indentation: 8,
},
};
function getAndroidManifestPath() {
const projectPath = (0, getProjectPath_1.getProjectPath)();
const buildGradlePath = path_1.default.join(projectPath, constants_1.Constants.ANDROID_MAIN_FILE_PATH, constants_1.Constants.ANDROID_MANIFEST_FILE_NAME);
if (!fs_1.default.existsSync(buildGradlePath))
throw new Error(`AndroidManifest.xml file not found at ${buildGradlePath}`);
return buildGradlePath;
}
function readAndroidManifestContent() {
const manifestPath = getAndroidManifestPath();
return fs_1.default.readFileSync(manifestPath, 'utf-8');
}
function writeAndroidManifestContent(content) {
const manifestPath = getAndroidManifestPath();
return fs_1.default.writeFileSync(manifestPath, content, 'utf-8');
}
async function runTask(args) {
let content = readAndroidManifestContent();
content = await androidManifestTask({
...args,
content,
});
writeAndroidManifestContent(content);
}
exports.summary = 'AndroidManifest.xml modification';