1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.addObjcImports = addObjcImports; 7exports.findObjcFunctionCodeBlock = findObjcFunctionCodeBlock; 8exports.findObjcInterfaceCodeBlock = findObjcInterfaceCodeBlock; 9exports.findSwiftFunctionCodeBlock = findSwiftFunctionCodeBlock; 10exports.insertContentsInsideObjcFunctionBlock = insertContentsInsideObjcFunctionBlock; 11exports.insertContentsInsideObjcInterfaceBlock = insertContentsInsideObjcInterfaceBlock; 12exports.insertContentsInsideSwiftClassBlock = insertContentsInsideSwiftClassBlock; 13exports.insertContentsInsideSwiftFunctionBlock = insertContentsInsideSwiftFunctionBlock; 14function _commonCodeMod() { 15 const data = require("../utils/commonCodeMod"); 16 _commonCodeMod = function () { 17 return data; 18 }; 19 return data; 20} 21function _matchBrackets() { 22 const data = require("../utils/matchBrackets"); 23 _matchBrackets = function () { 24 return data; 25 }; 26 return data; 27} 28/** 29 * Add Objective-C import 30 * @param source source contents 31 * @param imports array of imports, e.g. ['<Foundation/Foundation.h>'] 32 * @returns updated contents 33 */ 34function addObjcImports(source, imports) { 35 const lines = source.split('\n'); 36 // Try to insert statements after first #import where would probably not in #if block 37 const lineIndexWithFirstImport = lines.findIndex(line => line.match(/^#import .*$/)); 38 for (const importElement of imports) { 39 if (!source.includes(importElement)) { 40 const importStatement = `#import ${importElement}`; 41 lines.splice(lineIndexWithFirstImport + 1, 0, importStatement); 42 } 43 } 44 return lines.join('\n'); 45} 46 47/** 48 * Find code block of Objective-C interface or implementation 49 * 50 * @param contents source contents 51 * @param declaration interface/implementation, e.g. '@interface Foo' 52 * @returns found CodeBlock, or null if not found 53 */ 54function findObjcInterfaceCodeBlock(contents, declaration) { 55 const start = contents.search(new RegExp(`^${declaration}\\W`, 'm')); 56 if (start < 0) { 57 return null; 58 } 59 let end = contents.indexOf('\n@end', start); 60 end += 5; // '\n@end'.length === 5 61 62 return { 63 start, 64 end, 65 code: contents.substring(start, end) 66 }; 67} 68 69/** 70 * Find code block of Objective-C function without declaration, will return only {} block 71 * 72 * @param contents source contents 73 * @param selector function selector, e.g. 'doSomething:withSomeValue:' 74 * @returns found CodeBlock, or null if not found. 75 */ 76function findObjcFunctionCodeBlock(contents, selector) { 77 const symbols = selector.split(':'); 78 const argsCount = symbols.length - 1; 79 let pattern = '^[\\-+]\\s*\\(.+?\\)'; 80 if (argsCount === 0) { 81 pattern += `${symbols[0]}\\s+`; 82 } else { 83 for (let i = 0; i < argsCount; ++i) { 84 const argSymbol = `${symbols[i]}:\\(.+\\)\\w+`; 85 pattern += `${argSymbol}\\s+`; 86 } 87 } 88 pattern += '{'; 89 let start = contents.search(new RegExp(pattern, 'm')); 90 if (start < 0) { 91 return null; 92 } 93 start = contents.indexOf('{', start); 94 const end = (0, _matchBrackets().findMatchingBracketPosition)(contents, '{', start); 95 return { 96 start, 97 end, 98 code: contents.substring(start, end + 1) 99 }; 100} 101 102/** 103 * Insert contents to the Objective-C function block 104 * 105 * @param srcContents source contents 106 * @param selector function selector, e.g. 'doSomething:withSomeValue:' 107 * @param insertion code to insert 108 * @param options insertion options 109 * @returns updated contents 110 */ 111function insertContentsInsideObjcFunctionBlock(srcContents, selector, insertion, options) { 112 return insertContentsInsideFunctionBlock(srcContents, selector, insertion, options, 'objc'); 113} 114 115/** 116 * Insert contents to the Objective-C interface/implementation block 117 * 118 * @param srcContents source contents 119 * @param declaration interface/implementation, e.g. '@interface Foo' 120 * @param insertion code to insert 121 * @param options insertion options 122 * @returns updated contents 123 */ 124function insertContentsInsideObjcInterfaceBlock(srcContents, declaration, insertion, options) { 125 const codeBlock = findObjcInterfaceCodeBlock(srcContents, declaration); 126 if (!codeBlock) { 127 return srcContents; 128 } 129 const { 130 position 131 } = options; 132 if (position === 'head') { 133 const firstNewLineIndex = srcContents.indexOf('\n', codeBlock.start); 134 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, insertion, firstNewLineIndex); 135 } else if (position === 'tail') { 136 const endLen = '@end'.length; 137 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, insertion, codeBlock.end - endLen); 138 } 139 return srcContents; 140} 141 142/** 143 * Find code block of Swift function without declaration, will return only {} block 144 * 145 * @param contents source contents 146 * @param selector function selector, e.g. 'doSomething(_:withSomeValue:)' 147 * @returns found CodeBlock, or null if not found. 148 */ 149function findSwiftFunctionCodeBlock(contents, selector) { 150 const parenthesesIndex = selector.indexOf('('); 151 // `functName` === 'doSomething' of 'doSomething(_:withSomeValue:)' 152 const funcName = selector.substring(0, parenthesesIndex); 153 // `argLabels` === ['_', 'withSomeValue'] 'doSomething(_:withSomeValue:)' 154 const argLabels = selector.substring(parenthesesIndex + 1, selector.length - 2).split(':'); 155 let searchOffset = 0; 156 const funcCandidateRegExp = new RegExp(`\\sfunc\\s+${funcName}\\(`, 'm'); 157 let funcCandidateOffset = (0, _commonCodeMod().searchFromOffset)(contents, funcCandidateRegExp, searchOffset); 158 while (funcCandidateOffset >= 0) { 159 // Parse function parameters 160 const paramsStartOffset = contents.indexOf('(', funcCandidateOffset); 161 const paramsEndOffset = (0, _matchBrackets().findMatchingBracketPosition)(contents, '(', paramsStartOffset); 162 const paramsString = contents.substring(paramsStartOffset + 1, paramsEndOffset); 163 const params = paramsString.split(',').map(parseSwiftFunctionParam); 164 165 // Prepare offset for next round 166 searchOffset = paramsEndOffset + 1; 167 funcCandidateOffset = (0, _commonCodeMod().searchFromOffset)(contents, funcCandidateRegExp, searchOffset); 168 169 // Try to match function parameters 170 if (argLabels.length !== params.length) { 171 continue; 172 } 173 for (let i = 0; i < argLabels.length; ++i) { 174 if (argLabels[i] !== params[i].argumentLabel) { 175 continue; 176 } 177 } 178 179 // This function is matched one, get the code block. 180 const codeBlockStart = contents.indexOf('{', paramsEndOffset); 181 const codeBlockEnd = (0, _matchBrackets().findMatchingBracketPosition)(contents, '{', paramsEndOffset); 182 const codeBlock = contents.substring(codeBlockStart, codeBlockEnd + 1); 183 return { 184 start: codeBlockStart, 185 end: codeBlockEnd, 186 code: codeBlock 187 }; 188 } 189 return null; 190} 191function parseSwiftFunctionParam(paramTuple) { 192 const semiIndex = paramTuple.indexOf(':'); 193 const [argumentLabel, parameterName] = paramTuple.substring(0, semiIndex).split(/\s+/); 194 const typeString = paramTuple.substring(semiIndex + 1).trim(); 195 return { 196 argumentLabel, 197 parameterName, 198 typeString 199 }; 200} 201 202/** 203 * Insert contents to the swift class block 204 * 205 * @param srcContents source contents 206 * @param declaration class/extension declaration, e.g. 'class AppDelegate' 207 * @param insertion code to append 208 * @param options insertion options 209 * @returns updated contents 210 */ 211function insertContentsInsideSwiftClassBlock(srcContents, declaration, insertion, options) { 212 const start = srcContents.search(new RegExp(`\\s*${declaration}.*?[\\(\\{]`)); 213 if (start < 0) { 214 throw new Error(`Unable to find class code block - declaration[${declaration}]`); 215 } 216 const { 217 position 218 } = options; 219 if (position === 'head') { 220 const firstBracketIndex = srcContents.indexOf('{', start); 221 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, insertion, firstBracketIndex + 1); 222 } else if (position === 'tail') { 223 const endBracketIndex = (0, _matchBrackets().findMatchingBracketPosition)(srcContents, '{', start); 224 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, insertion, endBracketIndex); 225 } 226 return srcContents; 227} 228 229/** 230 * Insert contents to the Swift function block 231 * 232 * @param srcContents source contents 233 * @param selector function selector, e.g. 'doSomething:withSomeValue:' 234 * @param insertion code to insert 235 * @param options insertion options 236 * @returns updated contents 237 */ 238function insertContentsInsideSwiftFunctionBlock(srcContents, selector, insertion, options) { 239 return insertContentsInsideFunctionBlock(srcContents, selector, insertion, options, 'swift'); 240} 241function insertContentsInsideFunctionBlock(srcContents, selector, insertion, options, language) { 242 var _options$indent; 243 const codeBlock = language === 'objc' ? findObjcFunctionCodeBlock(srcContents, selector) : findSwiftFunctionCodeBlock(srcContents, selector); 244 if (!codeBlock) { 245 return srcContents; 246 } 247 const { 248 position 249 } = options; 250 const indent = ' '.repeat((_options$indent = options.indent) !== null && _options$indent !== void 0 ? _options$indent : 2); 251 if (position === 'head') { 252 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, `\n${indent}${insertion}`, codeBlock.start + 1); 253 } else if (position === 'tail') { 254 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, `\n${indent}${insertion}`, codeBlock.end - 1); 255 } else if (position === 'tailBeforeLastReturn') { 256 let lastReturnIndex = srcContents.lastIndexOf(' return ', codeBlock.end); 257 if (lastReturnIndex < 0) { 258 throw new Error(`Cannot find last return statement:\n${srcContents}`); 259 } 260 lastReturnIndex += 1; // +1 for the prefix space 261 srcContents = (0, _commonCodeMod().insertContentsAtOffset)(srcContents, `${insertion}\n${indent}`, lastReturnIndex); 262 } 263 return srcContents; 264} 265//# sourceMappingURL=codeMod.js.map