parent
52236bd765
commit
841f8789fd
32
gulpfile.js
32
gulpfile.js
|
@ -744,24 +744,31 @@ gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function (neverDon
|
||||||
watch('modules/**', buildAndTest);
|
watch('modules/**', buildAndTest);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Use this target to continuously run dartvm unit-tests (such as transformer
|
||||||
|
// tests) while coding. Note: these tests do not use Karma.
|
||||||
gulp.task('test.unit.dartvm', function (done) {
|
gulp.task('test.unit.dartvm', function (done) {
|
||||||
runSequence(
|
runSequence(
|
||||||
'build/tree.dart',
|
'build/tree.dart',
|
||||||
'build/pure-packages.dart',
|
'build/pure-packages.dart',
|
||||||
'build/pubspec.dart',
|
'!build/pubget.angular2.dart',
|
||||||
'!build/change_detect.dart',
|
'!build/change_detect.dart',
|
||||||
'!test.unit.dartvm/run',
|
'!test.unit.dartvm/run',
|
||||||
function(error) {
|
function(error) {
|
||||||
// if initial build failed (likely due to build or formatting step) then exit
|
// Watch for changes made in the TS and Dart code under "modules" and
|
||||||
// otherwise karma server doesn't start and we can't continue running properly
|
// run ts2dart and test change detector generator prior to rerunning the
|
||||||
if (error) {
|
// tests.
|
||||||
done(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch('modules/angular2/**', { ignoreInitial: true }, [
|
watch('modules/angular2/**', { ignoreInitial: true }, [
|
||||||
'!build/tree.dart',
|
'!build/tree.dart',
|
||||||
|
'!build/change_detect.dart',
|
||||||
|
'!test.unit.dartvm/run'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Watch for changes made in Dart code under "modules_dart", then copy it
|
||||||
|
// to dist and run test change detector generator prior to retunning the
|
||||||
|
// tests.
|
||||||
|
watch('modules_dart/**', { ignoreInitial: true }, [
|
||||||
|
'build/pure-packages.dart',
|
||||||
|
'!build/change_detect.dart',
|
||||||
'!test.unit.dartvm/run'
|
'!test.unit.dartvm/run'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -863,14 +870,17 @@ gulp.task('build/pure-packages.dart', function() {
|
||||||
var transformStream = gulp
|
var transformStream = gulp
|
||||||
.src([
|
.src([
|
||||||
'modules_dart/transform/**/*',
|
'modules_dart/transform/**/*',
|
||||||
'!modules_dart/transform/**/*.proto'
|
'!modules_dart/transform/**/*.proto',
|
||||||
|
'!modules_dart/transform/pubspec.yaml',
|
||||||
|
'!modules_dart/transform/**/packages{,/**}',
|
||||||
])
|
])
|
||||||
.pipe(gulp.dest(path.join(CONFIG.dest.dart, 'angular2')));
|
.pipe(gulp.dest(path.join(CONFIG.dest.dart, 'angular2')));
|
||||||
|
|
||||||
var moveStream = gulp.src([
|
var moveStream = gulp.src([
|
||||||
'modules_dart/**/*.dart',
|
'modules_dart/**/*.dart',
|
||||||
'modules_dart/**/pubspec.yaml',
|
'modules_dart/**/pubspec.yaml',
|
||||||
'!modules_dart/transform/**'
|
'!modules_dart/transform/**',
|
||||||
|
'!modules_dart/**/packages{,/**}'
|
||||||
])
|
])
|
||||||
.pipe(through2.obj(function(file, enc, done) {
|
.pipe(through2.obj(function(file, enc, done) {
|
||||||
if (/pubspec.yaml$/.test(file.path)) {
|
if (/pubspec.yaml$/.test(file.path)) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
analyzer: '>=0.24.4 <0.27.0'
|
analyzer: '>=0.24.4 <0.27.0'
|
||||||
barback: '^0.15.2+2'
|
barback: '^0.15.2+2'
|
||||||
|
csslib: '>=0.12.0 <1.0.0'
|
||||||
code_transformers: '^0.2.8'
|
code_transformers: '^0.2.8'
|
||||||
dart_style: '>=0.1.8 <0.3.0'
|
dart_style: '>=0.1.8 <0.3.0'
|
||||||
glob: '^1.0.0'
|
glob: '^1.0.0'
|
||||||
|
|
|
@ -0,0 +1,435 @@
|
||||||
|
library angular2.dom.abstractHtmlAdapter;
|
||||||
|
|
||||||
|
import 'package:html/parser.dart' as parser;
|
||||||
|
import 'package:html/dom.dart';
|
||||||
|
|
||||||
|
import 'dom_adapter.dart';
|
||||||
|
import 'emulated_css.dart';
|
||||||
|
|
||||||
|
abstract class AbstractHtml5LibAdapter implements DomAdapter {
|
||||||
|
hasProperty(element, String name) {
|
||||||
|
// This is needed for serverside compile to generate the right getters/setters.
|
||||||
|
// TODO: change this once we have property schema support.
|
||||||
|
// Attention: Keep this in sync with browser_adapter.dart!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProperty(Element element, String name, Object value) =>
|
||||||
|
throw 'not implemented';
|
||||||
|
|
||||||
|
getProperty(Element element, String name) => throw 'not implemented';
|
||||||
|
|
||||||
|
invoke(Element element, String methodName, List args) =>
|
||||||
|
throw 'not implemented';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final attrToPropMap = const {
|
||||||
|
'innerHtml': 'innerHTML',
|
||||||
|
'readonly': 'readOnly',
|
||||||
|
'tabindex': 'tabIndex',
|
||||||
|
};
|
||||||
|
|
||||||
|
set attrToPropMap(value) {
|
||||||
|
throw 'readonly';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
getGlobalEventTarget(String target) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
getTitle() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
setTitle(String newTitle) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getEventKey(event) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void replaceChild(el, newNode, oldNode) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic getBoundingClientRect(el) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
Element parse(String templateHtml) => parser.parse(templateHtml).firstChild;
|
||||||
|
query(selector) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
querySelector(el, String selector) {
|
||||||
|
return el.querySelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
List querySelectorAll(el, String selector) {
|
||||||
|
return el.querySelectorAll(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
on(el, evt, listener) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
Function onAndCancel(el, evt, listener) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(el, evt) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
createMouseEvent(eventType) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
createEvent(eventType) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
preventDefault(evt) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
isPrevented(evt) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerHTML(el) {
|
||||||
|
return el.innerHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOuterHTML(el) {
|
||||||
|
return el.outerHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
String nodeName(node) {
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case Node.ELEMENT_NODE:
|
||||||
|
return (node as Element).localName;
|
||||||
|
case Node.TEXT_NODE:
|
||||||
|
return '#text';
|
||||||
|
default:
|
||||||
|
throw 'not implemented for type ${node.nodeType}. '
|
||||||
|
'See http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247'
|
||||||
|
' for node types definitions.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String nodeValue(node) => node.data;
|
||||||
|
String type(node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
content(node) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstChild(el) => el is NodeList ? el.first : el.firstChild;
|
||||||
|
|
||||||
|
nextSibling(el) {
|
||||||
|
final parentNode = el.parentNode;
|
||||||
|
if (parentNode == null) return null;
|
||||||
|
final siblings = parentNode.nodes;
|
||||||
|
final index = siblings.indexOf(el);
|
||||||
|
if (index < siblings.length - 1) {
|
||||||
|
return siblings[index + 1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentElement(el) {
|
||||||
|
return el.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
List childNodes(el) => el.nodes;
|
||||||
|
List childNodesAsList(el) => el.nodes;
|
||||||
|
clearNodes(el) {
|
||||||
|
el.nodes.forEach((e) => e.remove());
|
||||||
|
}
|
||||||
|
|
||||||
|
appendChild(el, node) => el.append(node.remove());
|
||||||
|
removeChild(el, node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(el) => el.remove();
|
||||||
|
insertBefore(el, node) {
|
||||||
|
if (el.parent == null) throw '$el must have a parent';
|
||||||
|
el.parent.insertBefore(node, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertAllBefore(el, nodes) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
insertAfter(el, node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
setInnerHTML(el, value) {
|
||||||
|
el.innerHtml = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getText(el) {
|
||||||
|
return el.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(el, String value) => el.text = value;
|
||||||
|
|
||||||
|
getValue(el) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(el, String value) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getChecked(el) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
setChecked(el, bool value) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
createComment(String text) => new Comment(text);
|
||||||
|
createTemplate(String html) => createElement('template')..innerHtml = html;
|
||||||
|
createElement(tagName, [doc]) {
|
||||||
|
return new Element.tag(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
createTextNode(String text, [doc]) => new Text(text);
|
||||||
|
|
||||||
|
createScriptTag(String attrName, String attrValue, [doc]) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
createStyleElement(String css, [doc]) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
createShadowRoot(el) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getShadowRoot(el) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getHost(el) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
clone(node) => node.clone(true);
|
||||||
|
getElementsByClassName(element, String name) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getElementsByTagName(element, String name) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
List classList(element) => element.classes.toList();
|
||||||
|
|
||||||
|
addClass(element, String classname) {
|
||||||
|
element.classes.add(classname);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeClass(element, String classname) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
hasClass(element, String classname) => element.classes.contains(classname);
|
||||||
|
|
||||||
|
setStyle(element, String stylename, String stylevalue) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStyle(element, String stylename) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getStyle(element, String stylename) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
String tagName(element) => element.localName;
|
||||||
|
|
||||||
|
attributeMap(element) {
|
||||||
|
// `attributes` keys can be {@link AttributeName}s.
|
||||||
|
var map = <String, String>{};
|
||||||
|
element.attributes.forEach((key, value) {
|
||||||
|
map['$key'] = value;
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasAttribute(element, String attribute) {
|
||||||
|
// `attributes` keys can be {@link AttributeName}s.
|
||||||
|
return element.attributes.keys.any((key) => '$key' == attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttribute(element, String attribute) {
|
||||||
|
// `attributes` keys can be {@link AttributeName}s.
|
||||||
|
var key = element.attributes.keys.firstWhere((key) => '$key' == attribute,
|
||||||
|
orElse: () {});
|
||||||
|
return element.attributes[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
setAttribute(element, String name, String value) {
|
||||||
|
element.attributes[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAttribute(element, String attribute) {
|
||||||
|
element.attributes.remove(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
templateAwareRoot(el) => el;
|
||||||
|
|
||||||
|
createHtmlDocument() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultDoc() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool elementMatches(n, String selector) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTemplateElement(Element el) {
|
||||||
|
return el != null && el.localName.toLowerCase() == 'template';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTextNode(node) => node.nodeType == Node.TEXT_NODE;
|
||||||
|
bool isCommentNode(node) => node.nodeType == Node.COMMENT_NODE;
|
||||||
|
|
||||||
|
bool isElementNode(node) => node.nodeType == Node.ELEMENT_NODE;
|
||||||
|
|
||||||
|
bool hasShadowRoot(node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isShadowRoot(node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
importIntoDoc(node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
adoptNode(node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPageRule(rule) => (rule.type == 6);
|
||||||
|
|
||||||
|
bool isStyleRule(rule) => (rule.type == 1);
|
||||||
|
|
||||||
|
bool isMediaRule(rule) => (rule.type == 4);
|
||||||
|
|
||||||
|
bool isKeyframesRule(rule) => (rule.type == 7);
|
||||||
|
|
||||||
|
String getHref(element) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolveAndSetHref(element, baseUrl, href) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
List cssToRules(String css) {
|
||||||
|
return parseAndEmulateCssRules(css);
|
||||||
|
}
|
||||||
|
|
||||||
|
List getDistributedNodes(Node) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool supportsDOMEvents() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool supportsNativeShadowDOM() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool supportsUnprefixedCssAnimation() {
|
||||||
|
// Currently during code transformation we do not know what
|
||||||
|
// browsers we are targetting. To play it safe, we assume
|
||||||
|
// unprefixed animations are not supported.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHistory() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getLocation() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getBaseHref() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
resetBaseElement() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
String getUserAgent() {
|
||||||
|
return 'Angular 2 Dart Transformer';
|
||||||
|
}
|
||||||
|
|
||||||
|
void setData(Element element, String name, String value) {
|
||||||
|
this.setAttribute(element, 'data-${name}', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getComputedStyle(element) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
String getData(Element element, String name) {
|
||||||
|
return this.getAttribute(element, 'data-${name}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(tbosch): move this into a separate environment class once we have it
|
||||||
|
setGlobalVar(String name, value) {
|
||||||
|
// noop on the server
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(callback) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelAnimationFrame(id) {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
performanceNow() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getAnimationPrefix() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransitionEnd() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
supportsAnimation() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* Emulates browser CSS API.
|
||||||
|
*
|
||||||
|
* WARNING: this is a very incomplete emulation; it only has enough to support
|
||||||
|
* Angular's CSS scoping (a.k.a. shimming).
|
||||||
|
*/
|
||||||
|
library angular2.dom.emulated_css;
|
||||||
|
|
||||||
|
import 'package:csslib/parser.dart' as cssp;
|
||||||
|
import 'package:csslib/visitor.dart' as cssv;
|
||||||
|
|
||||||
|
/// Parses [css] string and emits the list of top-level CSS rules in it via
|
||||||
|
/// data structures that mimick browser CSS APIs.
|
||||||
|
List<EmulatedCssRule> parseAndEmulateCssRules(String css) {
|
||||||
|
var stylesheet = cssp.parse(css);
|
||||||
|
return emulateRules(stylesheet.topLevels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts `csslib` [rules] to their emulated counterparts.
|
||||||
|
List<EmulatedCssRule> emulateRules(Iterable<cssv.TreeNode> rules) {
|
||||||
|
return rules
|
||||||
|
.map((cssv.TreeNode node) {
|
||||||
|
if (node is cssv.RuleSet) {
|
||||||
|
if (node.declarationGroup.span.text.isEmpty) {
|
||||||
|
// Skip CSS matchers with no bodies
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new EmulatedCssStyleRule(node);
|
||||||
|
} else if (node is cssv.MediaDirective) {
|
||||||
|
return new EmulatedCssMedialRule(node);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.where((r) => r != null)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emulates [CSSRule](https://developer.mozilla.org/en-US/docs/Web/API/CSSRule)
|
||||||
|
abstract class EmulatedCssRule {
|
||||||
|
int type;
|
||||||
|
String cssText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emulates [CSSStyleRule](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleRule)
|
||||||
|
class EmulatedCssStyleRule extends EmulatedCssRule {
|
||||||
|
String selectorText;
|
||||||
|
EmulatedCssStyleDeclaration style;
|
||||||
|
|
||||||
|
EmulatedCssStyleRule(cssv.RuleSet ruleSet) {
|
||||||
|
final declarationText = new StringBuffer();
|
||||||
|
ruleSet.declarationGroup.declarations.forEach((d) {
|
||||||
|
if (d is! cssv.Declaration) {
|
||||||
|
// Nested selectors not supported
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: expression spans are currently broken in csslib; see:
|
||||||
|
// https://github.com/dart-lang/csslib/pull/14
|
||||||
|
var declarationSpan = d.span.text;
|
||||||
|
var colonIdx = declarationSpan.indexOf(':');
|
||||||
|
var expression = declarationSpan.substring(colonIdx + 1);
|
||||||
|
declarationText.write('${d.property}: ${expression};');
|
||||||
|
});
|
||||||
|
|
||||||
|
final style = new EmulatedCssStyleDeclaration()
|
||||||
|
..cssText = declarationText.toString();
|
||||||
|
|
||||||
|
this
|
||||||
|
..type = 1
|
||||||
|
..cssText = ruleSet.span.text
|
||||||
|
..selectorText = ruleSet.selectorGroup.span.text
|
||||||
|
..style = style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emulates [CSSStyleDeclaration](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration)
|
||||||
|
class EmulatedCssStyleDeclaration {
|
||||||
|
final String content = '';
|
||||||
|
String cssText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emulates [CSSMediaRule](https://developer.mozilla.org/en-US/docs/Web/API/CSSMediaRule)
|
||||||
|
class EmulatedCssMedialRule extends EmulatedCssRule {
|
||||||
|
List<EmulatedCssStyleRule> cssRules;
|
||||||
|
EmulatedMediaList media;
|
||||||
|
|
||||||
|
EmulatedCssMedialRule(cssv.MediaDirective directive) {
|
||||||
|
this
|
||||||
|
..type = 4
|
||||||
|
..media = new EmulatedMediaList(directive)
|
||||||
|
..cssText = directive.span.text
|
||||||
|
..cssRules = emulateRules(directive.rulesets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emulates [MediaList](https://developer.mozilla.org/en-US/docs/Web/API/MediaList)
|
||||||
|
class EmulatedMediaList {
|
||||||
|
String mediaText;
|
||||||
|
|
||||||
|
EmulatedMediaList(cssv.MediaDirective directive) {
|
||||||
|
this.mediaText = directive.mediaQueries
|
||||||
|
.map((q) => q.span.text).join(' and ');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
library angular2.compiler.shadow_css_html5lib.test;
|
||||||
|
|
||||||
|
import 'package:angular2/src/core/dom/html_adapter.dart';
|
||||||
|
import 'package:angular2/src/test_lib/test_lib.dart' show testSetup;
|
||||||
|
import 'shadow_css_spec.dart' as shadow_css_spec_test;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
Html5LibDomAdapter.makeCurrent();
|
||||||
|
testSetup();
|
||||||
|
shadow_css_spec_test.main();
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ export function main() {
|
||||||
expect(s(css, 'a')).toEqual(expected);
|
expect(s(css, 'a')).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should hanlde invalid css', () => {
|
it('should handle invalid css', () => {
|
||||||
var css = 'one {color: red;}garbage';
|
var css = 'one {color: red;}garbage';
|
||||||
var expected = 'one[a] {color:red;}';
|
var expected = 'one[a] {color:red;}';
|
||||||
expect(s(css, 'a')).toEqual(expected);
|
expect(s(css, 'a')).toEqual(expected);
|
||||||
|
@ -58,8 +58,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check that the browser supports unprefixed CSS animation
|
// Check that the browser supports unprefixed CSS animation
|
||||||
if (isPresent(DOM.defaultDoc().body.style) &&
|
if (DOM.supportsUnprefixedCssAnimation()) {
|
||||||
isPresent(DOM.defaultDoc().body.style.animationName)) {
|
|
||||||
it('should handle keyframes rules', () => {
|
it('should handle keyframes rules', () => {
|
||||||
var css = '@keyframes foo {0% {transform: translate(-50%) scaleX(0);}}';
|
var css = '@keyframes foo {0% {transform: translate(-50%) scaleX(0);}}';
|
||||||
var passRe =
|
var passRe =
|
||||||
|
@ -80,9 +79,9 @@ export function main() {
|
||||||
it('should handle complicated selectors', () => {
|
it('should handle complicated selectors', () => {
|
||||||
expect(s('one::before {}', 'a')).toEqual('one[a]::before {}');
|
expect(s('one::before {}', 'a')).toEqual('one[a]::before {}');
|
||||||
expect(s('one two {}', 'a')).toEqual('one[a] two[a] {}');
|
expect(s('one two {}', 'a')).toEqual('one[a] two[a] {}');
|
||||||
expect(s('one>two {}', 'a')).toEqual('one[a] > two[a] {}');
|
expect(s('one > two {}', 'a')).toEqual('one[a] > two[a] {}');
|
||||||
expect(s('one+two {}', 'a')).toEqual('one[a] + two[a] {}');
|
expect(s('one + two {}', 'a')).toEqual('one[a] + two[a] {}');
|
||||||
expect(s('one~two {}', 'a')).toEqual('one[a] ~ two[a] {}');
|
expect(s('one ~ two {}', 'a')).toEqual('one[a] ~ two[a] {}');
|
||||||
var res = s('.one.two > three {}', 'a'); // IE swap classes
|
var res = s('.one.two > three {}', 'a'); // IE swap classes
|
||||||
expect(res == '.one.two[a] > three[a] {}' || res == '.two.one[a] > three[a] {}')
|
expect(res == '.one.two[a] > three[a] {}' || res == '.two.one[a] > three[a] {}')
|
||||||
.toEqual(true);
|
.toEqual(true);
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
library angular2.transform.stylesheet_compiler.processor;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||||
|
import 'package:angular2/src/transform/common/code/source_module.dart';
|
||||||
|
import 'package:angular2/src/transform/common/names.dart';
|
||||||
|
import 'package:angular2/src/transform/common/ng_compiler.dart';
|
||||||
|
import 'package:angular2/src/compiler/source_module.dart';
|
||||||
|
|
||||||
|
import 'package:barback/barback.dart';
|
||||||
|
|
||||||
|
AssetId shimmedStylesheetAssetId(AssetId cssAssetId) => new AssetId(
|
||||||
|
cssAssetId.package, toShimmedStylesheetExtension(cssAssetId.path));
|
||||||
|
|
||||||
|
AssetId nonShimmedStylesheetAssetId(AssetId cssAssetId) => new AssetId(
|
||||||
|
cssAssetId.package, toNonShimmedStylesheetExtension(cssAssetId.path));
|
||||||
|
|
||||||
|
Future<Iterable<Asset>> processStylesheet(
|
||||||
|
AssetReader reader, AssetId stylesheetId) async {
|
||||||
|
final stylesheetUrl = '${stylesheetId.package}|${stylesheetId.path}';
|
||||||
|
final templateCompiler = createTemplateCompiler(reader);
|
||||||
|
final cssText = await reader.readAsString(stylesheetId);
|
||||||
|
final sourceModules =
|
||||||
|
templateCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
|
||||||
|
|
||||||
|
var libraryIdx = 0;
|
||||||
|
return sourceModules.map((SourceModule module) => new Asset.fromString(
|
||||||
|
new AssetId.parse('${module.moduleUrl}'),
|
||||||
|
writeSourceModule(module,
|
||||||
|
libraryName: '${_getLibBase(module.moduleUrl)}${libraryIdx++}')));
|
||||||
|
}
|
||||||
|
|
||||||
|
final _unsafeCharsPattern = new RegExp(r'[^a-zA-Z0-9_]');
|
||||||
|
String _getLibBase(String libraryName) {
|
||||||
|
return libraryName.replaceAll('/', '.').replaceAll(_unsafeCharsPattern, '_');
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
library angular2.transform.stylesheet_compiler.transformer;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:angular2/src/core/dom/html_adapter.dart';
|
||||||
|
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||||
|
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||||
|
import 'package:angular2/src/transform/common/names.dart';
|
||||||
|
|
||||||
|
import 'package:barback/barback.dart';
|
||||||
|
|
||||||
|
import 'processor.dart';
|
||||||
|
|
||||||
|
/// Pre-compiles CSS stylesheet files to Dart code for Angular 2.
|
||||||
|
class StylesheetCompiler extends Transformer implements DeclaringTransformer {
|
||||||
|
StylesheetCompiler();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isPrimary(AssetId id) {
|
||||||
|
return id.path.endsWith(CSS_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
declareOutputs(DeclaringTransform transform) {
|
||||||
|
transform.declareOutput(nonShimmedStylesheetAssetId(transform.primaryId));
|
||||||
|
transform.declareOutput(shimmedStylesheetAssetId(transform.primaryId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future apply(Transform transform) async {
|
||||||
|
await log.initZoned(transform, () async {
|
||||||
|
Html5LibDomAdapter.makeCurrent();
|
||||||
|
var reader = new AssetReader.fromTransform(transform);
|
||||||
|
var outputs = await processStylesheet(reader, transform.primaryInput.id);
|
||||||
|
outputs.forEach((Asset compiledStylesheet) {
|
||||||
|
transform.addOutput(compiledStylesheet);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
name: ng2_transform
|
||||||
|
version: 0.0.0
|
||||||
|
environment:
|
||||||
|
sdk: '>=1.8.0 <2.0.0'
|
||||||
|
dependencies:
|
||||||
|
angular2:
|
||||||
|
path: ../../dist/dart/angular2
|
||||||
|
analyzer: '>=0.24.4 <0.27.0'
|
||||||
|
barback: '^0.15.2+2'
|
||||||
|
code_transformers: '^0.2.8'
|
||||||
|
dart_style: '>=0.1.8 <0.3.0'
|
||||||
|
glob: '^1.0.0'
|
||||||
|
guinness: any
|
||||||
|
html: '^0.12.0'
|
||||||
|
intl: '^0.12.4'
|
||||||
|
logging: '>=0.9.0 <0.12.0'
|
||||||
|
observe: '^0.13.1'
|
||||||
|
protobuf: '^0.4.2'
|
||||||
|
quiver: '^0.21.4'
|
||||||
|
source_span: '^1.0.0'
|
||||||
|
stack_trace: '^1.1.1'
|
||||||
|
dev_dependencies:
|
||||||
|
test: '>=0.12.0 <0.13.0'
|
|
@ -0,0 +1,96 @@
|
||||||
|
library angular2.test.transform.stylesheet_compiler.all_tests;
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:angular2/src/transform/stylesheet_compiler/transformer.dart';
|
||||||
|
|
||||||
|
import 'package:barback/barback.dart';
|
||||||
|
import 'package:guinness/guinness.dart';
|
||||||
|
|
||||||
|
const SIMPLE_CSS = '''
|
||||||
|
.foo {
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
Html5LibDomAdapter.makeCurrent();
|
||||||
|
allTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
allTests() {
|
||||||
|
StylesheetCompiler subject;
|
||||||
|
|
||||||
|
beforeEach(() {
|
||||||
|
subject = new StylesheetCompiler();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept CSS assets', () {
|
||||||
|
expect(subject.isPrimary(new AssetId('somepackage', 'lib/style.css')))
|
||||||
|
.toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject non-CSS assets', () {
|
||||||
|
expect(subject.isPrimary(new AssetId('somepackage', 'lib/style.scss')))
|
||||||
|
.toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should declare outputs', () {
|
||||||
|
var transform = new FakeDeclaringTransform()
|
||||||
|
..primaryId = new AssetId('somepackage', 'lib/style.css');
|
||||||
|
subject.declareOutputs(transform);
|
||||||
|
expect(transform.outputs.length).toBe(2);
|
||||||
|
expect(transform.outputs[0].toString())
|
||||||
|
.toEqual('somepackage|lib/style.css.dart');
|
||||||
|
expect(transform.outputs[1].toString())
|
||||||
|
.toEqual('somepackage|lib/style.css.shim.dart');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compile stylesheets', () async {
|
||||||
|
var cssFile = new Asset.fromString(
|
||||||
|
new AssetId('somepackage', 'lib/style.css'), SIMPLE_CSS);
|
||||||
|
var transform = new FakeTransform()..primaryInput = cssFile;
|
||||||
|
await subject.apply(transform);
|
||||||
|
expect(transform.outputs.length).toBe(2);
|
||||||
|
expect(transform.outputs[0].id.toString())
|
||||||
|
.toEqual('somepackage|lib/style.css.dart');
|
||||||
|
expect(transform.outputs[1].id.toString())
|
||||||
|
.toEqual('somepackage|lib/style.css.shim.dart');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
class FakeTransform implements Transform {
|
||||||
|
final outputs = <Asset>[];
|
||||||
|
Asset primaryInput;
|
||||||
|
|
||||||
|
addOutput(Asset output) {
|
||||||
|
this.outputs.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
readInputAsString(AssetId id, {Encoding encoding}) {
|
||||||
|
if (id == primaryInput.id) {
|
||||||
|
return primaryInput.readAsString(encoding: encoding);
|
||||||
|
}
|
||||||
|
throw 'Could not read input $id';
|
||||||
|
}
|
||||||
|
|
||||||
|
noSuchMethod(Invocation i) {
|
||||||
|
throw '${i.memberName} not implemented';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
class FakeDeclaringTransform implements DeclaringTransform {
|
||||||
|
final outputs = <AssetId>[];
|
||||||
|
AssetId primaryId;
|
||||||
|
|
||||||
|
declareOutput(AssetId output) {
|
||||||
|
this.outputs.add(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
noSuchMethod(Invocation i) {
|
||||||
|
throw '${i.memberName} not implemented';
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue