( source: ts.SourceFile, fileToEdit: string, symbolName: string, fileName: string, isDefault = false, alias?: string, )
| 21 | * @return Change |
| 22 | */ |
| 23 | export function insertImport( |
| 24 | source: ts.SourceFile, |
| 25 | fileToEdit: string, |
| 26 | symbolName: string, |
| 27 | fileName: string, |
| 28 | isDefault = false, |
| 29 | alias?: string, |
| 30 | ): Change { |
| 31 | const rootNode = source; |
| 32 | const allImports = findNodes(rootNode, ts.isImportDeclaration); |
| 33 | const importExpression = alias ? `${symbolName} as ${alias}` : symbolName; |
| 34 | |
| 35 | // get nodes that map to import statements from the file fileName |
| 36 | const relevantImports = allImports.filter((node) => { |
| 37 | return ts.isStringLiteralLike(node.moduleSpecifier) && node.moduleSpecifier.text === fileName; |
| 38 | }); |
| 39 | |
| 40 | if (relevantImports.length > 0) { |
| 41 | const hasNamespaceImport = relevantImports.some((node) => { |
| 42 | return node.importClause?.namedBindings?.kind === ts.SyntaxKind.NamespaceImport; |
| 43 | }); |
| 44 | |
| 45 | // if imports * from fileName, don't add symbolName |
| 46 | if (hasNamespaceImport) { |
| 47 | return new NoopChange(); |
| 48 | } |
| 49 | |
| 50 | const imports = relevantImports.flatMap((node) => { |
| 51 | return node.importClause?.namedBindings && ts.isNamedImports(node.importClause.namedBindings) |
| 52 | ? node.importClause.namedBindings.elements |
| 53 | : []; |
| 54 | }); |
| 55 | |
| 56 | // insert import if it's not there |
| 57 | if (!imports.some((node) => (node.propertyName || node.name).text === symbolName)) { |
| 58 | const fallbackPos = |
| 59 | findNodes(relevantImports[0], ts.SyntaxKind.CloseBraceToken)[0].getStart() || |
| 60 | findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); |
| 61 | |
| 62 | return insertAfterLastOccurrence(imports, `, ${importExpression}`, fileToEdit, fallbackPos); |
| 63 | } |
| 64 | |
| 65 | return new NoopChange(); |
| 66 | } |
| 67 | |
| 68 | // no such import declaration exists |
| 69 | const useStrict = findNodes(rootNode, ts.isStringLiteral).filter((n) => n.text === 'use strict'); |
| 70 | let fallbackPos = 0; |
| 71 | if (useStrict.length > 0) { |
| 72 | fallbackPos = useStrict[0].end; |
| 73 | } |
| 74 | const open = isDefault ? '' : '{ '; |
| 75 | const close = isDefault ? '' : ' }'; |
| 76 | const eol = getEOL(rootNode.getText()); |
| 77 | // if there are no imports or 'use strict' statement, insert import at beginning of file |
| 78 | const insertAtBeginning = allImports.length === 0 && useStrict.length === 0; |
| 79 | const separator = insertAtBeginning ? '' : `;${eol}`; |
| 80 | const toInsert = |
no test coverage detected