diff --git a/lib/application.dart b/lib/application.dart index 2f80a8e4d..421e7f470 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -73,6 +73,7 @@ import 'package:intl/date_symbol_data_local.dart'; import 'package:di/di.dart'; import 'package:angular/angular.dart'; import 'package:angular/perf/module.dart'; +import 'package:angular/cache/module.dart'; import 'package:angular/core/module_internal.dart'; import 'package:angular/core/registry.dart'; import 'package:angular/core_dom/module_internal.dart'; @@ -94,6 +95,7 @@ import 'package:angular/core_dom/static_keys.dart'; */ class AngularModule extends Module { AngularModule() { + install(new CacheModule()); install(new CoreModule()); install(new CoreDomModule()); install(new DirectiveModule()); diff --git a/lib/core/cache.dart b/lib/cache/cache.dart similarity index 94% rename from lib/core/cache.dart rename to lib/cache/cache.dart index 8786af1e1..248c7f9ed 100644 --- a/lib/core/cache.dart +++ b/lib/cache/cache.dart @@ -1,4 +1,4 @@ -part of angular.core_internal; +part of angular.cache; class CacheStats { final int capacity; @@ -32,10 +32,15 @@ abstract class Cache { /** * Removes all entries from the cache. */ + @Deprecated('Use clear() instead') void removeAll(); int get capacity; + @Deprecated('Use length instead') int get size; CacheStats stats(); + + void clear() => removeAll(); + int get length => size; } diff --git a/lib/cache/cache_register.dart b/lib/cache/cache_register.dart new file mode 100644 index 000000000..4cce1ed5b --- /dev/null +++ b/lib/cache/cache_register.dart @@ -0,0 +1,64 @@ +part of angular.cache; + +class CacheRegisterStats { + final String name; + int length; + + CacheRegisterStats(this.name); +} + +@Injectable() +class CacheRegister { + Map _caches = {}; + List _stats = null; + + /** + * Registers a cache with the CacheRegister. The [name] is used for in the stats as + * well as a key for [clear]. + */ + void registerCache(String name, cache) { + if (_caches.containsKey(name)) { + throw "Cache [$name] already registered"; + } + _caches[name] = cache; + + // The stats object needs to be updated. + _stats = null; + + } + + /** + * A list of caches and their sizes. + */ + List get stats { + if (_stats == null) { + _stats = []; + _caches.forEach((k, v) { + _stats.add(new CacheRegisterStats(k)); + }); + } + + _stats.forEach((CacheRegisterStats stat) { + stat.length = _caches[stat.name].length; + }); + return _stats; + } + + /** + * Clears one or all the caches. If [name] is omitted, all caches will be cleared. + * Otherwise, only the cache named [name] will be cleared. + */ + void clear([String name]) { + if (name == null) { + _caches.forEach((k, Map v) { + v.clear(); + }); + return; + } + var cache = _caches[name]; + if (cache == null) { + return; + } + _caches[name].clear(); + } +} diff --git a/lib/cache/module.dart b/lib/cache/module.dart new file mode 100644 index 000000000..51cbfaab4 --- /dev/null +++ b/lib/cache/module.dart @@ -0,0 +1,16 @@ +library angular.cache; + +import 'dart:collection'; +import 'dart:async'; + +import 'package:di/di.dart'; +import 'package:angular/core/annotation_src.dart'; + +part "cache.dart"; +part "cache_register.dart"; + +class CacheModule extends Module { + CacheModule() { + bind(CacheRegister); + } +} diff --git a/lib/core/interpolate.dart b/lib/core/interpolate.dart index 92c69616f..792ef82d9 100644 --- a/lib/core/interpolate.dart +++ b/lib/core/interpolate.dart @@ -11,6 +11,10 @@ part of angular.core_internal; @Injectable() class Interpolate implements Function { var _cache = new HashMap(); + + Interpolate(CacheRegister cacheRegister) { + cacheRegister.registerCache("Interpolate", _cache); + } /** * Compiles markup text into expression. * diff --git a/lib/core/module.dart b/lib/core/module.dart index ba7a5c243..7341aa4fb 100644 --- a/lib/core/module.dart +++ b/lib/core/module.dart @@ -22,11 +22,15 @@ export "package:angular/change_detection/change_detection.dart" show AvgStopwatch, FieldGetterFactory; +export "package:angular/cache/module.dart" show + Cache, + CacheRegister, + CacheRegisterStats; + export "package:angular/core_dom/module_internal.dart" show Animation, AnimationResult, BrowserCookies, - Cache, Compiler, CompilerConfig, Cookies, diff --git a/lib/core/module_internal.dart b/lib/core/module_internal.dart index 04ed84507..054fc6303 100644 --- a/lib/core/module_internal.dart +++ b/lib/core/module_internal.dart @@ -13,6 +13,7 @@ import 'package:angular/utils.dart'; import 'package:angular/core/annotation_src.dart'; +import 'package:angular/cache/module.dart'; import 'package:angular/change_detection/watch_group.dart'; export 'package:angular/change_detection/watch_group.dart'; import 'package:angular/change_detection/ast_parser.dart'; @@ -24,7 +25,6 @@ import 'package:angular/core/parser/utils.dart'; import 'package:angular/core/registry.dart'; import 'package:angular/core/static_keys.dart'; -part "cache.dart"; part "exception_handler.dart"; part "interpolate.dart"; part "scope.dart"; @@ -36,7 +36,6 @@ class CoreModule extends Module { bind(ScopeDigestTTL); bind(MetadataExtractor); - bind(Cache); bind(ExceptionHandler); bind(FormatterMap); bind(Interpolate); diff --git a/lib/core/parser/dynamic_parser.dart b/lib/core/parser/dynamic_parser.dart index 041ebb33d..26486b15c 100644 --- a/lib/core/parser/dynamic_parser.dart +++ b/lib/core/parser/dynamic_parser.dart @@ -1,5 +1,6 @@ library angular.core.parser.dynamic_parser; +import 'package:angular/cache/module.dart'; import 'package:angular/core/annotation_src.dart' hide Formatter; import 'package:angular/core/module_internal.dart' show FormatterMap; @@ -24,7 +25,9 @@ class DynamicParser implements Parser { final Lexer _lexer; final ParserBackend _backend; final Map _cache = {}; - DynamicParser(this._lexer, this._backend); + DynamicParser(this._lexer, this._backend, CacheRegister cacheRegister) { + cacheRegister.registerCache("DynamicParser", _cache); + } Expression call(String input) { if (input == null) input = ''; diff --git a/lib/core/parser/static_parser.dart b/lib/core/parser/static_parser.dart index f7a045898..e1e38ad79 100644 --- a/lib/core/parser/static_parser.dart +++ b/lib/core/parser/static_parser.dart @@ -1,5 +1,6 @@ library angular.core.parser.static_parser; +import 'package:angular/cache/module.dart' show CacheRegister; import 'package:angular/core/annotation_src.dart' show Injectable; import 'package:angular/core/module_internal.dart' show FormatterMap; import 'package:angular/core/parser/parser.dart'; @@ -17,7 +18,9 @@ class StaticParser implements Parser { final StaticParserFunctions _functions; final DynamicParser _fallbackParser; final _cache = new HashMap(); - StaticParser(this._functions, this._fallbackParser); + StaticParser(this._functions, this._fallbackParser, CacheRegister cacheRegister) { + cacheRegister.registerCache("StaticParser", _cache); + } Expression call(String input) { if (input == null) input = ''; diff --git a/lib/core_dom/module_internal.dart b/lib/core_dom/module_internal.dart index 79f912024..5874061e1 100644 --- a/lib/core_dom/module_internal.dart +++ b/lib/core_dom/module_internal.dart @@ -8,6 +8,8 @@ import 'dart:js' as js; import 'package:di/di.dart'; import 'package:perf_api/perf_api.dart'; +import 'package:angular/cache/module.dart'; + import 'package:angular/core/annotation.dart'; import 'package:angular/core/annotation_src.dart' show SHADOW_DOM_INJECTOR_NAME; import 'package:angular/core/module_internal.dart'; @@ -55,7 +57,11 @@ class CoreDomModule extends Module { bind(ElementProbe, toValue: null); // Default to a unlimited-sized TemplateCache - bind(TemplateCache, toFactory: (_) => new TemplateCache()); + bind(TemplateCache, toFactory: (i) { + var templateCache = new TemplateCache(); + i.getByKey(CACHE_REGISTER_KEY).registerCache("TemplateCache", templateCache); + return templateCache; + }); bind(dom.NodeTreeSanitizer, toImplementation: NullTreeSanitizer); bind(TextMustache); @@ -64,7 +70,7 @@ class CoreDomModule extends Module { bind(Compiler, toImplementation: TaggingCompiler); bind(CompilerConfig); - bind(ComponentFactory, toImplementation: ShadowDomComponentFactory); + bind(ComponentFactory, toFactory: (i) => i.getByKey(SHADOW_DOM_COMPONENT_FACTORY_KEY)); bind(ShadowDomComponentFactory); bind(TranscludingComponentFactory); bind(Content); diff --git a/lib/core_dom/shadow_dom_component_factory.dart b/lib/core_dom/shadow_dom_component_factory.dart index d68827379..480db034a 100644 --- a/lib/core_dom/shadow_dom_component_factory.dart +++ b/lib/core_dom/shadow_dom_component_factory.dart @@ -45,7 +45,11 @@ class ShadowDomComponentFactory implements ComponentFactory { final Map<_ComponentAssetKey, async.Future> styleElementCache = {}; - ShadowDomComponentFactory(this.viewCache, this.http, this.templateCache, this.platform, this.componentCssRewriter, this.treeSanitizer, this.expando, this.config); + ShadowDomComponentFactory(this.viewCache, this.http, this.templateCache, this.platform, + this.componentCssRewriter, this.treeSanitizer, this.expando, + this.config, CacheRegister cacheRegister) { + cacheRegister.registerCache("ShadowDomComponentFactoryStyles", styleElementCache); + } bind(DirectiveRef ref, directives) => new BoundShadowDomComponentFactory(this, ref, directives); diff --git a/lib/core_dom/static_keys.dart b/lib/core_dom/static_keys.dart index 7f3253c40..63fde5af0 100644 --- a/lib/core_dom/static_keys.dart +++ b/lib/core_dom/static_keys.dart @@ -2,6 +2,7 @@ library angular.core_dom.static_keys; import 'dart:html' as dom; import 'package:di/di.dart'; +import 'package:angular/cache/module.dart'; import 'package:angular/core/static_keys.dart'; import 'package:angular/core_dom/module_internal.dart'; @@ -12,6 +13,7 @@ export 'package:angular/core/static_keys.dart'; Key ANIMATE_KEY = new Key(Animate); Key BOUND_VIEW_FACTORY_KEY = new Key(BoundViewFactory); +Key CACHE_REGISTER_KEY = new Key(CacheRegister); Key COMPILER_KEY = new Key(Compiler); Key COMPONENT_CSS_REWRITER_KEY = new Key(ComponentCssRewriter); Key DIRECTIVE_MAP_KEY = new Key(DirectiveMap); @@ -23,6 +25,7 @@ Key NG_ELEMENT_KEY = new Key(NgElement); Key NODE_ATTRS_KEY = new Key(NodeAttrs); Key NODE_KEY = new Key(dom.Node); Key NODE_TREE_SANITIZER_KEY = new Key(dom.NodeTreeSanitizer); +Key SHADOW_DOM_COMPONENT_FACTORY_KEY = new Key(ShadowDomComponentFactory); Key SHADOW_ROOT_KEY = new Key(dom.ShadowRoot); Key TEMPLATE_CACHE_KEY = new Key(TemplateCache); Key TEMPLATE_LOADER_KEY = new Key(TemplateLoader); diff --git a/lib/core_dom/view_factory.dart b/lib/core_dom/view_factory.dart index 2fec262ba..2d5e382d6 100644 --- a/lib/core_dom/view_factory.dart +++ b/lib/core_dom/view_factory.dart @@ -125,7 +125,9 @@ class ViewCache { final Compiler compiler; final dom.NodeTreeSanitizer treeSanitizer; - ViewCache(this.http, this.templateCache, this.compiler, this.treeSanitizer); + ViewCache(this.http, this.templateCache, this.compiler, this.treeSanitizer, CacheRegister cacheRegister) { + cacheRegister.registerCache('viewCache', viewFactoryCache); + } ViewFactory fromHtml(String html, DirectiveMap directives) { ViewFactory viewFactory = viewFactoryCache.get(html); diff --git a/test/_specs.dart b/test/_specs.dart index 038593d17..69e55a03f 100644 --- a/test/_specs.dart +++ b/test/_specs.dart @@ -18,6 +18,7 @@ export 'package:di/dynamic_injector.dart'; export 'package:angular/angular.dart'; export 'package:angular/application.dart'; export 'package:angular/introspection.dart'; +export 'package:angular/cache/module.dart'; export 'package:angular/core/annotation.dart'; export 'package:angular/core/registry.dart'; export 'package:angular/core/module_internal.dart'; diff --git a/test/angular_spec.dart b/test/angular_spec.dart index d4b90bd47..20f794437 100644 --- a/test/angular_spec.dart +++ b/test/angular_spec.dart @@ -94,6 +94,9 @@ main() { var ALLOWED_NAMES = [ "angular.app.AngularModule", "angular.app.Application", + "angular.cache.Cache", + "angular.cache.CacheRegister", + "angular.cache.CacheRegisterStats", "angular.core.annotation.ShadowRootAware", "angular.core.annotation_src.AttachAware", "angular.core.annotation_src.Component", @@ -142,7 +145,6 @@ main() { "angular.core.dom_internal.ViewCache", "angular.core.dom_internal.ViewFactory", "angular.core.dom_internal.ViewPort", - "angular.core_internal.CacheStats", "angular.core_internal.ExceptionHandler", "angular.core_internal.Interpolate", "angular.core_internal.RootScope", diff --git a/test/cache/cache_register_spec.dart b/test/cache/cache_register_spec.dart new file mode 100644 index 000000000..a797385ea --- /dev/null +++ b/test/cache/cache_register_spec.dart @@ -0,0 +1,49 @@ +library cache_register_spec; + +import '../_specs.dart'; + +main() => describe('CacheRegister', () { + it('should clear caches', (CacheRegister register) { + var map = {'a': 2}; + var map2 = {'b': 3}; + expect(map.length).toEqual(1); + expect(map2.length).toEqual(1); + + register.registerCache('a', map); + register.registerCache('b', map2); + register.clear('a'); + expect(map.length).toEqual(0); + expect(map2.length).toEqual(1); + + map['a'] = 2; + register.clear(); + expect(map.length).toEqual(0); + expect(map2.length).toEqual(0); + + + }); + + it('should return stats when empty', (CacheRegister register) { + expect(register.stats).toEqual([]); + }); + + it('should return correct stats', (CacheRegister register) { + var map = {'a': 2}; + var map2 = {'b': 3, 'c': 4}; + register.registerCache('a', map); + register.registerCache('b', map2); + + expect(register.stats.length).toEqual(2); + if (register.stats[0].name == 'a') { + expect(register.stats[0].length).toEqual(1); + expect(register.stats[1].name).toEqual('b'); + expect(register.stats[1].length).toEqual(2); + } else { + expect(register.stats[0].name).toEqual('b'); + expect(register.stats[0].length).toEqual(2); + expect(register.stats[1].name).toEqual('a'); + expect(register.stats[1].length).toEqual(1); + } + + }); +}); diff --git a/test/core/cache_spec.dart b/test/cache/cache_spec.dart similarity index 100% rename from test/core/cache_spec.dart rename to test/cache/cache_spec.dart