feat(@schematics/angular): only support known style extentions

Fixes #13149
This commit is contained in:
Alan 2019-01-18 15:56:34 +01:00 committed by Minko Gechev
parent b1b365e4fd
commit 4718de4dae
19 changed files with 77 additions and 32 deletions

View File

@ -140,9 +140,16 @@
"default": "css" "default": "css"
}, },
"style": { "style": {
"description": "The file extension to use for style files.", "description": "The file extension or preprocessor to use for style files.",
"type": "string", "type": "string",
"default": "css" "default": "css",
"enum": [
"css",
"scss",
"sass",
"less",
"styl"
]
}, },
"viewEncapsulation": { "viewEncapsulation": {
"description": "Specifies the view encapsulation strategy.", "description": "Specifies the view encapsulation strategy.",

View File

@ -33,7 +33,6 @@ describe('App Shell Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: true, routing: true,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -31,6 +31,7 @@ import {
url, url,
} from '@angular-devkit/schematics'; } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { styleToFileExtention } from '../component/index';
import { Schema as ComponentOptions } from '../component/schema'; import { Schema as ComponentOptions } from '../component/schema';
import { Schema as E2eOptions } from '../e2e/schema'; import { Schema as E2eOptions } from '../e2e/schema';
import { import {
@ -48,7 +49,7 @@ import {
WorkspaceProject, WorkspaceProject,
WorkspaceSchema, WorkspaceSchema,
} from '../utility/workspace-models'; } from '../utility/workspace-models';
import { Schema as ApplicationOptions } from './schema'; import { Schema as ApplicationOptions, Style } from './schema';
// TODO: use JsonAST // TODO: use JsonAST
@ -162,7 +163,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace
if (options.inlineTemplate === true if (options.inlineTemplate === true
|| options.inlineStyle === true || options.inlineStyle === true
|| options.style !== 'css') { || options.style !== Style.Css) {
schematics['@schematics/angular:component'] = {}; schematics['@schematics/angular:component'] = {};
if (options.inlineTemplate === true) { if (options.inlineTemplate === true) {
(schematics['@schematics/angular:component'] as JsonObject).inlineTemplate = true; (schematics['@schematics/angular:component'] as JsonObject).inlineTemplate = true;
@ -170,7 +171,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace
if (options.inlineStyle === true) { if (options.inlineStyle === true) {
(schematics['@schematics/angular:component'] as JsonObject).inlineStyle = true; (schematics['@schematics/angular:component'] as JsonObject).inlineStyle = true;
} }
if (options.style && options.style !== 'css') { if (options.style && options.style !== Style.Css) {
(schematics['@schematics/angular:component'] as JsonObject).styleext = options.style; (schematics['@schematics/angular:component'] as JsonObject).styleext = options.style;
} }
} }
@ -346,6 +347,8 @@ export default function (options: ApplicationOptions): Rule {
projectRoot: newProjectRoot ? `${newProjectRoot}/${options.name}-e2e` : 'e2e', projectRoot: newProjectRoot ? `${newProjectRoot}/${options.name}-e2e` : 'e2e',
}; };
const styleExt = styleToFileExtention(options.style);
return chain([ return chain([
addAppToWorkspaceFile(options, workspace), addAppToWorkspaceFile(options, workspace),
mergeWith( mergeWith(
@ -356,6 +359,7 @@ export default function (options: ApplicationOptions): Rule {
...options, ...options,
'dot': '.', 'dot': '.',
relativePathToWorkspaceRoot, relativePathToWorkspaceRoot,
styleExt,
}), }),
move(sourceRoot), move(sourceRoot),
])), ])),
@ -417,6 +421,7 @@ export default function (options: ApplicationOptions): Rule {
...options as any, // tslint:disable-line:no-any ...options as any, // tslint:disable-line:no-any
selector: appRootSelector, selector: appRootSelector,
...componentOptions, ...componentOptions,
styleExt,
}), }),
move(sourceDir), move(sourceDir),
]), MergeStrategy.Overwrite), ]), MergeStrategy.Overwrite),

View File

@ -28,7 +28,7 @@ import { Component } from '@angular/core';
`,<% } else { %> `,<% } else { %>
templateUrl: './app.component.html',<% } if(inlineStyle) { %> templateUrl: './app.component.html',<% } if(inlineStyle) { %>
styles: []<% } else { %> styles: []<% } else { %>
styleUrls: ['./app.component.<%= style %>']<% } %> styleUrls: ['./app.component.<%= styleExt %>']<% } %>
}) })
export class AppComponent { export class AppComponent {
title = '<%= name %>'; title = '<%= name %>';

View File

@ -54,9 +54,16 @@
"alias": "p" "alias": "p"
}, },
"style": { "style": {
"description": "The file extension to use for style files.", "description": "The file extension or preprocessor to use for style files.",
"type": "string", "type": "string",
"default": "css" "default": "css",
"enum": [
"css",
"scss",
"sass",
"less",
"styl"
]
}, },
"skipTests": { "skipTests": {
"description": "When true, does not create \"spec.ts\" test files for the app.", "description": "When true, does not create \"spec.ts\" test files for the app.",

View File

@ -35,7 +35,6 @@ describe('Class Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -9,7 +9,7 @@ import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }
`,<% } else { %> `,<% } else { %>
templateUrl: './<%= dasherize(name) %>.component.html',<% } if(inlineStyle) { %> templateUrl: './<%= dasherize(name) %>.component.html',<% } if(inlineStyle) { %>
styles: []<% } else { %> styles: []<% } else { %>
styleUrls: ['./<%= dasherize(name) %>.component.<%= style %>']<% } %><% if(!!viewEncapsulation) { %>, styleUrls: ['./<%= dasherize(name) %>.component.<%= styleExt %>']<% } %><% if(!!viewEncapsulation) { %>,
encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>, encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,
changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %> changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>
}) })

View File

@ -32,7 +32,7 @@ import { applyLintFix } from '../utility/lint-fix';
import { parseName } from '../utility/parse-name'; import { parseName } from '../utility/parse-name';
import { buildDefaultPath, getProject } from '../utility/project'; import { buildDefaultPath, getProject } from '../utility/project';
import { validateHtmlSelector, validateName } from '../utility/validation'; import { validateHtmlSelector, validateName } from '../utility/validation';
import { Schema as ComponentOptions } from './schema'; import { Schema as ComponentOptions, Style } from './schema';
function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile { function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {
const text = host.read(modulePath); const text = host.read(modulePath);
@ -145,9 +145,9 @@ export default function (options: ComponentOptions): Rule {
// todo remove these when we remove the deprecations // todo remove these when we remove the deprecations
options.style = ( options.style = (
options.style && options.style !== 'css' options.style && options.style !== Style.Css
? options.style : options.styleext ? options.style : options.styleext as Style
) || 'css'; ) || Style.Css;
options.skipTests = options.skipTests || !options.spec; options.skipTests = options.skipTests || !options.spec;
validateName(options.name); validateName(options.name);
@ -155,12 +155,13 @@ export default function (options: ComponentOptions): Rule {
const templateSource = apply(url('./files'), [ const templateSource = apply(url('./files'), [
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(), options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),
options.inlineStyle ? filter(path => !path.endsWith('.__style__.template')) : noop(), options.inlineStyle ? filter(path => !path.endsWith('.__styleExt__.template')) : noop(),
options.inlineTemplate ? filter(path => !path.endsWith('.html.template')) : noop(), options.inlineTemplate ? filter(path => !path.endsWith('.html.template')) : noop(),
applyTemplates({ applyTemplates({
...strings, ...strings,
'if-flat': (s: string) => options.flat ? '' : s, 'if-flat': (s: string) => options.flat ? '' : s,
...options, ...options,
styleExt: styleToFileExtention(options.style),
}), }),
move(parsedPath.path), move(parsedPath.path),
]); ]);
@ -174,3 +175,12 @@ export default function (options: ComponentOptions): Rule {
]); ]);
}; };
} }
export function styleToFileExtention(style: Style | undefined): string {
switch (style) {
case Style.Sass:
return 'scss';
default:
return style || 'css';
}
}

View File

@ -10,7 +10,7 @@ import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/te
import { Schema as ApplicationOptions } from '../application/schema'; import { Schema as ApplicationOptions } from '../application/schema';
import { createAppModule } from '../utility/test'; import { createAppModule } from '../utility/test';
import { Schema as WorkspaceOptions } from '../workspace/schema'; import { Schema as WorkspaceOptions } from '../workspace/schema';
import { ChangeDetection, Schema as ComponentOptions } from './schema'; import { ChangeDetection, Schema as ComponentOptions, Style } from './schema';
// tslint:disable:max-line-length // tslint:disable:max-line-length
describe('Component Schematic', () => { describe('Component Schematic', () => {
@ -24,7 +24,7 @@ describe('Component Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
changeDetection: ChangeDetection.Default, changeDetection: ChangeDetection.Default,
style: 'css', style: Style.Css,
skipTests: false, skipTests: false,
module: undefined, module: undefined,
export: false, export: false,
@ -43,7 +43,7 @@ describe('Component Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css', style: Style.Css,
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };
@ -250,7 +250,16 @@ describe('Component Schematic', () => {
}); });
it('should respect the style option', () => { it('should respect the style option', () => {
const options = { ...defaultOptions, style: 'scss' }; const options = { ...defaultOptions, style: Style.Scss };
const tree = schematicRunner.runSchematic('component', options, appTree);
const content = tree.readContent('/projects/bar/src/app/foo/foo.component.ts');
expect(content).toMatch(/styleUrls: \['.\/foo.component.scss/);
expect(tree.files).toContain('/projects/bar/src/app/foo/foo.component.scss');
expect(tree.files).not.toContain('/projects/bar/src/app/foo/foo.component.css');
});
it('should respect the style preprocessor option', () => {
const options = { ...defaultOptions, style: Style.Sass };
const tree = schematicRunner.runSchematic('component', options, appTree); const tree = schematicRunner.runSchematic('component', options, appTree);
const content = tree.readContent('/projects/bar/src/app/foo/foo.component.ts'); const content = tree.readContent('/projects/bar/src/app/foo/foo.component.ts');
expect(content).toMatch(/styleUrls: \['.\/foo.component.scss/); expect(content).toMatch(/styleUrls: \['.\/foo.component.scss/);

View File

@ -73,9 +73,16 @@
"x-deprecated": "Use \"style\" instead." "x-deprecated": "Use \"style\" instead."
}, },
"style": { "style": {
"description": "The file extension to use for style files.", "description": "The file extension or preprocessor to use for style files.",
"type": "string", "type": "string",
"default": "css" "default": "css",
"enum": [
"css",
"scss",
"sass",
"less",
"styl"
]
}, },
"spec": { "spec": {
"type": "boolean", "type": "boolean",

View File

@ -32,7 +32,6 @@ describe('Enum Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -34,7 +34,6 @@ describe('Interface Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -34,7 +34,6 @@ describe('Module Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -111,15 +111,22 @@
"alias": "p" "alias": "p"
}, },
"style": { "style": {
"description": "The file extension to use for style files.", "description": "The file extension or preprocessor to use for style files.",
"type": "string", "type": "string",
"default": "css", "default": "css",
"enum": [
"css",
"scss",
"sass",
"less",
"styl"
],
"x-prompt": { "x-prompt": {
"message": "Which stylesheet format would you like to use?", "message": "Which stylesheet format would you like to use?",
"type": "list", "type": "list",
"items": [ "items": [
{ "value": "css", "label": "CSS" }, { "value": "css", "label": "CSS" },
{ "value": "scss", "label": "Sass [ http://sass-lang.com ]" }, { "value": "sass", "label": "Sass [ http://sass-lang.com ]" },
{ "value": "less", "label": "Less [ http://lesscss.org ]" }, { "value": "less", "label": "Less [ http://lesscss.org ]" },
{ "value": "styl", "label": "Stylus [ http://stylus-lang.com ]" } { "value": "styl", "label": "Stylus [ http://stylus-lang.com ]" }
] ]

View File

@ -37,7 +37,6 @@ describe('Pipe Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -35,7 +35,6 @@ describe('Service Worker Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css',
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
import { Schema as ApplicationOptions } from '../application/schema'; import { Schema as ApplicationOptions, Style } from '../application/schema';
import { Schema as WorkspaceOptions } from '../workspace/schema'; import { Schema as WorkspaceOptions } from '../workspace/schema';
import { Schema as UniversalOptions } from './schema'; import { Schema as UniversalOptions } from './schema';
@ -33,7 +33,7 @@ describe('Universal Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css', style: Style.Css,
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };
@ -44,7 +44,7 @@ describe('Universal Schematic', () => {
inlineStyle: false, inlineStyle: false,
inlineTemplate: false, inlineTemplate: false,
routing: false, routing: false,
style: 'css', style: Style.Css,
skipTests: false, skipTests: false,
skipPackageJson: false, skipPackageJson: false,
}; };