@angular-eslint/eslint-plugin-template
Advanced tools
Comparing version 0.2.0-beta.1 to 0.3.0-beta.1
@@ -6,2 +6,33 @@ import { RULE_NAME as bananaInABoxRuleName } from './rules/banana-in-a-box'; | ||
declare const _default: { | ||
configs: { | ||
all: { | ||
extends: string; | ||
rules: { | ||
"@angular-eslint/template/banana-in-a-box": string; | ||
"@angular-eslint/template/cyclomatic-complexity": string; | ||
"@angular-eslint/template/no-call-expression": string; | ||
"@angular-eslint/template/no-negated-async": string; | ||
}; | ||
}; | ||
base: { | ||
parser: string; | ||
plugins: string[]; | ||
}; | ||
recommended: { | ||
extends: string; | ||
rules: { | ||
"@angular-eslint/template/banana-in-a-box": string; | ||
"@angular-eslint/template/no-negated-async": string; | ||
}; | ||
}; | ||
'process-inline-templates': { | ||
parser: string; | ||
parserOptions: { | ||
ecmaVersion: number; | ||
sourceType: string; | ||
}; | ||
plugins: string[]; | ||
processor: string; | ||
}; | ||
}; | ||
processors: { | ||
@@ -8,0 +39,0 @@ 'extract-inline-html': { |
@@ -1,1 +0,1 @@ | ||
var e,t=(e=require("typescript"))&&"object"==typeof e&&"default"in e?e.default:e,n=require("@typescript-eslint/experimental-utils");const r=new Map;var o={"extract-inline-html":{preprocess:function(e,n){if(!n.endsWith(".component.ts"))return[e];try{const o=t.createSourceFile(n,e,t.ScriptTarget.Latest,!0),s=o.statements.filter(e=>t.isClassDeclaration(e));if(!s||!s.length)return[e];const a=[];for(const e of s)if(e.decorators)for(const n of e.decorators)t.isCallExpression(n.expression)&&t.isIdentifier(n.expression.expression)&&"Component"===n.expression.expression.text&&a.push(n);if(!a||!a.length)return[e];if(a.length>1)throw new Error("@angular-eslint/eslint-plugin-template currently only supports 1 Component per file");const i=a[0];if(!t.isDecorator(i)||!t.isCallExpression(i.expression)||1!==i.expression.arguments.length)return[e];const c=i.expression.arguments[0];if(!t.isObjectLiteralExpression(c))return[e];const p=c.properties.find(e=>e&&e.name&&"template"===e.name.getText());if(c.properties.find(e=>e&&e.name&&"templateUrl"===e.name.getText())||!p)return[e];if(!t.isPropertyAssignment(p)||!t.isStringLiteralLike(p.initializer))return[e];const l=p.initializer.text,d=function(e,t){const n=e.indexOf(t);return[n,n+t.length]}(e,l);return r.set(n,{range:d,lineAndCharacter:{start:o.getLineAndCharacterOfPosition(d[0]),end:o.getLineAndCharacterOfPosition(d[1])}}),[e,{text:l,filename:"inline-template.component.html"}]}catch(t){if("@angular-eslint/eslint-plugin-template currently only supports 1 Component per file"===t.message)throw t;return console.log(t),console.error("preprocess: ERROR could not parse @Component() metadata",n),[e]}},postprocess:function(e,t){const n=e[0],o=e[1];if(!o||!o.length)return n;const s=r.get(t);return s?[...n,...o.map(e=>{e.line=e.line+s.lineAndCharacter.start.line,e.column=e.column,e.endLine=e.endLine+s.lineAndCharacter.start.line,e.endColumn=e.endColumn;const t=s.range[0];return e.fix.range=[t+e.fix.range[0],t+e.fix.range[1]],e})]:n},supportsAutofix:!0}};const s=n.ESLintUtils.RuleCreator(()=>"");function a(e){if(!e.parserServices||!e.parserServices.defineTemplateBodyVisitor||!e.parserServices.convertNodeSourceSpanToLoc)throw new Error("You have used a rule which requires '@angular-eslint/template-parser' to be used as the 'parser' in your ESLint config.");return e.parserServices}const i=/\[(.*)\]/;var c=s({name:"banana-in-a-box",meta:{type:"suggestion",docs:{description:"Ensures that the two-way data binding syntax is correct",category:"Best Practices",recommended:"error"},fixable:"code",schema:[],messages:{bananaInABox:"Invalid binding syntax. Use [(expr)] instead"}},defaultOptions:[],create(e){const t=a(e),n=e.getSourceCode();return t.defineTemplateBodyVisitor({BoundEvent(r){const o=r.name.match(i);if(!o)return;const s=`[(${o[1]})]`,a=t.convertNodeSourceSpanToLoc(r.sourceSpan),c=n.getIndexFromLoc(a.start);e.report({messageId:"bananaInABox",loc:a,fix:e=>e.replaceTextRange([c,"(".length+c+")".length+r.name.length],s)})}})}});const p=["ngForOf","ngIf","ngSwitchCase"],l=["ngSwitchDefault"];var d=s({name:"cyclomatic-complexity",meta:{type:"suggestion",docs:{description:"Checks cyclomatic complexity against a specified limit. It is a quantitative measure of the number of linearly independent paths through a program's source code",category:"Best Practices",recommended:!1},fixable:"code",schema:[{type:"object",properties:{maxComplexity:{type:"number",minimum:1}},additionalProperties:!1}],messages:{cyclomaticComplexity:"The cyclomatic complexity exceeded the defined limit of {{maxComplexity}}. Your template should be refactored."}},defaultOptions:[{maxComplexity:5}],create(e,[t]){let n=0;const r=a(e),{maxComplexity:o}=t,s=t=>{if(n+=1,n<=o)return;const s=r.convertNodeSourceSpanToLoc(t.sourceSpan);e.report({messageId:"cyclomaticComplexity",loc:s,data:{maxComplexity:o}})};return r.defineTemplateBodyVisitor({BoundAttribute(e){p.includes(e.name)&&s(e)},TextAttribute(e){l.includes(e.name)&&s(e)}})}});const m=new Set(["$any"]);var u=s({name:"no-call-expression",meta:{type:"suggestion",docs:{description:"Disallows calling expressions in templates, except for output handlers.",category:"Best Practices",recommended:!1},schema:[],messages:{noCallExpression:"Avoid calling expressions in templates."}},defaultOptions:[],create(e){const t=a(e),n=e.getSourceCode();return t.defineTemplateBodyVisitor({MethodCall(t){if(m.has(t.name)||"BoundEvent"===t.parent.parent.type)return;const r=n.getLocFromIndex(t.sourceSpan.start),o=n.getLocFromIndex(t.sourceSpan.end);e.report({messageId:"noCallExpression",loc:{start:r,end:o}})}})}}),g=s({name:"no-negated-async",meta:{type:"suggestion",docs:{description:"Ensures that strict equality is used when evaluating negations on async pipe output",category:"Best Practices",recommended:"error"},fixable:"code",schema:[],messages:{noNegatedAsync:"Async pipes should not be negated. Use (observable | async) === (false | null | undefined) to check its value instead",noLooseEquality:"Async pipes must use strict equality `===` when comparing with `false`"}},defaultOptions:[],create(e){const t=a(e),n=e.getSourceCode();return t.defineTemplateBodyVisitor({"BindingPipe[name=async]"(t){if("PrefixNot"!==t.parent.type)if("Binary"!==t.parent.type||"=="!==t.parent.operation);else{const r="Interpolation"===t.parent.parent.type?-1:0,o=n.getLocFromIndex(t.parent.sourceSpan.start+("Interpolation"===t.parent.parent.type?-2:-1)),s=n.getLocFromIndex(t.parent.sourceSpan.end+r);e.report({messageId:"noLooseEquality",loc:{start:o,end:s}})}else{const r="Interpolation"===t.parent.parent.type?-1:0,o=n.getLocFromIndex(t.parent.sourceSpan.start+r),s=n.getLocFromIndex(t.parent.sourceSpan.end+r);e.report({messageId:"noNegatedAsync",loc:{start:o,end:s}})}}})}});module.exports={processors:o,rules:{"banana-in-a-box":c,"cyclomatic-complexity":d,"no-call-expression":u,"no-negated-async":g}}; | ||
var e,t=(e=require("typescript"))&&"object"==typeof e&&"default"in e?e.default:e,n=require("@typescript-eslint/experimental-utils");const r=new Map;var a={"extract-inline-html":{preprocess:function(e,n){if(!n.endsWith(".component.ts"))return[e];try{const a=t.createSourceFile(n,e,t.ScriptTarget.Latest,!0),s=a.statements.filter(e=>t.isClassDeclaration(e));if(!s||!s.length)return[e];const o=[];for(const e of s)if(e.decorators)for(const n of e.decorators)t.isCallExpression(n.expression)&&t.isIdentifier(n.expression.expression)&&"Component"===n.expression.expression.text&&o.push(n);if(!o||!o.length)return[e];if(o.length>1)throw new Error("@angular-eslint/eslint-plugin-template currently only supports 1 Component per file");const i=o[0];if(!t.isDecorator(i)||!t.isCallExpression(i.expression)||1!==i.expression.arguments.length)return[e];const c=i.expression.arguments[0];if(!t.isObjectLiteralExpression(c))return[e];const l=c.properties.find(e=>e&&e.name&&"template"===e.name.getText());if(c.properties.find(e=>e&&e.name&&"templateUrl"===e.name.getText())||!l)return[e];if(!t.isPropertyAssignment(l)||!t.isStringLiteralLike(l.initializer))return[e];const p=l.initializer.text,m=function(e,t){const n=e.indexOf(t);return[n,n+t.length]}(e,p);return r.set(n,{range:m,lineAndCharacter:{start:a.getLineAndCharacterOfPosition(m[0]),end:a.getLineAndCharacterOfPosition(m[1])}}),[e,{text:p,filename:"inline-template.component.html"}]}catch(t){if("@angular-eslint/eslint-plugin-template currently only supports 1 Component per file"===t.message)throw t;return console.log(t),console.error("preprocess: ERROR could not parse @Component() metadata",n),[e]}},postprocess:function(e,t){const n=e[0],a=e[1];if(!a||!a.length)return n;const s=r.get(t);return s?[...n,...a.map(e=>{e.line=e.line+s.lineAndCharacter.start.line,e.column=e.column,e.endLine=e.endLine+s.lineAndCharacter.start.line,e.endColumn=e.endColumn;const t=s.range[0];return e.fix.range=[t+e.fix.range[0],t+e.fix.range[1]],e})]:n},supportsAutofix:!0}};const s=n.ESLintUtils.RuleCreator(()=>"");function o(e){if(!e.parserServices||!e.parserServices.defineTemplateBodyVisitor||!e.parserServices.convertNodeSourceSpanToLoc)throw new Error("You have used a rule which requires '@angular-eslint/template-parser' to be used as the 'parser' in your ESLint config.");return e.parserServices}const i=/\[(.*)\]/;var c=s({name:"banana-in-a-box",meta:{type:"suggestion",docs:{description:"Ensures that the two-way data binding syntax is correct",category:"Best Practices",recommended:"error"},fixable:"code",schema:[],messages:{bananaInABox:"Invalid binding syntax. Use [(expr)] instead"}},defaultOptions:[],create(e){const t=o(e),n=e.getSourceCode();return t.defineTemplateBodyVisitor({BoundEvent(r){const a=r.name.match(i);if(!a)return;const s=`[(${a[1]})]`,o=t.convertNodeSourceSpanToLoc(r.sourceSpan),c=n.getIndexFromLoc(o.start);e.report({messageId:"bananaInABox",loc:o,fix:e=>e.replaceTextRange([c,"(".length+c+")".length+r.name.length],s)})}})}});const l=["ngForOf","ngIf","ngSwitchCase"],p=["ngSwitchDefault"];var m=s({name:"cyclomatic-complexity",meta:{type:"suggestion",docs:{description:"Checks cyclomatic complexity against a specified limit. It is a quantitative measure of the number of linearly independent paths through a program's source code",category:"Best Practices",recommended:!1},fixable:"code",schema:[{type:"object",properties:{maxComplexity:{type:"number",minimum:1}},additionalProperties:!1}],messages:{cyclomaticComplexity:"The cyclomatic complexity exceeded the defined limit of {{maxComplexity}}. Your template should be refactored."}},defaultOptions:[{maxComplexity:5}],create(e,[t]){let n=0;const r=o(e),{maxComplexity:a}=t,s=t=>{if(n+=1,n<=a)return;const s=r.convertNodeSourceSpanToLoc(t.sourceSpan);e.report({messageId:"cyclomaticComplexity",loc:s,data:{maxComplexity:a}})};return r.defineTemplateBodyVisitor({BoundAttribute(e){l.includes(e.name)&&s(e)},TextAttribute(e){p.includes(e.name)&&s(e)}})}});const u=new Set(["$any"]);var d=s({name:"no-call-expression",meta:{type:"suggestion",docs:{description:"Disallows calling expressions in templates, except for output handlers.",category:"Best Practices",recommended:!1},schema:[],messages:{noCallExpression:"Avoid calling expressions in templates."}},defaultOptions:[],create(e){const t=o(e),n=e.getSourceCode();return t.defineTemplateBodyVisitor({MethodCall(t){if(u.has(t.name)||"BoundEvent"===t.parent.parent.type)return;const r=n.getLocFromIndex(t.sourceSpan.start),a=n.getLocFromIndex(t.sourceSpan.end);e.report({messageId:"noCallExpression",loc:{start:r,end:a}})}})}}),g=s({name:"no-negated-async",meta:{type:"suggestion",docs:{description:"Ensures that strict equality is used when evaluating negations on async pipe output",category:"Best Practices",recommended:"error"},fixable:"code",schema:[],messages:{noNegatedAsync:"Async pipes should not be negated. Use (observable | async) === (false | null | undefined) to check its value instead",noLooseEquality:"Async pipes must use strict equality `===` when comparing with `false`"}},defaultOptions:[],create(e){const t=o(e),n=e.getSourceCode();return t.defineTemplateBodyVisitor({"BindingPipe[name=async]"(t){if("PrefixNot"!==t.parent.type)if("Binary"!==t.parent.type||"=="!==t.parent.operation);else{const r="Interpolation"===t.parent.parent.type?-1:0,a=n.getLocFromIndex(t.parent.sourceSpan.start+("Interpolation"===t.parent.parent.type?-2:-1)),s=n.getLocFromIndex(t.parent.sourceSpan.end+r);e.report({messageId:"noLooseEquality",loc:{start:a,end:s}})}else{const r="Interpolation"===t.parent.parent.type?-1:0,a=n.getLocFromIndex(t.parent.sourceSpan.start+r),s=n.getLocFromIndex(t.parent.sourceSpan.end+r);e.report({messageId:"noNegatedAsync",loc:{start:a,end:s}})}}})}});module.exports={configs:{all:{extends:"./configs/base.json",rules:{"@angular-eslint/template/banana-in-a-box":"error","@angular-eslint/template/cyclomatic-complexity":"error","@angular-eslint/template/no-call-expression":"error","@angular-eslint/template/no-negated-async":"error"}},base:{parser:"@angular-eslint/template-parser",plugins:["@angular-eslint/template"]},recommended:{extends:"./configs/base.json",rules:{"@angular-eslint/template/banana-in-a-box":"error","@angular-eslint/template/no-negated-async":"error"}},"process-inline-templates":{parser:"@typescript-eslint/parser",parserOptions:{ecmaVersion:2020,sourceType:"module"},plugins:["@angular-eslint/template"],processor:"@angular-eslint/template/extract-inline-html"}},processors:a,rules:{"banana-in-a-box":c,"cyclomatic-complexity":m,"no-call-expression":d,"no-negated-async":g}}; |
{ | ||
"name": "@angular-eslint/eslint-plugin-template", | ||
"version": "0.2.0-beta.1", | ||
"version": "0.3.0-beta.1", | ||
"description": "ESLint plugin for Angular Templates", | ||
@@ -9,5 +9,6 @@ "license": "MIT", | ||
"scripts": { | ||
"build": "rm -rf ./dist && microbundle --tsconfig tsconfig.build.json --no-sourcemap --target=node --compress --format=cjs", | ||
"build": "rm -rf ./dist && microbundle --tsconfig tsconfig.build.json --no-sourcemap --target=node --compress --format=cjs && cp -R ./src/configs ./dist/configs", | ||
"test": "jest --coverage", | ||
"typecheck": "tsc -p tsconfig.json --noEmit" | ||
"typecheck": "tsc -p tsconfig.json --noEmit", | ||
"check-configs": "jest tests/configs.test.ts --runTestsByPath --runInBand" | ||
}, | ||
@@ -29,3 +30,3 @@ "repository": { | ||
"devDependencies": { | ||
"@angular-eslint/utils": "^0.2.0-beta.1" | ||
"@angular-eslint/utils": "^0.3.0-beta.1" | ||
}, | ||
@@ -37,3 +38,3 @@ "peerDependencies": { | ||
}, | ||
"gitHead": "1e96dd4097580bfc5517f5e5b8c60b23f80442fb" | ||
"gitHead": "9d5b5e624be680503aaf7337e9acb5dc3ac66d63" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17844
16
165
188