Skip to content

Commit

Permalink
Merge pull request #302 from GregOnNet/view-encapsulation
Browse files Browse the repository at this point in the history
Adding rule checking ViewEncapsulation
  • Loading branch information
mgechev committed May 3, 2017
2 parents 0fcdcd1 + 88e3cd4 commit 509c8d9
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 4 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
@@ -1,3 +1,5 @@
{
"typescript.tsdk": "./node_modules/typescript/lib"
"typescript.tsdk": "./node_modules/typescript/lib",
"angulardoc.repoId": "51f64839-b313-47fa-8d89-9317081ebe22",
"angulardoc.lastSync": 0
}
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -67,6 +67,8 @@ Create the following `tslint.json` file like:
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"use-host-property-decorator": true,
"use-view-encapsulation": true,
"no-attribute-parameter-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Expand Up @@ -20,5 +20,6 @@ export { Rule as UseOutputPropertyDecoratorRule } from './useOutputPropertyDecor
export { Rule as UsePipeTransformInterfaceRule } from './usePipeTransformInterfaceRule';
export { Rule as TemplateToNgTemplateRule } from './templateToNgTemplateRule';
export { Rule as UsePipeDecoratorRule } from './usePipeDecoratorRule';
export { Rule as UseViewEncapsulationRule } from './useViewEncapsulationRule';
export * from './angular/config';

47 changes: 47 additions & 0 deletions src/useViewEncapsulationRule.ts
@@ -0,0 +1,47 @@
import { getComponentDecorator, getDecoratorPropertyInitializer } from './util/utils';
import { ComponentMetadata } from './angular/metadata';
import * as Lint from 'tslint';
import * as ts from 'typescript';

import { NgWalker } from './angular/ngWalker';

export class Rule extends Lint.Rules.AbstractRule {

static metadata: Lint.IRuleMetadata = {
ruleName: 'use-view-encapsulation',
type: 'maintainability',
description: 'Disallows using of ViewEncapsulation.None',
rationale: '',
options: null,
optionsDescription: 'Not configurable',
typescriptOnly: true
};

static FAILURE = 'Using "ViewEncapsulation.None" will make your styles global which may have unintended effect';

apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const walker = new ViewEncapsulationWalker(sourceFile, this.getOptions());
return this.applyWithWalker(walker);
}
}

class ViewEncapsulationWalker extends NgWalker {

visitClassDeclaration(node: ts.ClassDeclaration) {
const decorator = getComponentDecorator(node);
const encapsulation = getDecoratorPropertyInitializer(decorator, 'encapsulation');

if(!encapsulation ||
encapsulation.name.text !== 'None') {
return;
}

this.addFailure(
this.createFailure(
encapsulation.getStart(),
encapsulation.getWidth(),
Rule.FAILURE
)
);
}
}
2 changes: 1 addition & 1 deletion test/directiveClassSuffix.spec.ts
Expand Up @@ -8,7 +8,7 @@ describe('directive-class-suffix', () => {
selector: 'sgBarFoo'
})
class Test {}
~~~~
~~~~
`;
assertAnnotated({
ruleName: 'directive-class-suffix',
Expand Down
4 changes: 2 additions & 2 deletions test/importDestructuringSpacingRule.spec.ts
Expand Up @@ -5,7 +5,7 @@ describe('import-destructuring-spacing', () => {
it('should fail when the imports have no spaces', () => {
let source = `
import {Foo} from './foo'
~~~~~
~~~~~
`;
assertAnnotated({
ruleName: 'import-destructuring-spacing',
Expand All @@ -29,7 +29,7 @@ describe('import-destructuring-spacing', () => {
it('should fail with spaces between items', () => {
let source = `
import {Foo, Bar} from './foo'
~~~~~~~~~~~
~~~~~~~~~~~
`;
assertAnnotated({
ruleName: 'import-destructuring-spacing',
Expand Down
59 changes: 59 additions & 0 deletions test/useViewEncapsulationRule.spec.ts
@@ -0,0 +1,59 @@
import { assertAnnotated, assertSuccess } from './testHelper';

describe('use-view-encapsulation', () => {
describe('invalid view encapsulation', () => {
it('should fail if ViewEncapsulation.None is set', () => {
const source = `
@Component({
selector: 'sg-foo-bar',
encapsulation: ViewEncapsulation.None
~~~~~~~~~~~~~~~~~~~~~~
})
export class TestComponent { }
`;

assertAnnotated({
ruleName: 'use-view-encapsulation',
message: 'Using "ViewEncapsulation.None" will make your styles global which may have unintended effect',
source
});
});
});

describe('valid view encapsulation', () => {
it('should succeed if ViewEncapsulation.Native is set', () => {
const source = `
@Component({
selector: 'sg-foo-bar',
encapsulation: ViewEncapsulation.Native
})
export class TestComponent { }
`;

assertSuccess('use-view-encapsulation', source);
});

it('should succeed if ViewEncapsulation.Emulated is set', () => {
const source = `
@Component({
selector: 'sg-foo-bar',
encapsulation: ViewEncapsulation.Emulated
})
export class TestComponent { }
`;

assertSuccess('use-view-encapsulation', source);
});

it('should succeed if no ViewEncapsulation is set explicitly', () => {
const source = `
@Component({
selector: 'sg-foo-bar',
})
export class TestComponent { }
`;

assertSuccess('use-view-encapsulation', source);
});
});
});

0 comments on commit 509c8d9

Please sign in to comment.