Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@angular-eslint/eslint-plugin-template

Package Overview
Dependencies
Maintainers
1
Versions
775
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@angular-eslint/eslint-plugin-template - npm Package Compare versions

Comparing version 0.2.0-beta.1 to 0.3.0-beta.1

dist/configs/all.json

31

dist/index.d.ts

@@ -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': {

2

dist/index.js

@@ -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"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc