protected Ruleset(NodeList<Selector> selectors, NodeList rules, Ruleset originalRuleset) : this() { Selectors = selectors; Rules = rules; OriginalRuleset = originalRuleset ?? this; }
public List<Closure> Find(Env env, Selector selector, Ruleset self) { self = self ?? this; var rules = new List<Closure>(); var key = selector.ToCSS(env); if (_lookups.ContainsKey(key)) return _lookups[key]; foreach (var rule in Rulesets().Where(rule => rule != self)) { if (rule.Selectors && rule.Selectors.Any(selector.Match)) { if (selector.Elements.Count > 1) { var remainingSelectors = new Selector(new NodeList<Element>(selector.Elements.Skip(1))); var closures = rule.Find(env, remainingSelectors, self); foreach (var closure in closures) { closure.Context.Insert(0, rule); } rules.AddRange(closures); } else rules.Add(new Closure { Ruleset = rule, Context = new List<Ruleset> { rule } }); } } return _lookups[key] = rules; }
public override Node Evaluate(Env env) { // create a clone so it is non destructive Ruleset clone = new Ruleset(Selectors, new NodeList(Rules), this.OriginalRuleset) .ReducedFrom<Ruleset>(this); clone.EvaluateRules(env); return clone; }
public Ruleset Evaluate(NodeList<Expression> args, Env env, List<Ruleset> closureContext) { if (args) Guard.ExpectMaxArguments(Params.Count, args.Count, String.Format("'{0}'", Name), Index); var frame = new Ruleset(null, new List<Node>()); for (var i = 0; i < Params.Count; i++) { if (!String.IsNullOrEmpty(Params[i].Name)) { Node val; if (args && i < args.Count) val = args[i]; else val = Params[i].Value; if (val) frame.Rules.Add(new Rule(Params[i].Name, val.Evaluate(env)) { Index = val.Index }); else throw new ParsingException(String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args.Count, _arity), Index); } } var frames = new[] { this, frame }.Concat(env.Frames).Concat(closureContext).Reverse(); var context = new Env {Frames = new Stack<Ruleset>(frames)}; var newRules = new List<Node>(); foreach (var rule in Rules) { if (rule is MixinDefinition) { var mixin = rule as MixinDefinition; var parameters = Enumerable.Concat(mixin.Params, frame.Rules.Cast<Rule>()); newRules.Add(new MixinDefinition(mixin.Name, new NodeList<Rule>(parameters), mixin.Rules)); } else if (rule is Ruleset) { var ruleset = (rule as Ruleset); var rules = ruleset.EvaluateRules(context); newRules.Add(new Ruleset(ruleset.Selectors, rules)); } else if (rule is MixinCall) { newRules.AddRange((NodeList) rule.Evaluate(context)); } else { newRules.Add(rule.Evaluate(context)); } } return new Ruleset(null, newRules); }
/// <summary> /// Simple case for the top media node being evaluated /// </summary> protected Node EvalTop(Env env) { Node result; // Render all dependent Media blocks. if (env.MediaBlocks.Count > 1) { result = new Ruleset(GetEmptySelector(), new NodeList(env.MediaBlocks.Cast<Node>())) { MultiMedia = true } .ReducedFrom<Ruleset>(this); } else { result = env.MediaBlocks[0]; } env.MediaPath.Clear(); env.MediaBlocks.Clear(); return result; }
private static IEnumerable<DocumentedRule> ExtractRulesRecursively(Ruleset rules) { var documentedRules = new List<DocumentedRule>(); var iterator = rules.Rules.GetEnumerator(); while (iterator.MoveNext()) { if (iterator.Current is Import) { var import = (Import)iterator.Current; var importedRules = ExtractRulesRecursively(import.InnerRoot); documentedRules.AddRange(importedRules); } else if (iterator.Current is Comment) { var comment = JoinConsecutiveComments(iterator); var ruleset = iterator.Current as Ruleset; if (ruleset != null) { documentedRules.Add(new DocumentedRule(string.Join(", ", ruleset.Selectors.Select(s => s.ToString().Trim())), comment)); } } } return documentedRules; }
public Media(Node features, NodeList rules) { Features = features; Ruleset = new Ruleset(GetEmptySelector(), rules); }
public override Node Evaluate(Env env) { if(Evaluated) return this; // create a clone so it is non destructive var clone = new Ruleset(new NodeList<Selector>(Selectors), new NodeList(Rules), OriginalRuleset).ReducedFrom<Ruleset>(this); clone.EvaluateRules(env); clone.Evaluated = true; return clone; }
public List <Closure> Find <TRuleset>(Env env, Selector selector, Ruleset self) where TRuleset : Ruleset { self = self ?? this; var rules = new List <Closure>(); var key = typeof(TRuleset).ToString() + ":" + selector.ToCSS(env); if (_lookups.ContainsKey(key)) { return(_lookups[key]); } var validRulesets = Rulesets().Where(rule => { if (!typeof(TRuleset).IsAssignableFrom(rule.GetType())) { return(false); } if (rule != self) { return(true); } MixinDefinition mixinRule = rule as MixinDefinition; if (mixinRule != null) { return(mixinRule.Condition != null); } return(false); }); foreach (var rule in validRulesets) { if (rule.Selectors && rule.Selectors.Any(selector.Match)) { if ((selector.Elements.Count == 1) || rule.Selectors.Any(s => s.ToCSS(new Env()) == selector.ToCSS(new Env()))) { rules.Add(new Closure { Ruleset = rule, Context = new List <Ruleset> { rule } }); } else if (selector.Elements.Count > 1) { var remainingSelectors = new Selector(new NodeList <Element>(selector.Elements.Skip(1))); var closures = rule.Find <Ruleset>(env, remainingSelectors, self); foreach (var closure in closures) { closure.Context.Insert(0, rule); } rules.AddRange(closures); } } } return(_lookups[key] = rules); }
public Ruleset EvaluateParams(Env env, List<NamedArgument> args) { var arguments = new Dictionary<string, Node>(); args = args ?? new List<NamedArgument>(); var hasNamedArgs = false; foreach (var arg in args) { if (!string.IsNullOrEmpty(arg.Name)) { hasNamedArgs = true; arguments[arg.Name] = new Rule(arg.Name, arg.Value.Evaluate(env)) { Location = arg.Value.Location }; } else if (hasNamedArgs) throw new ParsingException("Positional arguments must appear before all named arguments.", arg.Value.Location); } for (var i = 0; i < Params.Count; i++) { if (String.IsNullOrEmpty(Params[i].Name)) continue; if (arguments.ContainsKey(Params[i].Name)) continue; Node val; if (i < args.Count && string.IsNullOrEmpty(args[i].Name)) val = args[i].Value; else { //evaluate in scope of mixin definition? val = Params[i].Value; } if (val) { Node argRuleValue; if (Params[i].Variadic) { NodeList varArgs = new NodeList(); for (int j = i; j < args.Count; j++) { varArgs.Add(args[j].Value.Evaluate(env)); } argRuleValue = (new Expression(varArgs)).Evaluate(env); } else { argRuleValue = val.Evaluate(env); } arguments[Params[i].Name] = new Rule(Params[i].Name, argRuleValue) { Location = val.Location }; } else throw new ParsingException( String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args != null ? args.Count : 0, _arity), Location); } var argumentNodes = new List<Node>(); for(var i = 0; i < Math.Max(Params.Count, args.Count); i++) { argumentNodes.Add(i < args.Count ? args[i].Value : Params[i].Value); } var frame = new Ruleset(new NodeList<Selector>(), new NodeList()); frame.Rules.Insert(0, new Rule("@arguments", new Expression(argumentNodes.Where(a => a != null)).Evaluate(env))); foreach (var arg in arguments) { frame.Rules.Add(arg.Value); } return frame; }
/// <summary> /// Evaluate when you have a media inside another media /// </summary> protected Node EvalNested(Env env, Node features, Ruleset ruleset) { var path = new NodeList<Media>(env.MediaPath.ToList()); path.Add(this); NodeList<NodeList> derivedPath = new NodeList<NodeList>(); // Extract the media-query conditions separated with `,` (OR). for (int i = 0; i < path.Count; i++) { Node pathComponent; Value value = path[i].Features as Value; if (value != null) { pathComponent = value.Values; } else { pathComponent = path[i].Features; } derivedPath.Add((pathComponent as NodeList) ?? new NodeList() { pathComponent }); } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e NodeList<NodeList> pathWithAnds = new NodeList<NodeList>(); foreach (NodeList node in derivedPath) { pathWithAnds.Add(node); pathWithAnds.Add(new NodeList() { new TextNode("and") }); } pathWithAnds.RemoveAt(pathWithAnds.Count - 1); Features = new Value(Permute(pathWithAnds), null); // Fake a tree-node that doesn't output anything. return new Ruleset(new NodeList<Selector>(), new NodeList()); }
/// <summary> /// Copies selectors to media statements currently bubbling up, so they are not lost /// </summary> /// <param name="selectors"></param> public void BubbleSelectors(NodeList<Selector> selectors) { Ruleset = new Ruleset(new NodeList<Selector>(selectors), new NodeList() { Ruleset }); }
private Ruleset MakeRulesetImportant(Ruleset ruleset) { return new Ruleset(ruleset.Selectors, MakeRulesImportant(ruleset.Rules)).ReducedFrom<Ruleset>(ruleset); }
protected Root(NodeList rules, Func <ParsingException, ParserException> error, Ruleset master) : base(new NodeList <Selector>(), rules, master) { Error = error; }
private Ruleset MakeRulesetImportant(Ruleset ruleset) { return(new Ruleset(ruleset.Selectors, MakeRulesImportant(ruleset.Rules)).ReducedFrom <Ruleset>(ruleset)); }
public RuleExtractor(string fileName) { var parser = new Parser(new PlainStylizer(), new Importer(new FileReader(new RelativeToFileLocationResolver(fileName)))); rules = parser.Parse(File.ReadAllText(fileName), fileName); }
public Media(Node features, Ruleset ruleset, List <Extender> extensions) { Features = features; Ruleset = ruleset; Extensions = extensions ?? new List <Extender>(); }
public override void AppendCSS(Env env, Context ctx) { if (env.Compress && !Ruleset.Rules.Any()) { return; } // first deal with the contents, in case its empty env.Output.Push(); Ruleset.IsRoot = ctx.Count == 0; //Track the last media block being appended for extender filters env.ExtendMediaScope.Push(this); // Set the current feeatures to filter extenders Ruleset.AppendCSS(env, ctx); env.ExtendMediaScope.Pop(); if (!env.Compress) { env.Output.Trim().Indent(2); } var contents = env.Output.Pop(); // If we're the result of a reference import and none of the rulesets // have been unmarked as references, skip the whole block. if (IsReference && Ruleset.Rules.All(r => r.IsReference)) { return; } // if we have no contents, skip if (env.Compress && contents.Length == 0) { return; } // go ahead and output env.Output.Append("@media"); if (Features) { env.Output.Append(' '); env.Output.Append(Features); } if (env.Compress) { env.Output.Append('{'); } else { env.Output.Append(" {\n"); } env.Output.Append(contents); if (env.Compress) { env.Output.Append('}'); } else { env.Output.Append("\n}\n"); } }
public Media(Node features, Ruleset ruleset) { Features = features; Ruleset = ruleset; }
public Ruleset Evaluate(List <NamedArgument> args, Env env, List <Ruleset> closureContext) { // if (args != null && args.Any()) // Guard.ExpectMaxArguments(Params.Count, args.Count, String.Format("'{0}'", Name), Index); var arguments = new Dictionary <string, Node>(); args = args ?? new List <NamedArgument>(); var hasNamedArgs = false; foreach (var arg in args) { if (!string.IsNullOrEmpty(arg.Name)) { hasNamedArgs = true; arguments[arg.Name] = new Rule(arg.Name, arg.Value.Evaluate(env)) { Index = arg.Value.Index }; } else if (hasNamedArgs) { throw new ParsingException("Positional arguments must appear before all named arguments.", arg.Value.Index); } } for (var i = 0; i < Params.Count; i++) { if (String.IsNullOrEmpty(Params[i].Name)) { continue; } if (arguments.ContainsKey(Params[i].Name)) { continue; } Node val; if (i < args.Count && string.IsNullOrEmpty(args[i].Name)) { val = args[i].Value; } else { val = Params[i].Value; } if (val) { arguments[Params[i].Name] = new Rule(Params[i].Name, val.Evaluate(env)) { Index = val.Index } } ; else { throw new ParsingException( String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args != null ? args.Count : 0, _arity), Index); } } var _arguments = new List <Node>(); for (var i = 0; i < Math.Max(Params.Count, args.Count); i++) { _arguments.Add(i < args.Count ? args[i].Value : Params[i].Value); } var frame = new Ruleset(null, new NodeList()); frame.Rules.Insert(0, new Rule("@arguments", new Expression(_arguments.Where(a => a != null)).Evaluate(env))); foreach (var arg in arguments) { frame.Rules.Add(arg.Value); } var frames = new[] { this, frame }.Concat(env.Frames).Concat(closureContext).Reverse(); var context = env.CreateChildEnv(new Stack <Ruleset>(frames)); var newRules = new NodeList(); foreach (var rule in Rules) { if (rule is MixinDefinition) { var mixin = rule as MixinDefinition; var parameters = Enumerable.Concat(mixin.Params, frame.Rules.Cast <Rule>()); newRules.Add(new MixinDefinition(mixin.Name, new NodeList <Rule>(parameters), mixin.Rules)); } else if (rule is Directive) { newRules.Add(rule); } else if (rule is Ruleset) { var ruleset = (rule as Ruleset); context.Frames.Push(ruleset); var rules = new NodeList(NodeHelper.NonDestructiveExpandNodes <MixinCall>(context, ruleset.Rules) .Select(r => r.Evaluate(context))); context.Frames.Pop(); newRules.Add(new Ruleset(ruleset.Selectors, rules)); } else if (rule is MixinCall) { newRules.AddRange((NodeList)rule.Evaluate(context)); } else { newRules.Add(rule.Evaluate(context)); } } return(new Ruleset(null, newRules)); }
protected Ruleset() { _lookups = new Dictionary <string, List <Closure> >(); OriginalRuleset = this; }
public List<Closure> Find(Env env, Selector selector, Ruleset self) { self = self ?? this; var rules = new List<Closure>(); var key = selector.ToCSS(env); if (_lookups.ContainsKey(key)) return _lookups[key]; for(var x = 0; x < Rulesets.Count; x++) { var rule = Rulesets[x]; if (rule == self) continue; if(rule.Selectors && _AnyMatch(rule.Selectors, selector)) { if (selector.Elements.Count > 1) { var remainingSelectors = new Selector(new NodeList<Element>(selector.Elements.Skip(1))); var closures = rule.Find(env, remainingSelectors, self); for (var i = 0; i < closures.Count; i++) { var closure = closures[i]; closure.Context.Insert(0, rule); } rules.AddRange(closures); } else { rules.Add(new Closure { Ruleset = rule, Context = new List<Ruleset> { rule } }); } } } return _lookups[key] = rules; }
public Ruleset Evaluate(List<NamedArgument> args, Env env, List<Ruleset> closureContext) { // if (args != null && args.Any()) // Guard.ExpectMaxArguments(Params.Count, args.Count, String.Format("'{0}'", Name), Index); var arguments = new Dictionary<string, Node>(); args = args ?? new List<NamedArgument>(); var hasNamedArgs = false; foreach (var arg in args) { if (!string.IsNullOrEmpty(arg.Name)) { hasNamedArgs = true; arguments[arg.Name] = new Rule(arg.Name, arg.Value.Evaluate(env)) { Index = arg.Value.Index }; } else if (hasNamedArgs) throw new ParsingException("Positional arguments must appear before all named arguments.", arg.Value.Index); } for (var i = 0; i < Params.Count; i++) { if (String.IsNullOrEmpty(Params[i].Name)) continue; if (arguments.ContainsKey(Params[i].Name)) continue; Node val; if (i < args.Count && string.IsNullOrEmpty(args[i].Name)) val = args[i].Value; else val = Params[i].Value; if (val) arguments[Params[i].Name] = new Rule(Params[i].Name, val.Evaluate(env)) {Index = val.Index}; else throw new ParsingException( String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args != null ? args.Count : 0, _arity), Index); } var _arguments = new List<Node>(); for(var i = 0; i < Math.Max(Params.Count, args.Count); i++) { _arguments.Add(i < args.Count ? args[i].Value : Params[i].Value); } var frame = new Ruleset(null, new NodeList()); frame.Rules.Insert(0, new Rule("@arguments", new Expression(_arguments.Where(a => a != null)).Evaluate(env))); foreach (var arg in arguments) { frame.Rules.Add(arg.Value); } var frames = new[] { this, frame }.Concat(env.Frames).Concat(closureContext).Reverse(); var context = new Env {Frames = new Stack<Ruleset>(frames)}; var newRules = new NodeList(); foreach (var rule in Rules) { if (rule is MixinDefinition) { var mixin = rule as MixinDefinition; var parameters = Enumerable.Concat(mixin.Params, frame.Rules.Cast<Rule>()); newRules.Add(new MixinDefinition(mixin.Name, new NodeList<Rule>(parameters), mixin.Rules)); } else if (rule is Ruleset) { var ruleset = (rule as Ruleset); context.Frames.Push(ruleset); var rules = new NodeList(NodeHelper.NonDestructiveExpandNodes<MixinCall>(context, ruleset.Rules) .Select(r => r.Evaluate(context))); context.Frames.Pop(); newRules.Add(new Ruleset(ruleset.Selectors, rules)); } else if (rule is MixinCall) { newRules.AddRange((NodeList) rule.Evaluate(context)); } else { newRules.Add(rule.Evaluate(context)); } } return new Ruleset(null, newRules); }
protected Root(NodeList rules, Func<ParsingException, ParserException> error, Ruleset master) : base(new NodeList<Selector>(), rules, master) { Error = error; IsRoot = true; }
public Media(Node features, Ruleset ruleset, List<Extender> extensions) { Features = features; Ruleset = ruleset; Extensions = extensions ?? new List<Extender>(); }
public Ruleset Evaluate(NodeList <Expression> args, Env env, List <Ruleset> closureContext) { if (args) { Guard.ExpectMaxArguments(Params.Count, args.Count, String.Format("'{0}'", Name), Index); } var frame = new Ruleset(null, new List <Node>()); for (var i = 0; i < Params.Count; i++) { if (!String.IsNullOrEmpty(Params[i].Name)) { Node val; if (args && i < args.Count) { val = args[i]; } else { val = Params[i].Value; } if (val) { frame.Rules.Add(new Rule(Params[i].Name, val.Evaluate(env)) { Index = val.Index }); } else { throw new ParsingException(String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args.Count, _arity), Index); } } } var frames = new[] { this, frame }.Concat(env.Frames).Concat(closureContext).Reverse(); var context = new Env { Frames = new Stack <Ruleset>(frames) }; var newRules = new List <Node>(); foreach (var rule in Rules) { if (rule is MixinDefinition) { var mixin = rule as MixinDefinition; var parameters = Enumerable.Concat(mixin.Params, frame.Rules.Cast <Rule>()); newRules.Add(new MixinDefinition(mixin.Name, new NodeList <Rule>(parameters), mixin.Rules)); } else if (rule is Ruleset) { var ruleset = (rule as Ruleset); context.Frames.Push(ruleset); var rules = NodeHelper.NonDestructiveExpandNodes <MixinCall>(context, ruleset.Rules) .Select(r => r.Evaluate(context)).ToList(); context.Frames.Pop(); newRules.Add(new Ruleset(ruleset.Selectors, rules)); } else if (rule is MixinCall) { newRules.AddRange((NodeList)rule.Evaluate(context)); } else { newRules.Add(rule.Evaluate(context)); } } return(new Ruleset(null, newRules)); }
public override void Accept(Plugins.IVisitor visitor) { Features = VisitAndReplace(Features, visitor); Ruleset = VisitAndReplace(Ruleset, visitor); }
/// <summary> /// returns whether this rulset is equal to or cloned from another ruleset /// </summary> public bool IsEqualOrClonedFrom(Ruleset ruleset) { return(ruleset.OriginalRuleset == OriginalRuleset); }
/// <summary> /// returns whether this rulset is equal to or cloned from another ruleset /// </summary> public bool IsEqualOrClonedFrom(Ruleset ruleset) { return ruleset.OriginalRuleset == OriginalRuleset; }
protected override Node CloneCore() { return(new Media(Features.Clone(), (Ruleset)Ruleset.Clone(), Extensions)); }
public Ruleset EvaluateParams(Env env, List<NamedArgument> args) { var arguments = new Dictionary<string, Node>(); args = args ?? new List<NamedArgument>(); var hasNamedArgs = false; foreach (var arg in args) { if (!string.IsNullOrEmpty(arg.Name)) { hasNamedArgs = true; arguments[arg.Name] = new Rule(arg.Name, arg.Value.Evaluate(env)) { Index = arg.Value.Index }; } else if (hasNamedArgs) throw new ParsingException("Positional arguments must appear before all named arguments.", arg.Value.Index); } for (var i = 0; i < Params.Count; i++) { if (String.IsNullOrEmpty(Params[i].Name)) continue; if (arguments.ContainsKey(Params[i].Name)) continue; Node val; if (i < args.Count && string.IsNullOrEmpty(args[i].Name)) val = args[i].Value; else val = Params[i].Value; if (val) arguments[Params[i].Name] = new Rule(Params[i].Name, val.Evaluate(env)) {Index = val.Index}; else throw new ParsingException( String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args != null ? args.Count : 0, _arity), Index); } var argumentNodes = new List<Node>(); for(var i = 0; i < Math.Max(Params.Count, args.Count); i++) { argumentNodes.Add(i < args.Count ? args[i].Value : Params[i].Value); } var frame = new Ruleset(null, new NodeList()); frame.Rules.Insert(0, new Rule("@arguments", new Expression(argumentNodes.Where(a => a != null)).Evaluate(env))); foreach (var arg in arguments) { frame.Rules.Add(arg.Value); } return frame; }
public Ruleset EvaluateParams(Env env, List <NamedArgument> args) { var arguments = new Dictionary <string, Node>(); args = args ?? new List <NamedArgument>(); var hasNamedArgs = false; foreach (var arg in args) { if (!string.IsNullOrEmpty(arg.Name)) { hasNamedArgs = true; arguments[arg.Name] = new Rule(arg.Name, arg.Value.Evaluate(env)) { Location = arg.Value.Location }; } else if (hasNamedArgs) { throw new ParsingException("Positional arguments must appear before all named arguments.", arg.Value.Location); } } for (var i = 0; i < Params.Count; i++) { if (String.IsNullOrEmpty(Params[i].Name)) { continue; } if (arguments.ContainsKey(Params[i].Name)) { continue; } Node val; if (i < args.Count && string.IsNullOrEmpty(args[i].Name)) { val = args[i].Value; } else { //evaluate in scope of mixin definition? val = Params[i].Value; } if (val) { Node argRuleValue; if (Params[i].Variadic) { NodeList varArgs = new NodeList(); for (int j = i; j < args.Count; j++) { varArgs.Add(args[j].Value.Evaluate(env)); } argRuleValue = (new Expression(varArgs)).Evaluate(env); } else { argRuleValue = val.Evaluate(env); } arguments[Params[i].Name] = new Rule(Params[i].Name, argRuleValue) { Location = val.Location }; } else { throw new ParsingException( String.Format("wrong number of arguments for {0} ({1} for {2})", Name, args != null ? args.Count : 0, _arity), Location); } } var argumentNodes = new List <Node>(); for (var i = 0; i < Math.Max(Params.Count, args.Count); i++) { argumentNodes.Add(i < args.Count ? args[i].Value : Params[i].Value); } var frame = new Ruleset(null, new NodeList()); frame.Rules.Insert(0, new Rule("@arguments", new Expression(argumentNodes.Where(a => a != null)).Evaluate(env))); foreach (var arg in arguments) { frame.Rules.Add(arg.Value); } return(frame); }