/** * Visits a ruleset node * * @param ILess_Node_Ruleset $node The node * @param ILess_Visitor_Arguments $arguments The arguments */ public function visitRuleset(ILess_Node_Ruleset $node, ILess_Visitor_Arguments $arguments) { $paths = array(); if (!$node->root) { $selectors = array(); foreach ($node->selectors as $selector) { if ($selector->getIsOutput()) { $selectors[] = $selector; } } if (!count($selectors)) { $node->selectors = array(); $node->rules = array(); } else { $context = end($this->contexts); $paths = $node->joinSelectors($context, $selectors); } $node->paths = $paths; } $this->contexts[] = $paths; }
/** * Generates the CSS * * @param ILess_Environment $env * @return string */ public function generateCSS(ILess_Environment $env) { $output = new ILess_Output_Mapped($this->contentsMap, $this); // catch the output $this->root->generateCSS($env, $output); // prepare sources foreach ($this->contentsMap as $filename => $contents) { // match md5 hash in square brackets _[#HASH#]_ // see ILess_Parser_Core::parseString() if (preg_match('/(\\[__[0-9a-f]{32}__\\])+$/', $filename)) { $filename = substr($filename, 0, -38); } $this->sources[$this->normalizeFilename($filename)] = $contents; } $sourceMapUrl = null; if ($url = $this->getOption('url')) { $sourceMapUrl = $url; } elseif ($path = $this->getOption('filename')) { $sourceMapUrl = $this->normalizeFilename($path); // naming conventions, make it foobar.css.map if (!preg_match('/\\.map$/', $sourceMapUrl)) { $sourceMapUrl = sprintf('%s.map', $sourceMapUrl); } } $sourceMapContent = $this->generateJson(); // write map to a file if ($file = $this->getOption('write_to')) { // FIXME: should this happen here? $this->saveMap($file, $sourceMapContent); } else { $sourceMapUrl = sprintf('data:application/json,%s', ILess_Util::encodeURIComponent($sourceMapContent)); } if ($sourceMapUrl) { $output->add(sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl)); } return $output->toString(); }
/** * @covers getType */ public function testGetType() { $r = new ILess_Node_Ruleset(array(new ILess_Node_Element(' ', 'foobar')), array()); $this->assertEquals('Ruleset', $r->getType()); }
/** * @see ILess_Node */ public function compile(ILess_Environment $env, $arguments = null, $important = null) { if ($this->skip) { return array(); } if ($this->getOption('inline')) { // FIXME: this section is marked as "todo" in less.js project // see: lib/less/tree/import.js // original comment: todo needs to reference css file not import // $this->root is string here! $contents = new ILess_Node_Anonymous($this->root, 0, new ILess_FileInfo(array('filename' => $this->importedFilename)), true); return $this->features ? new ILess_Node_Media(array($contents), $this->features->value) : array($contents); } elseif ($this->css) { $features = $this->features ? $this->features->compile($env) : null; $import = new ILess_Node_Import($this->compilePath($env), $features, $this->options, $this->index); if (!$import->css && $import->hasError()) { throw $import->getError(); } return $import; } else { $ruleset = new ILess_Node_Ruleset(array(), $this->root ? $this->root->rules : array()); $ruleset->compileImports($env); return $this->features ? new ILess_Node_Media($ruleset->rules, $this->features->value) : $ruleset->rules; } }
/** * Compile parameters * * @param ILess_Environment $env The environment * @param ILess_Environment $mixinEnv The mixin environment * @param array $arguments Array of arguments * @param array $compiledArguments The compiled arguments */ public function compileParams(ILess_Environment $env, ILess_Environment $mixinEnv, $arguments = array(), array &$compiledArguments = array()) { $frame = new ILess_Node_Ruleset(array(), array()); $params = $this->params; // create a copy of mixin environment $mixinEnv = ILess_Environment::createCopy($mixinEnv, array_merge(array($frame), $mixinEnv->frames)); for ($i = 0; $i < count($arguments); $i++) { $arg = $arguments[$i]; if ($name = $arg['name']) { $isNamedFound = false; foreach ($params as $j => $param) { if (!isset($compiledArguments[$j]) && $name === $params[$j]['name']) { $compiledArguments[$j] = $arg['value']->compile($env); array_unshift($frame->rules, new ILess_Node_Rule($name, $arg['value']->compile($env))); $isNamedFound = true; break; } } if ($isNamedFound) { array_splice($arguments, $i, 1); $i--; continue; } else { throw new ILess_Exception_Compiler(sprintf('The named argument for `%s` %s was not found.', $this->name, $arguments[$i]['name'])); } } } $argIndex = 0; foreach ($params as $i => $param) { if (array_key_exists($i, $compiledArguments)) { continue; } $arg = null; if (array_key_exists($argIndex, $arguments)) { $arg = $arguments[$argIndex]; } if (isset($param['name']) && ($name = $param['name'])) { if (isset($param['variadic']) && $arguments) { $varArgs = array(); for ($j = $argIndex, $count = count($arguments); $j < $count; $j++) { $varArgs[] = $arguments[$j]['value']->compile($env); } $expression = new ILess_Node_Expression($varArgs); array_unshift($frame->rules, new ILess_Node_Rule($name, $expression->compile($env))); } else { $val = $arg && $arg['value'] ? $arg['value'] : false; if ($val) { $val = $val->compile($env); } elseif (isset($param['value'])) { $val = $param['value']->compile($mixinEnv); $frame->resetCache(); } else { throw new ILess_Exception_Compiler(sprintf('Wrong number of arguments for `%s` (%s for %s)', $this->name, count($arguments), $this->arity)); } array_unshift($frame->rules, new ILess_Node_Rule($name, $val)); $compiledArguments[$i] = $val; } } if (isset($param['variadic']) && $arguments) { for ($j = $argIndex, $count = count($arguments); $j < $count; $j++) { $compiledArguments[$j] = $arguments[$j]['value']->compile($env); } } $argIndex++; } ksort($compiledArguments); return $frame; }
/** * Visits a ruleset node * * @param ILess_Node_Ruleset $node The node * @param ILess_Visitor_Arguments $arguments The arguments * @return array|ILess_Node_Ruleset */ public function visitRuleset(ILess_Node_Ruleset $node, ILess_Visitor_Arguments $arguments) { $arguments->visitDeeper = false; $rulesets = array(); if ($node->firstRoot) { $this->checkPropertiesInRoot($node->rules); } if (!$node->root) { $paths = array(); foreach ($node->paths as $p) { if ($p[0]->elements[0]->combinator->value === ' ') { $p[0]->elements[0]->combinator = new ILess_Node_Combinator(''); } if ($p[0]->getIsReferenced() && $p[0]->getIsOutput()) { $paths[] = $p; } } $node->paths = $paths; // Compile rules and rulesets for ($i = 0, $count = count($node->rules); $i < $count;) { $rule = $node->rules[$i]; //if ($rule instanceof ILess_Node_Rule || $rule instanceof ILess_Node_Ruleset) { //if ($rule instanceof ILess_Node_Ruleset) { if (ILess_Node::propertyExists($rule, 'rules')) { // visit because we are moving them out from being a child $rulesets[] = $this->visit($rule); array_splice($node->rules, $i, 1); $count--; continue; } $i++; } // accept the visitor to remove rules and refactor itself // then we can decide now whether we want it or not if ($count > 0) { $node->accept($this); $count = count($node->rules); if ($count > 0) { if ($count > 1) { $this->mergeRules($node->rules); $this->removeDuplicateRules($node->rules); } // now decide whether we keep the ruleset if (count($node->paths) > 0) { array_splice($rulesets, 0, 0, array($node)); } } } else { $node->rules = array(); } } else { $node->accept($this); $arguments->visitDeeper = false; if ($node->firstRoot || count($node->rules) > 0) { array_splice($rulesets, 0, 0, array($node)); } } if (count($rulesets) === 1) { return $rulesets[0]; } return $rulesets; }