public static NodeList <CartoSelector> GetCartoSelectors(this Ruleset ruleset) { NodeList <CartoSelector> selectors = new NodeList <CartoSelector>(); foreach (Selector selector in ruleset.Selectors) { CartoSelector cs = selector as CartoSelector; if (cs) { selectors.Add(cs); } } return(selectors); }
public static List <CartoDefinition> Flatten(this Ruleset ruleset, List <CartoDefinition> result, NodeList <CartoSelector> parents, Env env, Logging.Logger logger) { NodeList <CartoSelector> selectors = GetCartoSelectors(ruleset); NodeList <CartoSelector> selectorsResult = new NodeList <CartoSelector>(); if (selectors.Count == 0) { env.Frames.Concat(ruleset.Rules); } // evaluate zoom variables on this object. EvaluateZooms(selectors, env); for (int i = 0; i < selectors.Count; i++) { CartoSelector child = selectors[i]; if (child.Filters == null) { // TODO: is this internal inconsistency? // This is an invalid filterset. continue; } if (parents.Count > 0) { foreach (CartoSelector parent in parents) { object mergedFilters = parent.Filters.CloneWith(child.Filters, env); //new CartoFilterSet(child.Filters); if (mergedFilters == null) { // Filters could be added, but they didn't change the // filters. This means that we only have to clone when // the zoom levels or the attachment is different too. if (parent.Zoom == (parent.Zoom & child.Zoom) && parent.Attachment == child.Attachment && parent.ElementsEqual(child)) { selectorsResult.Add(parent); continue; } else { mergedFilters = parent.Filters; } } else if (mergedFilters is bool && !(Convert.ToBoolean(mergedFilters))) { // The merged filters are invalid, that means we don't // have to clone. continue; } CartoSelector clone = new CartoSelector(child); clone.Filters = (CartoFilterSet)mergedFilters; clone.Zoom = parent.Zoom & child.Zoom; clone.Elements.Clear(); clone.Elements.AddRange(parent.Elements.Concat(child.Elements)); if (parent.Attachment != null && child.Attachment != null) { clone.Attachment = parent.Attachment + '/' + child.Attachment; } else { clone.Attachment = child.Attachment ?? parent.Attachment; } clone.Conditions = parent.Conditions + child.Conditions; clone.Index = child.Index; selectorsResult.Add(clone); } } else { selectorsResult.Add(child); } } NodeList <CartoRule> rules = new NodeList <CartoRule>(); foreach (dotless.Core.Parser.Infrastructure.Nodes.Node rule in ruleset.Rules) { // Recursively flatten any nested rulesets if (rule is Ruleset) { List <CartoDefinition> defs = Flatten(rule as Ruleset, result, selectorsResult, env, logger); } else if (rule is CartoRule) { rules.Add(rule as CartoRule); } else if (rule as CartoInvalidElement) { CartoInvalidElement cie = rule as CartoInvalidElement; env.Logger.Log(dotless.Core.Loggers.LogLevel.Error, "Rule"); Logging.LogFactory.WriteLogEntry(logger, new ParsingException(cie.Value, cie.Location.FileName, Zone.GetLineNumber(cie.Location))); } } int index = rules.Count > 0 ? rules[0].Index : -1; for (int i = 0; i < selectorsResult.Count; i++) { // For specificity sort, use the position of the first rule to allow // defining attachments that are under current element as a descendant // selector. CartoSelector selector = selectorsResult[i]; if (index >= 0) { selector.Index = index; } // make a copy of the rules array, since the next iteration will change zooms CartoRule[] arrRules = new CartoRule[rules.Count]; for (int j = 0; j < arrRules.Length; j++) { arrRules[j] = (CartoRule)rules[j].Clone(); } result.Add(new CartoDefinition(selector, arrRules)); } return(result); }