@stencil/eslint-plugin
Version:
ESLint rules specific to Stencil JS projects.
1,590 lines (1,561 loc) • 53.6 kB
JavaScript
import react from "eslint-plugin-react";
import * as ts$1 from "typescript";
import ts from "typescript";
import { getStaticValue } from "eslint-utils";
import { isThenableType } from "tsutils";
import { JSDOM } from "jsdom";
//#region src/utils.ts
const SyntaxKind = ts.SyntaxKind;
function isPrivate(originalNode) {
const modifiers = ts.canHaveModifiers(originalNode) ? ts.getModifiers(originalNode) : void 0;
if (modifiers) return modifiers.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword);
const firstChildNode = originalNode.getChildAt(0);
return firstChildNode ? firstChildNode.kind === SyntaxKind.PrivateIdentifier : false;
}
function getDecoratorList(originalNode) {
const decorators = ts.canHaveDecorators(originalNode) ? ts.getDecorators(originalNode) : void 0;
return decorators;
}
function getDecorator(node, decoratorName$1) {
if (decoratorName$1) return node.decorators && node.decorators.find(isDecoratorNamed(decoratorName$1));
return node.decorators ? node.decorators.filter((dec) => dec.expression) : [];
}
function parseDecorator(decorator) {
if (decorator && decorator.expression && decorator.expression.type === "CallExpression") return decorator.expression.arguments.map((a) => {
const parsed = getStaticValue(a);
return parsed ? parsed.value : void 0;
});
return [];
}
function decoratorName(dec) {
return dec.expression && dec.expression.callee.name;
}
function isDecoratorNamed(propName) {
return (dec) => {
return decoratorName(dec) === propName;
};
}
function stencilComponentContext() {
let componentNode;
return {
rules: {
"ClassDeclaration": (node) => {
const component = getDecorator(node, "Component");
if (component) componentNode = component;
},
"ClassDeclaration:exit": (node) => {
if (componentNode === node) componentNode = void 0;
}
},
isComponent() {
return !!componentNode;
}
};
}
function getType(node) {
return node.typeAnnotation?.typeAnnotation?.typeName?.name;
}
const stencilDecorators = [
"Component",
"Prop",
"State",
"Watch",
"Element",
"Method",
"Event",
"Listen",
"AttachInternals"
];
const stencilLifecycle = [
"connectedCallback",
"disconnectedCallback",
"componentWillLoad",
"componentDidLoad",
"componentWillRender",
"componentDidRender",
"componentShouldUpdate",
"componentWillUpdate",
"componentDidUpdate",
"formAssociatedCallback",
"formDisabledCallback",
"formResetCallback",
"formStateRestoreCallback",
"render"
];
const TOKEN_TO_TEXT = {
[SyntaxKind.OpenBraceToken]: "{",
[SyntaxKind.CloseBraceToken]: "}",
[SyntaxKind.OpenParenToken]: "(",
[SyntaxKind.CloseParenToken]: ")",
[SyntaxKind.OpenBracketToken]: "[",
[SyntaxKind.CloseBracketToken]: "]",
[SyntaxKind.DotToken]: ".",
[SyntaxKind.DotDotDotToken]: "...",
[SyntaxKind.SemicolonToken]: ",",
[SyntaxKind.CommaToken]: ",",
[SyntaxKind.LessThanToken]: "<",
[SyntaxKind.GreaterThanToken]: ">",
[SyntaxKind.LessThanEqualsToken]: "<=",
[SyntaxKind.GreaterThanEqualsToken]: ">=",
[SyntaxKind.EqualsEqualsToken]: "==",
[SyntaxKind.ExclamationEqualsToken]: "!=",
[SyntaxKind.EqualsEqualsEqualsToken]: "===",
[SyntaxKind.InstanceOfKeyword]: "instanceof",
[SyntaxKind.ExclamationEqualsEqualsToken]: "!==",
[SyntaxKind.EqualsGreaterThanToken]: "=>",
[SyntaxKind.PlusToken]: "+",
[SyntaxKind.MinusToken]: "-",
[SyntaxKind.AsteriskToken]: "*",
[SyntaxKind.AsteriskAsteriskToken]: "**",
[SyntaxKind.SlashToken]: "/",
[SyntaxKind.PercentToken]: "%",
[SyntaxKind.PlusPlusToken]: "++",
[SyntaxKind.MinusMinusToken]: "--",
[SyntaxKind.LessThanLessThanToken]: "<<",
[SyntaxKind.LessThanSlashToken]: "</",
[SyntaxKind.GreaterThanGreaterThanToken]: ">>",
[SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: ">>>",
[SyntaxKind.AmpersandToken]: "&",
[SyntaxKind.BarToken]: "|",
[SyntaxKind.CaretToken]: "^",
[SyntaxKind.ExclamationToken]: "!",
[SyntaxKind.TildeToken]: "~",
[SyntaxKind.AmpersandAmpersandToken]: "&&",
[SyntaxKind.BarBarToken]: "||",
[SyntaxKind.QuestionToken]: "?",
[SyntaxKind.ColonToken]: ":",
[SyntaxKind.EqualsToken]: "=",
[SyntaxKind.PlusEqualsToken]: "+=",
[SyntaxKind.MinusEqualsToken]: "-=",
[SyntaxKind.AsteriskEqualsToken]: "*=",
[SyntaxKind.AsteriskAsteriskEqualsToken]: "**=",
[SyntaxKind.SlashEqualsToken]: "/=",
[SyntaxKind.PercentEqualsToken]: "%=",
[SyntaxKind.LessThanLessThanEqualsToken]: "<<=",
[SyntaxKind.GreaterThanGreaterThanEqualsToken]: ">>=",
[SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: ">>>=",
[SyntaxKind.AmpersandEqualsToken]: "&=",
[SyntaxKind.BarEqualsToken]: "|=",
[SyntaxKind.CaretEqualsToken]: "^=",
[SyntaxKind.AtToken]: "@",
[SyntaxKind.InKeyword]: "in",
[SyntaxKind.UniqueKeyword]: "unique",
[SyntaxKind.KeyOfKeyword]: "keyof",
[SyntaxKind.NewKeyword]: "new",
[SyntaxKind.ImportKeyword]: "import",
[SyntaxKind.ReadonlyKeyword]: "readonly"
};
//#endregion
//#region src/rules/async-methods.ts
const rule$24 = {
meta: {
docs: {
description: "This rule catches Stencil public methods that are not async.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem",
fixable: "code"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
const typeChecker = parserServices.program.getTypeChecker();
return {
...stencil.rules,
"MethodDefinition > Decorator[expression.callee.name=Method]": (decoratorNode) => {
if (!stencil.isComponent()) return;
const node = decoratorNode.parent;
const method = parserServices.esTreeNodeToTSNodeMap.get(node);
const signature = typeChecker.getSignatureFromDeclaration(method);
const returnType = typeChecker.getReturnTypeOfSignature(signature);
if (!isThenableType(typeChecker, method, returnType)) {
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const text = String(originalNode.getFullText());
context.report({
node: node.key,
message: `External @Method() ${node.key.name}() must return a Promise. Consider prefixing the method with async, such as @Method() async ${node.key.name}().`,
fix(fixer) {
const result = text.trimLeft().replace(/@Method\(\)\n(\s*)/, "@Method()\n$1async ").replace("@Method() ", "@Method() async").replace("async public", "public async").replace("async private", "private async");
return fixer.replaceText(node, result);
}
});
}
}
};
}
};
var async_methods_default = rule$24;
//#endregion
//#region src/rules/ban-default-true.ts
const rule$23 = {
meta: {
docs: {
description: "This rule catches Stencil Props defaulting to true.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
return {
...stencil.rules,
"PropertyDefinition": (node) => {
const propDecorator = getDecorator(node, "Prop");
if (!(stencil.isComponent() && propDecorator)) return;
if (node.value?.value === true) context.report({
node,
message: `Boolean properties decorated with @Prop() should default to false`
});
}
};
}
};
var ban_default_true_default = rule$23;
//#endregion
//#region src/rules/ban-prefix.ts
const DEFAULTS$2 = [
"stencil",
"stnl",
"st"
];
const rule$22 = {
meta: {
docs: {
description: "This rule catches usages banned prefix in component tag name.",
category: "Possible Errors",
recommended: true
},
schema: [{
type: "array",
items: { type: "string" },
minLength: 1,
additionalProperties: false
}],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
return {
...stencil.rules,
"ClassDeclaration": (node) => {
const component = getDecorator(node, "Component");
if (!component) return;
const [opts] = parseDecorator(component);
if (!opts || !opts.tag) return;
const tag = opts.tag;
const options = context.options[0] || DEFAULTS$2;
const match = options.some((t) => tag.startsWith(`${t}-`));
if (match) context.report({
node,
message: `The component with tag name ${tag} have a banned prefix.`
});
}
};
}
};
var ban_prefix_default = rule$22;
//#endregion
//#region src/rules/class-pattern.ts
const rule$21 = {
meta: {
docs: {
description: "This rule catches usages of non valid class names.",
category: "Possible Errors",
recommended: false
},
schema: [{
type: "object",
properties: {
pattern: { type: "string" },
ignoreCase: { type: "boolean" }
},
additionalProperties: false
}],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
return {
...stencil.rules,
"ClassDeclaration": (node) => {
const component = getDecorator(node, "Component");
const options = context.options[0];
const { pattern, ignoreCase } = options || {};
if (!component || !options || !pattern) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const className = originalNode.symbol.escapedName;
const regExp = new RegExp(pattern, ignoreCase ? "i" : void 0);
if (!regExp.test(className)) {
const [opts] = parseDecorator(component);
if (!opts || !opts.tag) return;
context.report({
node,
message: `The class name in component with tag name ${opts.tag} is not valid (${regExp}).`
});
}
}
};
}
};
var class_pattern_default = rule$21;
//#endregion
//#region src/rules/decorators-context.ts
const rule$20 = {
meta: {
docs: {
description: "This rule catches Stencil Decorators used in incorrect locations.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
return {
...stencil.rules,
"Decorator": (node) => {
if (!stencil.isComponent()) return;
if (node.expression && node.expression.callee) {
const decName = node.expression.callee.name;
if (decName === "Prop" || decName === "State" || decName === "Element" || decName === "Event") {
if (node.parent.type !== "PropertyDefinition" && node.parent.type === "MethodDefinition" && ["get", "set"].indexOf(node.parent.kind) < 0) context.report({
node,
message: `The @${decName} decorator can only be applied to class properties.`
});
} else if (decName === "Method" || decName === "Watch" || decName === "Listen") {
if (node.parent.type !== "MethodDefinition") context.report({
node,
message: `The @${decName} decorator can only be applied to class methods.`
});
} else if (decName === "Component") {
if (node.parent.type !== "ClassDeclaration") context.report({
node,
message: `The @${decName} decorator can only be applied to a class.`
});
}
}
}
};
}
};
var decorators_context_default = rule$20;
//#endregion
//#region src/rules/decorators-style.ts
const ENUMERATE = [
"inline",
"multiline",
"ignore"
];
const DEFAULTS$1 = {
prop: "ignore",
state: "ignore",
element: "ignore",
event: "ignore",
method: "ignore",
watch: "ignore",
listen: "ignore"
};
const rule$19 = {
meta: {
docs: {
description: "This rule catches Stencil Decorators not used in consistent style.",
category: "Possible Errors",
recommended: true
},
schema: [{
type: "object",
properties: {
prop: {
type: "string",
enum: ENUMERATE
},
state: {
type: "string",
enum: ENUMERATE
},
element: {
type: "string",
enum: ENUMERATE
},
event: {
type: "string",
enum: ENUMERATE
},
method: {
type: "string",
enum: ENUMERATE
},
watch: {
type: "string",
enum: ENUMERATE
},
listen: {
type: "string",
enum: ENUMERATE
}
}
}],
type: "layout"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
const opts = context.options[0] || {};
const options = {
...DEFAULTS$1,
...opts
};
function checkStyle(decorator) {
const decName = decoratorName(decorator);
const config = options[decName.toLowerCase()];
if (!config || config === "ignore") return;
const decoratorNode = parserServices.esTreeNodeToTSNodeMap.get(decorator);
const decoratorText = decoratorNode.getText().replace("(", "\\(").replace(")", "\\)");
const text = decoratorNode.parent.getText();
const separator = config === "multiline" ? "\\r?\\n" : " ";
const regExp = new RegExp(`${decoratorText}${separator}`, "i");
if (!regExp.test(text)) {
const node = decorator.parent;
context.report({
node,
message: `The @${decName} decorator can only be applied as ${config}.`
});
}
}
function getStyle(node) {
if (!stencil.isComponent() || !options || !Object.keys(options).length) return;
const decorators = getDecorator(node);
decorators.filter((dec) => stencilDecorators.includes(decoratorName(dec))).forEach(checkStyle);
}
return {
...stencil.rules,
"PropertyDefinition": getStyle,
"MethodDefinition[kind=method]": getStyle
};
}
};
var decorators_style_default = rule$19;
//#endregion
//#region src/rules/element-type.ts
const rule$18 = {
meta: {
docs: {
description: "This rule catches Stencil Element type not matching tag name.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem",
fixable: "code"
},
create(context) {
const stencil = stencilComponentContext();
function parseTag(tag) {
let result = tag[0].toUpperCase() + tag.slice(1);
const tagBody = tag.split("-");
if (tagBody.length > 1) result = tagBody.map((tpart) => tpart[0].toUpperCase() + tpart.slice(1)).join("");
return result;
}
return {
...stencil.rules,
"PropertyDefinition > Decorator[expression.callee.name=Element]": (node) => {
if (stencil.isComponent()) {
const tagType = getType(node.parent);
const component = getDecorator(node.parent.parent.parent, "Component");
const [opts] = parseDecorator(component);
if (!opts || !opts.tag) return;
const parsedTag = `HTML${parseTag(opts.tag)}Element`;
if (tagType !== parsedTag) context.report({
node: node.parent.typeAnnotation ?? node.parent,
message: `@Element type is not matching tag for component (${parsedTag})`,
fix(fixer) {
if (node.parent.typeAnnotation?.typeAnnotation) return fixer.replaceText(node.parent.typeAnnotation.typeAnnotation, parsedTag);
const text = context.sourceCode.getText(node.parent).replace(";", "").concat(`: ${parsedTag};`);
return fixer.replaceText(node.parent, text);
}
});
}
}
};
}
};
var element_type_default = rule$18;
//#endregion
//#region src/rules/host-data-deprecated.ts
const rule$17 = {
meta: {
docs: {
description: "This rule catches usage of hostData method.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
return {
...stencil.rules,
"MethodDefinition[key.name=hostData]": (node) => {
if (stencil.isComponent()) context.report({
node: node.key,
message: `hostData() is deprecated and <Host> should be used in the render function instead.`
});
}
};
}
};
var host_data_deprecated_default = rule$17;
//#endregion
//#region src/rules/methods-must-be-public.ts
const rule$16 = {
meta: {
docs: {
description: "This rule catches Stencil Methods marked as private or protected.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
return {
...stencil.rules,
"MethodDefinition[kind=method]": (node) => {
if (stencil.isComponent() && getDecorator(node, "Method")) {
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
if (isPrivate(originalNode)) context.report({
node,
message: `Class methods decorated with @Method() cannot be private nor protected`
});
}
}
};
}
};
var methods_must_be_public_default = rule$16;
//#endregion
//#region src/rules/no-unused-watch.ts
const varsList = /* @__PURE__ */ new Set();
const rule$15 = {
meta: {
docs: {
description: "This rule catches Stencil Watch for not defined variables in Prop or State.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "suggestion"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
function getVars(node) {
if (!stencil.isComponent()) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const varName = originalNode.parent.name.escapedText;
varsList.add(varName);
}
function checkWatch(node) {
if (!stencil.isComponent()) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const varName = originalNode.expression.arguments[0].text;
if (!varsList.has(varName) && !isReservedAttribute(varName.toLowerCase())) context.report({
node,
message: `Watch decorator @Watch("${varName}") is not matching with any @Prop() or @State()`
});
}
return {
ClassDeclaration: stencil.rules.ClassDeclaration,
"PropertyDefinition > Decorator[expression.callee.name=Prop]": getVars,
"MethodDefinition[kind=get] > Decorator[expression.callee.name=Prop]": getVars,
"MethodDefinition[kind=set] > Decorator[expression.callee.name=Prop]": getVars,
"PropertyDefinition > Decorator[expression.callee.name=State]": getVars,
"MethodDefinition[kind=method] > Decorator[expression.callee.name=Watch]": checkWatch,
"ClassDeclaration:exit": (node) => {
if (!stencil.isComponent()) return;
stencil.rules["ClassDeclaration:exit"](node);
varsList.clear();
}
};
}
};
const GLOBAL_ATTRIBUTES$1 = [
"about",
"accessKey",
"autocapitalize",
"autofocus",
"class",
"contenteditable",
"contextmenu",
"dir",
"draggable",
"enterkeyhint",
"hidden",
"id",
"inert",
"inputmode",
"id",
"itemid",
"itemprop",
"itemref",
"itemscope",
"itemtype",
"lang",
"nonce",
"part",
"popover",
"role",
"slot",
"spellcheck",
"style",
"tabindex",
"title",
"translate",
"virtualkeyboardpolicy"
];
const RESERVED_PUBLIC_ATTRIBUTES = new Set([...GLOBAL_ATTRIBUTES$1].map((p) => p.toLowerCase()));
function isReservedAttribute(attributeName) {
return RESERVED_PUBLIC_ATTRIBUTES.has(attributeName.toLowerCase());
}
var no_unused_watch_default = rule$15;
//#endregion
//#region src/rules/own-methods-must-be-private.ts
const rule$14 = {
meta: {
docs: {
description: "This rule catches own class methods marked as public.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem",
fixable: "code"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
return {
...stencil.rules,
"MethodDefinition[kind=method]": (node) => {
if (!stencil.isComponent()) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const decorators = getDecoratorList(originalNode);
const stencilDecorator = decorators && decorators.some((dec) => stencilDecorators.includes(dec.expression.expression.escapedText));
const stencilCycle = stencilLifecycle.includes(originalNode.name.escapedText);
if (!stencilDecorator && !stencilCycle && !isPrivate(originalNode)) context.report({
node,
message: `Own class methods cannot be public`,
fix(fixer) {
const sourceCode = context.getSourceCode();
const tokens = sourceCode.getTokens(node);
const publicToken = tokens.find((token) => token.value === "public");
if (publicToken) return fixer.replaceText(publicToken, "private");
else return fixer.insertTextBefore(node.key, "private ");
}
});
}
};
}
};
var own_methods_must_be_private_default = rule$14;
//#endregion
//#region src/rules/own-props-must-be-private.ts
const rule$13 = {
meta: {
docs: {
description: "This rule catches own class attributes marked as public.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem",
fixable: "code"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
return {
...stencil.rules,
PropertyDefinition: (node) => {
if (!stencil.isComponent()) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const decorators = getDecoratorList(originalNode);
const stencilDecorator = decorators && decorators.some((dec) => stencilDecorators.includes(dec.expression.expression.escapedText));
if (!stencilDecorator && !isPrivate(originalNode)) context.report({
node,
message: `Own class properties cannot be public`,
fix(fixer) {
const sourceCode = context.getSourceCode();
const tokens = sourceCode.getTokens(node);
const publicToken = tokens.find((token) => token.value === "public");
if (publicToken) return fixer.replaceText(publicToken, "private");
else return fixer.insertTextBefore(node.key, "private ");
}
});
}
};
}
};
var own_props_must_be_private_default = rule$13;
//#endregion
//#region src/rules/prefer-vdom-listener.ts
const rule$12 = {
meta: {
docs: {
description: "This rule catches usages of events using @Listen decorator.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
return {
...stencil.rules,
"MethodDefinition[kind=method]": (node) => {
if (!stencil.isComponent()) return;
const listenDec = getDecorator(node, "Listen");
if (listenDec) {
const [eventName, opts] = parseDecorator(listenDec);
if (typeof eventName === "string" && opts === void 0) {
const eventName$1 = listenDec.expression.arguments[0].value;
if (PREFER_VDOM_LISTENER.includes(eventName$1)) context.report({
node: listenDec,
message: `Use vDOM listener instead.`
});
}
}
}
};
}
};
const PREFER_VDOM_LISTENER = [
"click",
"touchstart",
"touchend",
"touchmove",
"mousedown",
"mouseup",
"mousemove",
"keyup",
"keydown",
"focusin",
"focusout",
"focus",
"blur"
];
var prefer_vdom_listener_default = rule$12;
//#endregion
//#region src/rules/props-must-be-public.ts
const rule$11 = {
meta: {
docs: {
description: "This rule catches Stencil Props marked as private or protected.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
return {
...stencil.rules,
"PropertyDefinition": (node) => {
if (stencil.isComponent() && getDecorator(node, "Prop")) {
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
if (isPrivate(originalNode)) context.report({
node,
message: `Class properties decorated with @Prop() cannot be private nor protected`
});
}
}
};
}
};
var props_must_be_public_default = rule$11;
//#endregion
//#region src/rules/props-must-be-readonly.ts
const rule$10 = {
meta: {
docs: {
description: "This rule catches Stencil Props marked as non readonly.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "layout",
fixable: "code"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
return {
...stencil.rules,
"PropertyDefinition": (node) => {
const propDecorator = getDecorator(node, "Prop");
if (stencil.isComponent() && propDecorator) {
const [opts] = parseDecorator(propDecorator);
if (opts && opts.mutable === true) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const hasReadonly = !!(ts.canHaveModifiers(originalNode) && ts.getModifiers(originalNode)?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword));
if (!hasReadonly) context.report({
node: node.key,
message: `Class properties decorated with @Prop() should be readonly`,
fix(fixer) {
return fixer.insertTextBefore(node.key, "readonly ");
}
});
}
}
};
}
};
var props_must_be_readonly_default = rule$10;
//#endregion
//#region src/rules/render-returns-host.ts
const rule$9 = {
meta: {
docs: {
description: "This rule catches Stencil Prop names that share names of Global HTML Attributes.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
const typeChecker = parserServices.program.getTypeChecker();
return {
...stencil.rules,
"MethodDefinition[kind=method][key.name=render] ReturnStatement": (node) => {
if (!stencil.isComponent()) return;
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node.argument);
const type = typeChecker.getTypeAtLocation(originalNode);
if (type && type.symbol && type.symbol.escapedName === "Array") context.report({
node,
message: `Avoid returning an array in the render() function, use <Host> instead.`
});
}
};
}
};
var render_returns_host_default = rule$9;
//#endregion
//#region src/rules/required-jsdoc.ts
const DECORATORS = [
"Prop",
"Method",
"Event"
];
const INVALID_TAGS = ["type", "memberof"];
const rule$8 = {
meta: {
docs: {
description: "This rule catches Stencil Props and Methods using jsdoc.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "layout"
},
create(context) {
const stencil = stencilComponentContext();
const parserServices = context.sourceCode.parserServices;
function getJSDoc(node) {
if (!stencil.isComponent()) return;
DECORATORS.forEach((decName) => {
if (getDecorator(node, decName)) {
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const jsDoc = originalNode.jsDoc;
const isValid = jsDoc && jsDoc.length;
const haveTags = isValid && jsDoc.some((jsdoc) => jsdoc.tags && jsdoc.tags.length && jsdoc.tags.some((tag) => INVALID_TAGS.includes(tag.tagName.escapedText.toLowerCase())));
if (!isValid) context.report({
node,
message: `The @${decName} decorator must be documented.`
});
else if (haveTags) context.report({
node,
message: `The @${decName} decorator have not valid tags (${INVALID_TAGS.join(", ")}).`
});
}
});
}
return {
...stencil.rules,
"PropertyDefinition": getJSDoc,
"MethodDefinition[kind=method]": getJSDoc
};
}
};
var required_jsdoc_default = rule$8;
//#endregion
//#region src/rules/required-prefix.ts
const rule$7 = {
meta: {
docs: {
description: "This rule catches required prefix in component tag name.",
category: "Possible Errors",
recommended: false
},
schema: [{
type: "array",
minLength: 1,
additionalProperties: false
}],
type: "layout"
},
create(context) {
const stencil = stencilComponentContext();
return {
...stencil.rules,
"ClassDeclaration": (node) => {
const component = getDecorator(node, "Component");
if (!component) return;
const [{ tag }] = parseDecorator(component);
const options = context.options[0];
const match = options.some((t) => tag.startsWith(t));
if (!match) context.report({
node,
message: `The component with tagName ${tag} have not a valid prefix.`
});
}
};
}
};
var required_prefix_default = rule$7;
//#endregion
//#region src/rules/reserved-member-names.ts
const rule$6 = {
meta: {
docs: {
description: "This rule catches Stencil Prop names that share names of Global HTML Attributes.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const stencil = stencilComponentContext();
const checkName = (node) => {
if (!stencil.isComponent()) return;
const decoratorName$1 = node.expression.callee.name;
if (decoratorName$1 === "Prop" || decoratorName$1 === "Method") {
const propName = node.parent.key.name;
if (isReservedMember(propName)) context.report({
node: node.parent.key,
message: `The @${decoratorName$1} name "${propName} conflicts with a key in the HTMLElement prototype. Please choose a different name.`
});
if (propName.startsWith("data-")) context.report({
node: node.parent.key,
message: "Avoid using Global HTML Attributes as Prop names."
});
}
};
return {
...stencil.rules,
"PropertyDefinition > Decorator[expression.callee.name=Prop]": checkName,
"MethodDefinition[kind=method] > Decorator[expression.callee.name=Method]": checkName
};
}
};
const GLOBAL_ATTRIBUTES = [
"about",
"accessKey",
"autocapitalize",
"autofocus",
"class",
"contenteditable",
"contextmenu",
"dir",
"draggable",
"enterkeyhint",
"hidden",
"id",
"inert",
"inputmode",
"id",
"itemid",
"itemprop",
"itemref",
"itemscope",
"itemtype",
"lang",
"nonce",
"part",
"popover",
"role",
"slot",
"spellcheck",
"style",
"tabindex",
"title",
"translate",
"virtualkeyboardpolicy"
];
const JSX_KEYS = ["ref", "key"];
function getHtmlElementProperties() {
const { window: win } = new JSDOM();
const { document: doc } = win;
const htmlElement = doc.createElement("tester-component");
const relevantInterfaces = [
win.HTMLElement,
win.Element,
win.Node,
win.EventTarget
];
const props = /* @__PURE__ */ new Set();
let currentInstance = htmlElement;
while (currentInstance && relevantInterfaces.some((relevantInterface) => currentInstance instanceof relevantInterface)) {
Object.getOwnPropertyNames(currentInstance).forEach((prop) => props.add(prop));
currentInstance = Object.getPrototypeOf(currentInstance);
}
return Array.from(props);
}
const RESERVED_PUBLIC_MEMBERS = new Set([
...GLOBAL_ATTRIBUTES,
...getHtmlElementProperties(),
...JSX_KEYS
].map((p) => p.toLowerCase()));
function isReservedMember(memberName) {
return RESERVED_PUBLIC_MEMBERS.has(memberName.toLowerCase());
}
var reserved_member_names_default = rule$6;
//#endregion
//#region src/rules/single-export.ts
const rule$5 = {
meta: {
docs: {
description: "This rule catches modules that expose more than just the Stencil Component itself.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
const parserServices = context.sourceCode.parserServices;
const typeChecker = parserServices.program.getTypeChecker();
return { "ClassDeclaration": (node) => {
const component = getDecorator(node, "Component");
if (component) {
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const nonTypeExports = typeChecker.getExportsOfModule(typeChecker.getSymbolAtLocation(originalNode.getSourceFile())).filter((symbol) => (symbol.flags & (ts.SymbolFlags.Interface | ts.SymbolFlags.TypeAlias)) === 0).filter((symbol) => symbol.name !== originalNode.name.text);
nonTypeExports.forEach((symbol) => {
const errorNode = symbol.valueDeclaration ? parserServices.tsNodeToESTreeNodeMap.get(symbol.valueDeclaration).id : parserServices.tsNodeToESTreeNodeMap.get(symbol.declarations?.[0]);
context.report({
node: errorNode,
message: `To allow efficient bundling, modules using @Component() can only have a single export which is the component class itself. Any other exports should be moved to a separate file. For further information check out: https://stenciljs.com/docs/module-bundling`
});
});
}
} };
}
};
var single_export_default = rule$5;
//#endregion
//#region src/rules/strict-mutable.ts
const mutableProps = /* @__PURE__ */ new Map();
const mutableAssigned = /* @__PURE__ */ new Set();
const rule$4 = {
meta: {
docs: {
description: "This rule catches mutable Props that not need to be mutable.",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "layout"
},
create(context) {
const stencil = stencilComponentContext();
function getMutable(node) {
if (!stencil.isComponent()) return;
const parsed = parseDecorator(node);
const mutable = parsed && parsed.length && parsed[0].mutable || false;
if (mutable) {
const varName = node.parent.key.name;
mutableProps.set(varName, node);
}
}
function checkAssigment(node) {
if (!stencil.isComponent()) return;
const propName = node.left.property.name;
mutableAssigned.add(propName);
}
stencil.rules["ClassDeclaration:exit"];
return {
"ClassDeclaration": stencil.rules.ClassDeclaration,
"PropertyDefinition > Decorator[expression.callee.name=Prop]": getMutable,
"AssignmentExpression[left.object.type=ThisExpression][left.property.type=Identifier]": checkAssigment,
"ClassDeclaration:exit": (node) => {
const isCmp = stencil.isComponent();
stencil.rules["ClassDeclaration:exit"](node);
if (isCmp) {
mutableAssigned.forEach((propName) => mutableProps.delete(propName));
mutableProps.forEach((varNode, varName) => {
context.report({
node: varNode.parent,
message: `@Prop() "${varName}" should not be mutable`
});
});
mutableAssigned.clear();
mutableProps.clear();
}
}
};
}
};
var strict_mutable_default = rule$4;
//#endregion
//#region src/rules/ban-side-effects.ts
const rule$3 = {
meta: {
docs: {
description: "This rule catches function calls at the top level",
category: "Possible Errors",
recommended: false
},
schema: [{
type: "array",
items: { type: "string" },
minLength: 0,
additionalProperties: false
}],
type: "suggestion"
},
create(context) {
const shouldSkip = /\b(spec|e2e|test)\./.test(context.getFilename());
const skipFunctions = context.options[0] || DEFAULTS;
if (shouldSkip) return {};
return { "CallExpression": (node) => {
if (skipFunctions.includes(node.callee.name)) return;
if (!isInScope(node)) context.report({
node,
message: `Call expressions at the top-level should be avoided.`
});
} };
}
};
const isInScope = (n) => {
const type = n.type;
if (type === "ArrowFunctionExpression" || type === "FunctionDeclaration" || type === "ClassDeclaration" || type === "ExportNamedDeclaration") return true;
n = n.parent;
if (n) return isInScope(n);
return false;
};
const DEFAULTS = [
"describe",
"test",
"bind",
"createStore"
];
var ban_side_effects_default = rule$3;
//#endregion
//#region src/rules/strict-boolean-conditions.ts
const OPTION_ALLOW_NULL_UNION = "allow-null-union";
const OPTION_ALLOW_UNDEFINED_UNION = "allow-undefined-union";
const OPTION_ALLOW_STRING = "allow-string";
const OPTION_ALLOW_ENUM = "allow-enum";
const OPTION_ALLOW_NUMBER = "allow-number";
const OPTION_ALLOW_MIX = "allow-mix";
const OPTION_ALLOW_BOOLEAN_OR_UNDEFINED = "allow-boolean-or-undefined";
const OPTION_ALLOW_ANY_RHS = "allow-any-rhs";
const rule$2 = {
meta: {
docs: {
description: `Restricts the types allowed in boolean expressions. By default only booleans are allowed.
The following nodes are checked:
* Arguments to the \`!\`, \`&&\`, and \`||\` operators
* The condition in a conditional expression (\`cond ? x : y\`)
* Conditions for \`if\`, \`for\`, \`while\`, and \`do-while\` statements.`,
category: "Possible Errors",
recommended: true
},
schema: [{
type: "array",
items: {
type: "string",
enum: [
OPTION_ALLOW_NULL_UNION,
OPTION_ALLOW_UNDEFINED_UNION,
OPTION_ALLOW_STRING,
OPTION_ALLOW_ENUM,
OPTION_ALLOW_NUMBER,
OPTION_ALLOW_BOOLEAN_OR_UNDEFINED,
OPTION_ALLOW_ANY_RHS
]
},
minLength: 0,
maxLength: 5
}],
type: "problem"
},
create(context) {
const parserServices = context.sourceCode.parserServices;
const program = parserServices.program;
const rawOptions = context.options[0] || [
"allow-null-union",
"allow-undefined-union",
"allow-boolean-or-undefined"
];
const options = parseOptions(rawOptions, true);
const checker = program.getTypeChecker();
function walk(sourceFile) {
ts$1.forEachChild(sourceFile, function cb(node) {
switch (node.kind) {
case ts$1.SyntaxKind.PrefixUnaryExpression: {
const { operator, operand } = node;
if (operator === ts$1.SyntaxKind.ExclamationToken) checkExpression(operand, node);
break;
}
case ts$1.SyntaxKind.IfStatement:
case ts$1.SyntaxKind.WhileStatement:
case ts$1.SyntaxKind.DoStatement: {
const c = node;
checkExpression(c.expression, c);
break;
}
case ts$1.SyntaxKind.ConditionalExpression:
checkExpression(node.condition, node);
break;
case ts$1.SyntaxKind.ForStatement: {
const { condition } = node;
if (condition !== void 0) checkExpression(condition, node);
}
}
return ts$1.forEachChild(node, cb);
});
function checkExpression(node, location) {
const type = checker.getTypeAtLocation(node);
const failure = getTypeFailure(type, options);
if (failure !== void 0) {
if (failure === TypeFailure.AlwaysTruthy && !options.strictNullChecks && (options.allowNullUnion || options.allowUndefinedUnion)) return;
const originalNode = parserServices.tsNodeToESTreeNodeMap.get(node);
context.report({
node: originalNode,
message: showFailure(location, failure, isUnionType(type), options)
});
}
}
}
return { "Program": (node) => {
const sourceFile = parserServices.esTreeNodeToTSNodeMap.get(node);
walk(sourceFile);
} };
}
};
function parseOptions(ruleArguments, strictNullChecks) {
return {
strictNullChecks,
allowNullUnion: has(OPTION_ALLOW_NULL_UNION),
allowUndefinedUnion: has(OPTION_ALLOW_UNDEFINED_UNION),
allowString: has(OPTION_ALLOW_STRING),
allowEnum: has(OPTION_ALLOW_ENUM),
allowNumber: has(OPTION_ALLOW_NUMBER),
allowMix: has(OPTION_ALLOW_MIX),
allowBooleanOrUndefined: has(OPTION_ALLOW_BOOLEAN_OR_UNDEFINED),
allowAnyRhs: has(OPTION_ALLOW_ANY_RHS)
};
function has(name) {
return ruleArguments.indexOf(name) !== -1;
}
}
function getTypeFailure(type, options) {
if (isUnionType(type)) return handleUnion(type, options);
const kind = getKind(type);
const failure = failureForKind(kind, false, options);
if (failure !== void 0) return failure;
switch (triState(kind)) {
case true: return isTypeFlagSet(type, ts$1.TypeFlags.Any | ts$1.TypeFlags.BooleanLiteral) ? void 0 : TypeFailure.AlwaysTruthy;
case false: return isTypeFlagSet(type, ts$1.TypeFlags.BooleanLiteral) ? void 0 : TypeFailure.AlwaysFalsy;
case void 0: return void 0;
}
}
function isBooleanUndefined(type) {
let isTruthy = false;
for (const ty of type.types) if (isTypeFlagSet(ty, ts$1.TypeFlags.Boolean)) isTruthy = true;
else if (isTypeFlagSet(ty, ts$1.TypeFlags.BooleanLiteral)) isTruthy = isTruthy || ty.intrinsicName === "true";
else if (!isTypeFlagSet(ty, ts$1.TypeFlags.Void | ts$1.TypeFlags.Undefined)) return void 0;
return isTruthy;
}
function handleUnion(type, options) {
if (options.allowBooleanOrUndefined) switch (isBooleanUndefined(type)) {
case true: return void 0;
case false: return TypeFailure.AlwaysFalsy;
}
for (const ty of type.types) {
const kind = getKind(ty);
const failure = failureForKind(kind, true, options);
if (failure !== void 0) return failure;
}
return void 0;
}
/** Fails if a kind of falsiness is not allowed. */
function failureForKind(kind, isInUnion, options) {
switch (kind) {
case TypeKind.String:
case TypeKind.FalseStringLiteral: return options.allowString ? void 0 : TypeFailure.String;
case TypeKind.Number:
case TypeKind.FalseNumberLiteral: return options.allowNumber ? void 0 : TypeFailure.Number;
case TypeKind.Enum: return options.allowEnum ? void 0 : TypeFailure.Enum;
case TypeKind.Promise: return TypeFailure.Promise;
case TypeKind.Null: return isInUnion && !options.allowNullUnion ? TypeFailure.Null : void 0;
case TypeKind.Undefined: return isInUnion && !options.allowUndefinedUnion ? TypeFailure.Undefined : void 0;
default: return void 0;
}
}
let TypeFailure = /* @__PURE__ */ function(TypeFailure$1) {
TypeFailure$1[TypeFailure$1["AlwaysTruthy"] = 0] = "AlwaysTruthy";
TypeFailure$1[TypeFailure$1["AlwaysFalsy"] = 1] = "AlwaysFalsy";
TypeFailure$1[TypeFailure$1["String"] = 2] = "String";
TypeFailure$1[TypeFailure$1["Number"] = 3] = "Number";
TypeFailure$1[TypeFailure$1["Null"] = 4] = "Null";
TypeFailure$1[TypeFailure$1["Undefined"] = 5] = "Undefined";
TypeFailure$1[TypeFailure$1["Enum"] = 6] = "Enum";
TypeFailure$1[TypeFailure$1["Mixes"] = 7] = "Mixes";
TypeFailure$1[TypeFailure$1["Promise"] = 8] = "Promise";
return TypeFailure$1;
}({});
var TypeKind = /* @__PURE__ */ function(TypeKind$1) {
TypeKind$1[TypeKind$1["String"] = 0] = "String";
TypeKind$1[TypeKind$1["FalseStringLiteral"] = 1] = "FalseStringLiteral";
TypeKind$1[TypeKind$1["Number"] = 2] = "Number";
TypeKind$1[TypeKind$1["FalseNumberLiteral"] = 3] = "FalseNumberLiteral";
TypeKind$1[TypeKind$1["Boolean"] = 4] = "Boolean";
TypeKind$1[TypeKind$1["FalseBooleanLiteral"] = 5] = "FalseBooleanLiteral";
TypeKind$1[TypeKind$1["Null"] = 6] = "Null";
TypeKind$1[TypeKind$1["Undefined"] = 7] = "Undefined";
TypeKind$1[TypeKind$1["Enum"] = 8] = "Enum";
TypeKind$1[TypeKind$1["AlwaysTruthy"] = 9] = "AlwaysTruthy";
TypeKind$1[TypeKind$1["Promise"] = 10] = "Promise";
return TypeKind$1;
}(TypeKind || {});
/** Divides a type into always true, always false, or unknown. */
function triState(kind) {
switch (kind) {
case TypeKind.String:
case TypeKind.Number:
case TypeKind.Boolean:
case TypeKind.Enum: return void 0;
case TypeKind.Null:
case TypeKind.Undefined:
case TypeKind.FalseNumberLiteral:
case TypeKind.FalseStringLiteral:
case TypeKind.FalseBooleanLiteral: return false;
case TypeKind.AlwaysTruthy:
case TypeKind.Promise: return true;
}
}
function getKind(type) {
return is(ts$1.TypeFlags.StringLike) ? TypeKind.String : is(ts$1.TypeFlags.NumberLike) ? TypeKind.Number : is(ts$1.TypeFlags.Boolean) ? TypeKind.Boolean : isObject("Promise") ? TypeKind.Promise : is(ts$1.TypeFlags.Null) ? TypeKind.Null : is(ts$1.TypeFlags.Undefined | ts$1.TypeFlags.Void) ? TypeKind.Undefined : is(ts$1.TypeFlags.EnumLike) ? TypeKind.Enum : is(ts$1.TypeFlags.BooleanLiteral) ? type.intrinsicName === "true" ? TypeKind.AlwaysTruthy : TypeKind.FalseBooleanLiteral : TypeKind.AlwaysTruthy;
function is(flags) {
return isTypeFlagSet(type, flags);
}
function isObject(name) {
const symbol = type.getSymbol();
return symbol && symbol.getName() === name;
}
}
function binaryBooleanExpressionKind(node) {
switch (node.operatorToken.kind) {
case ts$1.SyntaxKind.AmpersandAmpersandToken: return "&&";
case ts$1.SyntaxKind.BarBarToken: return "||";
default: return void 0;
}
}
function stringOr(parts) {
switch (parts.length) {
case 1: return parts[0];
case 2: return `${parts[0]} or ${parts[1]}`;
default:
let res = "";
for (let i = 0; i < parts.length - 1; i++) res += `${parts[i]}, `;
return `${res}or ${parts[parts.length - 1]}`;
}
}
function isUnionType(type) {
return isTypeFlagSet(type, ts$1.TypeFlags.Union) && !isTypeFlagSet(type, ts$1.TypeFlags.Enum);
}
function showLocation(n) {
switch (n.kind) {
case ts$1.SyntaxKind.PrefixUnaryExpression: return "operand for the '!' operator";
case ts$1.SyntaxKind.ConditionalExpression: return "condition";
case ts$1.SyntaxKind.ForStatement: return "'for' condition";
case ts$1.SyntaxKind.IfStatement: return "'if' condition";
case ts$1.SyntaxKind.WhileStatement: return "'while' condition";
case ts$1.SyntaxKind.DoStatement: return "'do-while' condition";
case ts$1.SyntaxKind.BinaryExpression: return `operand for the '${binaryBooleanExpressionKind(n)}' operator`;
}
}
function showFailure(location, ty, unionType, options) {
const expectedTypes = showExpectedTypes(options);
const expected = expectedTypes.length === 1 ? `Only ${expectedTypes[0]}s are allowed` : `Allowed types are ${stringOr(expectedTypes)}`;
const tyFail = showTypeFailure(ty, unionType, options.strictNullChecks);
return `This type is not allowed in the ${showLocation(location)} because it ${tyFail}. ${expected}.`;
}
function showExpectedTypes(options) {
const parts = ["boolean"];
if (options.allowNullUnion) parts.push("null-union");
if (options.allowUndefinedUnion) parts.push("undefined-union");
if (options.allowString) parts.push("string");
if (options.allowEnum) parts.push("enum");
if (options.allowNumber) parts.push("number");
if (options.allowBooleanOrUndefined) parts.push("boolean-or-undefined");
return parts;
}
function showTypeFailure(ty, unionType, strictNullChecks) {
const is = unionType ? "could be" : "is";
switch (ty) {
case TypeFailure.AlwaysTruthy: return strictNullChecks ? "is always truthy" : `is always truthy. It may be null/undefined, but neither '${OPTION_ALLOW_NULL_UNION}' nor '${OPTION_ALLOW_UNDEFINED_UNION}' is set`;
case TypeFailure.AlwaysFalsy: return "is always falsy";
case TypeFailure.String: return `${is} a string`;
case TypeFailure.Number: return `${is} a number`;
case TypeFailure.Null: return `${is} null`;
case TypeFailure.Undefined: return `${is} undefined`;
case TypeFailure.Enum: return `${is} an enum`;
case TypeFailure.Promise: return "promise handled as boolean expression";
case TypeFailure.Mixes: return "unions more than one truthy/falsy type";
}
}
function isTypeFlagSet(obj, flag) {
return (obj.flags & flag) !== 0;
}
var strict_boolean_conditions_default = rule$2;
//#endregion
//#region src/rules/ban-exported-const-enums.ts
const rule$1 = {
meta: {
docs: {
description: "This rule catches exports of const enums",
category: "Possible Errors",
recommended: true
},
schema: [],
type: "problem"
},
create(context) {
return { "ExportNamedDeclaration > TSEnumDeclaration[const]": (node) => {
context.report({
node,
message: `Exported const enums are not allowed`
});
} };
}
};
var ban_exported_const_enums_default = rule$1;
//#endregion
//#region src/rules/dependency-suggestions.ts
const rule = {
meta: {
docs: {
description: "This rule can provide suggestions about dependencies in stencil apps",
recommended: true
},
schema: [],
type: "suggestion"
},
create(context) {
return { "ImportDeclaration": (node) => {
const importName = node.source.value;
const message = SUGGESTIONS[importName];
if (message) context.report({
node,
message
});
} };
}
};
const SUGGESTIONS = {
"classnames": `Stencil can already render conditional classes:
<div class={{disabled: condition}}>`,
"lodash": `"lodash" will bloat your build, use "lodash-es" instead: https://www.npmjs.com/package/lodash-es`,
"moment": `"moment" will bloat your build, use "dayjs", "date-fns" or other modern lightweight alternaitve`,
"core-js": `Stencil already include the core-js polyfills only when needed`
};
var dependency_suggestions_default = rule;
//#endregion
//#region src/rules/index.ts
var rules_default = {
"ban-side-effects": ban_side_effects_default,
"ban-default-true": ban_default_true_default,
"ban-exported-const-enums": ban_exported_const_enums_default,
"dependency-suggestions": dependency_suggestions_default,
"strict-boolean-conditions": strict_boolean_conditions_default,
"async-methods": async_methods_default,
"ban-prefix": ban_prefix_default,
"class-pattern": class_pattern_default,
"decorators-context": decorators_context_default,
"decorators-style": decorators_style_default,
"element-type": element_type_default,
"host-data-deprecated": host_data_deprecated_default,
"methods-must-be-public": methods_must_be_public_default,
"no-unused-watch": no_unused_watch_default,
"own-methods-must-be-private": own_methods_must_be_private_default,
"own-props-must-be-private": own_props_must_be_private_default,
"prefer-vdom-listener": prefer_vdom_listener_default,
"props-must-be-public": props_must_be_public_default,
"props-must-be-readonly": props_must_be_readonly_default,
"render-returns-host": render_returns_host_default,
"required-jsdoc": required_jsdoc_default,
"required-prefix": required_prefix_default,
"reserved-member-names": reserved_member_names_default,
"single-export": single_export_default,
"strict-mutable": strict_mutable_default
};
//#endregion
//#region src/configs/base.ts
var base_default = {
overrides: [{
files: ["*.ts", "*.tsx"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2018,
sourceType: "module",
ecmaFeatures: { "jsx": true }
},
env: {
es2020: true,
browser: true
},
plugins: ["stencil"],
rules: {
"stencil/async-methods": 2,
"stencil/ban-prefix": [2, [
"stencil",
"stnl",
"st"
]],
"stencil/decorators-context": 2,
"stencil/element-type": 2,
"stencil/host-data-deprecated": 2,
"stencil/methods-must-be-public": 2,
"stencil/no-unused-watch": 2,
"stencil/prefer-vdom-listener": 2,
"stencil/props-must-be-public": 2,
"stencil/render-returns-host": 2,
"stencil/reserved-member-names": 2,
"stencil/single-export": 2
}
}],
settings: { "react": { "version": "stencil-maintainers-put-an-invalid-version-intentionally-if-this-errors-please-raise-an-issue-https://github.com/stenciljs/eslint-plugin/issues" } }
};
//#endregion
//#region src/configs/recommended.ts
var recommended_default = {
plugins: ["react"],
extends: ["plugin:stencil/base"],