Theme.prototype._createThemeCssFile = function()

in src/server/theme.js [123:200]


Theme.prototype._createThemeCssFile = function (themeCssFileName) {
    var elementSelectors = this._simHostThemeInfo.elementSelectors;

    // We don't want to pollute provided theme object (or hash will change)
    var themeObject = JSON.parse(JSON.stringify(this.themeObject));
    var css = [];

    var defaultProperties = getOrCreate(themeObject, 'default', {});
    var defaultElementNormalStateProperties = getOrCreate(defaultProperties, '', {});

    // Ensure defaultElementNormalStateProperties is fully populated with basic properties
    var defaultThemeProperties = this._simHostThemeInfo.defaultTheme.default[''];
    ['border', 'background', 'color', 'font-family', 'font-size', 'font-weight'].forEach(function (propertyName) {
        defaultElementNormalStateProperties[propertyName] = defaultElementNormalStateProperties[propertyName] ||
            defaultThemeProperties[propertyName];
    });

    Object.keys(elementSelectors).forEach(function (element) {
        var themeElementData = getOrCreate(themeObject, element, {});

        // Populate it with default data...
        var elementNormalStateProperties = getOrCreate(themeElementData, '', {});

        // First specific states...
        if (appliedDefaultStates[element]) {
            appliedDefaultStates[element].forEach(function (state) {
                var elementStateProperties = getOrCreate(themeElementData, state, {});
                var defaultElementStateProperties = getOrCreate(defaultProperties, state, {});
                appliedDefaultProperties[element].forEach(function (propertyName) {
                    // If not defined, fallback on normal state, then default for this state, then default normal state
                    elementStateProperties[propertyName] = elementStateProperties[propertyName] ||
                        elementNormalStateProperties[propertyName] ||
                        defaultElementStateProperties[propertyName] ||
                        defaultElementNormalStateProperties[propertyName];
                });
            });
        }

        // Then the normal state (we do this second so that other states get right defaults)...
        appliedDefaultProperties[element].forEach(function (propertyName) {
            // If not defined, fallback on default
            elementNormalStateProperties[propertyName] = elementNormalStateProperties[propertyName] ||
                defaultElementNormalStateProperties[propertyName];
        });

        // Now generate the CSS for each state
        var selector = elementSelectors[element];
        Object.keys(themeElementData).forEach(function (state) {
            outputSelectorProperties(css, selector, themeElementData[state], state);
        });
    });

    // Allow the sim host to do any custom stuff that couldn't be handled with the default selector handling
    if (this._simHostThemeInfo.doCustom) {
        this._simHostThemeInfo.doCustom(css, themeObject);
    }

    // If sim host provides a CSS file to be scaled, scale and append it. Scaling searches for sizes declared in pixels,
    // and scales them based on the current font size compared to the sim-host's default font size (always rounded to a
    // whole pixel). This works better than, say, em sizing, which results in fractional pixel sizes and inconsistent
    // results.
    if (utils.existsSync(this._simHostScaledCssFile)) {
        var defaultFontSize = this._simHostThemeInfo.defaultFontSize;
        var fontSize = parseFontSize(themeObject.default['']) || 16;
        var scaledCss = fs.readFileSync(this._simHostScaledCssFile, 'utf8');

        if (fontSize === defaultFontSize) {
            css.push(scaledCss);
        } else {
            var scale = fontSize / defaultFontSize;
            css.push(scaledCss.replace(/\b([0-9.]+)px\b/g, function (_, pixels) {
                return Math.round(pixels * scale) + 'px';
            }));
        }
    }

    fs.writeFileSync(themeCssFileName, css.join('\n'), 'utf8');
};