feat(dart/transform): Support `part` directives
Allow users to split libraries using the `part` directive. Closes #1817
This commit is contained in:
parent
b6ee20846b
commit
aa480fee72
|
@ -1,3 +1,5 @@
|
||||||
|
library angular2.src.core.compiler.directive_lifecycle_reflector;
|
||||||
|
|
||||||
import 'package:angular2/src/core/annotations_impl/annotations.dart';
|
import 'package:angular2/src/core/annotations_impl/annotations.dart';
|
||||||
import 'package:angular2/src/core/compiler/interfaces.dart';
|
import 'package:angular2/src/core/compiler/interfaces.dart';
|
||||||
import 'package:angular2/src/reflection/reflection.dart';
|
import 'package:angular2/src/reflection/reflection.dart';
|
||||||
|
|
|
@ -100,7 +100,8 @@ class Expect extends gns.Expect {
|
||||||
void toThrowError([message = ""]) => toThrowWith(message: message);
|
void toThrowError([message = ""]) => toThrowWith(message: message);
|
||||||
void toThrowErrorWith(message) => expectException(this.actual, message);
|
void toThrowErrorWith(message) => expectException(this.actual, message);
|
||||||
void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future);
|
void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future);
|
||||||
void toHaveCssClass(className) => gns.guinness.matchers.toBeTrue(DOM.hasClass(actual, className));
|
void toHaveCssClass(className) =>
|
||||||
|
gns.guinness.matchers.toBeTrue(DOM.hasClass(actual, className));
|
||||||
void toImplement(expected) => toBeA(expected);
|
void toImplement(expected) => toBeA(expected);
|
||||||
void toBeNaN() =>
|
void toBeNaN() =>
|
||||||
gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0);
|
gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0);
|
||||||
|
@ -139,7 +140,8 @@ class NotExpect extends gns.NotExpect {
|
||||||
|
|
||||||
void toEqual(expected) => toHaveSameProps(expected);
|
void toEqual(expected) => toHaveSameProps(expected);
|
||||||
void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future);
|
void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future);
|
||||||
void toHaveCssClass(className) => gns.guinness.matchers.toBeFalse(DOM.hasClass(actual, className));
|
void toHaveCssClass(className) =>
|
||||||
|
gns.guinness.matchers.toBeFalse(DOM.hasClass(actual, className));
|
||||||
void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null);
|
void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null);
|
||||||
Function get _expect => gns.guinness.matchers.expect;
|
Function get _expect => gns.guinness.matchers.expect;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ class AsyncStringWriter extends PrintWriter {
|
||||||
: _curr = curr,
|
: _curr = curr,
|
||||||
_bufs = <StringBuffer>[curr];
|
_bufs = <StringBuffer>[curr];
|
||||||
|
|
||||||
AsyncStringWriter() : this._(new StringBuffer());
|
AsyncStringWriter([Object content = ""]) : this._(new StringBuffer(content));
|
||||||
|
|
||||||
void print(x) {
|
void print(x) {
|
||||||
_curr.write(x);
|
_curr.write(x);
|
||||||
|
|
|
@ -3,6 +3,7 @@ library angular2.transform.directive_processor.rewriter;
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:analyzer/analyzer.dart';
|
import 'package:analyzer/analyzer.dart';
|
||||||
|
import 'package:analyzer/src/generated/java_core.dart';
|
||||||
import 'package:angular2/src/render/xhr.dart' show XHR;
|
import 'package:angular2/src/render/xhr.dart' show XHR;
|
||||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||||
|
@ -13,7 +14,9 @@ import 'package:angular2/src/transform/common/names.dart';
|
||||||
import 'package:angular2/src/transform/common/xhr_impl.dart';
|
import 'package:angular2/src/transform/common/xhr_impl.dart';
|
||||||
import 'package:angular2/src/transform/common/ng_meta.dart';
|
import 'package:angular2/src/transform/common/ng_meta.dart';
|
||||||
import 'package:barback/barback.dart' show AssetId;
|
import 'package:barback/barback.dart' show AssetId;
|
||||||
|
import 'package:code_transformers/assets.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:source_span/source_span.dart';
|
||||||
|
|
||||||
import 'visitors.dart';
|
import 'visitors.dart';
|
||||||
|
|
||||||
|
@ -29,33 +32,233 @@ Future<String> createNgDeps(AssetReader reader, AssetId assetId,
|
||||||
{bool inlineViews}) async {
|
{bool inlineViews}) async {
|
||||||
// TODO(kegluneq): Shortcut if we can determine that there are no
|
// TODO(kegluneq): Shortcut if we can determine that there are no
|
||||||
// [Directive]s present, taking into account `export`s.
|
// [Directive]s present, taking into account `export`s.
|
||||||
|
var code = await reader.readAsString(assetId);
|
||||||
|
|
||||||
|
var directivesVisitor = new _NgDepsDirectivesVisitor();
|
||||||
|
parseDirectives(code, name: assetId.path)
|
||||||
|
.directives
|
||||||
|
.accept(directivesVisitor);
|
||||||
|
|
||||||
|
// If this is part of another library, its contents will be processed by its
|
||||||
|
// parent, so it does not need its own `.ng_deps.dart` file.
|
||||||
|
if (directivesVisitor.isPart) return null;
|
||||||
|
|
||||||
var writer = new AsyncStringWriter();
|
var writer = new AsyncStringWriter();
|
||||||
var visitor = new CreateNgDepsVisitor(
|
directivesVisitor.writeTo(writer, assetId);
|
||||||
writer,
|
|
||||||
|
writer
|
||||||
|
..println('var _visited = false;')
|
||||||
|
..println('void ${SETUP_METHOD_NAME}() {')
|
||||||
|
..println('if (_visited) return; _visited = true;');
|
||||||
|
|
||||||
|
var declarationsCode =
|
||||||
|
await _getAllDeclarations(reader, assetId, code, directivesVisitor);
|
||||||
|
var declarationsVisitor = new _NgDepsDeclarationsVisitor(
|
||||||
assetId,
|
assetId,
|
||||||
|
writer,
|
||||||
new XhrImpl(reader, assetId),
|
new XhrImpl(reader, assetId),
|
||||||
annotationMatcher,
|
annotationMatcher,
|
||||||
_interfaceMatcher,
|
_interfaceMatcher,
|
||||||
ngMeta,
|
ngMeta,
|
||||||
inlineViews: inlineViews);
|
inlineViews: inlineViews);
|
||||||
var code = await reader.readAsString(assetId);
|
parseCompilationUnit(declarationsCode, name: '${assetId.path} and parts')
|
||||||
parseCompilationUnit(code, name: assetId.path).accept(visitor);
|
.declarations
|
||||||
|
.accept(declarationsVisitor);
|
||||||
|
if (declarationsVisitor.shouldCreateNgDeps) {
|
||||||
|
writer.println(';');
|
||||||
|
}
|
||||||
|
writer.println('}');
|
||||||
|
|
||||||
// If this library does not define an `@Injectable` and it does not import
|
if (!directivesVisitor.shouldCreateNgDeps &&
|
||||||
// any libaries that could, then we do not need to generate a `.ng_deps
|
!declarationsVisitor.shouldCreateNgDeps) return null;
|
||||||
// .dart` file for it.
|
|
||||||
if (!visitor._foundNgInjectable && !visitor._usesNonLangLibs) return null;
|
|
||||||
|
|
||||||
return await writer.asyncToString();
|
return writer.asyncToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
InterfaceMatcher _interfaceMatcher = new InterfaceMatcher();
|
InterfaceMatcher _interfaceMatcher = new InterfaceMatcher();
|
||||||
|
|
||||||
/// Visitor responsible for processing [CompilationUnit] and creating an
|
/// Processes `visitor.parts`, reading and appending their contents to the
|
||||||
/// associated .ng_deps.dart file.
|
/// original `code`.
|
||||||
class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
/// Order of `part`s is preserved. That is, if in the main library we have
|
||||||
|
/// ```
|
||||||
|
/// library main;
|
||||||
|
///
|
||||||
|
/// part 'lib1.dart'
|
||||||
|
/// part 'lib2.dart'
|
||||||
|
/// ```
|
||||||
|
/// The output will first have the entirety of the original file, followed by
|
||||||
|
/// the contents of lib1.dart followed by the contents of lib2.dart.
|
||||||
|
Future<String> _getAllDeclarations(AssetReader reader, AssetId assetId,
|
||||||
|
String code, _NgDepsDirectivesVisitor visitor) {
|
||||||
|
if (visitor.parts.isEmpty) return new Future<String>.value(code);
|
||||||
|
|
||||||
|
var partsStart = visitor.parts.first.offset,
|
||||||
|
partsEnd = visitor.parts.last.end;
|
||||||
|
|
||||||
|
var asyncWriter = new AsyncStringWriter(code.substring(0, partsStart));
|
||||||
|
visitor.parts.forEach((partDirective) {
|
||||||
|
var uri = stringLiteralToString(partDirective.uri);
|
||||||
|
var partAssetId = uriToAssetId(assetId, uri, logger, null /* span */,
|
||||||
|
errorOnAbsolute: false);
|
||||||
|
asyncWriter.asyncPrint(reader.readAsString(partAssetId).then((partCode) {
|
||||||
|
if (partCode == null || partCode.isEmpty) {
|
||||||
|
logger.warning('Empty part at "${partDirective.uri}. Ignoring.',
|
||||||
|
asset: partAssetId);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// Remove any directives -- we just want declarations.
|
||||||
|
var parsedDirectives = parseDirectives(partCode, name: uri).directives;
|
||||||
|
return partCode.substring(parsedDirectives.last.end);
|
||||||
|
}).catchError((err, stackTrace) {
|
||||||
|
logger.warning(
|
||||||
|
'Failed while reading part at ${partDirective.uri}. Ignoring.\n'
|
||||||
|
'Error: $err\n'
|
||||||
|
'Stack Trace: $stackTrace',
|
||||||
|
asset: partAssetId,
|
||||||
|
span: new SourceFile(code, url: path.basename(assetId.path))
|
||||||
|
.span(partDirective.offset, partDirective.end));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
asyncWriter.print(code.substring(partsEnd));
|
||||||
|
|
||||||
|
return asyncWriter.asyncToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visitor responsible for flattening directives passed to it.
|
||||||
|
/// Once this has visited an Ast, use [#writeTo] to write out the directives
|
||||||
|
/// for the .ng_deps.dart file. See [#writeTo] for details.
|
||||||
|
class _NgDepsDirectivesVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
|
/// Whether this library `imports` or `exports` any non-'dart:' libraries.
|
||||||
|
bool _usesNonLangLibs = false;
|
||||||
|
|
||||||
|
/// Whether the file we are processing is a part, that is, whether we have
|
||||||
|
/// visited a `part of` directive.
|
||||||
|
bool _isPart = false;
|
||||||
|
|
||||||
|
// TODO(kegluneq): Support an intermediate representation of NgDeps and use it
|
||||||
|
// instead of storing generated code.
|
||||||
|
LibraryDirective _library = null;
|
||||||
|
ScriptTag _scriptTag = null;
|
||||||
|
final List<NamespaceDirective> _importAndExports = <NamespaceDirective>[];
|
||||||
|
final List<PartDirective> _parts = <PartDirective>[];
|
||||||
|
|
||||||
|
bool get shouldCreateNgDeps {
|
||||||
|
// If this library does not define an `@Injectable` and it does not import
|
||||||
|
// any libaries that could, then we do not need to generate a `.ng_deps
|
||||||
|
// .dart` file for it.
|
||||||
|
if (!_usesNonLangLibs) return false;
|
||||||
|
if (_isPart) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get usesNonLangLibs => _usesNonLangLibs;
|
||||||
|
bool get isPart => _isPart;
|
||||||
|
|
||||||
|
/// In the order encountered in the source.
|
||||||
|
Iterable<PartDirective> get parts => _parts;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitScriptTag(ScriptTag node) {
|
||||||
|
_scriptTag = node;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitCompilationUnit(CompilationUnit node) {
|
||||||
|
node.directives.accept(this);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateUsesNonLangLibs(UriBasedDirective directive) {
|
||||||
|
_usesNonLangLibs = _usesNonLangLibs ||
|
||||||
|
!stringLiteralToString(directive.uri).startsWith('dart:');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitImportDirective(ImportDirective node) {
|
||||||
|
_updateUsesNonLangLibs(node);
|
||||||
|
_importAndExports.add(node);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitExportDirective(ExportDirective node) {
|
||||||
|
_updateUsesNonLangLibs(node);
|
||||||
|
_importAndExports.add(node);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitLibraryDirective(LibraryDirective node) {
|
||||||
|
if (node != null) {
|
||||||
|
_library = node;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitPartDirective(PartDirective node) {
|
||||||
|
_parts.add(node);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object visitPartOfDirective(PartOfDirective node) {
|
||||||
|
_isPart = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the directives for the .ng_deps.dart for `processedFile` to
|
||||||
|
/// `writer`. The .ng_deps.dart file has the same directives as
|
||||||
|
/// `processedFile` with some exceptions (mentioned below).
|
||||||
|
void writeTo(PrintWriter writer, AssetId processedFile) {
|
||||||
|
var copyVisitor = new ToSourceVisitor(writer);
|
||||||
|
|
||||||
|
if (_scriptTag != null) {
|
||||||
|
_scriptTag.accept(copyVisitor);
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_library != null && _library.name != null) {
|
||||||
|
writer.print('library ');
|
||||||
|
_library.name.accept(copyVisitor);
|
||||||
|
writer.println('$DEPS_EXTENSION;');
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not output [PartDirective]s, which would not be valid now that we
|
||||||
|
// have changed the library.
|
||||||
|
|
||||||
|
// We need to import & export the original file.
|
||||||
|
var origDartFile = path.basename(processedFile.path);
|
||||||
|
writer.println('''import '$origDartFile';''');
|
||||||
|
writer.println('''export '$origDartFile';''');
|
||||||
|
|
||||||
|
// Used to register reflective information.
|
||||||
|
writer.println("import '$_REFLECTOR_IMPORT' as $_REF_PREFIX;");
|
||||||
|
|
||||||
|
_importAndExports.forEach((node) {
|
||||||
|
if (node.isSynthetic) return;
|
||||||
|
|
||||||
|
// Ignore deferred imports here so as to not load the deferred libraries
|
||||||
|
// code in the current library causing much of the code to not be
|
||||||
|
// deferred. Instead `DeferredRewriter` will rewrite the code as to load
|
||||||
|
// `ng_deps` in a deferred way.
|
||||||
|
if (node is ImportDirective && node.deferredKeyword != null) return;
|
||||||
|
|
||||||
|
node.accept(copyVisitor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Visitor responsible for visiting a file's [Declaration]s and outputting the
|
||||||
|
/// code necessary to register the file with the Angular 2 system.
|
||||||
|
class _NgDepsDeclarationsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
final AsyncStringWriter writer;
|
final AsyncStringWriter writer;
|
||||||
|
|
||||||
|
/// The file we are processing.
|
||||||
|
final AssetId assetId;
|
||||||
|
|
||||||
/// Output ngMeta information about aliases.
|
/// Output ngMeta information about aliases.
|
||||||
// TODO(sigmund): add more to ngMeta. Currently this only contains aliasing
|
// TODO(sigmund): add more to ngMeta. Currently this only contains aliasing
|
||||||
// information, but we could produce here all the metadata we need and avoid
|
// information, but we could produce here all the metadata we need and avoid
|
||||||
|
@ -65,25 +268,26 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
/// Whether an Angular 2 `Injectable` has been found.
|
/// Whether an Angular 2 `Injectable` has been found.
|
||||||
bool _foundNgInjectable = false;
|
bool _foundNgInjectable = false;
|
||||||
|
|
||||||
/// Whether this library `imports` or `exports` any non-'dart:' libraries.
|
/// Visitor that writes out code for AstNodes visited.
|
||||||
bool _usesNonLangLibs = false;
|
|
||||||
|
|
||||||
/// Whether we have written an import of base file
|
|
||||||
/// (the file we are processing).
|
|
||||||
bool _wroteBaseLibImport = false;
|
|
||||||
final ToSourceVisitor _copyVisitor;
|
final ToSourceVisitor _copyVisitor;
|
||||||
final FactoryTransformVisitor _factoryVisitor;
|
final FactoryTransformVisitor _factoryVisitor;
|
||||||
final ParameterTransformVisitor _paramsVisitor;
|
final ParameterTransformVisitor _paramsVisitor;
|
||||||
final AnnotationsTransformVisitor _metaVisitor;
|
final AnnotationsTransformVisitor _metaVisitor;
|
||||||
|
|
||||||
|
/// Responsible for testing whether [Annotation]s are those recognized by
|
||||||
|
/// Angular 2, for example `@Component`.
|
||||||
final AnnotationMatcher _annotationMatcher;
|
final AnnotationMatcher _annotationMatcher;
|
||||||
|
|
||||||
|
/// Responsible for testing whether interfaces are recognized by Angular2,
|
||||||
|
/// for example `OnChange`.
|
||||||
final InterfaceMatcher _interfaceMatcher;
|
final InterfaceMatcher _interfaceMatcher;
|
||||||
|
|
||||||
/// The assetId for the file which we are parsing.
|
/// Used to fetch linked files.
|
||||||
final AssetId assetId;
|
final XHR _xhr;
|
||||||
|
|
||||||
CreateNgDepsVisitor(
|
_NgDepsDeclarationsVisitor(
|
||||||
AsyncStringWriter writer,
|
|
||||||
AssetId assetId,
|
AssetId assetId,
|
||||||
|
AsyncStringWriter writer,
|
||||||
XHR xhr,
|
XHR xhr,
|
||||||
AnnotationMatcher annotationMatcher,
|
AnnotationMatcher annotationMatcher,
|
||||||
InterfaceMatcher interfaceMatcher,
|
InterfaceMatcher interfaceMatcher,
|
||||||
|
@ -98,75 +302,10 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
inlineViews: inlineViews),
|
inlineViews: inlineViews),
|
||||||
_annotationMatcher = annotationMatcher,
|
_annotationMatcher = annotationMatcher,
|
||||||
_interfaceMatcher = interfaceMatcher,
|
_interfaceMatcher = interfaceMatcher,
|
||||||
this.assetId = assetId;
|
this.assetId = assetId,
|
||||||
|
_xhr = xhr;
|
||||||
|
|
||||||
void _visitNodeListWithSeparator(NodeList<AstNode> list, String separator) {
|
bool get shouldCreateNgDeps => _foundNgInjectable;
|
||||||
if (list == null) return;
|
|
||||||
for (var i = 0, iLen = list.length; i < iLen; ++i) {
|
|
||||||
if (i != 0) {
|
|
||||||
writer.print(separator);
|
|
||||||
}
|
|
||||||
list[i].accept(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object visitCompilationUnit(CompilationUnit node) {
|
|
||||||
_visitNodeListWithSeparator(node.directives, " ");
|
|
||||||
_openFunctionWrapper();
|
|
||||||
_visitNodeListWithSeparator(node.declarations, " ");
|
|
||||||
_closeFunctionWrapper();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write the import to the file the .ng_deps.dart file is based on if it
|
|
||||||
/// has not yet been written.
|
|
||||||
void _maybeWriteImport() {
|
|
||||||
if (_wroteBaseLibImport) return;
|
|
||||||
_wroteBaseLibImport = true;
|
|
||||||
var origDartFile = path.basename(assetId.path);
|
|
||||||
writer.print('''import '$origDartFile';''');
|
|
||||||
writer.print('''export '$origDartFile';''');
|
|
||||||
writer.print("import '$_REFLECTOR_IMPORT' as $_REF_PREFIX;");
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateUsesNonLangLibs(UriBasedDirective directive) {
|
|
||||||
_usesNonLangLibs = _usesNonLangLibs ||
|
|
||||||
!stringLiteralToString(directive.uri).startsWith('dart:');
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object visitImportDirective(ImportDirective node) {
|
|
||||||
_maybeWriteImport();
|
|
||||||
_updateUsesNonLangLibs(node);
|
|
||||||
// Ignore deferred imports here so as to not load the deferred libraries
|
|
||||||
// code in the current library causing much of the code to not be
|
|
||||||
// deferred. Instead `DeferredRewriter` will rewrite the code as to load
|
|
||||||
// `ng_deps` in a deferred way.
|
|
||||||
if (node.deferredKeyword != null) return null;
|
|
||||||
return node.accept(_copyVisitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object visitExportDirective(ExportDirective node) {
|
|
||||||
_maybeWriteImport();
|
|
||||||
_updateUsesNonLangLibs(node);
|
|
||||||
return node.accept(_copyVisitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _openFunctionWrapper() {
|
|
||||||
_maybeWriteImport();
|
|
||||||
writer.print('var _visited = false;'
|
|
||||||
'void ${SETUP_METHOD_NAME}() {'
|
|
||||||
'if (_visited) return; _visited = true;');
|
|
||||||
}
|
|
||||||
|
|
||||||
void _closeFunctionWrapper() {
|
|
||||||
if (_foundNgInjectable) {
|
|
||||||
writer.print(';');
|
|
||||||
}
|
|
||||||
writer.print('}');
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstructorDeclaration _getCtor(ClassDeclaration node) {
|
ConstructorDeclaration _getCtor(ClassDeclaration node) {
|
||||||
int numCtorsFound = 0;
|
int numCtorsFound = 0;
|
||||||
|
@ -271,25 +410,6 @@ class CreateNgDepsVisitor extends Object with SimpleAstVisitor<Object> {
|
||||||
return node.accept(_copyVisitor);
|
return node.accept(_copyVisitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Object visitLibraryDirective(LibraryDirective node) {
|
|
||||||
if (node != null && node.name != null) {
|
|
||||||
writer.print('library ');
|
|
||||||
_nodeToSource(node.name);
|
|
||||||
writer.print('$DEPS_EXTENSION;');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object visitPartOfDirective(PartOfDirective node) {
|
|
||||||
// TODO(kegluneq): Consider importing [node.libraryName].
|
|
||||||
logger.warning('[${assetId}]: '
|
|
||||||
'Found `part of` directive while generating ${DEPS_EXTENSION} file, '
|
|
||||||
'Transform may fail due to missing imports in generated file.');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Object visitPrefixedIdentifier(PrefixedIdentifier node) =>
|
Object visitPrefixedIdentifier(PrefixedIdentifier node) =>
|
||||||
_nodeToSource(node);
|
_nodeToSource(node);
|
||||||
|
|
|
@ -95,7 +95,8 @@ Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): #3374. See above.
|
// TODO(jteplitz602): #3374. See above.
|
||||||
Map<String, dynamic> addTarget(dynamic e, Map<String, dynamic> serializedEvent) {
|
Map<String, dynamic> addTarget(
|
||||||
|
dynamic e, Map<String, dynamic> serializedEvent) {
|
||||||
if (NODES_WITH_VALUE.contains(e.target.tagName.toLowerCase())) {
|
if (NODES_WITH_VALUE.contains(e.target.tagName.toLowerCase())) {
|
||||||
serializedEvent['target'] = {'value': e.target.value};
|
serializedEvent['target'] = {'value': e.target.value};
|
||||||
if (e.target is InputElement) {
|
if (e.target is InputElement) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import 'package:code_transformers/messages/build_logger.dart';
|
||||||
import 'package:dart_style/dart_style.dart';
|
import 'package:dart_style/dart_style.dart';
|
||||||
import 'package:guinness/guinness.dart';
|
import 'package:guinness/guinness.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:source_span/source_span.dart';
|
||||||
import '../common/read_file.dart';
|
import '../common/read_file.dart';
|
||||||
|
|
||||||
var formatter = new DartFormatter();
|
var formatter = new DartFormatter();
|
||||||
|
@ -24,6 +25,14 @@ void allTests() {
|
||||||
_testProcessor('should preserve parameter annotations as const instances.',
|
_testProcessor('should preserve parameter annotations as const instances.',
|
||||||
'parameter_metadata/soup.dart');
|
'parameter_metadata/soup.dart');
|
||||||
|
|
||||||
|
_testProcessor('should handle `part` directives.', 'part_files/main.dart');
|
||||||
|
|
||||||
|
_testProcessor('should handle multiple `part` directives.',
|
||||||
|
'multiple_part_files/main.dart');
|
||||||
|
|
||||||
|
_testProcessor('should not generate .ng_deps.dart for `part` files.',
|
||||||
|
'part_files/part.dart');
|
||||||
|
|
||||||
_testProcessor('should recognize custom annotations with package: imports',
|
_testProcessor('should recognize custom annotations with package: imports',
|
||||||
'custom_metadata/package_soup.dart',
|
'custom_metadata/package_soup.dart',
|
||||||
customDescriptors: [
|
customDescriptors: [
|
||||||
|
@ -166,8 +175,9 @@ void _testProcessor(String name, String inputPath,
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
expect(await reader.hasInput(expectedNgDepsId)).toBeFalse();
|
expect(await reader.hasInput(expectedNgDepsId)).toBeFalse();
|
||||||
} else {
|
} else {
|
||||||
var input = await reader.readAsString(expectedNgDepsId);
|
var expectedOutput = await reader.readAsString(expectedNgDepsId);
|
||||||
expect(formatter.format(output)).toEqual(formatter.format(input));
|
expect(formatter.format(output))
|
||||||
|
.toEqual(formatter.format(expectedOutput));
|
||||||
}
|
}
|
||||||
if (ngMeta.isEmpty) {
|
if (ngMeta.isEmpty) {
|
||||||
expect(await reader.hasInput(expectedAliasesId)).toBeFalse();
|
expect(await reader.hasInput(expectedAliasesId)).toBeFalse();
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
library main.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'main.dart';
|
||||||
|
export 'main.dart';
|
||||||
|
import 'package:angular2/src/reflection/reflection.dart' as _ngRef;
|
||||||
|
import 'package:angular2/src/core/annotations_impl/annotations.dart';
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector() {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
_ngRef.reflector
|
||||||
|
..registerType(
|
||||||
|
Part1Component,
|
||||||
|
new _ngRef.ReflectionInfo(const [const Component(selector: '[part1]')],
|
||||||
|
const [], () => new Part1Component()))
|
||||||
|
..registerType(
|
||||||
|
Part2Component,
|
||||||
|
new _ngRef.ReflectionInfo(const [const Component(selector: '[part2]')],
|
||||||
|
const [], () => new Part2Component()))
|
||||||
|
..registerType(
|
||||||
|
MainComponent,
|
||||||
|
new _ngRef.ReflectionInfo(const [const Component(selector: '[main]')],
|
||||||
|
const [], () => new MainComponent()));
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
library main;
|
||||||
|
|
||||||
|
import 'package:angular2/src/core/annotations_impl/annotations.dart';
|
||||||
|
|
||||||
|
part 'part1.dart';
|
||||||
|
part 'part2.dart';
|
||||||
|
|
||||||
|
@Component(selector: '[main]')
|
||||||
|
class MainComponent {
|
||||||
|
MainComponent();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
part of main;
|
||||||
|
|
||||||
|
@Component(selector: '[part1]')
|
||||||
|
class Part1Component {
|
||||||
|
Part1Component();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
part of main;
|
||||||
|
|
||||||
|
@Component(selector: '[part2]')
|
||||||
|
class Part2Component {
|
||||||
|
Part2Component();
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
library main.ng_deps.dart;
|
||||||
|
|
||||||
|
import 'main.dart';
|
||||||
|
export 'main.dart';
|
||||||
|
import 'package:angular2/src/reflection/reflection.dart' as _ngRef;
|
||||||
|
import 'package:angular2/src/core/annotations_impl/annotations.dart';
|
||||||
|
|
||||||
|
var _visited = false;
|
||||||
|
void initReflector() {
|
||||||
|
if (_visited) return;
|
||||||
|
_visited = true;
|
||||||
|
_ngRef.reflector
|
||||||
|
..registerType(
|
||||||
|
PartComponent,
|
||||||
|
new _ngRef.ReflectionInfo(const [const Component(selector: '[part]')],
|
||||||
|
const [], () => new PartComponent()))
|
||||||
|
..registerType(
|
||||||
|
MainComponent,
|
||||||
|
new _ngRef.ReflectionInfo(const [const Component(selector: '[main]')],
|
||||||
|
const [], () => new MainComponent()));
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
library main;
|
||||||
|
|
||||||
|
import 'package:angular2/src/core/annotations_impl/annotations.dart';
|
||||||
|
|
||||||
|
part 'part.dart';
|
||||||
|
|
||||||
|
@Component(selector: '[main]')
|
||||||
|
class MainComponent {
|
||||||
|
MainComponent();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
part of main;
|
||||||
|
|
||||||
|
@Component(selector: '[part]')
|
||||||
|
class PartComponent {
|
||||||
|
PartComponent();
|
||||||
|
}
|
Loading…
Reference in New Issue