| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| part of '../visitor.dart'; | |
| // TODO(terry): Enable class for debug only; when conditional imports enabled. | |
| /// Helper function to dump the CSS AST. | |
| String treeToDebugString(StyleSheet styleSheet, [bool useSpan = false]) { | |
| var to = TreeOutput(); | |
| _TreePrinter(to, useSpan).visitTree(styleSheet); | |
| return to.toString(); | |
| } | |
| /// Tree dump for debug output of the CSS AST. | |
| class _TreePrinter extends Visitor { | |
| final TreeOutput output; | |
| final bool useSpan; | |
| _TreePrinter(this.output, this.useSpan) { | |
| output.printer = this; | |
| } | |
| @override | |
| void visitTree(StyleSheet tree) => visitStylesheet(tree); | |
| void heading(String heading, TreeNode node) { | |
| if (useSpan) { | |
| output.heading(heading, node.span); | |
| } else { | |
| output.heading(heading); | |
| } | |
| } | |
| void visitStylesheet(StyleSheet node) { | |
| heading('Stylesheet', node); | |
| output.depth++; | |
| super.visitStyleSheet(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitTopLevelProduction(TopLevelProduction node) { | |
| heading('TopLevelProduction', node); | |
| } | |
| @override | |
| void visitDirective(Directive node) { | |
| heading('Directive', node); | |
| } | |
| @override | |
| void visitCalcTerm(CalcTerm node) { | |
| heading('CalcTerm', node); | |
| output.depth++; | |
| super.visitCalcTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitCssComment(CssComment node) { | |
| heading('Comment', node); | |
| output.depth++; | |
| output.writeValue('comment value', node.comment); | |
| output.depth--; | |
| } | |
| @override | |
| void visitCommentDefinition(CommentDefinition node) { | |
| heading('CommentDefinition (CDO/CDC)', node); | |
| output.depth++; | |
| output.writeValue('comment value', node.comment); | |
| output.depth--; | |
| } | |
| @override | |
| void visitMediaExpression(MediaExpression node) { | |
| heading('MediaExpression', node); | |
| output.writeValue('feature', node.mediaFeature); | |
| if (node.andOperator) output.writeValue('AND operator', ''); | |
| visitExpressions(node.exprs); | |
| } | |
| void visitMediaQueries(MediaQuery query) { | |
| output.heading('MediaQueries'); | |
| output.writeValue('unary', query.unary); | |
| output.writeValue('media type', query.mediaType); | |
| output.writeNodeList('media expressions', query.expressions); | |
| } | |
| @override | |
| void visitMediaDirective(MediaDirective node) { | |
| heading('MediaDirective', node); | |
| output.depth++; | |
| output.writeNodeList('media queries', node.mediaQueries); | |
| output.writeNodeList('rule sets', node.rules); | |
| super.visitMediaDirective(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitDocumentDirective(DocumentDirective node) { | |
| heading('DocumentDirective', node); | |
| output.depth++; | |
| output.writeNodeList('functions', node.functions); | |
| output.writeNodeList('group rule body', node.groupRuleBody); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSupportsDirective(SupportsDirective node) { | |
| heading('SupportsDirective', node); | |
| output.depth++; | |
| output.writeNode('condition', node.condition); | |
| output.writeNodeList('group rule body', node.groupRuleBody); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSupportsConditionInParens(SupportsConditionInParens node) { | |
| heading('SupportsConditionInParens', node); | |
| output.depth++; | |
| output.writeNode('condition', node.condition); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSupportsNegation(SupportsNegation node) { | |
| heading('SupportsNegation', node); | |
| output.depth++; | |
| output.writeNode('condition', node.condition); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSupportsConjunction(SupportsConjunction node) { | |
| heading('SupportsConjunction', node); | |
| output.depth++; | |
| output.writeNodeList('conditions', node.conditions); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSupportsDisjunction(SupportsDisjunction node) { | |
| heading('SupportsDisjunction', node); | |
| output.depth++; | |
| output.writeNodeList('conditions', node.conditions); | |
| output.depth--; | |
| } | |
| @override | |
| void visitViewportDirective(ViewportDirective node) { | |
| heading('ViewportDirective', node); | |
| output.depth++; | |
| super.visitViewportDirective(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitPageDirective(PageDirective node) { | |
| heading('PageDirective', node); | |
| output.depth++; | |
| output.writeValue('pseudo page', node._pseudoPage); | |
| super.visitPageDirective(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitCharsetDirective(CharsetDirective node) { | |
| heading('Charset Directive', node); | |
| output.writeValue('charset encoding', node.charEncoding); | |
| } | |
| @override | |
| void visitImportDirective(ImportDirective node) { | |
| heading('ImportDirective', node); | |
| output.depth++; | |
| output.writeValue('import', node.import); | |
| super.visitImportDirective(node); | |
| output.writeNodeList('media', node.mediaQueries); | |
| output.depth--; | |
| } | |
| @override | |
| void visitContentDirective(ContentDirective node) { | |
| print('ContentDirective not implemented'); | |
| } | |
| @override | |
| void visitKeyFrameDirective(KeyFrameDirective node) { | |
| heading('KeyFrameDirective', node); | |
| output.depth++; | |
| output.writeValue('keyframe', node.keyFrameName); | |
| output.writeValue('name', node.name); | |
| output.writeNodeList('blocks', node._blocks); | |
| output.depth--; | |
| } | |
| @override | |
| void visitKeyFrameBlock(KeyFrameBlock node) { | |
| heading('KeyFrameBlock', node); | |
| output.depth++; | |
| super.visitKeyFrameBlock(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitFontFaceDirective(FontFaceDirective node) { | |
| // TODO(terry): To Be Implemented | |
| } | |
| @override | |
| void visitStyletDirective(StyletDirective node) { | |
| heading('StyletDirective', node); | |
| output.writeValue('dartClassName', node.dartClassName); | |
| output.depth++; | |
| output.writeNodeList('rulesets', node.rules); | |
| output.depth--; | |
| } | |
| @override | |
| void visitNamespaceDirective(NamespaceDirective node) { | |
| heading('NamespaceDirective', node); | |
| output.depth++; | |
| output.writeValue('prefix', node._prefix); | |
| output.writeValue('uri', node._uri); | |
| output.depth--; | |
| } | |
| @override | |
| void visitVarDefinitionDirective(VarDefinitionDirective node) { | |
| heading('Less variable definition', node); | |
| output.depth++; | |
| visitVarDefinition(node.def); | |
| output.depth--; | |
| } | |
| @override | |
| void visitMixinRulesetDirective(MixinRulesetDirective node) { | |
| heading('Mixin top-level ${node.name}', node); | |
| output.writeNodeList('parameters', node.definedArgs); | |
| output.depth++; | |
| _visitNodeList(node.rulesets); | |
| output.depth--; | |
| } | |
| @override | |
| void visitMixinDeclarationDirective(MixinDeclarationDirective node) { | |
| heading('Mixin declaration ${node.name}', node); | |
| output.writeNodeList('parameters', node.definedArgs); | |
| output.depth++; | |
| visitDeclarationGroup(node.declarations); | |
| output.depth--; | |
| } | |
| /// Added optional newLine for handling @include at top-level vs/ inside of | |
| /// a declaration group. | |
| @override | |
| void visitIncludeDirective(IncludeDirective node) { | |
| heading('IncludeDirective ${node.name}', node); | |
| var flattened = node.args.expand((e) => e).toList(); | |
| output.writeNodeList('parameters', flattened); | |
| } | |
| @override | |
| void visitIncludeMixinAtDeclaration(IncludeMixinAtDeclaration node) { | |
| heading('IncludeMixinAtDeclaration ${node.include.name}', node); | |
| output.depth++; | |
| visitIncludeDirective(node.include); | |
| output.depth--; | |
| } | |
| @override | |
| void visitExtendDeclaration(ExtendDeclaration node) { | |
| heading('ExtendDeclaration', node); | |
| output.depth++; | |
| _visitNodeList(node.selectors); | |
| output.depth--; | |
| } | |
| @override | |
| void visitRuleSet(RuleSet node) { | |
| heading('Ruleset', node); | |
| output.depth++; | |
| super.visitRuleSet(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitDeclarationGroup(DeclarationGroup node) { | |
| heading('DeclarationGroup', node); | |
| output.depth++; | |
| output.writeNodeList('declarations', node.declarations); | |
| output.depth--; | |
| } | |
| @override | |
| void visitMarginGroup(MarginGroup node) { | |
| heading('MarginGroup', node); | |
| output.depth++; | |
| output.writeValue('@directive', node.margin_sym); | |
| output.writeNodeList('declarations', node.declarations); | |
| output.depth--; | |
| } | |
| @override | |
| void visitDeclaration(Declaration node) { | |
| heading('Declaration', node); | |
| output.depth++; | |
| if (node.isIE7) output.write('IE7 property'); | |
| output.write('property'); | |
| super.visitDeclaration(node); | |
| output.writeNode('expression', node.expression); | |
| if (node.important) { | |
| output.writeValue('!important', 'true'); | |
| } | |
| output.depth--; | |
| } | |
| @override | |
| void visitVarDefinition(VarDefinition node) { | |
| heading('Var', node); | |
| output.depth++; | |
| output.write('definition'); | |
| super.visitVarDefinition(node); | |
| output.writeNode('expression', node.expression); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSelectorGroup(SelectorGroup node) { | |
| heading('Selector Group', node); | |
| output.depth++; | |
| output.writeNodeList('selectors', node.selectors); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSelector(Selector node) { | |
| heading('Selector', node); | |
| output.depth++; | |
| output.writeNodeList( | |
| 'simpleSelectorsSequences', node.simpleSelectorSequences); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSimpleSelectorSequence(SimpleSelectorSequence node) { | |
| heading('SimpleSelectorSequence', node); | |
| output.depth++; | |
| if (node.isCombinatorNone) { | |
| output.writeValue('combinator', 'NONE'); | |
| } else if (node.isCombinatorDescendant) { | |
| output.writeValue('combinator', 'descendant'); | |
| } else if (node.isCombinatorPlus) { | |
| output.writeValue('combinator', '+'); | |
| } else if (node.isCombinatorGreater) { | |
| output.writeValue('combinator', '>'); | |
| } else if (node.isCombinatorTilde) { | |
| output.writeValue('combinator', '~'); | |
| } else { | |
| output.writeValue('combinator', 'ERROR UNKNOWN'); | |
| } | |
| super.visitSimpleSelectorSequence(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitNamespaceSelector(NamespaceSelector node) { | |
| heading('Namespace Selector', node); | |
| output.depth++; | |
| super.visitNamespaceSelector(node); | |
| visitSimpleSelector(node.nameAsSimpleSelector!); | |
| output.depth--; | |
| } | |
| @override | |
| void visitElementSelector(ElementSelector node) { | |
| heading('Element Selector', node); | |
| output.depth++; | |
| super.visitElementSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitAttributeSelector(AttributeSelector node) { | |
| heading('AttributeSelector', node); | |
| output.depth++; | |
| super.visitAttributeSelector(node); | |
| var tokenStr = node.matchOperatorAsTokenString(); | |
| output.writeValue('operator', '${node.matchOperator()} ($tokenStr)'); | |
| output.writeValue('value', node.valueToString()); | |
| output.depth--; | |
| } | |
| @override | |
| void visitIdSelector(IdSelector node) { | |
| heading('Id Selector', node); | |
| output.depth++; | |
| super.visitIdSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitClassSelector(ClassSelector node) { | |
| heading('Class Selector', node); | |
| output.depth++; | |
| super.visitClassSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitPseudoClassSelector(PseudoClassSelector node) { | |
| heading('Pseudo Class Selector', node); | |
| output.depth++; | |
| super.visitPseudoClassSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitPseudoElementSelector(PseudoElementSelector node) { | |
| heading('Pseudo Element Selector', node); | |
| output.depth++; | |
| super.visitPseudoElementSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) { | |
| heading('Pseudo Class Function Selector', node); | |
| output.depth++; | |
| node.argument.visit(this); | |
| super.visitPseudoClassFunctionSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) { | |
| heading('Pseudo Element Function Selector', node); | |
| output.depth++; | |
| visitSelectorExpression(node.expression); | |
| super.visitPseudoElementFunctionSelector(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitSelectorExpression(SelectorExpression node) { | |
| heading('Selector Expression', node); | |
| output.depth++; | |
| output.writeNodeList('expressions', node.expressions); | |
| output.depth--; | |
| } | |
| @override | |
| void visitNegationSelector(NegationSelector node) { | |
| super.visitNegationSelector(node); | |
| output.depth++; | |
| heading('Negation Selector', node); | |
| output.writeNode('Negation arg', node.negationArg); | |
| output.depth--; | |
| } | |
| @override | |
| void visitUnicodeRangeTerm(UnicodeRangeTerm node) { | |
| heading('UnicodeRangeTerm', node); | |
| output.depth++; | |
| output.writeValue('1st value', node.first); | |
| output.writeValue('2nd value', node.second); | |
| output.depth--; | |
| } | |
| @override | |
| void visitLiteralTerm(LiteralTerm node) { | |
| heading('LiteralTerm', node); | |
| output.depth++; | |
| output.writeValue('value', node.text); | |
| output.depth--; | |
| } | |
| @override | |
| void visitHexColorTerm(HexColorTerm node) { | |
| heading('HexColorTerm', node); | |
| output.depth++; | |
| output.writeValue('hex value', node.text); | |
| output.writeValue('decimal value', node.value); | |
| output.depth--; | |
| } | |
| @override | |
| void visitNumberTerm(NumberTerm node) { | |
| heading('NumberTerm', node); | |
| output.depth++; | |
| output.writeValue('value', node.text); | |
| output.depth--; | |
| } | |
| @override | |
| void visitUnitTerm(UnitTerm node) { | |
| output.depth++; | |
| output.writeValue('value', node.text); | |
| output.writeValue('unit', node.unitToString()); | |
| output.depth--; | |
| } | |
| @override | |
| void visitLengthTerm(LengthTerm node) { | |
| heading('LengthTerm', node); | |
| super.visitLengthTerm(node); | |
| } | |
| @override | |
| void visitPercentageTerm(PercentageTerm node) { | |
| heading('PercentageTerm', node); | |
| output.depth++; | |
| super.visitPercentageTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitEmTerm(EmTerm node) { | |
| heading('EmTerm', node); | |
| output.depth++; | |
| super.visitEmTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitExTerm(ExTerm node) { | |
| heading('ExTerm', node); | |
| output.depth++; | |
| super.visitExTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitAngleTerm(AngleTerm node) { | |
| heading('AngleTerm', node); | |
| super.visitAngleTerm(node); | |
| } | |
| @override | |
| void visitTimeTerm(TimeTerm node) { | |
| heading('TimeTerm', node); | |
| super.visitTimeTerm(node); | |
| } | |
| @override | |
| void visitFreqTerm(FreqTerm node) { | |
| heading('FreqTerm', node); | |
| super.visitFreqTerm(node); | |
| } | |
| @override | |
| void visitFractionTerm(FractionTerm node) { | |
| heading('FractionTerm', node); | |
| output.depth++; | |
| super.visitFractionTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitUriTerm(UriTerm node) { | |
| heading('UriTerm', node); | |
| output.depth++; | |
| super.visitUriTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitFunctionTerm(FunctionTerm node) { | |
| heading('FunctionTerm', node); | |
| output.depth++; | |
| super.visitFunctionTerm(node); | |
| output.depth--; | |
| } | |
| @override | |
| void visitGroupTerm(GroupTerm node) { | |
| heading('GroupTerm', node); | |
| output.depth++; | |
| output.writeNodeList('grouped terms', node._terms); | |
| output.depth--; | |
| } | |
| @override | |
| void visitItemTerm(ItemTerm node) { | |
| heading('ItemTerm', node); | |
| super.visitItemTerm(node); | |
| } | |
| @override | |
| void visitIE8Term(IE8Term node) { | |
| heading('IE8Term', node); | |
| visitLiteralTerm(node); | |
| } | |
| @override | |
| void visitOperatorSlash(OperatorSlash node) { | |
| heading('OperatorSlash', node); | |
| } | |
| @override | |
| void visitOperatorComma(OperatorComma node) { | |
| heading('OperatorComma', node); | |
| } | |
| @override | |
| void visitOperatorPlus(OperatorPlus node) { | |
| heading('OperatorPlus', node); | |
| } | |
| @override | |
| void visitOperatorMinus(OperatorMinus node) { | |
| heading('OperatorMinus', node); | |
| } | |
| @override | |
| void visitVarUsage(VarUsage node) { | |
| heading('Var', node); | |
| output.depth++; | |
| output.write('usage ${node.name}'); | |
| output.writeNodeList('default values', node.defaultValues); | |
| output.depth--; | |
| } | |
| @override | |
| void visitExpressions(Expressions node) { | |
| heading('Expressions', node); | |
| output.depth++; | |
| output.writeNodeList('expressions', node.expressions); | |
| output.depth--; | |
| } | |
| @override | |
| void visitBinaryExpression(BinaryExpression node) { | |
| heading('BinaryExpression', node); | |
| // TODO(terry): TBD | |
| } | |
| @override | |
| void visitUnaryExpression(UnaryExpression node) { | |
| heading('UnaryExpression', node); | |
| // TODO(terry): TBD | |
| } | |
| @override | |
| void visitIdentifier(Identifier node) { | |
| heading('Identifier(${output.toValue(node.name)})', node); | |
| } | |
| @override | |
| void visitWildcard(Wildcard node) { | |
| heading('Wildcard(*)', node); | |
| } | |
| @override | |
| void visitDartStyleExpression(DartStyleExpression node) { | |
| heading('DartStyleExpression', node); | |
| } | |
| @override | |
| void visitFontExpression(FontExpression node) { | |
| heading('Dart Style FontExpression', node); | |
| } | |
| @override | |
| void visitBoxExpression(BoxExpression node) { | |
| heading('Dart Style BoxExpression', node); | |
| } | |
| @override | |
| void visitMarginExpression(MarginExpression node) { | |
| heading('Dart Style MarginExpression', node); | |
| } | |
| @override | |
| void visitBorderExpression(BorderExpression node) { | |
| heading('Dart Style BorderExpression', node); | |
| } | |
| @override | |
| void visitHeightExpression(HeightExpression node) { | |
| heading('Dart Style HeightExpression', node); | |
| } | |
| @override | |
| void visitPaddingExpression(PaddingExpression node) { | |
| heading('Dart Style PaddingExpression', node); | |
| } | |
| @override | |
| void visitWidthExpression(WidthExpression node) { | |
| heading('Dart Style WidthExpression', node); | |
| } | |
| } |