You are here

class ScssphpCompiler in SCSS/Less Compiler 8

Plugin implementation of the Scss compiler.

Plugin annotation


@ScssCompilerPlugin(
  id   = "scss_compiler_scssphp",
  name = "ScssPhp Compiler",
  description = "Compiler for SCSS written in PHP",
  extensions = {
    "scss" = "scss",
  }
)

Hierarchy

Expanded class hierarchy of ScssphpCompiler

File

src/Plugin/ScssCompiler/ScssphpCompiler.php, line 22

Namespace

Drupal\scss_compiler\Plugin\ScssCompiler
View source
class ScssphpCompiler extends ScssCompilerPluginBase {

  /**
   * Compiler object instance.
   *
   * @var \Drupal\scss_compiler\Plugin\ScssCompiler\Scssphp
   */
  protected $parser;

  /**
   * {@inheritdoc}
   */
  public function init() {
    $status = self::getStatus();
    if ($status !== TRUE) {
      throw new \Exception($status);
    }
    $this->parser = new Compiler();
    $this->parser
      ->setFormatter($this
      ->getScssPhpFormatClass($this->scssCompiler
      ->getOption('output_format')));

    // Disable utf-8 support to increase performance.
    $this->parser
      ->setEncoding(TRUE);
  }

  /**
   * {@inheritdoc}
   */
  public static function getVersion() {
    if (class_exists('ScssPhp\\ScssPhp\\Version')) {
      return Version::VERSION;
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public static function getStatus() {
    $compiler_class_exists = class_exists('ScssPhp\\ScssPhp\\Compiler');
    if (!$compiler_class_exists && !file_exists(DRUPAL_ROOT . '/libraries/scssphp/scss.inc.php')) {
      return t('ScssPhp Compiler library not found. Install it via composer "composer require scssphp/scssphp"');
    }

    // If library didn't autoload from the vendor folder, load it from the
    // libraries folder.
    if (!$compiler_class_exists) {
      require_once DRUPAL_ROOT . '/libraries/scssphp/scss.inc.php';

      // leafo/scssphp no longer supported, it was forked to
      // scssphp/scssphp.
      // @see https://github.com/leafo/scssphp/issues/707
      if (!class_exists('ScssPhp\\ScssPhp\\Compiler')) {
        $error_message = t('leafo/scssphp no longer supported. Update compiler library to scssphp/scssphp @url', [
          '@url' => '(https://github.com/scssphp/scssphp/releases)',
        ]);
      }
    }
    if (!empty($error_message)) {
      return $error_message;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function compile(array $scss_file) {
    $import_paths = [
      dirname($scss_file['source_path']),
      DRUPAL_ROOT,
      [
        $this,
        'getImportNamespace',
      ],
    ];
    if ($this->scssCompiler
      ->getAdditionalImportPaths()) {
      $import_paths = array_merge($import_paths, $this->scssCompiler
        ->getAdditionalImportPaths());
    }
    $this->parser
      ->setImportPaths($import_paths);

    // Alter variables.
    $variables = $this->scssCompiler
      ->getVariables()
      ->getAll($scss_file['namespace'], $scss_file['source_path']);
    $this->parser
      ->setVariables($variables);

    // Add assets path to compiler. By default it's theme/module root folder.
    $this->parser->assetsPath = isset($scss_file['assets_path']) ? $scss_file['assets_path'] : '';
    $css_folder = dirname($scss_file['css_path']);
    if ($this->scssCompiler
      ->getOption('sourcemaps')) {
      $this->parser
        ->setSourceMap(Compiler::SOURCE_MAP_FILE);
      $sourcemap_file = $css_folder . '/' . $scss_file['name'] . '.css.map';
      $this->parser
        ->setSourceMapOptions([
        'sourceMapWriteTo' => $sourcemap_file,
        'sourceMapURL' => $scss_file['name'] . '.css.map',
        'sourceMapBasepath' => DRUPAL_ROOT,
        'sourceMapRootpath' => '/',
      ]);
    }
    $this->fileSystem
      ->prepareDirectory($css_folder, FileSystemInterface::CREATE_DIRECTORY);
    $source_content = file_get_contents($scss_file['source_path']);
    return $this->parser
      ->compile($source_content, $scss_file['source_path']);
  }

  /**
   * {@inheritdoc}
   */
  public function checkLastModifyTime(array &$source_file) {
    $last_modify_time = filemtime($source_file['source_path']);
    $source_folder = dirname($source_file['source_path']);
    $import = [];
    $content = file_get_contents($source_file['source_path']);
    preg_match_all('/@import(.*);/', $content, $import);
    if (!empty($import[1])) {
      foreach ($import[1] as $file) {

        // Normalize @import path.
        $file_path = trim($file, '\'" ');
        $pathinfo = pathinfo($file_path);
        $extension = '.scss';
        $filename = $pathinfo['filename'];
        $dirname = $pathinfo['dirname'] === '.' ? '' : $pathinfo['dirname'] . '/';
        $file_path = $source_folder . '/' . $dirname . $filename . $extension;
        $scss_path = $source_folder . '/' . $dirname . '_' . $filename . $extension;
        if (file_exists($file_path) || file_exists($file_path = $scss_path)) {
          $file_modify_time = filemtime($file_path);
          if ($file_modify_time > $last_modify_time) {
            $last_modify_time = $file_modify_time;
          }
        }
      }
    }
    return $last_modify_time;
  }

  /**
   * Processes the import paths using prefixed module/theme.
   *
   * @param string $path
   *   The import path to process.
   *
   * @return string|null
   *   Path to file or NULL if path not found.
   */
  public function getImportNamespace($path) {
    if (!preg_match('#([^/]+)/#', $path, $match)) {
      return NULL;
    }
    $namespace = $match[1];

    // Prevent name conflicts when module/theme name same as subfolder name,
    // use @module to import from module.
    if (substr($namespace, 0, 1) === '@') {
      $namespace = substr($namespace, 1);
    }
    $namespace_path = substr($path, strlen($match[0]));
    $type = 'theme';
    if ($this->moduleHandler
      ->moduleExists($namespace)) {
      $type = 'module';
    }
    $path = @drupal_get_path($type, $namespace);
    if (empty($path)) {
      return NULL;
    }

    // Try different extensions to allow for import from the usual scss sources.
    $base_path = DRUPAL_ROOT . '/' . $path . '/' . $namespace_path;
    foreach ([
      '',
      '.scss',
      '.css',
    ] as $extension) {
      if ($path = realpath($base_path . $extension)) {
        return $path;
      }
    }
    return NULL;
  }

  /**
   * Returns ScssPhp Compiler format classname.
   *
   * @param string $format
   *   Format name.
   *
   * @return string
   *   Format type classname.
   */
  private function getScssPhpFormatClass($format) {
    switch ($format) {
      case 'expanded':
        return '\\ScssPhp\\ScssPhp\\Formatter\\Expanded';
      case 'nested':
        return '\\ScssPhp\\ScssPhp\\Formatter\\Nested';
      case 'compact':
        return '\\ScssPhp\\ScssPhp\\Formatter\\Compact';
      case 'crunched':
        return '\\ScssPhp\\ScssPhp\\Formatter\\Crunched';
      default:
        return '\\ScssPhp\\ScssPhp\\Formatter\\Compressed';
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
ScssCompilerPluginBase::$fileSystem protected property The file system service.
ScssCompilerPluginBase::$moduleHandler protected property The module handler.
ScssCompilerPluginBase::$request protected property The current request.
ScssCompilerPluginBase::$scssCompiler protected property The scss compiler service.
ScssCompilerPluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
ScssCompilerPluginBase::__construct public function Constructs a SCSS Compiler base plugin. Overrides PluginBase::__construct
ScssphpCompiler::$parser protected property Compiler object instance.
ScssphpCompiler::checkLastModifyTime public function Checks if file was changed. Overrides ScssCompilerPluginInterface::checkLastModifyTime
ScssphpCompiler::compile public function Compiles single source file. Overrides ScssCompilerPluginInterface::compile
ScssphpCompiler::getImportNamespace public function Processes the import paths using prefixed module/theme.
ScssphpCompiler::getScssPhpFormatClass private function Returns ScssPhp Compiler format classname.
ScssphpCompiler::getStatus public static function Returns status of compiler library. Overrides ScssCompilerPluginInterface::getStatus
ScssphpCompiler::getVersion public static function Returns compiler version. Overrides ScssCompilerPluginInterface::getVersion
ScssphpCompiler::init public function Calls a code on plugin initialization. Overrides ScssCompilerPluginBase::init
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.