first chunk of interfaces that are valid via dart analyzer

This commit is contained in:
Misko Hevery 2014-09-19 16:38:37 -07:00 committed by Tobias Bosch
parent 29c20f7a50
commit 8afa421d75
40 changed files with 462 additions and 9 deletions

View File

@ -58,9 +58,10 @@ var sourceTypeConfigs = {
compiler: function() {
return traceur(js2dartOptions, true);
},
transpileSrc: ['modules/**/*.es6d'],
transpileSrc: ['modules/**/*.js'],
htmlSrc: ['modules/*/src/**/*.html'],
copySrc: ['modules/**/*.dart'],
// TODO: execute pub get after a yaml changed and was copied over to 'build' folder
copySrc: ['modules/**/*.dart', 'modules/**/*.yaml'],
outputDir: 'build/dart',
outputExt: 'dart',
mimeType: 'application/dart'
@ -69,9 +70,9 @@ var sourceTypeConfigs = {
compiler: function() {
return traceur(js2es5Options, true);
},
transpileSrc: ['modules/**/*.es*'],
transpileSrc: ['modules/**/*.js', 'modules/**/*.es6'],
htmlSrc: ['modules/*/src/**/*.html'],
copySrc: ['modules/**/*.js'],
copySrc: ['modules/**/*.es5'],
outputDir: 'build/js',
outputExt: 'js'
}
@ -82,18 +83,25 @@ gulp.task('modules/clean', function() {
.pipe(clean());
});
function renameSrcToLib(file) {
file.dirname = file.dirname.replace(/\bsrc\b/, 'lib');
}
function createModuleTask(sourceTypeConfig, isWatch) {
var start = isWatch ? watch : gulp.src.bind(gulp);
return function(done) {
var transpile = start(sourceTypeConfig.transpileSrc)
.pipe(rename({extname: '.'+sourceTypeConfig.outputExt}))
.pipe(rename(renameSrcToLib))
.pipe(sourceTypeConfig.compiler())
.pipe(gulp.dest(sourceTypeConfig.outputDir));
var copy = start(sourceTypeConfig.copySrc)
.pipe(rename(renameSrcToLib))
.pipe(gulp.dest(sourceTypeConfig.outputDir));
// TODO: provide the list of files to the template
// automatically!
var html = start(sourceTypeConfig.htmlSrc)
.pipe(rename(renameSrcToLib))
.pipe(ejs({
type: sourceTypeConfig.outputExt
}))

View File

@ -0,0 +1,6 @@
name: change_detection
environment:
sdk: '>=1.4.0'
dependencies:
dev_dependencies:
unittest: '>=0.10.1 <0.12.0'

View File

@ -0,0 +1,5 @@
export class ChangeDetection {
detectChanges():int {}
}

View File

@ -0,0 +1,3 @@
export class ProtoRecord {
}

View File

@ -0,0 +1,27 @@
export class ProtoWatchGroup {
watch(
expression:String,
context:dynamic,
{isCollection})
{
}
}
/*
@Component(
bind: {
'title': 'title',
'name': 'name'
}
)
class MyComponent implements ChangeListener {
String name;
String title;
onChange(List<Record> changes) {
}
}
*/

View File

@ -0,0 +1,3 @@
export class Record {
}

View File

@ -0,0 +1,4 @@
export class WatchGroup {
@FIELD('final dispatcher:WatchGroupDispatcher')
constructor() {}
}

View File

@ -0,0 +1,4 @@
export class WatchGroupDispatcher {
notify(record:Record, context) {}
}

12
modules/core/pubspec.yaml Normal file
View File

@ -0,0 +1,12 @@
name: core
environment:
sdk: '>=1.4.0'
dependencies:
change_detection:
path: ../change_detection
di:
path: ../di
facade:
path: ../facade
dev_dependencies:
unittest: '>=0.10.1 <0.12.0'

12
modules/core/src/angular.js vendored Normal file
View File

@ -0,0 +1,12 @@
/**
* Define public API for Angular here
*/
export * from './annotations/directive';
export * from './annotations/component';
export * from './annotations/template_config';
export * from './compiler/compiler';
export * from './compiler/template_loader';
export * from './view/proto_view';
export * from './view/view';

View File

@ -0,0 +1,65 @@
import {Directive} from './directive';
export class Component extends Directive {
@CONST constructor({
selector,
template,
elementServices,
componentServices,
implementsTypes
}:{
selector:String,
template:TemplateConfig,
lightDomServices:DomServicesFunction,
shadowDomServices:DomServicesFunction,
componentServices:ComponentServicesFunction,
implementsTypes:Array<Type>
})
{
// super({selector, lightDomServices, implementsTypes});
}
}
///////////////////////////
/*
import 'package:angular/core.dart' as core;
@Component(
selector: 'example',
template: const TemplateConfig(
url: 'example.dart',
uses: const [core.CONFIG],
directives: const [CompA],
formatters: const [Stringify]
),
componentServices: Example.componentServices,
elementServices: Example.elementServices,
implementsTypes: const [App]
)
class Example implements App {
static componentServices(Module m) {
m.bind();
}
static elementServices(ElementModule m) {
m.bind();
}
}
class CompA {}
@Formatter()
class Stringify {}
<CompA>
LightDOM:
</CompA>
CompA ShadowDOM:
<div>
<CompB></CompB>
</div>
CompB SHadowDOM:
<div></div>
*/

View File

@ -0,0 +1,19 @@
import {Type} from 'facade/lang';
import {ElementServicesFunction} from './facade';
@ABSTRACT
export class Directive {
@CONST constructor({
selector,
lightDomServices,
implementsTypes
}:{
selector:String,
lightDomServices:ElementServicesFunction,
implementsTypes:Array<Type>
})
{
this.lightDomServices = lightDomServices;
this.selector = selector;
}
}

View File

@ -0,0 +1,5 @@
import 'package:di/di.dart' show Module;
import '../view/element_module.dart' show ElementModule;
typedef DomServicesFunction(ElementModule m);
typedef ComponentServicesFunction(Module m);

View File

@ -0,0 +1,2 @@
export var DomServicesFunction = Function;
export var ComponentServicesFunction = Function;

View File

@ -0,0 +1,16 @@
import {Type, List} from 'facade/lang';
export class TemplateConfig {
@CONST constructor({
url,
directives,
formatters,
source
}: {
url: String,
directives: List<Type>,
formatters: List<Type>,
source: List<TemplateConfig>
})
{}
}

View File

@ -1,7 +1,15 @@
import {Future} from '../facade';
import {ProtoView} from './proto_view';
import {Future} from 'facade/lang';
import {Element} from 'facade/dom';
import {ProtoView} from '../view/proto_view';
import {TemplateLoader} from './template_loader';
export class Compiler {
@FIELD('final _templateLoader:TemplateLoader')
constructor(templateLoader:TemplateLoader) {
this._templateLoader = templateLoader;
}
/**
* # Why future?
* - compilation will load templates. Instantiating views before templates are loaded will
@ -10,7 +18,9 @@ export class Compiler {
* - don't know about injector in deserialization
* - compile does not need the injector, only the ViewFactory does
*/
@of(ProtoView) compile(element:TemplateElement):Future {
compile(component:Type, element:Element/* = null*/):Future<ProtoView> {
return null;
}
}

View File

@ -0,0 +1,11 @@
import {Future} from 'facade/lang';
import {Document} from 'facade/dom';
export class TemplateLoader {
constructor() {}
load(url:String):Future<Document> {
return null;
}
}

View File

@ -0,0 +1,11 @@
export class LifeCycle {
@FIELD('final _changeDetection:ChangeDetection')
@FIELD('final _onChangeDispatcher:OnChangeDispatcher')
constructor() {}
digest() {
_changeDetection.detectChanges();
_onChangeDispatcher.done();
}
}

View File

@ -0,0 +1,13 @@
export class ElementInjectorTarget {
@FIELD('final _elementInjectorIndex:int')
@FIELD('final _directiveIndex:int')
@FIELD('final _setterName:String')
@FIELD('final _setter:SetterFn')
constructor() {}
invoke(record:Record, elementInjectors:List<ElementInjector>) {
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
var directive = elementInjectors.getByIndex(this._directiveIndex);
this._setter(directive, record.currentValue);
}
}

View File

@ -0,0 +1 @@
export class ElementModule {}

View File

@ -0,0 +1,19 @@
//TODO(tbosch): I don't like to have done be called from a different place than notify
// notify is called by change detection, but done is called by our wrapper on detect changes.
export class OnChangeDispatcher {
@FIELD('_lastView:View')
@FIELD('_lastTarget:ElementInjectorTarget')
constructor() {
}
notify(view:View, eTarget:ElementInjectorTarget) {
}
done() {
}
}

View File

@ -0,0 +1,27 @@
/**
Difference beteween di.Injector and ElementInjector
di.Injector (di.Module):
- imperative based (can create child injectors imperativly)
- Lazy loading of code
- Component/App Level services which are usually not DOM Related.
ElementInjector (ElementModule):
- ProtoBased (Injector structure fixed at compile time)
- understands @Ancestor, @Parent, @Child, @Descendent
- Fast
- Query mechanism for children
- 1:1 to DOM structure.
*/
export class ProtoElementInjector {
@FIELD('final _parent:ProtoElementInjector')
/// Temporory instance while instantiating
@FIELD('_instance:ElementInjector')
constructor() {}
}

View File

@ -0,0 +1,10 @@
import {Module} from 'di/di';
import {TemplateElement} from 'facade/dom';
export class ProtoView {
@FIELD('final _template:TemplateElement')
@FIELD('final _module:Module')
@FIELD('final _protoElementInjectors:List<ProtoElementInjector>')
@FIELD('final _protoWatchGroup:ProtoWatchGroup')
@CONST constructor() { }
}

View File

@ -0,0 +1,34 @@
import {Node, DocumentFragment} from 'facade/dom';
import {ListWrapper wraps List} from 'facade/collection';
import {Record} from 'change_detection/record';
@IMPLEMENTS(WatchGroupDispatcher)
export class View {
@FIELD('final _fragment:DocumentFragment')
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
@FIELD('final _rootElementInjectors:List<ElementInjector>')
@FIELD('final _elementInjectors:List<ElementInjector>')
@FIELD('final _textNodes:List<Text>')
@FIELD('final _watchGroup:WatchGroup')
/// When the view is part of render tree, the DocumentFragment is empty, which is why we need
/// to keep track of the nodes.
@FIELD('final _nodes:List<Node>')
constructor(fragment:DocumentFragment) {
this._fragment = fragment;
this._nodes = ListWrapper.clone(fragment.childNodes);
}
notify(record:Record, target) {
/*
// dispatch to element injector or text nodes based on context
if (Number.is(target)) {
// we know it refferst to _textNodes.
} else {
// we know that it is ElementInjectorTarge
var eTarget:ElementInjectorTarget = target;
onChangeDispatcher.notify(this, eTarget);
eTarget.invoke(record, _elementInjectors);
}
*/
}
}

View File

@ -0,0 +1,9 @@
import {describe, id} from 'spec/spec';
function main() {
describe('compiler', () => {
it('should hello', () => {
print('I am working');
});
});
}

6
modules/di/pubspec.yaml Normal file
View File

@ -0,0 +1,6 @@
name: di
environment:
sdk: '>=1.4.0'
dependencies:
dev_dependencies:
unittest: '>=0.10.1 <0.12.0'

1
modules/di/src/di.js Normal file
View File

@ -0,0 +1 @@
export * from './module';

24
modules/di/src/module.js Normal file
View File

@ -0,0 +1,24 @@
import {Type} from 'facade/lang';
import {Map, MapWrapper wraps Map} from 'facade/collection';
/// becouse we need to know when toValue was not set.
/// (it could be that toValue is set to null or undefined in js)
var _UNDEFINED = {}
export class Module {
@FIELD('final bindings:Map<Key, Binding>')
constructor(){
this.bindings = new MapWrapper();
}
bind(type:Type,
{toValue=_UNDEFINED, toFactory, toImplementation, inject, toInstanceOf, withAnnotation}/*:
{toFactory:Function, toImplementation: Type, inject: Array, toInstanceOf:Type}*/) {}
bindByKey(key:Key,
{toValue=_UNDEFINED, toFactory, toImplementation, inject, toInstanceOf}/*:
{toFactory:Function, toImplementation: Type, inject: Array, toInstanceOf:Type}*/) {}
install(module:Module) {}
}

View File

@ -0,0 +1,6 @@
name: examples
environment:
sdk: '>=1.4.0'
dependencies:
dev_dependencies:
unittest: '>=0.10.1 <0.12.0'

View File

@ -1,5 +1,6 @@
import {DOM} from './dom';
export class App {
@field('input:Element')
constructor() {
this.input = null;
this.list = null;

View File

@ -0,0 +1,12 @@
/**
* This is a special facade used to bootstrap JS automatically.
* (In contrast to door wheere the user needs to explicitly call into angular.)
* This file is appened to AngularJS and needs to be written in ES5.
*/
(function(window, document) {
document.addEventListener('DOMContentLoaded', bootstrap, false);
function bootstrap() {
// TODO(misko): load application factory from the module system.
applicationFactory().run();
}
})(window, document);

View File

@ -0,0 +1,6 @@
name: facade
environment:
sdk: '>=1.4.0'
dependencies:
dev_dependencies:
unittest: '>=0.10.1 <0.12.0'

View File

@ -0,0 +1,20 @@
library facade.collection;
import 'dart:collection' show HashMap;
export 'dart:collection' show Map;
export 'dart:core' show List;
class MapWrapper {
static HashMap create() => new HashMap();
static get(m, k) => m[k];
static void set(m, k, v){ m[k] = v; }
static contains(m, k) => m.containsKey(k);
}
class ListWrapper {
static List clone(List l) => new List.from(l);
static List create() => new List();
static get(m, k) => m[k];
static void set(m, k, v) { m[k] = v; }
static contains(m, k) => m.containsKey(k);
}

View File

@ -0,0 +1,15 @@
export var List = window.Array;
export var Map = window.Map;
export class MapWrapper {
static create():HashMap { return new HashMap(); }
static get(m, k) { return m[k]; }
static set(m, k, v) { m[k] = v; }
static contains(m, k) { return m.containsKey(k); }
}
export class ListWrapper {
static create():List { return new List(); }
static get(m, k) { return m[k]; }
static set(m, k, v) { m[k] = v; }
}

View File

@ -1,7 +1,9 @@
library dom;
library angular.core.facade.dom;
import 'dart:html';
export 'dart:html' show DocumentFragment, Node, Element, TemplateElement;
class DOM {
static query(selector) {
return document.query(selector);

View File

@ -1,3 +1,8 @@
export var DocumentFragment = window.DocumentFragment;
export var Node = window.Node;
export var Element = window.HTMLElement;
export var TemplateElement = window.HTMLTemplateElement;
export class DOM {
static query(selector) {
return document.querySelector(selector);

View File

@ -0,0 +1,4 @@
library angular.core.facade.async;
export 'dart:async' show Future;
export 'dart:core' show Type;

View File

@ -0,0 +1,2 @@
export var Future = Promise;
export var Type = Function;

13
modules/facade/test.dart Normal file
View File

@ -0,0 +1,13 @@
import 'dart:core' as core;
import 'dart:collection';
class Map {
new() => null;
ping() => core.print('map');
}
main() {
new Map().ping();
}

@ -1 +1 @@
Subproject commit 9fc0b738664c75ac16c44f190322b4b7ca95a1ea
Subproject commit 971ffb32b88bcad5eab5877ecbde2995e30c96c1