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