Skip to content

Commit 5b69f40

Browse files
authored
Merge pull request #8944 from IgniteUI/iganchev/hammer-js-to-angular-json-10.2.x
Add hammerjs to Angular options - 10.2.x
2 parents 6e7398d + 31d31a8 commit 5b69f40

File tree

3 files changed

+110
-80
lines changed

3 files changed

+110
-80
lines changed

projects/igniteui-angular/schematics/ng-add/index.spec.ts

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -103,49 +103,61 @@ describe('ng-add schematics', () => {
103103
expect(pkgJsonData.dependencies['hammerjs']).toBeTruthy();
104104
});
105105

106-
it('should add hammer.js to the main.ts file', async () => {
106+
it('should NOT add hammer.js to the main.ts file', async () => {
107107
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
108108
const mainTs = tree.read(`${sourceRoot}/main.ts`).toString();
109-
expect(mainTs).toContain('import \'hammerjs\';');
109+
expect(mainTs).not.toContain('import \'hammerjs\';');
110110
});
111111

112-
it('should not add hammer.js if it exists in angular.json build options', async () => {
113-
const workspace = getWorkspace(tree) as any;
114-
const currentProjectName = workspace.defaultProject;
115-
workspace.projects[currentProjectName].architect.build.options.scripts.push('./node_modules/hammerjs/hammer.min.js');
116-
tree.overwrite('angular.json', JSON.stringify(workspace));
112+
it('should NOT add hammer.js to the test.ts file', async () => {
117113
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
114+
const testTs = tree.read(`${sourceRoot}/test.ts`).toString();
115+
expect(testTs).not.toContain('import \'hammerjs\';');
116+
});
118117

119-
const newContent = tree.read(`${sourceRoot}/main.ts`).toString();
120-
expect(newContent.split('import \'hammerjs\';\n// test comment').length).toEqual(1);
118+
it('should add hammer.js in angular.json build options under scripts', async () => {
119+
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
120+
const ngJsonConfigResult = JSON.parse(tree.read('/angular.json').toString());
121+
expect(ngJsonConfigResult.projects.testProj.architect.build.options.scripts).toContain('./node_modules/hammerjs/hammer.min.js');
121122
});
122123

123-
it('should add hammer.js to the test.ts file', async () => {
124+
it('should add hammer.js in angular.json test options under scripts', async () => {
124125
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
125-
const testTs = tree.read(`${sourceRoot}/test.ts`).toString();
126-
expect(testTs).toContain('import \'hammerjs\';');
126+
const ngJsonConfigResult = JSON.parse(tree.read('/angular.json').toString());
127+
expect(ngJsonConfigResult.projects.testProj.architect.test.options.scripts).toContain('./node_modules/hammerjs/hammer.min.js');
127128
});
128129

129-
it('should not add hammer.js if it exists in angular.json test options', async () => {
130-
const workspace = getWorkspace(tree) as any;
131-
const currentProjectName = workspace.defaultProject;
132-
workspace.projects[currentProjectName].architect.test.options.scripts.push('./node_modules/hammerjs/hammer.min.js');
133-
tree.overwrite('angular.json', JSON.stringify(workspace));
130+
it('should NOT duplicate hammer.js if it exists in angular.json build options', async () => {
131+
const ngJsonConfig1 = JSON.parse(tree.read('/angular.json').toString());
132+
ngJsonConfig1.projects.testProj.architect.build.options.scripts.push('./node_modules/hammerjs/hammer.min.js');
133+
tree.overwrite('/angular.json', JSON.stringify(ngJsonConfig1));
134134
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
135135

136-
const testTs = tree.read(`${sourceRoot}/test.ts`).toString();
137-
expect(testTs).toMatch('// test comment');
136+
const ngJsonConfigResult = JSON.parse(tree.read('/angular.json').toString());
137+
expect(ngJsonConfigResult.projects.testProj.architect.build.options.scripts.length).toBe(1);
138+
expect(ngJsonConfigResult.projects.testProj.architect.build.options.scripts).toMatch('./node_modules/hammerjs/hammer.min.js');
138139
});
139140

140-
it('should not add hammer.js if it exists in main.ts', async () => {
141+
it('should NOT duplicate hammer.js if it exists in angular.json test options', async () => {
142+
const ngJsonConfig1 = JSON.parse(tree.read('/angular.json').toString());
143+
ngJsonConfig1.projects.testProj.architect.test.options.scripts.push('./node_modules/hammerjs/hammer.min.js');
144+
tree.overwrite('/angular.json', JSON.stringify(ngJsonConfig1));
145+
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
146+
147+
const ngJsonConfigResult = JSON.parse(tree.read('/angular.json').toString());
148+
expect(ngJsonConfigResult.projects.testProj.architect.test.options.scripts.length).toBe(1);
149+
expect(ngJsonConfigResult.projects.testProj.architect.test.options.scripts).toMatch('./node_modules/hammerjs/hammer.min.js');
150+
});
141151

152+
it('should NOT add hammer.js to angular.json if it exists in main.ts options', async () => {
142153
const mainTsPath = `${sourceRoot}/main.ts`;
143154
const content = tree.read(mainTsPath).toString();
144155
tree.overwrite(mainTsPath, 'import \'hammerjs\';\n' + content);
145156
await runner.runSchematicAsync('ng-add', { normalizeCss: false }, tree).toPromise();
146157

147-
const newContent = tree.read(mainTsPath).toString();
148-
expect(newContent.split('import \'hammerjs\';\n// test comment').length).toEqual(2);
158+
const ngJsonConfigResult = JSON.parse(tree.read('/angular.json').toString());
159+
expect(ngJsonConfigResult.projects.testProj.architect.build.options.scripts.length).toBe(0);
160+
expect(ngJsonConfigResult.projects.testProj.architect.build.options.scripts).not.toContain('./node_modules/hammerjs/hammer.min.js');
149161
});
150162

151163
it('should add hammer.js to package.json dependencies', async () => {
@@ -270,14 +282,14 @@ import 'web-animations-js'; // Run \`npm install --save web-animations-js\`.
270282
// import 'classlist.js'; // Run \`npm install --save classlist.js\`.
271283
272284
// import 'web-animations-js'; // Run \`npm install --save web-animations-js\`.
273-
`;
285+
`;
274286

275287
const result = `
276288
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
277289
// import 'classlist.js'; // Run \`npm install --save classlist.js\`.
278290
279291
import 'web-animations-js'; // Run \`npm install --save web-animations-js\`.
280-
`;
292+
`;
281293

282294
tree.create(`${sourceRoot}/polyfills.ts`, polyfills);
283295
const newJson: any = JSON.parse(tree.read('/angular.json').toString());

projects/igniteui-angular/schematics/ng-add/index.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { chain, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
22
import { Options } from '../interfaces/options';
33
import { installPackageJsonDependencies } from '../utils/package-handler';
4-
import { logSuccess, addDependencies, overwriteJsonFile,
5-
getPropertyFromWorkspace, getConfigFile } from '../utils/dependency-handler';
4+
import {
5+
logSuccess, addDependencies, overwriteJsonFile,
6+
getPropertyFromWorkspace, getConfigFile
7+
} from '../utils/dependency-handler';
68

79
import { addResetCss } from './add-normalize';
810
import { getWorkspace } from '@schematics/angular/utility/config';
@@ -20,7 +22,7 @@ function propertyExistsInWorkspace(targetProp: string, workspace: WorkspaceSchem
2022
function enablePolyfills(tree: Tree, context: SchematicContext): string {
2123
const workspace = getWorkspace(tree);
2224
const project = workspace.projects[workspace.defaultProject];
23-
const targetFile = getConfigFile(project, 'polyfills');
25+
const targetFile = getConfigFile(project, 'polyfills', context);
2426
if (!tree.exists(targetFile)) {
2527
context.logger.warn(`${targetFile} not found. You may need to update polyfills.ts manually.`);
2628
return;
@@ -54,18 +56,22 @@ function readInput(options: Options): Rule {
5456
const workspace = getWorkspace(tree);
5557
const targetProperty = 'es5BrowserSupport';
5658
const project = workspace.projects[workspace.defaultProject];
57-
const polyfillsFile = getConfigFile(project, 'polyfills');
58-
const propertyExists = propertyExistsInWorkspace(targetProperty, workspace);
59-
let polyfillsData = tree.read(polyfillsFile).toString();
60-
if (propertyExists) {
61-
// If project targets angular cli version >= 7.3
62-
workspace.projects[workspace.defaultProject].architect.build.options[targetProperty] = true;
63-
enableWebAnimationsAndGridSupport(tree, polyfillsFile, polyfillsData);
64-
overwriteJsonFile(tree, 'angular.json', workspace);
59+
const polyfillsFile = getConfigFile(project, 'polyfills', context);
60+
if (polyfillsFile !== undefined) {
61+
const propertyExists = propertyExistsInWorkspace(targetProperty, workspace);
62+
let polyfillsData = tree.read(polyfillsFile).toString();
63+
if (propertyExists) {
64+
// If project targets angular cli version >= 7.3
65+
workspace.projects[workspace.defaultProject].architect.build.options[targetProperty] = true;
66+
enableWebAnimationsAndGridSupport(tree, polyfillsFile, polyfillsData);
67+
overwriteJsonFile(tree, 'angular.json', workspace);
68+
} else {
69+
// If project targets angular cli version < 7.3
70+
polyfillsData = enablePolyfills(tree, context);
71+
enableWebAnimationsAndGridSupport(tree, polyfillsFile, polyfillsData);
72+
}
6573
} else {
66-
// If project targets angular cli version < 7.3
67-
polyfillsData = enablePolyfills(tree, context);
68-
enableWebAnimationsAndGridSupport(tree, polyfillsFile, polyfillsData);
74+
context.logger.warn(`You may want to manually uncomment '// import 'web-animations-js' in polyfills.ts`);
6975
}
7076
}
7177
};

projects/igniteui-angular/schematics/utils/dependency-handler.ts

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,31 @@ const schematicsPackage = '@igniteui/angular-schematics';
2222
* unnecessary packages to the consuming project's deps
2323
*/
2424
export const DEPENDENCIES_MAP: PackageEntry[] = [
25-
// dependencies
26-
{ name: 'hammerjs', target: PackageTarget.REGULAR },
27-
{ name: 'jszip', target: PackageTarget.REGULAR },
28-
{ name: 'tslib', target: PackageTarget.NONE },
29-
{ name: 'resize-observer-polyfill', target: PackageTarget.REGULAR },
30-
{ name: '@types/hammerjs', target: PackageTarget.DEV },
31-
{ name: 'igniteui-trial-watermark', target: PackageTarget.NONE },
32-
{ name: 'lodash.mergewith', target: PackageTarget.NONE },
33-
{ name: 'uuid', target: PackageTarget.NONE },
34-
{ name: 'web-animations-js', target: PackageTarget.REGULAR },
35-
{ name: '@igniteui/material-icons-extended', target: PackageTarget.REGULAR },
36-
// peerDependencies
37-
{ name: '@angular/forms', target: PackageTarget.NONE },
38-
{ name: '@angular/common', target: PackageTarget.NONE },
39-
{ name: '@angular/core', target: PackageTarget.NONE },
40-
{ name: '@angular/animations', target: PackageTarget.NONE },
41-
// igxDevDependencies
42-
{ name: '@igniteui/angular-schematics', target: PackageTarget.DEV }
25+
// dependencies
26+
{ name: 'hammerjs', target: PackageTarget.REGULAR },
27+
{ name: 'jszip', target: PackageTarget.REGULAR },
28+
{ name: 'tslib', target: PackageTarget.NONE },
29+
{ name: 'resize-observer-polyfill', target: PackageTarget.REGULAR },
30+
{ name: '@types/hammerjs', target: PackageTarget.DEV },
31+
{ name: 'igniteui-trial-watermark', target: PackageTarget.NONE },
32+
{ name: 'lodash.mergewith', target: PackageTarget.NONE },
33+
{ name: 'uuid', target: PackageTarget.NONE },
34+
{ name: 'web-animations-js', target: PackageTarget.REGULAR },
35+
{ name: '@igniteui/material-icons-extended', target: PackageTarget.REGULAR },
36+
// peerDependencies
37+
{ name: '@angular/forms', target: PackageTarget.NONE },
38+
{ name: '@angular/common', target: PackageTarget.NONE },
39+
{ name: '@angular/core', target: PackageTarget.NONE },
40+
{ name: '@angular/animations', target: PackageTarget.NONE },
41+
// igxDevDependencies
42+
{ name: '@igniteui/angular-schematics', target: PackageTarget.DEV }
4343
];
4444

4545
function logIncludingDependency(context: SchematicContext, pkg: string, version: string): void {
4646
context.logger.info(`Including ${pkg} - Version: ${version}`);
4747
}
4848

49-
function getTargetedProjectOptions(project: WorkspaceProject<ProjectType>, target: string) {
49+
function getTargetedProjectOptions(project: WorkspaceProject<ProjectType>, target: string, context: SchematicContext) {
5050
if (project.targets &&
5151
project.targets[target] &&
5252
project.targets[target].options) {
@@ -59,22 +59,29 @@ function getTargetedProjectOptions(project: WorkspaceProject<ProjectType>, targe
5959
return project.architect[target].options;
6060
}
6161

62-
throw new SchematicsException(`Cannot determine the project's configuration for: ${target}`);
62+
context.logger.warn(`Could not find matching ${target} options ` +
63+
`in Angular workspace ${project.sourceRoot}. ` +
64+
`It could require you to manually add and update the ${target} section.`);
6365
}
6466

65-
export function getConfigFile(project: WorkspaceProject<ProjectType>, option: string, configSection: string = 'build'): string {
66-
const options = getTargetedProjectOptions(project, configSection);
67+
export function getConfigFile(
68+
project: WorkspaceProject<ProjectType>, option: string, context: SchematicContext, configSection: string = 'build'): string {
69+
const options = getTargetedProjectOptions(project, configSection, context);
6770
if (!options) {
68-
throw new SchematicsException(`Could not find matching ${configSection} section` +
69-
`inside of the workspace config ${project.sourceRoot} `);
71+
context.logger.warn(`Could not find matching ${configSection} options in Angular workspace. ` +
72+
`It could require you to manually add and update the ${configSection} options.`);
73+
7074
}
71-
if (!options[option]) {
72-
throw new SchematicsException(`Could not find the project ${option} file inside of the ` +
73-
`workspace config ${project.sourceRoot}`);
75+
if (options) {
76+
if (!options[option]) {
77+
context.logger.warn(`Could not find a matching ${option} property under ${configSection} options in Angular workspace. ` +
78+
`Some updates may not execute correctly.`);
79+
} else {
80+
return options[option];
81+
}
7482
}
75-
return options[option];
76-
7783
}
84+
7885
export function overwriteJsonFile(tree: Tree, targetFile: string, data: any) {
7986
tree.overwrite(targetFile, JSON.stringify(data, null, 2) + '\n');
8087
}
@@ -139,35 +146,40 @@ export function getPropertyFromWorkspace(targetProp: string, workspace: any, cur
139146
return null;
140147
}
141148

142-
function addHammerToConfig(project: WorkspaceProject<ProjectType>, tree: Tree, config: string) {
143-
const projectOptions = getTargetedProjectOptions(project, config);
144-
const tsPath = getConfigFile(project, 'main', config);
149+
const addHammerToConfig = (workspace, project: WorkspaceProject<ProjectType>, tree: Tree, config: string, context: SchematicContext) => {
150+
const projectOptions = getTargetedProjectOptions(project, config, context);
151+
const tsPath = getConfigFile(project, 'main', context, config);
145152
const hammerImport = 'import \'hammerjs\';\n';
146-
const tsContent = tree.read(tsPath).toString();
153+
const tsContent = tree.read(tsPath)?.toString();
147154
// if there are no elements in the architect[config]options.scripts array that contain hammerjs
148155
// and the "main" file does not contain an import with hammerjs
149-
if (!projectOptions.scripts.some(el => el.includes('hammerjs')) && !tsContent.includes(hammerImport)) {
150-
// import hammerjs in the specified by config main file
151-
const mainContents = hammerImport + tsContent;
152-
tree.overwrite(tsPath, mainContents);
156+
if (!projectOptions?.scripts?.some(el => el.includes('hammerjs')) && !tsContent?.includes(hammerImport)) {
157+
const hammerjsFilePath = './node_modules/hammerjs/hammer.min.js';
158+
if (projectOptions?.scripts) {
159+
projectOptions.scripts.push(hammerjsFilePath);
160+
overwriteJsonFile(tree, 'angular.json', workspace);
161+
return;
162+
}
163+
context.logger.warn(`Could not find a matching scripts array property under ${config} options. ` +
164+
`It could require you to manually update it to 'scripts': [ ${hammerjsFilePath}] `);
153165
}
154-
}
166+
};
155167

156168
function includeDependencies(pkgJson: any, context: SchematicContext, tree: Tree) {
157169
Object.keys(pkgJson.dependencies).forEach(pkg => {
158170
const version = pkgJson.dependencies[pkg];
159171
const entry = DEPENDENCIES_MAP.find(e => e.name === pkg);
172+
const workspace = getWorkspace(tree);
173+
const defaultProject = workspace.projects[workspace.defaultProject];
160174
if (!entry || entry.target === PackageTarget.NONE) {
161175
return;
162176
}
163177
switch (pkg) {
164178
case 'hammerjs':
165179
logIncludingDependency(context, pkg, version);
166180
addPackageToPkgJson(tree, pkg, version, entry.target);
167-
const workspace = getWorkspace(tree);
168-
const project = workspace.projects[workspace.defaultProject];
169-
addHammerToConfig(project, tree, 'build');
170-
addHammerToConfig(project, tree, 'test');
181+
addHammerToConfig(workspace, defaultProject, tree, 'build', context);
182+
addHammerToConfig(workspace, defaultProject, tree, 'test', context);
171183
break;
172184
default:
173185
logIncludingDependency(context, pkg, version);

0 commit comments

Comments
 (0)