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

eslint-plugin-lit

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-lit - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

lib/template-analyzer.d.ts

32

lib/rules/attribute-value-entities.js

@@ -6,2 +6,3 @@ "use strict";

*/
const template_analyzer_1 = require("../template-analyzer");
//------------------------------------------------------------------------------

@@ -17,2 +18,6 @@ // Rule Definition

url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/attribute-value-entities.md'
},
messages: {
unencoded: 'Attribute values may not contain unencoded HTML ' +
'entities, e.g. use `>` instead of `>`'
}

@@ -22,3 +27,3 @@ },

// variables should be defined here
const disallowedPattern = /[^\s=]+=('[^"']*"|("[^&<>"]*|'[^&<>']*)[&<>]+)/;
const disallowedPattern = /[&<>"]/;
//----------------------------------------------------------------------

@@ -35,11 +40,20 @@ // Helpers

node.tag.name === 'html') {
for (const quasi of node.quasi.quasis) {
if (disallowedPattern.test(quasi.value.raw)) {
context.report({
node: quasi,
message: 'Attribute values may not contain unencoded HTML ' +
'entities, e.g. use `&gt;` instead of `>`'
});
const analyzer = template_analyzer_1.TemplateAnalyzer.create(node);
analyzer.traverse({
enterElement: (element) => {
// eslint-disable-next-line guard-for-in
for (const attr in element.attribs) {
const loc = analyzer.getLocationForAttribute(element, attr);
if (!loc) {
continue;
}
if (disallowedPattern.test(element.attribs[attr])) {
context.report({
loc: loc,
messageId: 'unencoded'
});
}
}
}
}
});
}

@@ -46,0 +60,0 @@ }

@@ -6,2 +6,3 @@ "use strict";

*/
const template_analyzer_1 = require("../template-analyzer");
//------------------------------------------------------------------------------

@@ -16,2 +17,5 @@ // Rule Definition

url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-duplicate-template-bindings.md'
},
messages: {
duplicateBinding: 'Duplicate bindings are not allowed.'
}

@@ -21,4 +25,2 @@ },

// variables should be defined here
const propertyPattern = /\b([\.@\?])?([\w\-]+)([=\s>])/g;
const tagPattern = /<[^\/][^>]*>/g; // todo: handle `foo=">"`
//----------------------------------------------------------------------

@@ -35,23 +37,11 @@ // Helpers

node.tag.name === 'html') {
const html = node.quasi.quasis
.map((q) => q.value.raw)
.join('{{__lint__}}');
const tags = html.match(tagPattern);
if (tags) {
for (const tag of tags) {
const pattern = new RegExp(propertyPattern.source, 'g');
let match;
let seen = [];
while ((match = pattern.exec(tag)) !== null) {
if (seen.includes(match[2])) {
// todo: maybe report column of this property
context.report({
node: node,
message: `Duplicate bindings are not allowed, "${match[2]}" was set multiple times.`
});
}
else {
seen.push(match[2]);
}
}
const analyzer = template_analyzer_1.TemplateAnalyzer.create(node);
const dupeErrors = analyzer.errors.filter((err) => err.code === 'duplicate-attribute');
for (const err of dupeErrors) {
const loc = analyzer.resolveLocation(err);
if (loc) {
context.report({
loc: loc,
messageId: 'duplicateBinding'
});
}

@@ -58,0 +48,0 @@ }

@@ -6,2 +6,3 @@ "use strict";

*/
const template_analyzer_1 = require("../template-analyzer");
//------------------------------------------------------------------------------

@@ -16,2 +17,5 @@ // Rule Definition

url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-legacy-template-syntax.md'
},
messages: {
unsupported: 'Legacy lit-extended syntax is unsupported, did you mean to use "{{replacement}}"?'
}

@@ -21,3 +25,3 @@ },

// variables should be defined here
const legacyPropertyPattern = /\b(on\-([\w\-]+)|([\w\-]+)([\$\?]))=$/;
const legacyEventPattern = /^on-./;
//----------------------------------------------------------------------

@@ -34,24 +38,36 @@ // Helpers

node.tag.name === 'html') {
for (const quasi of node.quasi.quasis) {
const val = quasi.value.raw;
const match = val.match(legacyPropertyPattern);
if (match) {
if (match[3]) {
let replacement = `${match[3]}=`;
if (match[4] === '?') {
replacement = `?${match[3]}=`;
const analyzer = template_analyzer_1.TemplateAnalyzer.create(node);
analyzer.traverse({
enterElement: (element) => {
// eslint-disable-next-line guard-for-in
for (const attr in element.attribs) {
const loc = analyzer.getLocationForAttribute(element, attr);
if (!loc) {
continue;
}
context.report({
node: quasi,
message: `Legacy lit-extended syntax is unsupported, did you mean to use "${replacement}"?`
});
const lastChar = attr.slice(-1);
if (legacyEventPattern.test(attr)) {
const replacement = `@${attr.substr(3)}=`;
context.report({
loc: loc,
messageId: 'unsupported',
data: {
replacement: replacement
}
});
}
else if (lastChar === '?' || lastChar === '$') {
const prefix = lastChar === '?' ? '?' : '';
const replacement = `${prefix}${attr.slice(0, -1)}=`;
context.report({
loc: loc,
messageId: 'unsupported',
data: {
replacement: replacement
}
});
}
}
else {
context.report({
node: quasi,
message: `Legacy lit-extended syntax is unsupported, did you mean to use "@${match[2]}="?`
});
}
}
}
});
}

@@ -58,0 +74,0 @@ }

@@ -16,1 +16,17 @@ import * as ESTree from 'estree';

export declare function getPropertyMap(node: ESTree.Class): ReadonlyMap<string, ESTree.ObjectExpression>;
/**
* Generates a placeholder string for a given quasi
*
* @param {ESTree.TaggedTemplateExpression} node Root node
* @param {ESTree.TemplateElement} quasi Quasi to generate placeholder
* for
* @return {string}
*/
export declare function getExpressionPlaceholder(node: ESTree.TaggedTemplateExpression, quasi: ESTree.TemplateElement): string;
/**
* Converts a template expression into HTML
*
* @param {ESTree.TaggedTemplateExpression} node Node to convert
* @return {string}
*/
export declare function templateExpressionToHtml(node: ESTree.TaggedTemplateExpression): string;

@@ -65,1 +65,36 @@ "use strict";

exports.getPropertyMap = getPropertyMap;
/**
* Generates a placeholder string for a given quasi
*
* @param {ESTree.TaggedTemplateExpression} node Root node
* @param {ESTree.TemplateElement} quasi Quasi to generate placeholder
* for
* @return {string}
*/
function getExpressionPlaceholder(node, quasi) {
const i = node.quasi.quasis.indexOf(quasi);
if (/=$/.test(quasi.value.raw)) {
return `"{{__Q:${i}__}}"`;
}
return `{{__Q:${i}__}}`;
}
exports.getExpressionPlaceholder = getExpressionPlaceholder;
/**
* Converts a template expression into HTML
*
* @param {ESTree.TaggedTemplateExpression} node Node to convert
* @return {string}
*/
function templateExpressionToHtml(node) {
let html = '';
for (let i = 0; i < node.quasi.quasis.length; i++) {
const quasi = node.quasi.quasis[i];
const expr = node.quasi.expressions[i];
html += quasi.value.raw;
if (expr) {
html += getExpressionPlaceholder(node, quasi);
}
}
return html;
}
exports.templateExpressionToHtml = templateExpressionToHtml;
{
"name": "eslint-plugin-lit",
"version": "0.2.1",
"version": "0.3.0",
"description": "lit-html support for ESLint",

@@ -29,2 +29,4 @@ "main": "lib/index.js",

"dependencies": {
"parse5": "^5.1.0",
"parse5-htmlparser2-tree-adapter": "^5.1.0",
"requireindex": "^1.2.0"

@@ -36,2 +38,4 @@ },

"@types/node": "^10.7.1",
"@types/parse5": "^5.0.0",
"@types/parse5-htmlparser2-tree-adapter": "^5.0.1",
"babel-eslint": "^9.0.0",

@@ -38,0 +42,0 @@ "chai": "^4.1.2",

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