"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const suppress_entry_chunks_webpack_plugin_1 = require("../../plugins/suppress-entry-chunks-webpack-plugin");
const utils_1 = require("./utils");
const eject_1 = require("../../tasks/eject");
const cssnano = require('cssnano');
const postcssUrl = require('postcss-url');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
/**
 * Enumerate loaders and their dependencies from this file to let the dependency validator
 * know they are used.
 *
 * require('exports-loader')
 * require('style-loader')
 * require('postcss-loader')
 * require('css-loader')
 * require('stylus')
 * require('stylus-loader')
 * require('less')
 * require('less-loader')
 * require('node-sass')
 * require('sass-loader')
 */
function getStylesConfig(wco) {
    const { projectRoot, buildOptions, appConfig } = wco;
    const appRoot = path.resolve(projectRoot, appConfig.root);
    const entryPoints = {};
    const globalStylePaths = [];
    const extraPlugins = [];
    // style-loader does not support sourcemaps without absolute publicPath, so it's
    // better to disable them when not extracting css
    // https://github.com/webpack-contrib/style-loader#recommended-configuration
    const cssSourceMap = buildOptions.extractCss && buildOptions.sourcemaps;
    // Minify/optimize css in production.
    const minimizeCss = buildOptions.target === 'production';
    // Convert absolute resource URLs to account for base-href and deploy-url.
    const baseHref = wco.buildOptions.baseHref || '';
    const deployUrl = wco.buildOptions.deployUrl || '';
    const postcssPluginCreator = function () {
        return [
            autoprefixer(),
            postcssUrl({
                url: (URL) => {
                    // Only convert root relative URLs, which CSS-Loader won't process into require().
                    if (!URL.startsWith('/') || URL.startsWith('//')) {
                        return URL;
                    }
                    if (deployUrl.match(/:\/\//)) {
                        // If deployUrl contains a scheme, ignore baseHref use deployUrl as is.
                        return `${deployUrl.replace(/\/$/, '')}${URL}`;
                    }
                    else if (baseHref.match(/:\/\//)) {
                        // If baseHref contains a scheme, include it as is.
                        return baseHref.replace(/\/$/, '') +
                            `/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
                    }
                    else {
                        // Join together base-href, deploy-url and the original URL.
                        // Also dedupe multiple slashes into single ones.
                        return `/${baseHref}/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
                    }
                }
            })
        ].concat(minimizeCss ? [cssnano({ safe: true, autoprefixer: false })] : []);
    };
    postcssPluginCreator[eject_1.postcssArgs] = {
        variableImports: {
            'autoprefixer': 'autoprefixer',
            'postcss-url': 'postcssUrl',
            'cssnano': 'cssnano'
        },
        variables: { minimizeCss, baseHref, deployUrl }
    };
    // determine hashing format
    const hashFormat = utils_1.getOutputHashFormat(buildOptions.outputHashing);
    // use includePaths from appConfig
    const includePaths = [];
    if (appConfig.stylePreprocessorOptions
        && appConfig.stylePreprocessorOptions.includePaths
        && appConfig.stylePreprocessorOptions.includePaths.length > 0) {
        appConfig.stylePreprocessorOptions.includePaths.forEach((includePath) => includePaths.push(path.resolve(appRoot, includePath)));
    }
    // process global styles
    if (appConfig.styles.length > 0) {
        const globalStyles = utils_1.extraEntryParser(appConfig.styles, appRoot, 'styles');
        // add style entry points
        globalStyles.forEach(style => entryPoints[style.entry]
            ? entryPoints[style.entry].push(style.path)
            : entryPoints[style.entry] = [style.path]);
        // add global css paths
        globalStylePaths.push(...globalStyles.map((style) => style.path));
    }
    // set base rules to derive final rules from
    const baseRules = [
        { test: /\.css$/, use: [] },
        { test: /\.scss$|\.sass$/, use: [{
                    loader: 'sass-loader',
                    options: {
                        sourceMap: cssSourceMap,
                        // bootstrap-sass requires a minimum precision of 8
                        precision: 8,
                        includePaths
                    }
                }]
        },
        { test: /\.less$/, use: [{
                    loader: 'less-loader',
                    options: {
                        sourceMap: cssSourceMap
                    }
                }]
        },
        {
            test: /\.styl$/, use: [{
                    loader: 'stylus-loader',
                    options: {
                        sourceMap: cssSourceMap,
                        paths: includePaths
                    }
                }]
        }
    ];
    const commonLoaders = [
        {
            loader: 'css-loader',
            options: {
                sourceMap: cssSourceMap,
                importLoaders: 1
            }
        },
        {
            loader: 'postcss-loader',
            options: {
                // A non-function property is required to workaround a webpack option handling bug
                ident: 'postcss',
                plugins: postcssPluginCreator
            }
        }
    ];
    // load component css as raw strings
    let rules = baseRules.map(({ test, use }) => ({
        exclude: globalStylePaths, test, use: [
            'exports-loader?module.exports.toString()',
            ...commonLoaders,
            ...use
        ]
    }));
    // load global css as css files
    if (globalStylePaths.length > 0) {
        rules.push(...baseRules.map(({ test, use }) => {
            const extractTextPlugin = {
                use: [
                    ...commonLoaders,
                    ...use
                ],
                fallback: 'style-loader',
                // publicPath needed as a workaround https://github.com/angular/angular-cli/issues/4035
                publicPath: ''
            };
            const ret = {
                include: globalStylePaths,
                test,
                use: ExtractTextPlugin.extract(extractTextPlugin)
            };
            // Save the original options as arguments for eject.
            ret[eject_1.pluginArgs] = extractTextPlugin;
            return ret;
        }));
    }
    if (buildOptions.extractCss) {
        // suppress empty .js files in css only entry points
        extraPlugins.push(new suppress_entry_chunks_webpack_plugin_1.SuppressExtractedTextChunksWebpackPlugin());
    }
    const styleVariables = appConfig.styleVariables ? path.resolve(appRoot, appConfig.styleVariables) : '';
    const styleVariablesRules = styleVariables ? [{
            enforce: 'pre',
            test: /\.less$|\.scss$|\.sass$|\.styl$/,
            loader: `sass-variables-inject-loader?${styleVariables}`
        }] : [];
    rules = styleVariablesRules.concat(rules);
    return {
        entry: entryPoints,
        module: { rules },
        plugins: [
            // extract global css from js files into own css file
            new ExtractTextPlugin({
                filename: `[name]${hashFormat.extract}.bundle.css`,
                disable: !buildOptions.extractCss
            })
        ].concat(extraPlugins)
    };
}
exports.getStylesConfig = getStylesConfig;
//# sourceMappingURL=/users/johnny/myfiles/angular-cli/models/webpack-configs/styles.js.map