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

feat(@schematics/angular): Add directive and component selector rules #644

Merged
merged 1 commit into from
Apr 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "<%= relativeTsLintPath %>/tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"<%= prefix %>",
"camelCase"
],
"component-selector": [
true,
"element",
"<%= prefix %>",
"kebab-case"
]
}
}
23 changes: 22 additions & 1 deletion packages/schematics/angular/application/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ export default function (options: ApplicationOptions): Rule {
throw new SchematicsException(`Invalid options, "name" is required.`);
}
validateProjectName(options.name);
const appRootSelector = `${options.prefix || 'app'}-root`;
const prefix = options.prefix || 'app';
const appRootSelector = `${prefix}-root`;
const componentOptions = {
inlineStyle: options.inlineStyle,
inlineTemplate: options.inlineTemplate,
Expand All @@ -285,6 +286,7 @@ export default function (options: ApplicationOptions): Rule {
let sourceRoot = `${appDir}/src`;
let sourceDir = `${sourceRoot}/app`;
let relativeTsConfigPath = appDir.split('/').map(x => '..').join('/');
let relativeTsLintPath = appDir.split('/').map(x => '..').join('/');
const rootInSrc = options.projectRoot !== undefined;
if (options.projectRoot !== undefined) {
newProjectRoot = options.projectRoot;
Expand All @@ -295,7 +297,12 @@ export default function (options: ApplicationOptions): Rule {
if (relativeTsConfigPath === '') {
relativeTsConfigPath = '.';
}
relativeTsLintPath = relative(normalize('/' + sourceRoot), normalize('/'));
if (relativeTsLintPath === '') {
relativeTsLintPath = '.';
}
}
const tsLintRoot = appDir;

const e2eOptions: E2eOptions = {
name: `${options.name}-e2e`,
Expand Down Expand Up @@ -330,6 +337,20 @@ export default function (options: ApplicationOptions): Rule {
}),
move(appDir),
])),
mergeWith(
apply(url('./files/lint'), [
template({
utils: strings,
...options,
tsLintRoot,
relativeTsLintPath,
prefix,
}),
// TODO: Moving should work but is bugged right now.
// The __tsLintRoot__ is being used meanwhile.
// Otherwise the tslint.json file could be inside of the root folder and
// this block and the lint folder could be removed.
])),
schematic('module', {
name: 'app',
commonModule: false,
Expand Down
21 changes: 21 additions & 0 deletions packages/schematics/angular/application/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe('Application Schematic', () => {
expect(files.indexOf('/projects/foo/karma.conf.js')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/tsconfig.app.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/tsconfig.spec.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/tslint.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/src/environments/environment.ts')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/src/environments/environment.prod.ts')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/src/favicon.ico')).toBeGreaterThanOrEqual(0);
Expand Down Expand Up @@ -109,6 +110,15 @@ describe('Application Schematic', () => {
expect(specTsConfig.files).toEqual(['src/test.ts', 'src/polyfills.ts']);
});

it('should set the right path and prefix in the tslint file', () => {
const tree = schematicRunner.runSchematic('application', defaultOptions, workspaceTree);
const path = '/projects/foo/tslint.json';
const content = JSON.parse(tree.readContent(path));
expect(content.extends).toMatch('../../tslint.json');
expect(content.rules['directive-selector'][2]).toMatch('app');
expect(content.rules['component-selector'][2]).toMatch('app');
});

describe(`update package.json`, () => {
it(`should add build-angular to devDependencies`, () => {
const tree = schematicRunner.runSchematic('application', defaultOptions, workspaceTree);
Expand Down Expand Up @@ -157,6 +167,7 @@ describe('Application Schematic', () => {
expect(files.indexOf('/src/karma.conf.js')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/src/tsconfig.app.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/src/tsconfig.spec.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/src/tslint.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/src/environments/environment.ts')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/src/environments/environment.prod.ts')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/src/favicon.ico')).toBeGreaterThanOrEqual(0);
Expand Down Expand Up @@ -196,5 +207,15 @@ describe('Application Schematic', () => {
expect(specTsConfig.extends).toEqual('../tsconfig.json');
expect(specTsConfig.files).toEqual(['test.ts', 'polyfills.ts']);
});

it('should set the relative path and prefix in the tslint file', () => {
const options = { ...defaultOptions, projectRoot: '' };

const tree = schematicRunner.runSchematic('application', options, workspaceTree);
const content = JSON.parse(tree.readContent('/src/tslint.json'));
expect(content.extends).toMatch('../tslint.json');
expect(content.rules['directive-selector'][2]).toMatch('app');
expect(content.rules['component-selector'][2]).toMatch('app');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "<%= relativeTsLintPath %>/tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"<%= prefix %>",
"camelCase"
],
"component-selector": [
true,
"element",
"<%= prefix %>",
"kebab-case"
]
}
}
5 changes: 5 additions & 0 deletions packages/schematics/angular/library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,21 @@ export default function (options: LibraryOptions): Rule {
throw new SchematicsException(`Invalid options, "name" is required.`);
}
const name = options.name;
const prefix = options.prefix || 'lib';

const workspace = getWorkspace(host);
const newProjectRoot = workspace.newProjectRoot;
const projectRoot = `${newProjectRoot}/${options.name}`;
const sourceDir = `${projectRoot}/src/lib`;
const relativeTsLintPath = projectRoot.split('/').map(x => '..').join('/');

const templateSource = apply(url('./files'), [
template({
...strings,
...options,
projectRoot,
relativeTsLintPath,
prefix,
}),
// TODO: Moving inside `branchAndMerge` should work but is bugged right now.
// The __projectRoot__ is being used meanwhile.
Expand All @@ -203,6 +207,7 @@ export default function (options: LibraryOptions): Rule {
}),
schematic('component', {
name: name,
selector: `${prefix}-${name}`,
inlineStyle: true,
inlineTemplate: true,
flat: true,
Expand Down
10 changes: 10 additions & 0 deletions packages/schematics/angular/library/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('Library Schematic', () => {
expect(files.indexOf('/projects/foo/karma.conf.js')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/ng-package.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/package.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/tslint.json')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/src/test.ts')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/src/my_index.ts')).toBeGreaterThanOrEqual(0);
expect(files.indexOf('/projects/foo/src/lib/foo.module.ts')).toBeGreaterThanOrEqual(0);
Expand Down Expand Up @@ -88,6 +89,15 @@ describe('Library Schematic', () => {
expect(fileContent).toContain('exports: [FooComponent]');
});

it('should set the right path and prefix in the tslint file', () => {
const tree = schematicRunner.runSchematic('library', defaultOptions, workspaceTree);
const path = '/projects/foo/tslint.json';
const content = JSON.parse(tree.readContent(path));
expect(content.extends).toMatch('../../tslint.json');
expect(content.rules['directive-selector'][2]).toMatch('lib');
expect(content.rules['component-selector'][2]).toMatch('lib');
});

describe(`update package.json`, () => {
it(`should add ng-packagr to devDependencies`, () => {
const tree = schematicRunner.runSchematic('library', defaultOptions, workspaceTree);
Expand Down
4 changes: 4 additions & 0 deletions packages/schematics/angular/library/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export interface Schema {
* The path to create the interface.
*/
entryFile: string;
/**
* The prefix to apply to generated selectors.
*/
prefix?: string;
/**
* Do not add dependencies to package.json (e.g., --skipPackageJson)
*/
Expand Down
9 changes: 8 additions & 1 deletion packages/schematics/angular/library/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
"description": "The path to create the library's public API file.",
"default": "public_api"
},
"prefix": {
"type": "string",
"format": "html-selector",
"description": "The prefix to apply to generated selectors.",
"default": "lib",
"alias": "p"
},
"skipPackageJson": {
"type": "boolean",
"default": false,
Expand All @@ -30,4 +37,4 @@
}
},
"required": []
}
}