jqwidgets-ng
Version:
[](https://jqwidgets.com/license/)
180 lines (176 loc) • 9.9 kB
JavaScript
/**
* @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
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addTypographyClass = exports.addThemeToAppStyles = void 0;
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const schematics_2 = require("jqwidgets-ng/schematics/cdk/schematics");
const change_1 = require("@schematics/angular/utility/change");
const workspace_1 = require("@schematics/angular/utility/workspace");
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. */
let prebuiltThemePathSegment = 'jqwidgets-ng/jqwidgets/styles';
/** Default file name of the custom theme that can be generated. */
const defaultCustomThemeFilename = 'custom-theme.scss';
/** Add pre-built styles to the main project style file. */
function addThemeToAppStyles(options) {
return (host, context) => {
const themeName = options.theme || 'base';
return themeName === 'custom' ?
insertCustomTheme(options.project, host, context.logger) :
insertPrebuiltTheme(options.project, 'jqx.' + themeName, context.logger);
};
}
exports.addThemeToAppStyles = addThemeToAppStyles;
/** Adds the global typography class to the body element. */
function addTypographyClass(options) {
return (host) => __awaiter(this, void 0, void 0, function* () {
const workspace = yield workspace_1.getWorkspace(host);
const project = schematics_2.getProjectFromWorkspace(workspace, options.project);
const projectIndexFiles = schematics_2.getProjectIndexFiles(project);
if (!projectIndexFiles.length) {
throw new schematics_1.SchematicsException('No project index HTML file could be found.');
}
if (options.typography) {
projectIndexFiles.forEach(path => schematics_2.addBodyClass(host, path, 'mat-typography'));
}
});
}
exports.addTypographyClass = addTypographyClass;
/**
* 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(projectName, host, logger) {
return __awaiter(this, void 0, void 0, function* () {
const workspace = yield workspace_1.getWorkspace(host);
const project = schematics_2.getProjectFromWorkspace(workspace, projectName);
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)) {
logger.warn(`Cannot create a custom Angular Material theme because
${customThemePath} already exists. Skipping custom theme generation.`);
return schematics_1.noop();
}
host.create(customThemePath, themeContent);
return addThemeStyleToTarget(projectName, 'build', customThemePath, logger);
}
const insertion = new change_1.InsertChange(stylesPath, 0, themeContent);
const recorder = host.beginUpdate(stylesPath);
recorder.insertLeft(insertion.pos, insertion.toAdd);
host.commitUpdate(recorder);
return schematics_1.noop();
});
}
/** Insert a pre-built theme into the angular.json file. */
function insertPrebuiltTheme(project, theme, logger) {
// Path needs to be always relative to the `package.json` or workspace root.
const baseThemePath = `./node_modules/jqwidgets-ng/jqwidgets/styles/jqx.base.css`;
const themePath = `./node_modules/jqwidgets-ng/jqwidgets/styles/${theme}.css`;
if (theme === 'jqx.base') {
return schematics_1.chain([
addThemeStyleToTarget(project, 'build', themePath, logger),
addThemeStyleToTarget(project, 'test', themePath, logger)
]);
}
else {
prebuiltThemePathSegment += "/" + theme;
return schematics_1.chain([
addThemeStyleToTarget(project, 'build', baseThemePath, logger),
addThemeStyleToTarget(project, 'test', baseThemePath, logger),
addThemeStyleToTarget(project, 'build', themePath, logger),
addThemeStyleToTarget(project, 'test', themePath, logger)
]);
}
}
/** Adds a theming style entry to the given project target options. */
function addThemeStyleToTarget(projectName, targetName, assetPath, logger) {
return workspace_1.updateWorkspace(workspace => {
const project = schematics_2.getProjectFromWorkspace(workspace, projectName);
// Do not update the builder options in case the target does not use the default CLI builder.
if (!validateDefaultTargetBuilder(project, targetName, logger)) {
return;
}
const targetOptions = schematics_2.getProjectTargetOptions(project, targetName);
const styles = targetOptions.styles;
if (!styles) {
targetOptions.styles = [assetPath];
}
else {
const existingStyles = 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)) {
logger.error(`Could not add the selected theme to the CLI project ` +
`configuration because there is already a custom theme file referenced.`);
logger.info(`Please manually add the following style file to your configuration:`);
logger.info(` ${assetPath}`);
return;
}
else if (stylePath.includes(prebuiltThemePathSegment)) {
styles.splice(index, 1);
}
}
styles.push(assetPath);
}
});
}
/**
* 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, logger) {
const defaultBuilder = schematics_2.defaultTargetBuilders[targetName];
const targetConfig = project.targets && project.targets.get(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) {
// for non-build targets we gracefully report the error without actually aborting the
// setup schematic. This is because a theme is not mandatory for running tests.
logger.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;
}
;