diff --git a/src/lib/schematics/address-form/schema.json b/src/lib/schematics/address-form/schema.json index a1cc0c4629b6..10b9d2edb3b9 100644 --- a/src/lib/schematics/address-form/schema.json +++ b/src/lib/schematics/address-form/schema.json @@ -58,8 +58,7 @@ }, "styleext": { "description": "The file extension to be used for style files.", - "type": "string", - "default": "css" + "type": "string" }, "spec": { "type": "boolean", diff --git a/src/lib/schematics/dashboard/index.spec.ts b/src/lib/schematics/dashboard/index.spec.ts index 75bd231dd279..7fb9a1b4f4ea 100644 --- a/src/lib/schematics/dashboard/index.spec.ts +++ b/src/lib/schematics/dashboard/index.spec.ts @@ -5,13 +5,10 @@ import {Schema} from './schema'; describe('material-dashboard-schematic', () => { let runner: SchematicTestRunner; - const options: Schema = { + + const baseOptions: Schema = { name: 'foo', project: 'material', - changeDetection: 'Default', - styleext: 'css', - spec: true, - export: false, }; beforeEach(() => { @@ -19,7 +16,7 @@ describe('material-dashboard-schematic', () => { }); it('should create dashboard files and add them to module', () => { - const tree = runner.runSchematic('dashboard', { ...options }, createTestApp()); + const tree = runner.runSchematic('dashboard', baseOptions, createTestApp()); const files = tree.files; expect(files).toContain('/projects/material/src/app/foo/foo.component.css'); @@ -33,7 +30,7 @@ describe('material-dashboard-schematic', () => { }); it('should add dashboard imports to module', () => { - const tree = runner.runSchematic('dashboard', { ...options }, createTestApp()); + const tree = runner.runSchematic('dashboard', baseOptions, createTestApp()); const moduleContent = getFileContent(tree, '/projects/material/src/app/app.module.ts'); expect(moduleContent).toContain('MatGridListModule'); @@ -47,4 +44,17 @@ describe('material-dashboard-schematic', () => { `import { MatGridListModule, MatCardModule, MatMenuModule, MatIconModule, MatButtonModule } from '@angular/material';`); }); + it('should support passing the style extension option', () => { + const tree = runner.runSchematic( + 'dashboard', {styleext: 'scss', ...baseOptions}, createTestApp()); + + expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss'); + }); + + it('should fallback to the default angular:component style extension', () => { + const tree = runner.runSchematic('dashboard', baseOptions, createTestApp({style: 'less'})); + + expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less'); + }); + }); diff --git a/src/lib/schematics/dashboard/schema.json b/src/lib/schematics/dashboard/schema.json index 0d5075b99580..2806d5536324 100644 --- a/src/lib/schematics/dashboard/schema.json +++ b/src/lib/schematics/dashboard/schema.json @@ -58,8 +58,7 @@ }, "styleext": { "description": "The file extension to be used for style files.", - "type": "string", - "default": "css" + "type": "string" }, "spec": { "type": "boolean", diff --git a/src/lib/schematics/install/index.spec.ts b/src/lib/schematics/install/index.spec.ts index c2a4ed3bc455..f5adc31c01e1 100644 --- a/src/lib/schematics/install/index.spec.ts +++ b/src/lib/schematics/install/index.spec.ts @@ -41,7 +41,11 @@ describe('material-install-schematic', () => { './node_modules/@angular/material/prebuilt-themes/indigo-pink.css'); }); - it('should add custom theme', () => { + it('should support adding a custom theme', () => { + // TODO(devversion): currently a "custom" theme does only work for projects using SCSS. + // TODO(devversion): Throw an error if a custom theme is being installed in a CSS project. + appTree = createTestApp({style: 'scss'}); + const tree = runner.runSchematic('ng-add', {theme: 'custom'}, appTree); const workspace = getWorkspace(tree); diff --git a/src/lib/schematics/nav/index.spec.ts b/src/lib/schematics/nav/index.spec.ts index 37af2ca83cfd..bc2b2315544b 100644 --- a/src/lib/schematics/nav/index.spec.ts +++ b/src/lib/schematics/nav/index.spec.ts @@ -6,13 +6,9 @@ import {collectionPath, createTestApp} from '../test-setup/test-app'; describe('material-nav-schematic', () => { let runner: SchematicTestRunner; - const options: Schema = { + const baseOptions: Schema = { name: 'foo', project: 'material', - changeDetection: 'Default', - styleext: 'css', - spec: true, - export: false, }; beforeEach(() => { @@ -20,7 +16,7 @@ describe('material-nav-schematic', () => { }); it('should create nav files and add them to module', () => { - const tree = runner.runSchematic('nav', { ...options }, createTestApp()); + const tree = runner.runSchematic('nav', baseOptions, createTestApp()); const files = tree.files; expect(files).toContain('/projects/material/src/app/foo/foo.component.css'); @@ -34,7 +30,7 @@ describe('material-nav-schematic', () => { }); it('should add nav imports to module', () => { - const tree = runner.runSchematic('nav', { ...options }, createTestApp()); + const tree = runner.runSchematic('nav', baseOptions, createTestApp()); const moduleContent = getFileContent(tree, '/projects/material/src/app/app.module.ts'); expect(moduleContent).toContain('LayoutModule'); @@ -50,4 +46,15 @@ describe('material-nav-schematic', () => { `MatListModule } from '@angular/material';`); }); + it('should support passing the style extension option', () => { + const tree = runner.runSchematic('nav', {styleext: 'scss', ...baseOptions}, createTestApp()); + + expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss'); + }); + + it('should fallback to the default angular:component style extension', () => { + const tree = runner.runSchematic('nav', baseOptions, createTestApp({style: 'less'})); + + expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less'); + }); }); diff --git a/src/lib/schematics/nav/schema.json b/src/lib/schematics/nav/schema.json index ab0ab41202a2..2c73b0a35c51 100644 --- a/src/lib/schematics/nav/schema.json +++ b/src/lib/schematics/nav/schema.json @@ -58,8 +58,7 @@ }, "styleext": { "description": "The file extension to be used for style files.", - "type": "string", - "default": "css" + "type": "string" }, "spec": { "type": "boolean", diff --git a/src/lib/schematics/table/index.spec.ts b/src/lib/schematics/table/index.spec.ts index 5b32f7fea18e..317ccb25794d 100644 --- a/src/lib/schematics/table/index.spec.ts +++ b/src/lib/schematics/table/index.spec.ts @@ -6,13 +6,9 @@ import {collectionPath, createTestApp} from '../test-setup/test-app'; describe('material-table-schematic', () => { let runner: SchematicTestRunner; - const options: Schema = { + const baseOptions: Schema = { name: 'foo', project: 'material', - changeDetection: 'Default', - styleext: 'css', - spec: true, - export: false, }; beforeEach(() => { @@ -20,7 +16,7 @@ describe('material-table-schematic', () => { }); it('should create table files and add them to module', () => { - const tree = runner.runSchematic('table', { ...options }, createTestApp()); + const tree = runner.runSchematic('table', baseOptions, createTestApp()); const files = tree.files; expect(files).toContain('/projects/material/src/app/foo/foo.component.css'); @@ -45,8 +41,20 @@ describe('material-table-schematic', () => { expect(componentContent).toContain('FooDataSource'); }); + it('should support passing the style extension option', () => { + const tree = runner.runSchematic('table', {styleext: 'scss', ...baseOptions}, createTestApp()); + + expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.scss'); + }); + + it('should fallback to the default angular:component style extension', () => { + const tree = runner.runSchematic('table', baseOptions, createTestApp({style: 'less'})); + + expect(tree.files).toContain('/projects/material/src/app/foo/foo.component.less'); + }); + it('should add table imports to module', () => { - const tree = runner.runSchematic('table', { ...options }, createTestApp()); + const tree = runner.runSchematic('table', baseOptions, createTestApp()); const moduleContent = getFileContent(tree, '/projects/material/src/app/app.module.ts'); expect(moduleContent).toContain('MatTableModule'); diff --git a/src/lib/schematics/table/schema.json b/src/lib/schematics/table/schema.json index 89a07cd18a12..d12369c29167 100644 --- a/src/lib/schematics/table/schema.json +++ b/src/lib/schematics/table/schema.json @@ -58,8 +58,7 @@ }, "styleext": { "description": "The file extension to be used for style files.", - "type": "string", - "default": "css" + "type": "string" }, "spec": { "type": "boolean", diff --git a/src/lib/schematics/test-setup/test-app.ts b/src/lib/schematics/test-setup/test-app.ts index 65ce95870743..109b04cef7f4 100644 --- a/src/lib/schematics/test-setup/test-app.ts +++ b/src/lib/schematics/test-setup/test-app.ts @@ -16,7 +16,7 @@ export const collectionPath = join(__dirname, '..', 'collection.json'); export const migrationCollection = join(__dirname, '..', 'migration.json'); /** Create a base app used for testing. */ -export function createTestApp(): UnitTestTree { +export function createTestApp(appOptions = {}): UnitTestTree { const baseRunner = new SchematicTestRunner('material-schematics', collectionPath); const workspaceTree = baseRunner.runExternalSchematic('@schematics/angular', 'workspace', { @@ -25,12 +25,6 @@ export function createTestApp(): UnitTestTree { newProjectRoot: 'projects', }); - return baseRunner.runExternalSchematic('@schematics/angular', 'application', { - name: 'material', - inlineStyle: false, - inlineTemplate: false, - routing: false, - style: 'scss', - skipTests: false, - }, workspaceTree); + return baseRunner.runExternalSchematic('@schematics/angular', 'application', + {...appOptions, name: 'material'}, workspaceTree); } diff --git a/src/lib/schematics/tree/schema.json b/src/lib/schematics/tree/schema.json index d76921c4a0ad..196de863380e 100644 --- a/src/lib/schematics/tree/schema.json +++ b/src/lib/schematics/tree/schema.json @@ -58,8 +58,7 @@ }, "styleext": { "description": "The file extension to be used for style files.", - "type": "string", - "default": "css" + "type": "string" }, "spec": { "type": "boolean", diff --git a/src/lib/schematics/utils/build-component.ts b/src/lib/schematics/utils/build-component.ts index 88d91f48b704..f9fa09f71dd6 100644 --- a/src/lib/schematics/utils/build-component.ts +++ b/src/lib/schematics/utils/build-component.ts @@ -39,6 +39,7 @@ import {validateHtmlSelector, validateName} from '@schematics/angular/utility/va import {resolve, dirname, join} from 'path'; import {readFileSync} from 'fs'; import * as ts from 'typescript'; +import {determineDefaultStyleExt} from './default-style-ext'; function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile { const text = host.read(modulePath); @@ -137,7 +138,7 @@ function buildSelector(options: ComponentOptions, projectPrefix: string) { */ function indentTextContent(text: string, numSpaces: number): string { // In the Material project there should be only LF line-endings, but the schematic files - // are not being linted and therefore there can be also use CRLF or just CR line-endings. + // are not being linted and therefore there can be also CRLF or just CR line-endings. return text.replace(/(\r\n|\r|\n)/g, `$1${' '.repeat(numSpaces)}`); } @@ -160,6 +161,10 @@ export function buildComponent(options: ComponentOptions, const schematicFilesPath = resolve(dirname(context.schematic.description.path), schematicFilesUrl); + if (!options.styleext) { + options.styleext = determineDefaultStyleExt(project); + } + if (options.path === undefined) { options.path = buildDefaultPath(project); } @@ -167,6 +172,7 @@ export function buildComponent(options: ComponentOptions, options.module = findModuleFromOptions(host, options); const parsedPath = parseName(options.path, options.name); + options.name = parsedPath.name; options.path = parsedPath.path; options.selector = options.selector || buildSelector(options, project.prefix); diff --git a/src/lib/schematics/utils/default-style-ext.ts b/src/lib/schematics/utils/default-style-ext.ts new file mode 100644 index 000000000000..39ce0cd52510 --- /dev/null +++ b/src/lib/schematics/utils/default-style-ext.ts @@ -0,0 +1,31 @@ +/** + * @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 + */ + +import {WorkspaceProject} from '@schematics/angular/utility/config'; + +/** + * Style extension that will be used if no default style extension for the CLI project + * could be determined. + */ +const fallbackStyleExtension = 'css'; + +/** + * Determines the default style extension in the Angular CLI project by looking for the default + * component schematic options. This is necessary for now because when creating CLI projects, + * the CLI only makes the default `--style` option available for the `angular:component` schematic. + */ +export function determineDefaultStyleExt(project: WorkspaceProject): string | null { + if (project.schematics && + project.schematics['@schematics/angular:component'] && + project.schematics['@schematics/angular:component']['styleext']) { + + return project.schematics['@schematics/angular:component']['styleext']; + } + + return fallbackStyleExtension; +}