Dart Documentationangular.core.domCompiler

Compiler class

class Compiler {
 final DirectiveMap directives;
 final Profiler _perf;
 final Parser _parser;

 DirectiveSelector selector;

 Compiler(DirectiveMap this.directives, Profiler this._perf, Parser this._parser) {
   selector = directiveSelectorFactory(directives);
 }

 _compileBlock(NodeCursor domCursor, NodeCursor templateCursor,
              List<DirectiveRef> useExistingDirectiveRefs) {
   if (domCursor.nodeList().length == 0) return null;

   var directivePositions = null; // don't pre-create to create sparse tree and prevent GC pressure.
   var cursorAlreadyAdvanced;

   do {
     var declaredDirectiveRefs = useExistingDirectiveRefs == null
         ?  selector(domCursor.nodeList()[0])
         : useExistingDirectiveRefs;
     var children = NgAnnotation.COMPILE_CHILDREN;
     var childDirectivePositions = null;
     List<DirectiveRef> usableDirectiveRefs = null;

     cursorAlreadyAdvanced = false;

     for (var j = 0, jj = declaredDirectiveRefs.length; j < jj; j++) {
       DirectiveRef directiveRef = declaredDirectiveRefs[j];
       NgAnnotation annotation = directiveRef.annotation;
       var blockFactory = null;

       if (annotation.children != children &&
           children == NgAnnotation.COMPILE_CHILDREN) {
         children = annotation.children;
       }

       if (children == NgAnnotation.TRANSCLUDE_CHILDREN) {
         var remainingDirectives = declaredDirectiveRefs.sublist(j + 1);
         blockFactory = compileTransclusion(
             domCursor, templateCursor,
             directiveRef, remainingDirectives);

         j = jj; // stop processing further directives since they belong to transclusion;
       }
       if (usableDirectiveRefs == null) {
         usableDirectiveRefs = [];
       }
       directiveRef.blockFactory = blockFactory;
       createMappings(directiveRef);
       usableDirectiveRefs.add(directiveRef);
     }

     if (children == NgAnnotation.COMPILE_CHILDREN && domCursor.descend()) {
       templateCursor.descend();

       childDirectivePositions = _compileBlock(domCursor, templateCursor, null);

       domCursor.ascend();
       templateCursor.ascend();
     }

     if (childDirectivePositions != null || usableDirectiveRefs != null) {
       if (directivePositions == null) directivePositions = [];
       var directiveOffsetIndex = templateCursor.index;

       directivePositions
           ..add(directiveOffsetIndex)
           ..add(usableDirectiveRefs)
           ..add(childDirectivePositions);
     }
   } while (templateCursor.microNext() && domCursor.microNext());

   return directivePositions;
 }

 BlockFactory compileTransclusion(
                     NodeCursor domCursor, NodeCursor templateCursor,
                     DirectiveRef directiveRef,
                     List<DirectiveRef> transcludedDirectiveRefs) {
   var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
   var blockFactory;
   var blocks;

   var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
   var domCursorIndex = domCursor.index;
   var directivePositions = _compileBlock(domCursor, transcludeCursor, transcludedDirectiveRefs);
   if (directivePositions == null) directivePositions = [];

   blockFactory = new BlockFactory(transcludeCursor.elements, directivePositions, _perf);
   domCursor.index = domCursorIndex;

   if (domCursor.isInstance()) {
     domCursor.insertAnchorBefore(anchorName);
     blocks = [blockFactory(domCursor.nodeList())];
     domCursor.macroNext();
     templateCursor.macroNext();
     while (domCursor.isValid() && domCursor.isInstance()) {
       blocks.add(blockFactory(domCursor.nodeList()));
       domCursor.macroNext();
       templateCursor.remove();
     }
   } else {
     domCursor.replaceWithAnchor(anchorName);
   }

   return blockFactory;
 }

 BlockFactory call(List<dom.Node> elements) {
   assert(_perf.startTimer('ng.compile(${_html(elements)}') != false);
   List<dom.Node> domElements = elements;
   List<dom.Node> templateElements = cloneElements(domElements);
   var directivePositions = _compileBlock(
       new NodeCursor(domElements), new NodeCursor(templateElements),
       null);

   var blockFactory = new BlockFactory(templateElements,
       directivePositions == null ? [] : directivePositions, _perf);

   assert(_perf.stopTimer('ng.compile(${_html(elements)}') != false);
   return blockFactory;
 }

 static RegExp _MAPPING = new RegExp(r'^(\@|=\>\!|\=\>|\<\=\>|\&)\s*(.*)$');

 createMappings(DirectiveRef ref) {
   NgAnnotation annotation = ref.annotation;
   if (annotation.map != null) annotation.map.forEach((attrName, mapping) {
     Match match = _MAPPING.firstMatch(mapping);
     if (match == null) {
       throw "Unknown mapping '$mapping' for attribute '$attrName'.";
     }
     var mode = match[1];
     var dstPath = match[2];

     Expression dstPathFn = _parser(dstPath.isEmpty ? attrName : dstPath);
     if (!dstPathFn.assignable) {
       throw "Expression '$dstPath' is not assignable in mapping '$mapping' for attribute '$attrName'.";
     }
     ApplyMapping mappingFn;
     switch (mode) {
       case '@':
         mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
           attrs.observe(attrName, (value) => dstPathFn.assign(dst, value));
         };
         break;
       case '<=>':
         mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
           Expression attrExprFn = _parser(attrs[attrName]);
           var shadowValue = null;
           scope.$watch(
                   () => attrExprFn.eval(scope),
                   (v) => dstPathFn.assign(dst, shadowValue = v),
               attrs[attrName]);
           if (attrExprFn.assignable) {
             scope.$watch(
                     () => dstPathFn.eval(dst),
                     (v) {
                   if (shadowValue != v) {
                     shadowValue = v;
                     attrExprFn.assign(scope, v);
                   }
                 },
                 dstPath);
           }
         };
         break;
       case '=>':
         mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
           Expression attrExprFn = _parser(attrs[attrName]);
           var shadowValue = null;
           scope.$watch(
                   () => attrExprFn.eval(scope),
                   (v) => dstPathFn.assign(dst, shadowValue = v),
                   attrs[attrName]);
         };
         break;
       case '=>!':
         mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
           Expression attrExprFn = _parser(attrs[attrName]);
           var stopWatching;
           stopWatching = scope.$watch(
               () => attrExprFn.eval(scope),
               (value) {
                 if (dstPathFn.assign(dst, value) != null) {
                   stopWatching();
                 }
               },
               attrs[attrName]);
         };
         break;
       case '&':
         mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
           dstPathFn.assign(dst, _parser(attrs[attrName]).bind(scope));
         };
         break;
     }
     ref.mappings.add(mappingFn);
   });
 }
}

Constructors

new Compiler(DirectiveMap directives, Profiler _perf, Parser _parser) #

Creates a new Object instance.

Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.

docs inherited from Object
Compiler(DirectiveMap this.directives, Profiler this._perf, Parser this._parser) {
 selector = directiveSelectorFactory(directives);
}

Properties

final DirectiveMap directives #

final DirectiveMap directives

DirectiveSelector selector #

DirectiveSelector selector

Methods

BlockFactory call(List<Node> elements) #

BlockFactory call(List<dom.Node> elements) {
 assert(_perf.startTimer('ng.compile(${_html(elements)}') != false);
 List<dom.Node> domElements = elements;
 List<dom.Node> templateElements = cloneElements(domElements);
 var directivePositions = _compileBlock(
     new NodeCursor(domElements), new NodeCursor(templateElements),
     null);

 var blockFactory = new BlockFactory(templateElements,
     directivePositions == null ? [] : directivePositions, _perf);

 assert(_perf.stopTimer('ng.compile(${_html(elements)}') != false);
 return blockFactory;
}

BlockFactory compileTransclusion(NodeCursor domCursor, NodeCursor templateCursor, DirectiveRef directiveRef, List<DirectiveRef> transcludedDirectiveRefs) #

BlockFactory compileTransclusion(
                   NodeCursor domCursor, NodeCursor templateCursor,
                   DirectiveRef directiveRef,
                   List<DirectiveRef> transcludedDirectiveRefs) {
 var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
 var blockFactory;
 var blocks;

 var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
 var domCursorIndex = domCursor.index;
 var directivePositions = _compileBlock(domCursor, transcludeCursor, transcludedDirectiveRefs);
 if (directivePositions == null) directivePositions = [];

 blockFactory = new BlockFactory(transcludeCursor.elements, directivePositions, _perf);
 domCursor.index = domCursorIndex;

 if (domCursor.isInstance()) {
   domCursor.insertAnchorBefore(anchorName);
   blocks = [blockFactory(domCursor.nodeList())];
   domCursor.macroNext();
   templateCursor.macroNext();
   while (domCursor.isValid() && domCursor.isInstance()) {
     blocks.add(blockFactory(domCursor.nodeList()));
     domCursor.macroNext();
     templateCursor.remove();
   }
 } else {
   domCursor.replaceWithAnchor(anchorName);
 }

 return blockFactory;
}

dynamic createMappings(DirectiveRef ref) #

createMappings(DirectiveRef ref) {
 NgAnnotation annotation = ref.annotation;
 if (annotation.map != null) annotation.map.forEach((attrName, mapping) {
   Match match = _MAPPING.firstMatch(mapping);
   if (match == null) {
     throw "Unknown mapping '$mapping' for attribute '$attrName'.";
   }
   var mode = match[1];
   var dstPath = match[2];

   Expression dstPathFn = _parser(dstPath.isEmpty ? attrName : dstPath);
   if (!dstPathFn.assignable) {
     throw "Expression '$dstPath' is not assignable in mapping '$mapping' for attribute '$attrName'.";
   }
   ApplyMapping mappingFn;
   switch (mode) {
     case '@':
       mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
         attrs.observe(attrName, (value) => dstPathFn.assign(dst, value));
       };
       break;
     case '<=>':
       mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
         Expression attrExprFn = _parser(attrs[attrName]);
         var shadowValue = null;
         scope.$watch(
                 () => attrExprFn.eval(scope),
                 (v) => dstPathFn.assign(dst, shadowValue = v),
             attrs[attrName]);
         if (attrExprFn.assignable) {
           scope.$watch(
                   () => dstPathFn.eval(dst),
                   (v) {
                 if (shadowValue != v) {
                   shadowValue = v;
                   attrExprFn.assign(scope, v);
                 }
               },
               dstPath);
         }
       };
       break;
     case '=>':
       mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
         Expression attrExprFn = _parser(attrs[attrName]);
         var shadowValue = null;
         scope.$watch(
                 () => attrExprFn.eval(scope),
                 (v) => dstPathFn.assign(dst, shadowValue = v),
                 attrs[attrName]);
       };
       break;
     case '=>!':
       mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
         Expression attrExprFn = _parser(attrs[attrName]);
         var stopWatching;
         stopWatching = scope.$watch(
             () => attrExprFn.eval(scope),
             (value) {
               if (dstPathFn.assign(dst, value) != null) {
                 stopWatching();
               }
             },
             attrs[attrName]);
       };
       break;
     case '&':
       mappingFn = (NodeAttrs attrs, Scope scope, Object dst) {
         dstPathFn.assign(dst, _parser(attrs[attrName]).bind(scope));
       };
       break;
   }
   ref.mappings.add(mappingFn);
 });
}