function parseRules()

in src/core/services/theming/theming.js [1001:1122]


function parseRules(theme, colorType, rules) {
  checkValidPalette(theme, colorType);

  rules = rules.replace(/THEME_NAME/g, theme.name);
  var themeNameRegex = new RegExp('\\.md-' + theme.name + '-theme', 'g');
  // Matches '{{ primary-color }}', etc
  var hueRegex = new RegExp('([\'"])?{{\\s*([a-zA-Z]+)-?(color|default)?-?(contrast)?-?((?:\\d\\.?\\d*)|(?:[a-zA-Z]+))?\\s*}}(["\'])?','g');
  var simpleVariableRegex = /'?"?{{\s*([a-zA-Z]+)-(A?\d+|hue-[0-3]|shadow|default)-?(contrast)?-?((?:\d\.?\d*)|(?:[a-zA-Z]+))?\s*}}'?"?/g;
  var defaultBgHue = theme.colors['background'].hues['default'];
  var defaultBgContrastType = PALETTES[theme.colors['background'].name][defaultBgHue].contrastType;

  // find and replace simple variables where we use a specific hue, not an entire palette
  // eg. "{{primary-100}}"
  // \(' + THEME_COLOR_TYPES.join('\|') + '\)'
  rules = rules.replace(simpleVariableRegex, function(match, colorType, hue, contrast, opacity) {
    var regexColorType = colorType;
    if (colorType === 'foreground') {
      if (hue === 'shadow') {
        return theme.foregroundShadow;
      } else if (theme.foregroundPalette[hue]) {
        // Use user defined palette number (ie: foreground-2)
        return rgba(colorToRgbaArray(theme.foregroundPalette[hue]));
      } else if (theme.foregroundPalette['1']){
        return rgba(colorToRgbaArray(theme.foregroundPalette['1']));
      }
      // Default to background-default-contrast-{opacity}
      colorType = 'background';
      contrast = 'contrast';
      if (!opacity && hue) {
        // Convert references to legacy hues to opacities (i.e. foreground-4 to *-divider)
        switch (hue) {
          // hue-1 uses default opacity
          case '2':
            opacity = 'secondary';
            break;
          case '3':
            opacity = 'disabled';
            break;
          case '4':
            opacity = 'divider';
        }
      }
      hue = 'default';
    }

    // `default` is also accepted as a hue-value, because the background palettes are
    // using it as a name for the default hue.
    if (hue.indexOf('hue') === 0 || hue === 'default') {
      hue = theme.colors[colorType].hues[hue];
    }

    var colorDetails = (PALETTES[ theme.colors[colorType].name ][hue] || '');

    // If user has specified a foreground color, use those
    if (colorType === 'background' && contrast && regexColorType !== 'foreground' &&
        colorDetails.contrastType === defaultBgContrastType) {
      // Don't process if colorType was changed
      switch (opacity) {
        case 'secondary':
        case 'icon':
          if (theme.foregroundPalette['2']) {
            return rgba(colorToRgbaArray(theme.foregroundPalette['2']));
          }
          break;
        case 'disabled':
        case 'hint':
          if (theme.foregroundPalette['3']) {
            return rgba(colorToRgbaArray(theme.foregroundPalette['3']));
          }
          break;
        case 'divider':
          if (theme.foregroundPalette['4']) {
            return rgba(colorToRgbaArray(theme.foregroundPalette['4']));
          }
          break;
        default:
          if (theme.foregroundPalette['1']) {
            return rgba(colorToRgbaArray(theme.foregroundPalette['1']));
          }
          break;
      }
    }

    if (contrast && opacity) {
      opacity = colorDetails.opacity[opacity] || opacity;
    }

    return rgba(colorDetails[contrast ? 'contrast' : 'value'], opacity);
  });

  var generatedRules = [];

  // For each type, generate rules for each hue (ie. default, md-hue-1, md-hue-2, md-hue-3)
  angular.forEach(['default', 'hue-1', 'hue-2', 'hue-3'], function(hueName) {
    var newRule = rules
      .replace(hueRegex, function(match, _, matchedColorType, hueType, contrast, opacity) {
        var color = theme.colors[matchedColorType];
        var palette = PALETTES[color.name];
        var hueValue = color.hues[hueName];
        if (contrast && opacity) {
          opacity = palette[hueValue].opacity[opacity] || opacity;
        }
        return rgba(palette[hueValue][hueType === 'color' ? 'value' : 'contrast'], opacity);
      });
    if (hueName !== 'default') {
      newRule = newRule.replace(themeNameRegex, '.md-' + theme.name + '-theme.md-' + hueName);
    }

    // Don't apply a selector rule to the default theme, making it easier to override
    // styles of the base-component
    if (theme.name === 'default') {
      var themeRuleRegex = /((?:\s|>|\.|\w|-|:|\(|\)|\[|]|"|'|=)*)\.md-default-theme((?:\s|>|\.|\w|-|:|\(|\)|\[|]|"|'|=)*)/g;

      newRule = newRule.replace(themeRuleRegex, function(match, start, end) {
        return match + ', ' + start + end;
      });
    }
    generatedRules.push(newRule);
  });

  return generatedRules;
}