refactor(ng-generate): use .template suffix for schematic template files (#16213)

Switches all schematic template files to the `.template` file extension. This
ensures that these files are not accidentally picked up in external
projects (e.g. when building the summary files with ngc).

Related to https://github.com/angular/components/issues/16189
This commit is contained in:
Paul Gschwendtner
2019-06-07 05:28:37 +02:00
committed by Joey Perrott
parent f7ce72146b
commit f6903da4bb
45 changed files with 333 additions and 196 deletions
+4 -2
View File
@@ -17,7 +17,9 @@ describe('CDK ng-add', () => {
const dependencies = packageJson.dependencies;
expect(dependencies['@angular/cdk']).toBeDefined();
expect(Object.keys(dependencies)).toEqual(Object.keys(dependencies).sort(),
'Expected the modified "dependencies" to be sorted alphabetically.');
expect(Object.keys(dependencies))
.toEqual(
Object.keys(dependencies).sort(),
'Expected the modified "dependencies" to be sorted alphabetically.');
});
});
+1 -1
View File
@@ -29,7 +29,7 @@ export default function(): Rule {
}
/** Loads the full version from the given Angular package gracefully. */
function loadPackageVersionGracefully(packageName: string): string | null {
function loadPackageVersionGracefully(packageName: string): string|null {
try {
return require(`${packageName}/package.json`).version;
} catch {
@@ -44,8 +44,11 @@ describe('CDK drag-drop schematic', () => {
describe('style option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'drag-drop', {style: 'scss', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'drag-drop', {style: 'scss', ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});
@@ -68,21 +71,30 @@ describe('CDK drag-drop schematic', () => {
});
it('should not generate invalid stylesheets', async () => {
const tree = await runner.runSchematicAsync(
'drag-drop', {style: 'styl', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'drag-drop', {style: 'styl', ...baseOptions}, await createTestApp(runner))
.toPromise();
// In this case we expect the schematic to generate a plain "css" file because
// the component schematics are using CSS style templates which are not compatible
// with all CLI supported styles (e.g. Stylus or Sass)
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.css',
'Expected the schematic to generate a plain "css" file.');
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.styl',
'Expected the schematic to not generate a "stylus" file');
expect(tree.files)
.toContain(
'/projects/material/src/app/foo/foo.component.css',
'Expected the schematic to generate a plain "css" file.');
expect(tree.files)
.not.toContain(
'/projects/material/src/app/foo/foo.component.styl',
'Expected the schematic to not generate a "stylus" file');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'drag-drop', baseOptions, await createTestApp(runner, {style: 'less'})).toPromise();
const tree = await runner
.runSchematicAsync(
'drag-drop', baseOptions, await createTestApp(runner, {style: 'less'}))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
@@ -91,15 +103,19 @@ describe('CDK drag-drop schematic', () => {
describe('inlineStyle option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'drag-drop', {inlineStyle: true, ...baseOptions}, app).toPromise();
const tree =
await runner.runSchematicAsync('drag-drop', {inlineStyle: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'drag-drop', baseOptions, await createTestApp(runner, {inlineStyle: true})).toPromise();
const tree =
await runner
.runSchematicAsync(
'drag-drop', baseOptions, await createTestApp(runner, {inlineStyle: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
@@ -108,8 +124,9 @@ describe('CDK drag-drop schematic', () => {
describe('inlineTemplate option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'drag-drop', {inlineTemplate: true, ...baseOptions}, app).toPromise();
const tree =
await runner.runSchematicAsync('drag-drop', {inlineTemplate: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
@@ -124,8 +141,11 @@ describe('CDK drag-drop schematic', () => {
describe('skipTests option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'drag-drop', {skipTests: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'drag-drop', {skipTests: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -148,8 +168,10 @@ describe('CDK drag-drop schematic', () => {
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'drag-drop', baseOptions, await createTestApp(runner, {skipTests: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'drag-drop', baseOptions, await createTestApp(runner, {skipTests: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -14,8 +14,9 @@ import {Schema} from './schema';
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__',
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet:
'./__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template',
}),
options.skipImport ? noop() : addDragDropModulesToModule(options)
]);
+3 -2
View File
@@ -46,7 +46,8 @@ export function postUpdate(): Rule {
console.log();
console.log(green(' ✓ Angular CDK update complete'));
console.log();
console.log(yellow(' ⚠ Please check the output above for any issues that were detected ' +
'but could not be automatically fixed.'));
console.log(yellow(
' ⚠ Please check the output above for any issues that were detected ' +
'but could not be automatically fixed.'));
};
}
+5 -5
View File
@@ -9,6 +9,7 @@
import {strings, template as interpolateTemplate} from '@angular-devkit/core';
import {
apply,
applyTemplates,
branchAndMerge,
chain,
filter,
@@ -17,7 +18,6 @@ import {
noop,
Rule,
SchematicsException,
template,
Tree,
url,
} from '@angular-devkit/schematics';
@@ -238,12 +238,12 @@ export function buildComponent(options: ComponentOptions,
}
const templateSource = apply(url(schematicFilesUrl), [
options.skipTests ? filter(path => !path.endsWith('.spec.ts')) : noop(),
options.inlineStyle ? filter(path => !path.endsWith('.__style__')) : noop(),
options.inlineTemplate ? filter(path => !path.endsWith('.html')) : noop(),
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),
options.inlineStyle ? filter(path => !path.endsWith('.__style__.template')) : noop(),
options.inlineTemplate ? filter(path => !path.endsWith('.html.template')) : noop(),
// Treat the template options as any, because the type definition for the template options
// is made unnecessarily explicit. Every type of object can be used in the EJS template.
template({indentTextContent, resolvedFiles, ...baseTemplateContext} as any),
applyTemplates({indentTextContent, resolvedFiles, ...baseTemplateContext} as any),
// TODO(devversion): figure out why we cannot just remove the first parameter
// See for example: angular-cli#schematics/angular/component/index.ts#L160
move(null as any, parsedPath.path),
+79 -62
View File
@@ -23,8 +23,9 @@ describe('ng-add schematic', () => {
/** Expects the given file to be in the styles of the specified workspace project. */
function expectProjectStyleFile(project: WorkspaceProject, filePath: string) {
expect(getProjectTargetOptions(project, 'build').styles).toContain(filePath,
`Expected "${filePath}" to be added to the project styles in the workspace.`);
expect(getProjectTargetOptions(project, 'build').styles)
.toContain(
filePath, `Expected "${filePath}" to be added to the project styles in the workspace.`);
}
/** Removes the specified dependency from the /package.json in the given tree. */
@@ -48,13 +49,19 @@ describe('ng-add schematic', () => {
expect(dependencies['@angular/material']).toBeDefined();
expect(dependencies['@angular/cdk']).toBeDefined();
expect(dependencies['hammerjs']).toBeDefined();
expect(dependencies['@angular/forms']).toBe(angularCoreVersion,
'Expected the @angular/forms package to have the same version as @angular/core.');
expect(dependencies['@angular/animations']).toBe(angularCoreVersion,
'Expected the @angular/animations package to have the same version as @angular/core.');
expect(dependencies['@angular/forms'])
.toBe(
angularCoreVersion,
'Expected the @angular/forms package to have the same version as @angular/core.');
expect(dependencies['@angular/animations'])
.toBe(
angularCoreVersion,
'Expected the @angular/animations package to have the same version as @angular/core.');
expect(Object.keys(dependencies)).toEqual(Object.keys(dependencies).sort(),
'Expected the modified "dependencies" to be sorted alphabetically.');
expect(Object.keys(dependencies))
.toEqual(
Object.keys(dependencies).sort(),
'Expected the modified "dependencies" to be sorted alphabetically.');
expect(runner.tasks.some(task => task.name === 'run-schematic')).toBe(true);
});
@@ -63,8 +70,9 @@ describe('ng-add schematic', () => {
const tree = await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
const fileContent = getFileContent(tree, '/projects/material/src/main.ts');
expect(fileContent).toContain(`import 'hammerjs';`,
'Expected the project main file to contain a HammerJS import.');
expect(fileContent)
.toContain(
`import 'hammerjs';`, 'Expected the project main file to contain a HammerJS import.');
});
it('should add default theme', async () => {
@@ -73,16 +81,16 @@ describe('ng-add schematic', () => {
const workspace = getWorkspace(tree);
const project = getProjectFromWorkspace(workspace);
expectProjectStyleFile(project,
'./node_modules/@angular/material/prebuilt-themes/indigo-pink.css');
expectProjectStyleFile(
project, './node_modules/@angular/material/prebuilt-themes/indigo-pink.css');
});
it('should support adding a custom theme', async () => {
// TODO(devversion): do not re-create test app here.
appTree = await createTestApp(runner, {style: 'scss'});
const tree = await runner.runSchematicAsync('ng-add-setup-project',
{theme: 'custom'}, appTree).toPromise();
const tree = await runner.runSchematicAsync('ng-add-setup-project', {theme: 'custom'}, appTree)
.toPromise();
const workspace = getWorkspace(tree);
const project = getProjectFromWorkspace(workspace);
@@ -99,8 +107,8 @@ describe('ng-add schematic', () => {
// TODO(devversion): do not re-create test app here.
appTree = await createTestApp(runner, {style: 'css'});
const tree = await runner.runSchematicAsync('ng-add-setup-project',
{theme: 'custom'}, appTree).toPromise();
const tree = await runner.runSchematicAsync('ng-add-setup-project', {theme: 'custom'}, appTree)
.toPromise();
const workspace = getWorkspace(tree);
const project = getProjectFromWorkspace(workspace);
const expectedStylesPath = normalize(`/${project.root}/src/custom-theme.scss`);
@@ -121,10 +129,10 @@ describe('ng-add schematic', () => {
// Ensure that the indentation has been determined properly. We want to make sure that
// the created links properly align with the existing HTML. Default CLI projects use an
// indentation of two columns.
expect(htmlContent).toContain(
' <link href="https://fonts.googleapis.com/icon?family=Material+Icons"');
expect(htmlContent).toContain(
' <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"');
expect(htmlContent)
.toContain(' <link href="https://fonts.googleapis.com/icon?family=Material+Icons"');
expect(htmlContent)
.toContain(' <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"');
});
it('should add material app styles', async () => {
@@ -136,26 +144,27 @@ describe('ng-add schematic', () => {
const htmlContent = tree.read(defaultStylesPath)!.toString();
expect(htmlContent).toContain('html, body { height: 100%; }');
expect(htmlContent).toContain(
'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }');
expect(htmlContent)
.toContain('body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }');
});
describe('gestures disabled', () => {
it('should not add hammerjs to package.json', async () => {
const tree = await runner.runSchematicAsync('ng-add', {gestures: false}, appTree).toPromise();
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
expect(packageJson.dependencies['hammerjs'])
.toBeUndefined(`Expected 'hammerjs' to be not added to the package.json`);
.toBeUndefined(`Expected 'hammerjs' to be not added to the package.json`);
});
it('should not add hammerjs import to project main file', async () => {
const tree = await runner.runSchematicAsync('ng-add', {gestures: false}, appTree).toPromise();
const fileContent = getFileContent(tree, '/projects/material/src/main.ts');
expect(fileContent).not.toContain(`import 'hammerjs';`,
'Expected the project main file to not contain a HammerJS import.');
expect(fileContent)
.not.toContain(
`import 'hammerjs';`,
'Expected the project main file to not contain a HammerJS import.');
});
});
@@ -164,8 +173,10 @@ describe('ng-add schematic', () => {
const tree = await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
const fileContent = getFileContent(tree, '/projects/material/src/app/app.module.ts');
expect(fileContent).toContain('BrowserAnimationsModule',
'Expected the project app module to import the "BrowserAnimationsModule".');
expect(fileContent)
.toContain(
'BrowserAnimationsModule',
'Expected the project app module to import the "BrowserAnimationsModule".');
});
it('should not add BrowserAnimationsModule if NoopAnimationsModule is set up', async () => {
@@ -176,25 +187,29 @@ describe('ng-add schematic', () => {
// explicitly uses the `NoopAnimationsModule`. It would be wrong to forcibly enable browser
// animations without knowing what other components would be affected. In this case, we
// just print a warning message.
addModuleImportToRootModule(appTree, 'NoopAnimationsModule',
'@angular/platform-browser/animations', project);
addModuleImportToRootModule(
appTree, 'NoopAnimationsModule', '@angular/platform-browser/animations', project);
spyOn(console, 'warn');
await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
expect(console.warn).toHaveBeenCalledWith(
jasmine.stringMatching(/Could not set up "BrowserAnimationsModule"/));
expect(console.warn)
.toHaveBeenCalledWith(
jasmine.stringMatching(/Could not set up "BrowserAnimationsModule"/));
});
});
describe('animations disabled', () => {
it('should add the NoopAnimationsModule to the project module', async () => {
const tree = await runner.runSchematicAsync('ng-add-setup-project',
{animations: false}, appTree).toPromise();
const tree =
await runner.runSchematicAsync('ng-add-setup-project', {animations: false}, appTree)
.toPromise();
const fileContent = getFileContent(tree, '/projects/material/src/app/app.module.ts');
expect(fileContent).toContain('NoopAnimationsModule',
'Expected the project app module to import the "NoopAnimationsModule".');
expect(fileContent)
.toContain(
'NoopAnimationsModule',
'Expected the project app module to import the "NoopAnimationsModule".');
});
it('should not add NoopAnimationsModule if BrowserAnimationsModule is set up', () => {
@@ -204,22 +219,23 @@ describe('ng-add schematic', () => {
// Simulate the case where a developer uses `ng-add` on an Angular CLI project which already
// explicitly uses the `BrowserAnimationsModule`. It would be wrong to forcibly change
// to noop animations.
const fileContent = addModuleImportToRootModule(appTree, 'BrowserAnimationsModule',
'@angular/platform-browser/animations', project);
const fileContent = addModuleImportToRootModule(
appTree, 'BrowserAnimationsModule', '@angular/platform-browser/animations', project);
expect(fileContent).not.toContain('NoopAnimationsModule',
'Expected the project app module to not import the "NoopAnimationsModule".');
expect(fileContent)
.not.toContain(
'NoopAnimationsModule',
'Expected the project app module to not import the "NoopAnimationsModule".');
});
});
describe('custom project builders', () => {
/** Overwrites a target builder for the workspace in the given tree */
function overwriteTargetBuilder(tree: Tree, targetName: string, newBuilder: string) {
const workspace = getWorkspace(tree);
const project = getProjectFromWorkspace(workspace);
const targetConfig = project.architect && project.architect[targetName] ||
project.targets && project.targets[targetName];
project.targets && project.targets[targetName];
targetConfig['builder'] = newBuilder;
tree.overwrite('/angular.json', JSON.stringify(workspace, null, 2));
}
@@ -227,7 +243,7 @@ describe('ng-add schematic', () => {
it('should throw an error if the "build" target has been changed', async () => {
overwriteTargetBuilder(appTree, 'build', 'thirdparty-builder');
let message: string | null = null;
let message: string|null = null;
try {
await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
@@ -244,16 +260,16 @@ describe('ng-add schematic', () => {
spyOn(console, 'warn');
await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
expect(console.warn).toHaveBeenCalledWith(
jasmine.stringMatching(/not using the default builders.*cannot add the configured theme/));
expect(console.warn)
.toHaveBeenCalledWith(jasmine.stringMatching(
/not using the default builders.*cannot add the configured theme/));
});
});
describe('theme files', () => {
/** Path to the default prebuilt theme file that will be added when running ng-add. */
const defaultPrebuiltThemePath =
'./node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
'./node_modules/@angular/material/prebuilt-themes/indigo-pink.css';
/** Writes a specific style file to the workspace in the given tree */
function writeStyleFileToWorkspace(tree: Tree, stylePath: string) {
@@ -271,8 +287,7 @@ describe('ng-add schematic', () => {
}
it('should replace existing prebuilt theme files', async () => {
const existingThemePath =
'./node_modules/@angular/material/prebuilt-themes/purple-green.css';
const existingThemePath = './node_modules/@angular/material/prebuilt-themes/purple-green.css';
writeStyleFileToWorkspace(appTree, existingThemePath);
const tree = await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
@@ -280,10 +295,10 @@ describe('ng-add schematic', () => {
const project = getProjectFromWorkspace(workspace);
const styles = getProjectTargetOptions(project, 'build').styles;
expect(styles).not.toContain(existingThemePath,
'Expected the existing prebuilt theme file to be removed.');
expect(styles).toContain(defaultPrebuiltThemePath,
'Expected the default prebuilt theme to be added.');
expect(styles).not.toContain(
existingThemePath, 'Expected the existing prebuilt theme file to be removed.');
expect(styles).toContain(
defaultPrebuiltThemePath, 'Expected the default prebuilt theme to be added.');
});
it('should not replace existing custom theme files', async () => {
@@ -295,10 +310,10 @@ describe('ng-add schematic', () => {
const project = getProjectFromWorkspace(workspace);
const styles = getProjectTargetOptions(project, 'build').styles;
expect(styles).not.toContain(defaultPrebuiltThemePath,
'Expected the default prebuilt theme to be not configured.');
expect(console.warn).toHaveBeenCalledWith(
jasmine.stringMatching(/Could not add the selected theme/));
expect(styles).not.toContain(
defaultPrebuiltThemePath, 'Expected the default prebuilt theme to be not configured.');
expect(console.warn)
.toHaveBeenCalledWith(jasmine.stringMatching(/Could not add the selected theme/));
});
it('should not add a theme file multiple times', async () => {
@@ -309,17 +324,19 @@ describe('ng-add schematic', () => {
const project = getProjectFromWorkspace(workspace);
const styles = getProjectTargetOptions(project, 'build').styles;
expect(styles).toEqual(['projects/material/src/styles.css', defaultPrebuiltThemePath],
expect(styles).toEqual(
['projects/material/src/styles.css', defaultPrebuiltThemePath],
'Expected the "styles.css" file and default prebuilt theme to be the only styles');
});
it('should not overwrite existing custom theme files', async () => {
appTree.create('/projects/material/custom-theme.scss', 'custom-theme');
const tree = await runner.runSchematicAsync('ng-add-setup-project',
{theme: 'custom'}, appTree).toPromise();
const tree =
await runner.runSchematicAsync('ng-add-setup-project', {theme: 'custom'}, appTree)
.toPromise();
expect(tree.readContent('/projects/material/custom-theme.scss')).toBe('custom-theme',
'Expected the old custom theme content to be unchanged.');
expect(tree.readContent('/projects/material/custom-theme.scss'))
.toBe('custom-theme', 'Expected the old custom theme content to be unchanged.');
});
});
});
+1 -1
View File
@@ -25,7 +25,7 @@ export default function(options: Schema): Rule {
// of the CLI project. This tag should be preferred because all Angular dependencies should
// have the same version tag if possible.
const ngCoreVersionTag = getPackageVersionFromPackageJson(host, '@angular/core');
const angularDependencyVersion = ngCoreVersionTag || requiredAngularVersionRange;
const angularDependencyVersion = ngCoreVersionTag || requiredAngularVersionRange;
// In order to align the Material and CDK version with the other Angular dependencies,
// we use tilde instead of caret. This is default for Angular dependencies in new CLI projects.
@@ -43,7 +43,7 @@ describe('Material address-form schematic', () => {
it('should throw if no name has been specified', async () => {
const appTree = await createTestApp(runner);
let message: string | null = null;
let message: string|null = null;
try {
await runner.runSchematicAsync('address-form', {project: 'material'}, appTree).toPromise();
@@ -56,15 +56,21 @@ describe('Material address-form schematic', () => {
describe('style option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'address-form', {style: 'scss', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'address-form', {style: 'scss', ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'address-form', baseOptions, await createTestApp(runner, {style: 'less'})).toPromise();
const tree =
await runner
.runSchematicAsync(
'address-form', baseOptions, await createTestApp(runner, {style: 'less'}))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
@@ -73,10 +79,13 @@ describe('Material address-form schematic', () => {
describe('inlineStyle option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'address-form', {inlineStyle: true, ...baseOptions}, app).toPromise();
const tree =
await runner.runSchematicAsync('address-form', {inlineStyle: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
expect(tree.readContent('/projects/material/src/app/foo/foo.component.ts'))
.toContain('styles: [`');
});
it('should fall back to the @schematics/angular:component option value', async () => {
@@ -90,10 +99,14 @@ describe('Material address-form schematic', () => {
describe('inlineTemplate option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'address-form', {inlineTemplate: true, ...baseOptions}, app).toPromise();
const tree =
await runner
.runSchematicAsync('address-form', {inlineTemplate: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
expect(tree.readContent('/projects/material/src/app/foo/foo.component.ts'))
.toContain('template: `');
});
it('should fall back to the @schematics/angular:component option value', async () => {
@@ -107,15 +120,19 @@ describe('Material address-form schematic', () => {
describe('skipTests option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'address-form', {skipTests: true, ...baseOptions}, app).toPromise();
const tree =
await runner.runSchematicAsync('address-form', {skipTests: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'address-form', baseOptions, await createTestApp(runner, {skipTests: true})).toPromise();
const tree =
await runner
.runSchematicAsync(
'address-form', baseOptions, await createTestApp(runner, {skipTests: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -21,8 +21,9 @@ import {Schema} from './schema';
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__',
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet:
'./__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template',
}),
options.skipImport ? noop() : addFormModulesToModule(options)
]);
@@ -47,7 +47,7 @@ describe('material-dashboard-schematic', () => {
it('should throw if no name has been specified', async () => {
const appTree = await createTestApp(runner);
let message: string | null = null;
let message: string|null = null;
try {
await runner.runSchematicAsync('dashboard', {project: 'material'}, appTree).toPromise();
@@ -60,15 +60,20 @@ describe('material-dashboard-schematic', () => {
describe('style option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'dashboard', {style: 'scss', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'dashboard', {style: 'scss', ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'dashboard', baseOptions, await createTestApp(runner, {style: 'less'})).toPromise();
const tree = await runner
.runSchematicAsync(
'dashboard', baseOptions, await createTestApp(runner, {style: 'less'}))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
@@ -77,15 +82,19 @@ describe('material-dashboard-schematic', () => {
describe('inlineStyle option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'dashboard', {inlineStyle: true, ...baseOptions}, app).toPromise();
const tree =
await runner.runSchematicAsync('dashboard', {inlineStyle: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'dashboard', baseOptions, await createTestApp(runner, {inlineStyle: true})).toPromise();
const tree =
await runner
.runSchematicAsync(
'dashboard', baseOptions, await createTestApp(runner, {inlineStyle: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
@@ -94,8 +103,9 @@ describe('material-dashboard-schematic', () => {
describe('inlineTemplate option', () => {
it('should respect the option value', async () => {
const app = await createTestApp(runner);
const tree = await runner.runSchematicAsync(
'dashboard', {inlineTemplate: true, ...baseOptions}, app).toPromise();
const tree =
await runner.runSchematicAsync('dashboard', {inlineTemplate: true, ...baseOptions}, app)
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
@@ -110,15 +120,20 @@ describe('material-dashboard-schematic', () => {
describe('skipTests option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'dashboard', {skipTests: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'dashboard', {skipTests: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'dashboard', baseOptions, await createTestApp(runner, {skipTests: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'dashboard', baseOptions, await createTestApp(runner, {skipTests: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -21,8 +21,9 @@ import {Schema} from './schema';
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__',
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet:
'./__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template',
}),
options.skipImport ? noop() : addNavModulesToModule(options)
]);
@@ -1,7 +1,8 @@
import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
import {Schema} from './schema';
import {createTestApp, getFileContent} from '@angular/cdk/schematics/testing';
import {Schema} from './schema';
describe('material-nav-schematic', () => {
let runner: SchematicTestRunner;
@@ -42,14 +43,15 @@ describe('material-nav-schematic', () => {
expect(moduleContent).toContain('MatListModule');
expect(moduleContent).toContain(`import { LayoutModule } from '@angular/cdk/layout';`);
expect(moduleContent).toContain(
`import { MatToolbarModule, MatButtonModule, MatSidenavModule, MatIconModule, ` +
`MatListModule } from '@angular/material';`);
expect(moduleContent)
.toContain(
`import { MatToolbarModule, MatButtonModule, MatSidenavModule, MatIconModule, ` +
`MatListModule } from '@angular/material';`);
});
it('should throw if no name has been specified', async () => {
const appTree = await createTestApp(runner);
let message: string | null = null;
let message: string|null = null;
try {
await runner.runSchematicAsync('nav', {project: 'material'}, appTree).toPromise();
@@ -62,15 +64,19 @@ describe('material-nav-schematic', () => {
describe('style option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', {style: 'scss', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'nav', {style: 'scss', ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', baseOptions, await createTestApp(runner, {style: 'less'})).toPromise();
const tree =
await runner
.runSchematicAsync('nav', baseOptions, await createTestApp(runner, {style: 'less'}))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
@@ -78,15 +84,19 @@ describe('material-nav-schematic', () => {
describe('inlineStyle option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', {inlineStyle: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'nav', {inlineStyle: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', baseOptions, await createTestApp(runner, {inlineStyle: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'nav', baseOptions, await createTestApp(runner, {inlineStyle: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
@@ -94,15 +104,20 @@ describe('material-nav-schematic', () => {
describe('inlineTemplate option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', {inlineTemplate: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'nav', {inlineTemplate: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', baseOptions, await createTestApp(runner, {inlineTemplate: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'nav', baseOptions, await createTestApp(runner, {inlineTemplate: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
@@ -110,15 +125,19 @@ describe('material-nav-schematic', () => {
describe('skipTests option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', {skipTests: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'nav', {skipTests: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'nav', baseOptions, await createTestApp(runner, {skipTests: true})).toPromise();
const tree =
await runner
.runSchematicAsync('nav', baseOptions, await createTestApp(runner, {skipTests: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -21,8 +21,9 @@ import {Schema} from './schema';
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__',
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet:
'./__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template',
}),
options.skipImport ? noop() : addNavModulesToModule(options)
]);
@@ -29,14 +29,14 @@ describe('material-table-schematic', () => {
expect(moduleContent).toMatch(/import.*Foo.*from '.\/foo\/foo.component'/);
expect(moduleContent).toMatch(/declarations:\s*\[[^\]]+?,\r?\n\s+FooComponent\r?\n/m);
const datasourceContent = getFileContent(tree,
'/projects/material/src/app/foo/foo-datasource.ts');
const datasourceContent =
getFileContent(tree, '/projects/material/src/app/foo/foo-datasource.ts');
expect(datasourceContent).toContain('FooItem');
expect(datasourceContent).toContain('FooDataSource');
const componentContent = getFileContent(tree,
'/projects/material/src/app/foo/foo.component.ts');
const componentContent =
getFileContent(tree, '/projects/material/src/app/foo/foo.component.ts');
expect(componentContent).toContain('FooDataSource');
});
@@ -51,12 +51,12 @@ describe('material-table-schematic', () => {
expect(moduleContent).toContain('MatSortModule');
expect(moduleContent).toContain(
`import { MatTableModule, MatPaginatorModule, MatSortModule } from '@angular/material';`);
`import { MatTableModule, MatPaginatorModule, MatSortModule } from '@angular/material';`);
});
it('should throw if no name has been specified', async () => {
const appTree = await createTestApp(runner);
let message: string | null = null;
let message: string|null = null;
try {
await runner.runSchematicAsync('table', {project: 'material'}, appTree).toPromise();
@@ -69,15 +69,19 @@ describe('material-table-schematic', () => {
describe('style option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'table', {style: 'scss', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'table', {style: 'scss', ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {style: 'less'})).toPromise();
const tree =
await runner
.runSchematicAsync('table', baseOptions, await createTestApp(runner, {style: 'less'}))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
@@ -85,15 +89,20 @@ describe('material-table-schematic', () => {
describe('inlineStyle option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'table', {inlineStyle: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'table', {inlineStyle: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {inlineStyle: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {inlineStyle: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
@@ -101,15 +110,21 @@ describe('material-table-schematic', () => {
describe('inlineTemplate option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'table', {inlineTemplate: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'table', {inlineTemplate: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {inlineTemplate: true})).toPromise();
const tree =
await runner
.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {inlineTemplate: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
@@ -117,15 +132,19 @@ describe('material-table-schematic', () => {
describe('skipTests option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'table', {skipTests: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'table', {skipTests: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {skipTests: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'table', baseOptions, await createTestApp(runner, {skipTests: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -21,8 +21,9 @@ import {Schema} from './schema';
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__'
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet:
'./__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template'
}),
options.skipImport ? noop() : addTableModulesToModule(options)
]);
@@ -41,7 +41,7 @@ describe('Material tree schematic', () => {
it('should throw if no name has been specified', async () => {
const appTree = await createTestApp(runner);
let message: string | null = null;
let message: string|null = null;
try {
await runner.runSchematicAsync('tree', {project: 'material'}, appTree).toPromise();
@@ -54,15 +54,19 @@ describe('Material tree schematic', () => {
describe('style option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', {style: 'scss', ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'tree', {style: 'scss', ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {style: 'less'})).toPromise();
const tree =
await runner
.runSchematicAsync('tree', baseOptions, await createTestApp(runner, {style: 'less'}))
.toPromise();
expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less');
});
@@ -70,15 +74,19 @@ describe('Material tree schematic', () => {
describe('inlineStyle option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', {inlineStyle: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'tree', {inlineStyle: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {inlineStyle: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {inlineStyle: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.css');
});
@@ -86,15 +94,20 @@ describe('Material tree schematic', () => {
describe('inlineTemplate option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', {inlineTemplate: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree =
await runner
.runSchematicAsync(
'tree', {inlineTemplate: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {inlineTemplate: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {inlineTemplate: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.html');
});
@@ -102,15 +115,19 @@ describe('Material tree schematic', () => {
describe('skipTests option', () => {
it('should respect the option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', {skipTests: true, ...baseOptions}, await createTestApp(runner)).toPromise();
const tree = await runner
.runSchematicAsync(
'tree', {skipTests: true, ...baseOptions}, await createTestApp(runner))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
it('should fall back to the @schematics/angular:component option value', async () => {
const tree = await runner.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {skipTests: true})).toPromise();
const tree = await runner
.runSchematicAsync(
'tree', baseOptions, await createTestApp(runner, {skipTests: true}))
.toPromise();
expect(tree.files).not.toContain('/projects/material/src/app/foo/foo.component.spec.ts');
});
@@ -21,8 +21,9 @@ import {Schema} from './schema';
export default function(options: Schema): Rule {
return chain([
buildComponent({...options}, {
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html',
stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__',
template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',
stylesheet:
'./__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template',
}),
options.skipImport ? noop() : addTreeModulesToModule(options)
]);
+5 -3
View File
@@ -7,9 +7,10 @@
*/
import {Rule} from '@angular-devkit/schematics';
import {TargetVersion, createUpgradeRule, UpgradeTSLintConfig} from '@angular/cdk/schematics';
import {createUpgradeRule, TargetVersion, UpgradeTSLintConfig} from '@angular/cdk/schematics';
import {green, yellow} from 'chalk';
import {sync as globSync} from 'glob';
import {materialUpgradeData} from './upgrade-data';
/** List of additional upgrade rules for Angular Material. */
@@ -62,7 +63,8 @@ export function postUpdate(): Rule {
console.log();
console.log(green(' ✓ Angular Material update complete'));
console.log();
console.log(yellow(' ⚠ Please check the output above for any issues that were detected ' +
'but could not be automatically fixed.'));
console.log(yellow(
' ⚠ Please check the output above for any issues that were detected ' +
'but could not be automatically fixed.'));
};
}