From ffb85921cbc8fc49e83f4715c10eadcca139ff64 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Sun, 28 Aug 2016 17:12:03 -0700 Subject: [PATCH] Buggy implementation of CSS @import. --- lib/src/ast/css.dart | 1 + lib/src/ast/css/import.dart | 18 ++++++++++++++++ lib/src/ast/sass.dart | 1 + lib/src/ast/sass/statement/plain_import.dart | 22 ++++++++++++++++++++ lib/src/parser.dart | 21 ++++++++++++++++--- lib/src/visitor/interface/css.dart | 1 + lib/src/visitor/interface/statement.dart | 1 + lib/src/visitor/perform.dart | 3 +++ lib/src/visitor/serialize.dart | 7 +++++++ 9 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 lib/src/ast/css/import.dart create mode 100644 lib/src/ast/sass/statement/plain_import.dart diff --git a/lib/src/ast/css.dart b/lib/src/ast/css.dart index fe975e5f..b463388a 100644 --- a/lib/src/ast/css.dart +++ b/lib/src/ast/css.dart @@ -5,6 +5,7 @@ export 'css/at_rule.dart'; export 'css/comment.dart'; export 'css/declaration.dart'; +export 'css/import.dart'; export 'css/media_query.dart'; export 'css/media_rule.dart'; export 'css/node.dart'; diff --git a/lib/src/ast/css/import.dart b/lib/src/ast/css/import.dart new file mode 100644 index 00000000..7cfb7511 --- /dev/null +++ b/lib/src/ast/css/import.dart @@ -0,0 +1,18 @@ +// Copyright 2016 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:source_span/source_span.dart'; + +import '../../visitor/interface/css.dart'; +import 'node.dart'; + +class CssImport extends CssNode { + final Uri url; + + final FileSpan span; + + CssImport(this.url, this.span); + + /*=T*/ accept/**/(CssVisitor/**/ visitor) => visitor.visitImport(this); +} diff --git a/lib/src/ast/sass.dart b/lib/src/ast/sass.dart index 0d757869..2775d120 100644 --- a/lib/src/ast/sass.dart +++ b/lib/src/ast/sass.dart @@ -33,6 +33,7 @@ export 'sass/statement/import.dart'; export 'sass/statement/include.dart'; export 'sass/statement/media_rule.dart'; export 'sass/statement/mixin_declaration.dart'; +export 'sass/statement/plain_import.dart'; export 'sass/statement/return.dart'; export 'sass/statement/style_rule.dart'; export 'sass/statement/stylesheet.dart'; diff --git a/lib/src/ast/sass/statement/plain_import.dart b/lib/src/ast/sass/statement/plain_import.dart new file mode 100644 index 00000000..7b242337 --- /dev/null +++ b/lib/src/ast/sass/statement/plain_import.dart @@ -0,0 +1,22 @@ +// Copyright 2016 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:source_span/source_span.dart'; + +import '../../../visitor/interface/statement.dart'; +import '../expression/string.dart'; +import '../statement.dart'; + +class PlainImport implements Statement { + final Uri url; + + final FileSpan span; + + PlainImport(this.url, this.span); + + /*=T*/ accept/**/(StatementVisitor/**/ visitor) => + visitor.visitPlainImport(this); + + String toString() => "@import ${StringExpression.quoteText(url.toString())};"; +} diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 98092ea9..fc78afa0 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -395,17 +395,32 @@ class Parser { return new If(expression, children, _scanner.spanFrom(start)); } - Import _import(LineScannerState start) { + Statement _import(LineScannerState start) { if (_inControlDirective) { _disallowedAtRule(start); return null; + } + + // TODO: wrap error with a span + // TODO: parse supports clauses, url(), and query lists + var urlString = _string(static: true).text.asPlain; + var url = Uri.parse(urlString); + if (_isPlainImportUrl(urlString)) { + return new PlainImport(url, _scanner.spanFrom(start)); } else { - // TODO: wrap error with a span - var url = Uri.parse(_string(static: true).text.asPlain); return new Import(url, _scanner.spanFrom(start)); } } + bool _isPlainImportUrl(String url) { + if (url.length < "//".length) return false; + + var first = url.codeUnitAt(0); + if (first == $slash) return url.codeUnitAt(1) == $slash; + if (first != $h) return false; + return url.startsWith("http://") || url.startsWith("https://"); + } + Include _include(LineScannerState start) { var name = _identifier(); _ignoreComments(); diff --git a/lib/src/visitor/interface/css.dart b/lib/src/visitor/interface/css.dart index c7993ed6..94b3c1a5 100644 --- a/lib/src/visitor/interface/css.dart +++ b/lib/src/visitor/interface/css.dart @@ -10,6 +10,7 @@ abstract class CssVisitor extends SelectorVisitor implements ValueVisitor { T visitComment(CssComment node) => null; T visitDeclaration(CssDeclaration node) => null; + T visitImport(CssImport node) => null; T visitAtRule(CssAtRule node) { if (node.children == null) return null; diff --git a/lib/src/visitor/interface/statement.dart b/lib/src/visitor/interface/statement.dart index 90c0dfbc..cf8acd62 100644 --- a/lib/src/visitor/interface/statement.dart +++ b/lib/src/visitor/interface/statement.dart @@ -9,6 +9,7 @@ abstract class StatementVisitor { T visitContent(Content node) => null; T visitExtendRule(ExtendRule node) => null; T visitImport(Import node) => null; + T visitPlainImport(PlainImport node) => null; T visitReturn(Return node) => null; T visitVariableDeclaration(VariableDeclaration node) => null; diff --git a/lib/src/visitor/perform.dart b/lib/src/visitor/perform.dart index a6074356..24073165 100644 --- a/lib/src/visitor/perform.dart +++ b/lib/src/visitor/perform.dart @@ -291,6 +291,9 @@ class PerformVisitor extends StatementVisitor return new CssMediaQuery(type, modifier: modifier, features: features); } + CssImport visitPlainImport(PlainImport node) => + new CssImport(node.url, node.span); + Value visitReturn(Return node) => node.expression.accept(this); void visitStyleRule(StyleRule node) { diff --git a/lib/src/visitor/serialize.dart b/lib/src/visitor/serialize.dart index e2e45aba..ca6cda66 100644 --- a/lib/src/visitor/serialize.dart +++ b/lib/src/visitor/serialize.dart @@ -95,6 +95,13 @@ class _SerializeCssVisitor extends CssVisitor { _visitChildren(node.children); } + void visitImport(CssImport node) { + _writeIndentation(); + _buffer.write("@import "); + _visitString(node.url.toString()); + _buffer.writeCharCode($semicolon); + } + void visitMediaQuery(CssMediaQuery query) { if (query.modifier != null) { _buffer.write(query.modifier.value);