Skip to content
This repository was archived by the owner on Feb 2, 2025. It is now read-only.

[Feature] Angular Schematics update #1543

Merged
merged 3 commits into from
May 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 36 additions & 28 deletions schematics/src/ng-add/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
import { Rule, SchematicContext, Tree, chain } from '@angular-devkit/schematics';
import { addPackageToPackageJson } from './utils';
import { addAssetToAngularJson, addPackageToPackageJson } from './utils';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { IADTSchematicsOptions } from './models/schematics-options';
import { ADT_SUPPORTED_STYLES, ADTStyleOptions } from './models/style-options';

export default function (_options: any): Rule {
export default function (_options: IADTSchematicsOptions): Rule {
return chain([
addPackageJsonDependencies(),
addPackageJsonDependencies(_options),
installPackageJsonDependencies(),
updateAngularJsonFile()
updateAngularJsonFile(_options)
]);
}

function addPackageJsonDependencies() {
function addPackageJsonDependencies(options: IADTSchematicsOptions) {
return (tree: Tree, context: SchematicContext) => {
// Update package.json
const styleDeps = ADT_SUPPORTED_STYLES.find(e => e.style == options.style);

const dependencies = [
{ version: '^3.4.1', name: 'jquery', isDev: false },
{ version: '^1.10.20', name: 'datatables.net', isDev: false },
{ version: '^1.10.20', name: 'datatables.net-dt', isDev: false },
{ version: '^11.0.0', name: 'angular-datatables', isDev: false },
{ version: '^3.3.33', name: '@types/jquery', isDev: true },
{ version: '^1.10.18', name: '@types/datatables.net', isDev: true }
];

if (styleDeps) {
if (styleDeps.style != ADTStyleOptions.DT)
context.logger.log('warn', 'Your project needs Bootstrap CSS installed and configured for changes to take affect.');
styleDeps.packageJson.forEach(e => dependencies.push(e));
}

dependencies.forEach(dependency => {
addPackageToPackageJson(tree, dependency.name, dependency.version, dependency.isDev);
context.logger.log('info', `✅️ Added "${dependency.name}" into "${dependency.isDev ? 'devDependencies' : 'dependencies' }"`);
const result = addPackageToPackageJson(tree, dependency.name, dependency.version, dependency.isDev);
if (result) {
context.logger.log('info', `✅️ Added "${dependency.name}" into "${dependency.isDev ? 'devDependencies' : 'dependencies'}"`);
} else {
context.logger.log('info', `ℹ️ Skipped adding "${dependency.name}" into package.json`);
}
});
return tree;
};
Expand All @@ -40,31 +52,27 @@ function installPackageJsonDependencies(): Rule {
}


function updateAngularJsonFile() {
function updateAngularJsonFile(options: IADTSchematicsOptions) {
return (tree: Tree, context: SchematicContext) => {
try {
const angularJsonFile = tree.read('angular.json');

if (angularJsonFile) {
const angularJsonFileObject = JSON.parse(angularJsonFile.toString('utf-8'));
const project = Object.keys(angularJsonFileObject['projects'])[0];
const projectObject = angularJsonFileObject.projects[project];
const targets = projectObject.targets ? projectObject.targets : projectObject.architect;
const styleDeps = ADT_SUPPORTED_STYLES.find(e => e.style == options.style);

const styles = targets.build.options.styles;
const scripts = targets.build.options.scripts;
const assets = [
{ path: 'node_modules/jquery/dist/jquery.js', target: 'scripts', fancyName: 'jQuery Core' },
{ path: 'node_modules/datatables.net/js/jquery.dataTables.js', target: 'scripts', fancyName: 'DataTables.net Core JS' },
];

styles.push('node_modules/datatables.net-dt/css/jquery.dataTables.css');
scripts.push('node_modules/jquery/dist/jquery.js');
scripts.push('node_modules/datatables.net/js/jquery.dataTables.js');
if (styleDeps) {
styleDeps.angularJson.forEach(e => assets.push(e));
}

tree.overwrite('angular.json', JSON.stringify(angularJsonFileObject, null, 2));
context.logger.log('info', `✅️ Updated angular.json`);
assets.forEach(asset => {
const result = addAssetToAngularJson(tree, asset.target, asset.path);
if (result) {
context.logger.log('info', `✅️ Added "${asset.fancyName}" into angular.json`);
} else {
context.logger.log('error', '🚫 Failed to locate angular.json else.');
context.logger.log('info', `ℹ️ Skipped adding "${asset.fancyName}" into angular.json`);
}
} catch (e) {
context.logger.log('error', `🚫 Failed to update angular.json foobar.`);
}
});
};
}
6 changes: 6 additions & 0 deletions schematics/src/ng-add/models/schematics-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ADTStyleOptions } from "./style-options";

export interface IADTSchematicsOptions {
project: string,
style: ADTStyleOptions
}
37 changes: 37 additions & 0 deletions schematics/src/ng-add/models/style-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export enum ADTStyleOptions {
DT="dt",
BS3="bs3",
BS4="bs4",
}

export const ADT_SUPPORTED_STYLES = [
{
style: ADTStyleOptions.DT,
packageJson: [
{ version: '^1.10.20', name: 'datatables.net-dt', isDev: false },
],
angularJson: [
{ path: 'node_modules/datatables.net-dt/css/jquery.dataTables.css', target: 'styles', fancyName: 'DataTables.net Core CSS' },
]
},
{
style: ADTStyleOptions.BS3,
packageJson: [
{ version: '^1.10.20', name: 'datatables.net-bs', isDev: false },
],
angularJson: [
{ path: 'node_modules/datatables.net-bs/css/dataTables.bootstrap.min.css', target: 'styles', fancyName: 'DataTables.net Bootstrap 3 CSS' },
{ path: 'node_modules/datatables.net-bs/js/dataTables.bootstrap.min.js', target: 'scripts', fancyName: 'DataTables.net Bootstrap 3 JS' },
]
},
{
style: ADTStyleOptions.BS4,
packageJson: [
{ version: '^1.10.20', name: 'datatables.net-bs4', isDev: false },
],
angularJson: [
{ path: 'node_modules/datatables.net-bs4/css/dataTables.bootstrap4.min.css', target: 'styles', fancyName: 'DataTables.net Bootstrap 4 CSS' },
{ path: 'node_modules/datatables.net-bs4/js/dataTables.bootstrap4.min.js', target: 'scripts', fancyName: 'DataTables.net Bootstrap 4 JS' },
]
},
]
23 changes: 22 additions & 1 deletion schematics/src/ng-add/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@
"$default": {
"$source": "projectName"
}
},
"style": {
"description": "The styling library to use for Datatables.",
"type": "string",
"default": "dt",
"enum": ["dt", "bs3", "bs4"],
"x-prompt": {
"message": "Which styling library would you like to use for DataTables?",
"type": "list",
"items": [
{ "value": "dt", "label": "DataTables (Default)" },
{
"value": "bs3",
"label": "Bootstrap 3"
},
{
"value": "bs4",
"label": "Bootstrap 4"
}
]
}
}
}
}
}
36 changes: 32 additions & 4 deletions schematics/src/ng-add/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function installPackageJsonDependencies(): Rule {
}

export function addStyleToTarget(project: WorkspaceProject, targetName: string, host: Tree,
assetPath: string, workspace: WorkspaceSchema) {
assetPath: string, workspace: WorkspaceSchema) {

const targetOptions = getProjectTargetOptions(project, targetName);

Expand Down Expand Up @@ -99,7 +99,7 @@ function sortObjectByKeys(obj: { [key: string]: string }) {
* Note: This function accepts an additional parameter `isDevDependency` so we
* can place a given dependency in the correct dependencies array inside package.json
*/
export function addPackageToPackageJson(host: Tree, pkg: string, version: string, isDevDependency = false): Tree {
export function addPackageToPackageJson(host: Tree, pkg: string, version: string, isDevDependency = false): boolean {

if (host.exists('package.json')) {
/* tslint:disable-next-line: no-non-null-assertion */
Expand All @@ -114,20 +114,48 @@ export function addPackageToPackageJson(host: Tree, pkg: string, version: string
json.dependencies = {};
}

// update UI that `pkg` wasn't re-added to package.json
if (json.dependencies[pkg] || json.devDependencies[pkg]) return false;

if (!json.dependencies[pkg] && !isDevDependency) {
json.dependencies[pkg] = version;
json.dependencies = sortObjectByKeys(json.dependencies);
}

if(!json.devDependencies[pkg] && isDevDependency) {
if (!json.devDependencies[pkg] && isDevDependency) {
json.devDependencies[pkg] = version;
json.devDependencies = sortObjectByKeys(json.devDependencies);
}

host.overwrite('package.json', JSON.stringify(json, null, 2));
return true;
}

return host;
return false;
}

export function addAssetToAngularJson(host: Tree, assetType: string, assetPath: string): boolean {
/* tslint:disable-next-line: no-non-null-assertion */
const sourceText = host.read('angular.json')!.toString('utf-8');
const json = JSON.parse(sourceText);

if (!json) return false;

const projectName = Object.keys(json['projects'])[0];
const projectObject = json.projects[projectName];
const targets = projectObject.targets || projectObject.architect;

const targetLocation: string[] = targets.build.options[assetType];

// update UI that `assetPath` wasn't re-added to angular.json
if (targetLocation.indexOf(assetPath) != -1) return false;

targetLocation.push(assetPath);

host.overwrite('angular.json', JSON.stringify(json, null, 2));

return true;

}

export function removePackageJsonDependency(tree: Tree, dependencyName: string) {
Expand Down