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