@fluid-topics/ft-eslint 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/plugin.d.ts +3 -0
- package/build/plugin.js +20 -0
- package/build/rules/interface-no-commas.d.ts +2 -0
- package/build/rules/interface-no-commas.js +33 -0
- package/build/rules/quoted-attributes.d.ts +2 -0
- package/build/rules/quoted-attributes.js +84 -0
- package/build/rules/typography-variant.d.ts +2 -0
- package/build/rules/typography-variant.js +49 -0
- package/package.json +25 -0
package/build/plugin.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { quotedAttributesRule } from "./rules/quoted-attributes";
|
|
2
|
+
import { typographyVariantRule } from "./rules/typography-variant";
|
|
3
|
+
import { interfaceNoCommaRule } from "./rules/interface-no-commas";
|
|
4
|
+
const plugin = {
|
|
5
|
+
rules: {
|
|
6
|
+
"quoted-attributes": quotedAttributesRule,
|
|
7
|
+
"typography-variant": typographyVariantRule,
|
|
8
|
+
"interface-no-commas": interfaceNoCommaRule,
|
|
9
|
+
},
|
|
10
|
+
configs: {
|
|
11
|
+
recommended: {
|
|
12
|
+
rules: {
|
|
13
|
+
"ft/quoted-attributes": "error",
|
|
14
|
+
"ft/typography-variant": "warn",
|
|
15
|
+
"ft/interface-no-commas": "error",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export default plugin;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const interfaceNoCommaRule = {
|
|
2
|
+
meta: {
|
|
3
|
+
docs: {
|
|
4
|
+
description: "Enforces that interfaces declarations do not use commas",
|
|
5
|
+
recommended: false,
|
|
6
|
+
},
|
|
7
|
+
fixable: "code",
|
|
8
|
+
schema: [],
|
|
9
|
+
messages: {
|
|
10
|
+
forbiddenComma: "Commas are not allowed in interfaces declarations",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
create(context) {
|
|
14
|
+
return {
|
|
15
|
+
TSInterfaceDeclaration(node) {
|
|
16
|
+
for (const element of node.body.body) {
|
|
17
|
+
if (element.type !== "TSPropertySignature") {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const property = element;
|
|
21
|
+
const lastToken = context.sourceCode.getLastToken(property);
|
|
22
|
+
if ((lastToken === null || lastToken === void 0 ? void 0 : lastToken.type) === "Punctuator" && lastToken.value === ",") {
|
|
23
|
+
context.report({
|
|
24
|
+
loc: lastToken.loc,
|
|
25
|
+
messageId: "forbiddenComma",
|
|
26
|
+
fix: fixer => fixer.remove(lastToken),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* Inspiried by lit/quoted-expressions */
|
|
2
|
+
export const quotedAttributesRule = {
|
|
3
|
+
meta: {
|
|
4
|
+
docs: {
|
|
5
|
+
description: "Enforces the presence or absence of quotes around expressions",
|
|
6
|
+
recommended: false,
|
|
7
|
+
},
|
|
8
|
+
fixable: "code",
|
|
9
|
+
schema: [],
|
|
10
|
+
messages: {
|
|
11
|
+
alwaysQuote: "Attributes must be quoted inside templates " +
|
|
12
|
+
" (e.g. `foo=\"${bar}\"`)",
|
|
13
|
+
neverQuote: "Properties, events and booleans must not be quoted inside templates " +
|
|
14
|
+
" (e.g. `.foo=${bar}`)",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
create(context) {
|
|
18
|
+
const quotePattern = /=(["'])?$/;
|
|
19
|
+
const attributePattern = /[?@.]\w+=["']?$/;
|
|
20
|
+
function addQuotes(previousQuasi, nextQuasi) {
|
|
21
|
+
return (fixer) => {
|
|
22
|
+
if (!previousQuasi.range || !nextQuasi.range) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
return [
|
|
26
|
+
fixer.insertTextAfterRange([previousQuasi.range[0], previousQuasi.range[1] - 2], "\""),
|
|
27
|
+
fixer.insertTextBeforeRange([nextQuasi.range[0] + 1, nextQuasi.range[1]], "\""),
|
|
28
|
+
];
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function removeQuotes(previousQuasi, nextQuasi) {
|
|
32
|
+
return (fixer) => {
|
|
33
|
+
if (!previousQuasi.range || !nextQuasi.range) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
return [
|
|
37
|
+
fixer.removeRange([
|
|
38
|
+
previousQuasi.range[1] - 3,
|
|
39
|
+
previousQuasi.range[1] - 2,
|
|
40
|
+
]),
|
|
41
|
+
fixer.removeRange([
|
|
42
|
+
nextQuasi.range[0] + 1,
|
|
43
|
+
nextQuasi.range[0] + 2,
|
|
44
|
+
]),
|
|
45
|
+
];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
TaggedTemplateExpression: (node) => {
|
|
50
|
+
if (node.type !== "TaggedTemplateExpression"
|
|
51
|
+
|| node.tag.type !== "Identifier"
|
|
52
|
+
|| node.tag.name !== "html") {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
for (let i = 0; i < node.quasi.expressions.length; i++) {
|
|
56
|
+
const expression = node.quasi.expressions[i];
|
|
57
|
+
const previousQuasi = node.quasi.quasis[i];
|
|
58
|
+
const nextQuasi = node.quasi.quasis[i + 1];
|
|
59
|
+
const quoteMatch = previousQuasi.value.raw.match(quotePattern);
|
|
60
|
+
if (!quoteMatch) { // we are not at a `foo=` token
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const needQuote = previousQuasi.value.raw.match(attributePattern) === null;
|
|
64
|
+
const hasStartQuote = quoteMatch[1] !== undefined;
|
|
65
|
+
const isQuoted = hasStartQuote && nextQuasi.value.raw.startsWith(quoteMatch[1]);
|
|
66
|
+
if (needQuote && !hasStartQuote) {
|
|
67
|
+
context.report({
|
|
68
|
+
node: expression,
|
|
69
|
+
messageId: "alwaysQuote",
|
|
70
|
+
fix: addQuotes(previousQuasi, nextQuasi),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (!needQuote && isQuoted) {
|
|
74
|
+
context.report({
|
|
75
|
+
node: expression,
|
|
76
|
+
messageId: "neverQuote",
|
|
77
|
+
fix: removeQuotes(previousQuasi, nextQuasi),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TemplateAnalyzer } from "eslint-plugin-lit/lib/template-analyzer";
|
|
2
|
+
import { isExpressionPlaceholder } from "eslint-plugin-lit/lib/util";
|
|
3
|
+
export const typographyVariantRule = {
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: "Enforces that variant attribute uses enum values",
|
|
7
|
+
recommended: false,
|
|
8
|
+
},
|
|
9
|
+
schema: [],
|
|
10
|
+
messages: {
|
|
11
|
+
mandatoryVariant: "<ft-typography> must have a variant attribute",
|
|
12
|
+
variantUsesEnum: "variant attribute must use an enum value " +
|
|
13
|
+
" (e.g. `variant=\"${ FtTypographyVariants.title1 }\"`)",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
create(context) {
|
|
17
|
+
return {
|
|
18
|
+
TaggedTemplateExpression: (node) => {
|
|
19
|
+
if (node.type !== "TaggedTemplateExpression"
|
|
20
|
+
|| node.tag.type !== "Identifier"
|
|
21
|
+
|| node.tag.name !== "html") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const analyzer = TemplateAnalyzer.create(node);
|
|
25
|
+
analyzer.traverse({
|
|
26
|
+
enterElement: (element) => {
|
|
27
|
+
if (element.tagName === "ft-typography") {
|
|
28
|
+
if (!("variant" in element.attribs)) {
|
|
29
|
+
const loc = analyzer.resolveLocation(element.sourceCodeLocation, context.sourceCode);
|
|
30
|
+
context.report({
|
|
31
|
+
loc,
|
|
32
|
+
messageId: "mandatoryVariant",
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!isExpressionPlaceholder(element.attribs["variant"])) {
|
|
37
|
+
const loc = analyzer.getLocationForAttribute(element, "variant", context.sourceCode);
|
|
38
|
+
context.report({
|
|
39
|
+
loc,
|
|
40
|
+
messageId: "variantUsesEnum",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluid-topics/ft-eslint",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "ESlint rules for web components",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"Lit"
|
|
7
|
+
],
|
|
8
|
+
"author": "Fluid Topics <devtopics@antidot.net>",
|
|
9
|
+
"license": "ISC",
|
|
10
|
+
"main": "build/index.js",
|
|
11
|
+
"web": "build/ft-eslint.min.js",
|
|
12
|
+
"typings": "build/index",
|
|
13
|
+
"files": [
|
|
14
|
+
"build/**/*.js",
|
|
15
|
+
"build/**/*.ts"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "ssh://git@scm.mrs.antidot.net:2222/fluidtopics/ft-web-components.git"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"lit": "3.1.0"
|
|
23
|
+
},
|
|
24
|
+
"gitHead": "cc982effbf27c0483e03961ad450fd2057a108b2"
|
|
25
|
+
}
|