1import { CodeBlock, insertContentsAtOffset } from '../utils/commonCodeMod'; 2import { findMatchingBracketPosition } from '../utils/matchBrackets'; 3 4/** 5 * Find java or kotlin new class instance code block 6 * 7 * @param contents source contents 8 * @param classDeclaration class declaration or just a class name 9 * @param language 'java' | 'kt' 10 * @returns `CodeBlock` for start/end offset and code block contents 11 */ 12export function findNewInstanceCodeBlock( 13 contents: string, 14 classDeclaration: string, 15 language: 'java' | 'kt' 16): CodeBlock | null { 17 const isJava = language === 'java'; 18 let start = isJava 19 ? contents.indexOf(` new ${classDeclaration}(`) 20 : contents.search(new RegExp(` (object\\s*:\\s*)?${classDeclaration}\\(`)); 21 if (start < 0) { 22 return null; 23 } 24 // `+ 1` for the prefix space 25 start += 1; 26 let end = findMatchingBracketPosition(contents, '(', start); 27 28 // For anonymous class, should search further to the {} block. 29 // ```java 30 // new Foo() { 31 // @Override 32 // protected void interfaceMethod {} 33 // }; 34 // ``` 35 // 36 // ```kotlin 37 // object : Foo() { 38 // override fun interfaceMethod {} 39 // } 40 // ``` 41 const nextBrace = contents.indexOf('{', end + 1); 42 const isAnonymousClass = 43 nextBrace >= end && !!contents.substring(end + 1, nextBrace).match(/^\s*$/); 44 if (isAnonymousClass) { 45 end = findMatchingBracketPosition(contents, '{', end); 46 } 47 48 return { 49 start, 50 end, 51 code: contents.substring(start, end + 1), 52 }; 53} 54 55/** 56 * Append contents to the end of code declaration block, support class or method declarations. 57 * 58 * @param srcContents source contents 59 * @param declaration class declaration or method declaration 60 * @param insertion code to append 61 * @returns updated contents 62 */ 63export function appendContentsInsideDeclarationBlock( 64 srcContents: string, 65 declaration: string, 66 insertion: string 67): string { 68 const start = srcContents.search(new RegExp(`\\s*${declaration}.*?[\\(\\{]`)); 69 if (start < 0) { 70 throw new Error(`Unable to find code block - declaration[${declaration}]`); 71 } 72 const end = findMatchingBracketPosition(srcContents, '{', start); 73 return insertContentsAtOffset(srcContents, insertion, end); 74} 75 76export function addImports(source: string, imports: string[], isJava: boolean): string { 77 const lines = source.split('\n'); 78 const lineIndexWithPackageDeclaration = lines.findIndex((line) => line.match(/^package .*;?$/)); 79 for (const javaImport of imports) { 80 if (!source.includes(javaImport)) { 81 const importStatement = `import ${javaImport}${isJava ? ';' : ''}`; 82 lines.splice(lineIndexWithPackageDeclaration + 1, 0, importStatement); 83 } 84 } 85 return lines.join('\n'); 86} 87