"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@angular-devkit/core"); const schematics_1 = require("@angular-devkit/schematics"); const schematics_2 = require("@angular/cdk/schematics"); const change_1 = require("@schematics/angular/utility/change"); const config_1 = require("@schematics/angular/utility/config"); const chalk_1 = require("chalk"); const path_1 = require("path"); const create_custom_theme_1 = require("./create-custom-theme"); /** Path segment that can be found in paths that refer to a prebuilt theme. */ const prebuiltThemePathSegment = '@angular/material/prebuilt-themes'; /** Default file name of the custom theme that can be generated. */ const defaultCustomThemeFilename = 'custom-theme.scss'; /** Object that maps a CLI target to its default builder name. */ const defaultTargetBuilders = { build: '@angular-devkit/build-angular:browser', test: '@angular-devkit/build-angular:karma', }; /** Add pre-built styles to the main project style file. */ function addThemeToAppStyles(options) { return function (host) { const workspace = config_1.getWorkspace(host); const project = schematics_2.getProjectFromWorkspace(workspace, options.project); const themeName = options.theme || 'indigo-pink'; if (themeName === 'custom') { insertCustomTheme(project, options.project, host, workspace); } else { insertPrebuiltTheme(project, host, themeName, workspace); } return host; }; } exports.addThemeToAppStyles = addThemeToAppStyles; /** * Insert a custom theme to project style file. If no valid style file could be found, a new * Scss file for the custom theme will be created. */ function insertCustomTheme(project, projectName, host, workspace) { const stylesPath = schematics_2.getProjectStyleFile(project, 'scss'); const themeContent = create_custom_theme_1.createCustomTheme(projectName); if (!stylesPath) { if (!project.sourceRoot) { throw new schematics_1.SchematicsException(`Could not find source root for project: "${projectName}". ` + `Please make sure that the "sourceRoot" property is set in the workspace config.`); } // Normalize the path through the devkit utilities because we want to avoid having // unnecessary path segments and windows backslash delimiters. const customThemePath = core_1.normalize(path_1.join(project.sourceRoot, defaultCustomThemeFilename)); if (host.exists(customThemePath)) { console.warn(chalk_1.yellow(`Cannot create a custom Angular Material theme because ${chalk_1.bold(customThemePath)} already exists. Skipping custom theme generation.`)); return; } host.create(customThemePath, themeContent); addThemeStyleToTarget(project, 'build', host, customThemePath, workspace); return; } const insertion = new change_1.InsertChange(stylesPath, 0, themeContent); const recorder = host.beginUpdate(stylesPath); recorder.insertLeft(insertion.pos, insertion.toAdd); host.commitUpdate(recorder); } /** Insert a pre-built theme into the angular.json file. */ function insertPrebuiltTheme(project, host, theme, workspace) { // Path needs to be always relative to the `package.json` or workspace root. const themePath = `./node_modules/@angular/material/prebuilt-themes/${theme}.css`; addThemeStyleToTarget(project, 'build', host, themePath, workspace); addThemeStyleToTarget(project, 'test', host, themePath, workspace); } /** Adds a theming style entry to the given project target options. */ function addThemeStyleToTarget(project, targetName, host, assetPath, workspace) { // Do not update the builder options in case the target does not use the default CLI builder. if (!validateDefaultTargetBuilder(project, targetName)) { return; } const targetOptions = schematics_2.getProjectTargetOptions(project, targetName); if (!targetOptions.styles) { targetOptions.styles = [assetPath]; } else { const existingStyles = targetOptions.styles.map(s => typeof s === 'string' ? s : s.input); for (let [index, stylePath] of existingStyles.entries()) { // If the given asset is already specified in the styles, we don't need to do anything. if (stylePath === assetPath) { return; } // In case a prebuilt theme is already set up, we can safely replace the theme with the new // theme file. If a custom theme is set up, we are not able to safely replace the custom // theme because these files can contain custom styles, while prebuilt themes are // always packaged and considered replaceable. if (stylePath.includes(defaultCustomThemeFilename)) { console.warn(chalk_1.red(`Could not add the selected theme to the CLI project configuration ` + `because there is already a custom theme file referenced.`)); console.warn(chalk_1.red(`Please manually add the following style file to your configuration:`)); console.warn(chalk_1.yellow(` ${chalk_1.bold(assetPath)}`)); return; } else if (stylePath.includes(prebuiltThemePathSegment)) { targetOptions.styles.splice(index, 1); } } targetOptions.styles.unshift(assetPath); } host.overwrite('angular.json', JSON.stringify(workspace, null, 2)); } /** * Validates that the specified project target is configured with the default builders which are * provided by the Angular CLI. If the configured builder does not match the default builder, * this function can either throw or just show a warning. */ function validateDefaultTargetBuilder(project, targetName) { const defaultBuilder = defaultTargetBuilders[targetName]; const targetConfig = project.architect && project.architect[targetName] || project.targets && project.targets[targetName]; const isDefaultBuilder = targetConfig && targetConfig['builder'] === defaultBuilder; // Because the build setup for the Angular CLI can be customized by developers, we can't know // where to put the theme file in the workspace configuration if custom builders are being // used. In case the builder has been changed for the "build" target, we throw an error and // exit because setting up a theme is a primary goal of `ng-add`. Otherwise if just the "test" // builder has been changed, we warn because a theme is not mandatory for running tests // with Material. See: https://github.com/angular/components/issues/14176 if (!isDefaultBuilder && targetName === 'build') { throw new schematics_1.SchematicsException(`Your project is not using the default builders for ` + `"${targetName}". The Angular Material schematics cannot add a theme to the workspace ` + `configuration if the builder has been changed.`); } else if (!isDefaultBuilder) { console.warn(`Your project is not using the default builders for "${targetName}". This ` + `means that we cannot add the configured theme to the "${targetName}" target.`); } return isDefaultBuilder; } //# sourceMappingURL=theming.js.map