OLD | NEW |
(Empty) | |
| 1 library di.transformers.refactor; |
| 2 |
| 3 import 'package:analyzer/src/generated/ast.dart'; |
| 4 import 'package:analyzer/src/generated/element.dart'; |
| 5 import 'package:barback/barback.dart'; |
| 6 import 'package:code_transformers/resolver.dart'; |
| 7 import 'package:source_maps/refactor.dart'; |
| 8 |
| 9 |
| 10 /// Transforms all simple identifiers of [identifier] to be |
| 11 /// [importPrefix].[replacement] in the entry point of the application. |
| 12 /// |
| 13 /// When the identifier is replaced, this function also adds a prefixed import |
| 14 /// of the form `import "[importUrl]" as [importPrefix]`. |
| 15 /// |
| 16 /// This will resolve the full name of [identifier] and warn if it cannot be |
| 17 /// resolved. This will only modify the main entry point of the application and |
| 18 /// will not traverse into parts. |
| 19 void transformIdentifiers(Transform transform, Resolver resolver, |
| 20 {String identifier, String replacement, String importUrl, |
| 21 String importPrefix}) { |
| 22 |
| 23 var identifierElement = resolver.getLibraryVariable(identifier); |
| 24 if (identifierElement != null) { |
| 25 identifierElement = identifierElement.getter; |
| 26 } else { |
| 27 identifierElement = resolver.getLibraryFunction(identifier); |
| 28 } |
| 29 |
| 30 if (identifierElement == null) { |
| 31 // TODO(blois) enable once on barback 0.12.0 |
| 32 // transform.logger.fine('Unable to resolve $identifier, not ' |
| 33 // 'transforming entry point.'); |
| 34 transform.addOutput(transform.primaryInput); |
| 35 return; |
| 36 } |
| 37 |
| 38 var lib = resolver.getLibrary(transform.primaryInput.id); |
| 39 var transaction = resolver.createTextEditTransaction(lib); |
| 40 var unit = lib.definingCompilationUnit.node; |
| 41 |
| 42 unit.accept(new _IdentifierTransformer(transaction, identifierElement, |
| 43 '$importPrefix.$replacement', transform.logger)); |
| 44 |
| 45 if (transaction.hasEdits) { |
| 46 _addImport(transaction, unit, importUrl, importPrefix); |
| 47 } |
| 48 _commitTransaction(transaction, transform); |
| 49 } |
| 50 |
| 51 /// Commits the transaction if there have been edits, otherwise just adds |
| 52 /// the input as an output. |
| 53 void _commitTransaction(TextEditTransaction transaction, Transform transform) { |
| 54 var id = transform.primaryInput.id; |
| 55 |
| 56 if (transaction.hasEdits) { |
| 57 var printer = transaction.commit(); |
| 58 var url = id.path.startsWith('lib/') |
| 59 ? 'package:${id.package}/${id.path.substring(4)}' : id.path; |
| 60 printer.build(url); |
| 61 transform.addOutput(new Asset.fromString(id, printer.text)); |
| 62 } else { |
| 63 // No modifications, so just pass the source through. |
| 64 transform.addOutput(transform.primaryInput); |
| 65 } |
| 66 } |
| 67 |
| 68 /// Injects an import into the list of imports in the file. |
| 69 void _addImport(TextEditTransaction transaction, CompilationUnit unit, |
| 70 String uri, String prefix) { |
| 71 var libDirective; |
| 72 for (var directive in unit.directives) { |
| 73 if (directive is ImportDirective) { |
| 74 transaction.edit(directive.keyword.offset, directive.keyword.offset, |
| 75 'import \'$uri\' as $prefix;\n'); |
| 76 return; |
| 77 } else if (directive is LibraryDirective) { |
| 78 libDirective = directive; |
| 79 } |
| 80 } |
| 81 |
| 82 // No imports, add after the library directive if there was one. |
| 83 if (libDirective != null) { |
| 84 transaction.edit(libDirective.endToken.offset + 2, |
| 85 libDirective.endToken.offset + 2, |
| 86 'import \'$uri\' as $prefix;\n'); |
| 87 } |
| 88 } |
| 89 |
| 90 /// Vistior which changes every reference to a resolved element to a specific |
| 91 /// string value. |
| 92 class _IdentifierTransformer extends GeneralizingAstVisitor { |
| 93 final TextEditTransaction transaction; |
| 94 /// The element which all references to should be replaced. |
| 95 final Element original; |
| 96 /// The text which should replace [original]. |
| 97 final String replacement; |
| 98 /// The current logger. |
| 99 final TransformLogger logger; |
| 100 |
| 101 _IdentifierTransformer(this.transaction, this.original, this.replacement, |
| 102 this.logger); |
| 103 |
| 104 visitIdentifier(Identifier node) { |
| 105 if (node.bestElement == original) { |
| 106 transaction.edit(node.beginToken.offset, node.endToken.end, replacement); |
| 107 return; |
| 108 } |
| 109 |
| 110 super.visitIdentifier(node); |
| 111 } |
| 112 |
| 113 // Top-level methods are not treated as prefixed identifiers, so handle those |
| 114 // here. |
| 115 visitMethodInvocation(MethodInvocation m) { |
| 116 if (m.methodName.bestElement == original) { |
| 117 if (m.target is SimpleIdentifier) { |
| 118 // Include the prefix in the rename. |
| 119 transaction.edit(m.target.beginToken.offset, m.methodName.endToken.end, |
| 120 replacement); |
| 121 } else { |
| 122 transaction.edit(m.methodName.beginToken.offset, |
| 123 m.methodName.endToken.end, replacement); |
| 124 } |
| 125 return; |
| 126 } |
| 127 super.visitMethodInvocation(m); |
| 128 } |
| 129 |
| 130 // Skip the contents of imports/exports/parts |
| 131 visitUriBasedDirective(ImportDirective d) {} |
| 132 |
| 133 visitPartDirective(PartDirective node) { |
| 134 logger.warning('Not transforming code within ${node.uri}.'); |
| 135 } |
| 136 } |
OLD | NEW |