feat: docker compose maybe

This commit is contained in:
2023-11-13 16:10:04 -05:00
parent 180b261e40
commit b625ccd8d6
8031 changed files with 2182966 additions and 0 deletions

View File

@ -0,0 +1,5 @@
declare const _default: {
extends: string[];
rules: any;
};
export = _default;

16
node_modules/eslint-plugin-svelte/lib/configs/all.js generated vendored Normal file
View File

@ -0,0 +1,16 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const rules_1 = require("../utils/rules");
const base = require.resolve('./base');
const baseExtend = path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
module.exports = {
extends: [baseExtend],
rules: Object.fromEntries(rules_1.rules
.map((rule) => [`svelte/${rule.meta.docs.ruleName}`, 'error'])
.filter(([ruleName]) => ![
'svelte/no-restricted-html-elements'
].includes(ruleName)))
};

View File

@ -0,0 +1,14 @@
declare const _default: {
plugins: string[];
overrides: {
files: string[];
parser: string;
rules: {
'no-inner-declarations': string;
'no-self-assign': string;
'svelte/comment-directive': string;
'svelte/system': string;
};
}[];
};
export = _default;

16
node_modules/eslint-plugin-svelte/lib/configs/base.js generated vendored Normal file
View File

@ -0,0 +1,16 @@
"use strict";
module.exports = {
plugins: ['svelte'],
overrides: [
{
files: ['*.svelte'],
parser: require.resolve('svelte-eslint-parser'),
rules: {
'no-inner-declarations': 'off',
'no-self-assign': 'off',
'svelte/comment-directive': 'error',
'svelte/system': 'error'
}
}
]
};

View File

@ -0,0 +1,17 @@
declare const _default: {
extends: string[];
rules: {
'svelte/first-attribute-linebreak': string;
'svelte/html-closing-bracket-spacing': string;
'svelte/html-quotes': string;
'svelte/html-self-closing': string;
'svelte/indent': string;
'svelte/max-attributes-per-line': string;
'svelte/mustache-spacing': string;
'svelte/no-spaces-around-equal-signs-in-attribute': string;
'svelte/no-trailing-spaces': string;
'svelte/shorthand-attribute': string;
'svelte/shorthand-directive': string;
};
};
export = _default;

View File

@ -0,0 +1,23 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const base = require.resolve('./base');
const baseExtend = path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
module.exports = {
extends: [baseExtend],
rules: {
'svelte/first-attribute-linebreak': 'off',
'svelte/html-closing-bracket-spacing': 'off',
'svelte/html-quotes': 'off',
'svelte/html-self-closing': 'off',
'svelte/indent': 'off',
'svelte/max-attributes-per-line': 'off',
'svelte/mustache-spacing': 'off',
'svelte/no-spaces-around-equal-signs-in-attribute': 'off',
'svelte/no-trailing-spaces': 'off',
'svelte/shorthand-attribute': 'off',
'svelte/shorthand-directive': 'off'
}
};

View File

@ -0,0 +1,20 @@
declare const _default: {
extends: string[];
rules: {
'svelte/comment-directive': string;
'svelte/no-at-debug-tags': string;
'svelte/no-at-html-tags': string;
'svelte/no-dupe-else-if-blocks': string;
'svelte/no-dupe-style-properties': string;
'svelte/no-dynamic-slot-name': string;
'svelte/no-inner-declarations': string;
'svelte/no-not-function-handler': string;
'svelte/no-object-in-text-mustaches': string;
'svelte/no-shorthand-style-property-overrides': string;
'svelte/no-unknown-style-directive-property': string;
'svelte/no-unused-svelte-ignore': string;
'svelte/system': string;
'svelte/valid-compile': string;
};
};
export = _default;

View File

@ -0,0 +1,26 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const base = require.resolve('./base');
const baseExtend = path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
module.exports = {
extends: [baseExtend],
rules: {
'svelte/comment-directive': 'error',
'svelte/no-at-debug-tags': 'warn',
'svelte/no-at-html-tags': 'error',
'svelte/no-dupe-else-if-blocks': 'error',
'svelte/no-dupe-style-properties': 'error',
'svelte/no-dynamic-slot-name': 'error',
'svelte/no-inner-declarations': 'error',
'svelte/no-not-function-handler': 'error',
'svelte/no-object-in-text-mustaches': 'error',
'svelte/no-shorthand-style-property-overrides': 'error',
'svelte/no-unknown-style-directive-property': 'error',
'svelte/no-unused-svelte-ignore': 'error',
'svelte/system': 'error',
'svelte/valid-compile': 'error'
}
};

67
node_modules/eslint-plugin-svelte/lib/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,67 @@
import type { RuleModule } from './types';
import * as processor from './processor';
declare const _default: {
meta: typeof processor.meta;
configs: {
base: {
plugins: string[];
overrides: {
files: string[];
parser: string;
rules: {
'no-inner-declarations': string;
'no-self-assign': string;
'svelte/comment-directive': string;
'svelte/system': string;
};
}[];
};
recommended: {
extends: string[];
rules: {
'svelte/comment-directive': string;
'svelte/no-at-debug-tags': string;
'svelte/no-at-html-tags': string;
'svelte/no-dupe-else-if-blocks': string;
'svelte/no-dupe-style-properties': string;
'svelte/no-dynamic-slot-name': string;
'svelte/no-inner-declarations': string;
'svelte/no-not-function-handler': string;
'svelte/no-object-in-text-mustaches': string;
'svelte/no-shorthand-style-property-overrides': string;
'svelte/no-unknown-style-directive-property': string;
'svelte/no-unused-svelte-ignore': string;
'svelte/system': string;
'svelte/valid-compile': string;
};
};
prettier: {
extends: string[];
rules: {
'svelte/first-attribute-linebreak': string;
'svelte/html-closing-bracket-spacing': string;
'svelte/html-quotes': string;
'svelte/html-self-closing': string;
'svelte/indent': string;
'svelte/max-attributes-per-line': string;
'svelte/mustache-spacing': string;
'svelte/no-spaces-around-equal-signs-in-attribute': string;
'svelte/no-trailing-spaces': string;
'svelte/shorthand-attribute': string;
'svelte/shorthand-directive': string;
};
};
all: {
extends: string[];
rules: any;
};
};
rules: {
[key: string]: RuleModule;
};
processors: {
'.svelte': typeof processor;
svelte: typeof processor;
};
};
export = _default;

53
node_modules/eslint-plugin-svelte/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,53 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const rules_1 = require("./utils/rules");
const base_1 = __importDefault(require("./configs/base"));
const recommended_1 = __importDefault(require("./configs/recommended"));
const prettier_1 = __importDefault(require("./configs/prettier"));
const all_1 = __importDefault(require("./configs/all"));
const processor = __importStar(require("./processor"));
const meta = __importStar(require("./meta"));
const configs = {
base: base_1.default,
recommended: recommended_1.default,
prettier: prettier_1.default,
all: all_1.default
};
const rules = rules_1.rules.reduce((obj, r) => {
obj[r.meta.docs.ruleName] = r;
return obj;
}, {});
module.exports = {
meta,
configs,
rules,
processors: {
'.svelte': processor,
svelte: processor
}
};

2
node_modules/eslint-plugin-svelte/lib/meta.d.ts generated vendored Normal file
View File

@ -0,0 +1,2 @@
export declare const name: "eslint-plugin-svelte";
export declare const version: "2.35.0";

5
node_modules/eslint-plugin-svelte/lib/meta.js generated vendored Normal file
View File

@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = exports.name = void 0;
exports.name = 'eslint-plugin-svelte';
exports.version = '2.35.0';

View File

@ -0,0 +1,5 @@
import type { Linter } from 'eslint';
export * as meta from '../meta';
export declare function preprocess(code: string, filename: string): string[];
export declare function postprocess([messages]: Linter.LintMessage[][], filename: string): Linter.LintMessage[];
export declare const supportsAutofix = true;

View File

@ -0,0 +1,54 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.supportsAutofix = exports.postprocess = exports.preprocess = exports.meta = void 0;
const shared_1 = require("../shared");
exports.meta = __importStar(require("../meta"));
function preprocess(code, filename) {
if (filename) {
(0, shared_1.beginShared)(filename);
}
return [code];
}
exports.preprocess = preprocess;
function postprocess([messages], filename) {
const shared = (0, shared_1.terminateShared)(filename);
if (shared) {
return filter(messages, shared);
}
return messages;
}
exports.postprocess = postprocess;
exports.supportsAutofix = true;
function filter(messages, shared) {
if (shared.commentDirectives.length === 0) {
return messages;
}
let filteredMessages = messages;
for (const cd of shared.commentDirectives) {
filteredMessages = cd.filterMessages(filteredMessages);
}
return filteredMessages;
}

View File

@ -0,0 +1,2 @@
declare const _default: import("../../types").RuleModule;
export default _default;

View File

@ -0,0 +1,424 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../../utils");
const ts_utils_1 = require("../../utils/ts-utils");
const compat_1 = require("../../utils/compat");
function unionTypeParts(type) {
return [...iterate(type)];
function* iterate(t) {
if (t.isUnion()) {
for (const type of t.types) {
yield* iterate(type);
}
}
else {
yield t;
}
}
}
function isPossiblyFalsy(type, tsTools) {
return (unionTypeParts(type)
.filter((t) => !(0, ts_utils_1.isTruthyLiteral)(t, tsTools))
.some((type) => (0, ts_utils_1.isPossiblyFalsyType)(type, tsTools.ts)));
}
function isPossiblyTruthy(type, tsTools) {
return unionTypeParts(type).some((type) => !(0, ts_utils_1.isFalsyType)(type, tsTools));
}
function isPossiblyNullish(type, tsTools) {
return (0, ts_utils_1.isNullableType)(type, tsTools.ts);
}
function isAlwaysNullish(type, tsTools) {
return (0, ts_utils_1.isNullishType)(type, tsTools.ts);
}
function isLiteral(type, tsTools) {
return ((0, ts_utils_1.isBooleanLiteralType)(type, tsTools.ts) || (0, ts_utils_1.isNullishType)(type, tsTools.ts) || type.isLiteral());
}
exports.default = (0, utils_1.createRule)('@typescript-eslint/no-unnecessary-condition', {
meta: {
docs: {
description: 'disallow conditionals where the type is always truthy or always falsy',
category: 'Extension Rules',
recommended: false,
extensionRule: {
plugin: '@typescript-eslint/eslint-plugin',
url: 'https://typescript-eslint.io/rules/no-unnecessary-condition/'
}
},
schema: [
{
type: 'object',
properties: {
allowConstantLoopConditions: {
description: 'Whether to ignore constant loop conditions, such as `while (true)`.',
type: 'boolean'
},
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: {
description: 'Whether to not error when running with a tsconfig that has strictNullChecks turned.',
type: 'boolean'
}
},
additionalProperties: false
}
],
fixable: 'code',
messages: {
alwaysTruthy: 'Unnecessary conditional, value is always truthy.',
alwaysFalsy: 'Unnecessary conditional, value is always falsy.',
alwaysTruthyFunc: 'This callback should return a conditional, but return is always truthy.',
alwaysFalsyFunc: 'This callback should return a conditional, but return is always falsy.',
neverNullish: 'Unnecessary conditional, expected left-hand side of `??` operator to be possibly null or undefined.',
alwaysNullish: 'Unnecessary conditional, left-hand side of `??` operator is always `null` or `undefined`.',
literalBooleanExpression: 'Unnecessary conditional, both sides of the expression are literal values.',
noOverlapBooleanExpression: 'Unnecessary conditional, the types have no overlap.',
never: 'Unnecessary conditional, value is `never`.',
neverOptionalChain: 'Unnecessary optional chain on a non-nullish value.',
noStrictNullCheck: 'This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.'
},
type: 'suggestion',
deprecated: true,
replacedBy: {
note: 'This rule is no longer needed when using svelte-eslint-parser>=v0.19.0.'
}
},
create(context) {
const { allowConstantLoopConditions = false, allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing = false } = (context.options[0] || {});
const tools = (0, ts_utils_1.getTypeScriptTools)(context);
if (!tools) {
return {};
}
const { service, ts } = tools;
const checker = service.program.getTypeChecker();
const sourceCode = (0, compat_1.getSourceCode)(context);
const compilerOptions = service.program.getCompilerOptions();
const isStrictNullChecks = compilerOptions.strict
? compilerOptions.strictNullChecks !== false
: compilerOptions.strictNullChecks;
if (!isStrictNullChecks && allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing !== true) {
context.report({
loc: {
start: { line: 0, column: 0 },
end: { line: 0, column: 0 }
},
messageId: 'noStrictNullCheck'
});
}
const mutableVarReferenceIds = [];
const scriptElements = [];
let inSvelteReactiveStatement = false;
for (const scope of [
sourceCode.scopeManager.globalScope,
sourceCode.scopeManager.globalScope?.childScopes.find((scope) => scope.type === 'module')
]) {
if (!scope)
continue;
for (const variable of scope.variables) {
if (variable.defs.some((def) => def.type === 'Variable' && (def.parent.kind === 'var' || def.parent.kind === 'let'))) {
for (const reference of variable.references) {
mutableVarReferenceIds.push(reference.identifier);
}
}
}
}
for (const body of sourceCode.ast.body) {
if (body.type === 'SvelteScriptElement') {
scriptElements.push(body);
}
}
function hasSvelteReactiveVar(node) {
const inReactiveScope = inSvelteReactiveStatement ||
(scriptElements.length &&
scriptElements.every((elem) => node.range[1] <= elem.range[0] || elem.range[1] <= node.range[0]));
if (!inReactiveScope) {
return false;
}
return mutableVarReferenceIds.some((id) => node.range[0] <= id.range[0] && id.range[1] <= node.range[1]);
}
function getNodeType(node) {
const tsNode = service.esTreeNodeToTSNodeMap.get(node);
return tsNode && (0, ts_utils_1.getConstrainedTypeAtLocation)(checker, tsNode);
}
function nodeIsArrayType(node) {
const nodeType = getNodeType(node);
if (!nodeType) {
return false;
}
return checker.isArrayType(nodeType);
}
function nodeIsTupleType(node) {
const nodeType = getNodeType(node);
return Boolean(nodeType && (0, ts_utils_1.isTupleType)(nodeType, ts));
}
function isArrayIndexExpression(node) {
return (node.type === 'MemberExpression' &&
node.computed &&
(nodeIsArrayType(node.object) ||
(nodeIsTupleType(node.object) &&
node.property.type !== 'Literal')));
}
function checkNode(node, isUnaryNotArgument = false) {
if (hasSvelteReactiveVar(node)) {
return;
}
if (node.type === 'UnaryExpression' && node.operator === '!') {
checkNode(node.argument, true);
return;
}
if (isArrayIndexExpression(node)) {
return;
}
if (node.type === 'LogicalExpression' && node.operator !== '??') {
checkNode(node.right);
return;
}
const type = getNodeType(node);
if (!type ||
unionTypeParts(type).some((part) => (0, ts_utils_1.isAnyType)(part, ts) || (0, ts_utils_1.isUnknownType)(part, ts) || part.isTypeParameter())) {
return;
}
let messageId = null;
if (unionTypeParts(type).some((part) => (0, ts_utils_1.isNeverType)(part, ts))) {
messageId = 'never';
}
else if (!isPossiblyTruthy(type, tools)) {
messageId = !isUnaryNotArgument ? 'alwaysFalsy' : 'alwaysTruthy';
}
else if (!isPossiblyFalsy(type, tools)) {
messageId = !isUnaryNotArgument ? 'alwaysTruthy' : 'alwaysFalsy';
}
if (messageId) {
context.report({ node, messageId });
}
}
function checkNodeForNullish(node) {
if (hasSvelteReactiveVar(node)) {
return;
}
const type = getNodeType(node);
if (!type || (0, ts_utils_1.isAnyType)(type, ts) || (0, ts_utils_1.isUnknownType)(type, ts)) {
return;
}
let messageId = null;
if (unionTypeParts(type).some((part) => (0, ts_utils_1.isNeverType)(part, ts))) {
messageId = 'never';
}
else if (!isPossiblyNullish(type, tools)) {
if (!isArrayIndexExpression(node) &&
!(node.type === 'ChainExpression' &&
node.expression.type !== 'TSNonNullExpression' &&
optionChainContainsOptionArrayIndex(node.expression))) {
messageId = 'neverNullish';
}
}
else if (isAlwaysNullish(type, tools)) {
messageId = 'alwaysNullish';
}
if (messageId) {
context.report({ node, messageId });
}
}
const BOOL_OPERATORS = new Set(['<', '>', '<=', '>=', '==', '===', '!=', '!==']);
function checkIfBinaryExpressionIsNecessaryConditional(node) {
if (hasSvelteReactiveVar(node)) {
return;
}
if (!BOOL_OPERATORS.has(node.operator)) {
return;
}
const leftType = getNodeType(node.left);
const rightType = getNodeType(node.right);
if (!leftType || !rightType) {
return;
}
if (isLiteral(leftType, tools) && isLiteral(rightType, tools)) {
context.report({ node, messageId: 'literalBooleanExpression' });
return;
}
if (isStrictNullChecks) {
const UNDEFINED = ts.TypeFlags.Undefined;
const NULL = ts.TypeFlags.Null;
const isComparable = (type, f) => {
let flag = f;
flag |= ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.TypeParameter;
if (node.operator === '==' || node.operator === '!=') {
flag |= NULL | UNDEFINED;
}
return unionTypeParts(type).some((t) => (t.flags & flag) !== 0);
};
if ((leftType.flags === UNDEFINED && !isComparable(rightType, UNDEFINED)) ||
(rightType.flags === UNDEFINED && !isComparable(leftType, UNDEFINED)) ||
(leftType.flags === NULL && !isComparable(rightType, NULL)) ||
(rightType.flags === NULL && !isComparable(leftType, NULL))) {
context.report({ node, messageId: 'noOverlapBooleanExpression' });
}
}
}
function checkLogicalExpressionForUnnecessaryConditionals(node) {
if (node.operator === '??') {
checkNodeForNullish(node.left);
return;
}
checkNode(node.left);
}
function checkIfLoopIsNecessaryConditional(node) {
if (node.test === null) {
return;
}
if (allowConstantLoopConditions) {
const nodeType = getNodeType(node.test);
if (nodeType &&
(0, ts_utils_1.isBooleanLiteralType)(nodeType, ts) &&
checker.typeToString(nodeType) === 'true')
return;
}
checkNode(node.test);
}
const ARRAY_PREDICATE_FUNCTIONS = new Set(['filter', 'find', 'some', 'every']);
function isArrayPredicateFunction(node) {
const { callee } = node;
return (callee.type === 'MemberExpression' &&
callee.property.type === 'Identifier' &&
ARRAY_PREDICATE_FUNCTIONS.has(callee.property.name) &&
(nodeIsArrayType(callee.object) || nodeIsTupleType(callee.object)));
}
function checkCallExpression(node) {
if (isArrayPredicateFunction(node) && node.arguments.length) {
const callback = node.arguments[0];
if ((callback.type === 'ArrowFunctionExpression' || callback.type === 'FunctionExpression') &&
callback.body) {
if (callback.body.type !== 'BlockStatement') {
checkNode(callback.body);
return;
}
const callbackBody = callback.body.body;
if (callbackBody.length === 1 &&
callbackBody[0].type === 'ReturnStatement' &&
callbackBody[0].argument) {
checkNode(callbackBody[0].argument);
return;
}
}
const nodeType = getNodeType(callback);
if (!nodeType) {
return;
}
const returnTypes = (0, ts_utils_1.getCallSignaturesOfType)(nodeType).map((sig) => sig.getReturnType());
if (returnTypes.length === 0) {
return;
}
if (returnTypes.some((t) => (0, ts_utils_1.isAnyType)(t, ts) || (0, ts_utils_1.isUnknownType)(t, ts))) {
return;
}
if (!returnTypes.some((t) => isPossiblyFalsy(t, tools))) {
context.report({
node: callback,
messageId: 'alwaysTruthyFunc'
});
return;
}
if (!returnTypes.some((t) => isPossiblyTruthy(t, tools))) {
context.report({
node: callback,
messageId: 'alwaysFalsyFunc'
});
}
}
}
function optionChainContainsOptionArrayIndex(node) {
const lhsNode = node.type === 'CallExpression' ? node.callee : node.object;
if (node.optional && isArrayIndexExpression(lhsNode)) {
return true;
}
if (lhsNode.type === 'MemberExpression' || lhsNode.type === 'CallExpression') {
return optionChainContainsOptionArrayIndex(lhsNode);
}
return false;
}
function isNullablePropertyType(objType, propertyType) {
if (propertyType.isUnion()) {
return propertyType.types.some((type) => isNullablePropertyType(objType, type));
}
if (propertyType.isNumberLiteral() || propertyType.isStringLiteral()) {
const propType = (0, ts_utils_1.getTypeOfPropertyOfType)(objType, propertyType.value.toString(), checker);
if (propType) {
return (0, ts_utils_1.isNullableType)(propType, ts);
}
}
const typeName = (0, ts_utils_1.getTypeName)(propertyType, tools);
return Boolean((typeName === 'string' && checker.getIndexInfoOfType(objType, ts.IndexKind.String)) ||
(typeName === 'number' && checker.getIndexInfoOfType(objType, ts.IndexKind.Number)));
}
function isNullableOriginFromPrev(node) {
const prevType = getNodeType(node.object);
const property = node.property;
if (prevType && prevType.isUnion() && property.type === 'Identifier') {
const isOwnNullable = prevType.types.some((type) => {
if (node.computed) {
const propertyType = getNodeType(node.property);
return Boolean(propertyType && isNullablePropertyType(type, propertyType));
}
const propType = (0, ts_utils_1.getTypeOfPropertyOfType)(type, property.name, checker);
return propType && (0, ts_utils_1.isNullableType)(propType, ts);
});
return !isOwnNullable && (0, ts_utils_1.isNullableType)(prevType, ts);
}
return false;
}
function isOptionableExpression(node) {
const type = getNodeType(node);
if (!type) {
return false;
}
const isOwnNullable = node.type === 'MemberExpression' ? !isNullableOriginFromPrev(node) : true;
return ((0, ts_utils_1.isAnyType)(type, ts) ||
(0, ts_utils_1.isUnknownType)(type, ts) ||
((0, ts_utils_1.isNullableType)(type, ts) && isOwnNullable));
}
function checkOptionalChain(node, beforeOperator, fix) {
if (!node.optional) {
return;
}
if (optionChainContainsOptionArrayIndex(node)) {
return;
}
const nodeToCheck = node.type === 'CallExpression' ? node.callee : node.object;
if (hasSvelteReactiveVar(nodeToCheck)) {
return;
}
if (isOptionableExpression(nodeToCheck)) {
return;
}
const questionDotOperator = sourceCode.getTokenAfter(beforeOperator, {
includeComments: false,
filter: (token) => token.type === 'Punctuator' && token.value === '?.'
});
context.report({
node,
loc: questionDotOperator.loc,
messageId: 'neverOptionalChain',
fix(fixer) {
return fixer.replaceText(questionDotOperator, fix);
}
});
}
function checkOptionalMemberExpression(node) {
checkOptionalChain(node, node.object, node.computed ? '' : '.');
}
function checkOptionalCallExpression(node) {
checkOptionalChain(node, node.callee, '');
}
return {
SvelteReactiveStatement: () => (inSvelteReactiveStatement = true),
'SvelteReactiveStatement:exit': () => (inSvelteReactiveStatement = false),
BinaryExpression: checkIfBinaryExpressionIsNecessaryConditional,
CallExpression: checkCallExpression,
ConditionalExpression: (node) => checkNode(node.test),
DoWhileStatement: checkIfLoopIsNecessaryConditional,
ForStatement: checkIfLoopIsNecessaryConditional,
IfStatement: (node) => checkNode(node.test),
LogicalExpression: checkLogicalExpressionForUnnecessaryConditionals,
WhileStatement: checkIfLoopIsNecessaryConditional,
'MemberExpression[optional = true]': checkOptionalMemberExpression,
'CallExpression[optional = true]': checkOptionalCallExpression
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,123 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('block-lang', {
meta: {
docs: {
description: 'disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks.',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
enforceScriptPresent: {
type: 'boolean'
},
enforceStylePresent: {
type: 'boolean'
},
script: {
oneOf: [
{
type: ['string', 'null']
},
{
type: 'array',
items: {
type: ['string', 'null']
},
minItems: 1
}
]
},
style: {
oneOf: [
{
type: ['string', 'null']
},
{
type: 'array',
items: {
type: ['string', 'null']
},
minItems: 1
}
]
}
},
additionalProperties: false
}
],
messages: {},
type: 'suggestion'
},
create(context) {
if (!(0, compat_1.getSourceCode)(context).parserServices.isSvelte) {
return {};
}
const enforceScriptPresent = context.options[0]?.enforceScriptPresent ?? false;
const enforceStylePresent = context.options[0]?.enforceStylePresent ?? false;
const scriptOption = context.options[0]?.script ?? null;
const allowedScriptLangs = Array.isArray(scriptOption)
? scriptOption
: [scriptOption];
const scriptNodes = [];
const styleOption = context.options[0]?.style ?? null;
const allowedStyleLangs = Array.isArray(styleOption)
? styleOption
: [styleOption];
const styleNodes = [];
return {
SvelteScriptElement(node) {
scriptNodes.push(node);
},
SvelteStyleElement(node) {
styleNodes.push(node);
},
'Program:exit'() {
if (scriptNodes.length === 0 && enforceScriptPresent) {
context.report({
loc: { line: 1, column: 1 },
message: `The <script> block should be present and its lang attribute should be ${prettyPrintLangs(allowedScriptLangs)}.`
});
}
for (const scriptNode of scriptNodes) {
if (!allowedScriptLangs.includes((0, ast_utils_1.getLangValue)(scriptNode)?.toLowerCase() ?? null)) {
context.report({
node: scriptNode,
message: `The lang attribute of the <script> block should be ${prettyPrintLangs(allowedScriptLangs)}.`
});
}
}
if (styleNodes.length === 0 && enforceStylePresent) {
context.report({
loc: { line: 1, column: 1 },
message: `The <style> block should be present and its lang attribute should be ${prettyPrintLangs(allowedStyleLangs)}.`
});
}
for (const styleNode of styleNodes) {
if (!allowedStyleLangs.includes((0, ast_utils_1.getLangValue)(styleNode)?.toLowerCase() ?? null)) {
context.report({
node: styleNode,
message: `The lang attribute of the <style> block should be ${prettyPrintLangs(allowedStyleLangs)}.`
});
}
}
}
};
}
});
function prettyPrintLangs(langs) {
const hasNull = langs.includes(null);
const nonNullLangs = langs.filter((lang) => lang !== null).map((lang) => `"${lang}"`);
if (nonNullLangs.length === 0) {
return 'omitted';
}
const hasNullText = hasNull ? 'either omitted or ' : '';
const nonNullText = nonNullLangs.length === 1 ? nonNullLangs[0] : `one of ${nonNullLangs.join(', ')}`;
return hasNullText + nonNullText;
}

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
exports.default = (0, utils_1.createRule)('button-has-type', {
meta: {
docs: {
description: 'disallow usage of button without an explicit type attribute',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
button: {
type: 'boolean'
},
submit: {
type: 'boolean'
},
reset: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
missingTypeAttribute: 'Missing an explicit type attribute for button.',
invalidTypeAttribute: '{{value}} is an invalid value for button type attribute.',
forbiddenTypeAttribute: '{{value}} is a forbidden value for button type attribute.',
emptyTypeAttribute: 'A value must be set for button type attribute.'
},
type: 'suggestion'
},
create(context) {
const configuration = {
button: true,
submit: true,
reset: true,
...(context.options[0] ?? {})
};
function isButtonType(type) {
return type === 'button' || type === 'submit' || type === 'reset';
}
function report(node, messageId, data = {}) {
context.report({
node,
messageId,
data
});
}
function validateAttribute(attribute) {
if (attribute.value.length === 0) {
report(attribute, 'emptyTypeAttribute');
return;
}
const strValue = (0, ast_utils_1.getStaticAttributeValue)(attribute);
if (strValue == null) {
return;
}
if (!isButtonType(strValue)) {
report(attribute, 'invalidTypeAttribute', { value: strValue });
}
else if (!configuration[strValue]) {
report(attribute, 'forbiddenTypeAttribute', { value: strValue });
}
}
function validateDirective(directive) {
if (!directive.expression) {
report(directive, 'emptyTypeAttribute');
}
}
return {
"SvelteElement[name.name='button'] > SvelteStartTag"(node) {
const typeAttr = (0, ast_utils_1.findAttribute)(node, 'type');
if (typeAttr) {
validateAttribute(typeAttr);
return;
}
const typeDir = (0, ast_utils_1.findBindDirective)(node, 'type');
if (typeDir) {
validateDirective(typeDir);
return;
}
const typeShortAttr = (0, ast_utils_1.findShorthandAttribute)(node, 'type');
if (typeShortAttr) {
return;
}
for (const attr of node.attributes) {
if (attr.type === 'SvelteSpreadAttribute') {
return;
}
}
report(node, 'missingTypeAttribute');
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,182 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const shared_1 = require("../shared");
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
const COMMENT_DIRECTIVE_B = /^\s*(eslint-(?:en|dis)able)(?:\s+|$)/;
const COMMENT_DIRECTIVE_L = /^\s*(eslint-disable(?:-next)?-line)(?:\s+|$)/;
const ALL_RULES = () => true;
function stripDirectiveComment(value) {
return value.split(/\s-{2,}\s/u)[0];
}
exports.default = (0, utils_1.createRule)('comment-directive', {
meta: {
docs: {
description: 'support comment-directives in HTML template',
category: 'System',
recommended: 'base'
},
schema: [
{
type: 'object',
properties: {
reportUnusedDisableDirectives: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
unused: 'Unused {{kind}} directive (no problems were reported).',
unusedRule: "Unused {{kind}} directive (no problems were reported from '{{rule}}').",
unusedEnable: 'Unused {{kind}} directive (reporting is not suppressed).',
unusedEnableRule: "Unused {{kind}} directive (reporting from '{{rule}}' is not suppressed)."
},
type: 'problem'
},
create(context) {
const shared = (0, shared_1.getShared)((0, compat_1.getFilename)(context));
if (!shared)
return {};
const options = context.options[0] || {};
const reportUnusedDisableDirectives = Boolean(options.reportUnusedDisableDirectives);
const directives = shared.newCommentDirectives({
ruleId: 'svelte/comment-directive',
reportUnusedDisableDirectives
});
const sourceCode = (0, compat_1.getSourceCode)(context);
function parse(pattern, comment) {
const text = stripDirectiveComment(comment.value);
const match = pattern.exec(text);
if (match == null) {
return null;
}
const type = match[1];
const rules = [];
const rulesRe = /([^\s,]+)[\s,]*/g;
let startIndex = match[0].length;
rulesRe.lastIndex = startIndex;
let res;
while ((res = rulesRe.exec(text))) {
const ruleId = res[1].trim();
const commentStart = comment.range[0] + 4;
const start = sourceCode.getLocFromIndex(commentStart + startIndex);
const end = sourceCode.getLocFromIndex(commentStart + startIndex + ruleId.length);
rules.push({
ruleId,
loc: {
start,
end
}
});
startIndex = rulesRe.lastIndex;
}
return { type, rules };
}
function processBlock(directives, comment) {
const parsed = parse(COMMENT_DIRECTIVE_B, comment);
if (parsed != null) {
if (parsed.type === 'eslint-disable') {
if (parsed.rules.length) {
for (const rule of parsed.rules) {
if (reportUnusedDisableDirectives) {
context.report({
loc: rule.loc,
messageId: 'unusedRule',
data: { rule: rule.ruleId, kind: parsed.type }
});
}
directives.disableBlock(comment.loc.end, rule.ruleId, {
loc: rule.loc.start
});
}
}
else {
if (reportUnusedDisableDirectives) {
context.report({
loc: comment.loc,
messageId: 'unused',
data: { kind: parsed.type }
});
}
directives.disableBlock(comment.loc.end, ALL_RULES, {
loc: comment.loc.start
});
}
}
else {
if (parsed.rules.length) {
for (const rule of parsed.rules) {
if (reportUnusedDisableDirectives) {
context.report({
loc: rule.loc,
messageId: 'unusedEnableRule',
data: { rule: rule.ruleId, kind: parsed.type }
});
}
directives.enableBlock(comment.loc.start, rule.ruleId, {
loc: rule.loc.start
});
}
}
else {
if (reportUnusedDisableDirectives) {
context.report({
loc: comment.loc,
messageId: 'unusedEnable',
data: { kind: parsed.type }
});
}
directives.enableBlock(comment.loc.start, ALL_RULES, {
loc: comment.loc.start
});
}
}
}
}
function processLine(directives, comment) {
const parsed = parse(COMMENT_DIRECTIVE_L, comment);
if (parsed != null && comment.loc.start.line === comment.loc.end.line) {
const line = comment.loc.start.line + (parsed.type === 'eslint-disable-line' ? 0 : 1);
if (parsed.rules.length) {
for (const rule of parsed.rules) {
if (reportUnusedDisableDirectives) {
context.report({
loc: rule.loc,
messageId: 'unusedRule',
data: { rule: rule.ruleId, kind: parsed.type }
});
}
directives.disableLine(line, rule.ruleId, {
loc: rule.loc.start
});
}
}
else {
if (reportUnusedDisableDirectives) {
context.report({
loc: comment.loc,
messageId: 'unused',
data: { kind: parsed.type }
});
}
directives.disableLine(line, ALL_RULES, {
loc: comment.loc.start
});
}
}
}
return {
SvelteHTMLComment(node) {
processBlock(directives, node);
processLine(directives, node);
},
SvelteScriptElement(node) {
directives.enableBlock(node.startTag.loc.end, ALL_RULES, {
loc: node.loc.start
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,80 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const svelte_store_1 = require("./reference-helpers/svelte-store");
exports.default = (0, utils_1.createRule)('derived-has-same-inputs-outputs', {
meta: {
docs: {
description: 'derived store should use same variable names between values and callback',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: false
},
schema: [],
messages: {
unexpected: "The argument name should be '{{name}}'."
},
type: 'suggestion'
},
create(context) {
function isIdentifierOrArrayExpression(node) {
return ['Identifier', 'ArrayExpression'].includes(node.type);
}
function isFunctionExpression(node) {
return ['ArrowFunctionExpression', 'FunctionExpression'].includes(node.type);
}
function checkIdentifier(context, args, fn) {
const fnParam = fn.params[0];
if (fnParam.type !== 'Identifier')
return;
const expectedName = `$${args.name}`;
if (expectedName !== fnParam.name) {
context.report({
node: fn,
loc: fnParam.loc,
messageId: 'unexpected',
data: { name: expectedName }
});
}
}
function checkArrayExpression(context, args, fn) {
const fnParam = fn.params[0];
if (fnParam.type !== 'ArrayPattern')
return;
const argNames = args.elements.map((element) => {
return element && element.type === 'Identifier' ? element.name : null;
});
fnParam.elements.forEach((element, index) => {
const argName = argNames[index];
if (element && element.type === 'Identifier' && argName) {
const expectedName = `$${argName}`;
if (expectedName !== element.name) {
context.report({
node: fn,
loc: element.loc,
messageId: 'unexpected',
data: { name: expectedName }
});
}
}
});
}
return {
Program() {
for (const { node } of (0, svelte_store_1.extractStoreReferences)(context, ['derived'])) {
const [args, fn] = node.arguments;
if (!args || !isIdentifierOrArrayExpression(args))
continue;
if (!fn || !isFunctionExpression(fn))
continue;
if (!fn.params || fn.params.length === 0)
continue;
if (args.type === 'Identifier')
checkIdentifier(context, args, fn);
else
checkArrayExpression(context, args, fn);
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const SLOTS_TYPE_NAME = '$$Slots';
exports.default = (0, utils_1.createRule)('experimental-require-slot-types', {
meta: {
docs: {
description: 'require slot type declaration using the `$$Slots` interface',
category: 'Experimental',
recommended: false
},
schema: [],
messages: {
missingSlotsInterface: `The component must define the $$Slots interface.`
},
type: 'suggestion'
},
create(context) {
let isTs = false;
let hasSlot = false;
let hasDeclaredSlots = false;
return {
SvelteScriptElement(node) {
const lang = (0, ast_utils_1.getLangValue)(node)?.toLowerCase();
isTs = lang === 'ts' || lang === 'typescript';
},
SvelteElement(node) {
if (node.name.type === 'SvelteName' && node.name.name === 'slot') {
hasSlot = true;
}
},
TSInterfaceDeclaration(node) {
if (node.id.name === SLOTS_TYPE_NAME) {
hasDeclaredSlots = true;
}
},
TSTypeAliasDeclaration(node) {
if (node.id.name === SLOTS_TYPE_NAME) {
hasDeclaredSlots = true;
}
},
'Program:exit'() {
if (isTs && hasSlot && !hasDeclaredSlots) {
context.report({
loc: {
line: 1,
column: 1
},
messageId: 'missingSlotsInterface'
});
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const EVENTS_TYPE_NAME = '$$Events';
exports.default = (0, utils_1.createRule)('experimental-require-strict-events', {
meta: {
docs: {
description: 'require the strictEvents attribute on `<script>` tags',
category: 'Experimental',
recommended: false
},
schema: [],
messages: {
missingStrictEvents: `The component must have the strictEvents attribute on its <script> tag or it must define the $$Events interface.`
},
type: 'suggestion'
},
create(context) {
let isTs = false;
let hasAttribute = false;
let hasDeclaredEvents = false;
let scriptNode;
return {
SvelteScriptElement(node) {
const lang = (0, ast_utils_1.getLangValue)(node)?.toLowerCase();
isTs = lang === 'ts' || lang === 'typescript';
hasAttribute = (0, ast_utils_1.findAttribute)(node, 'strictEvents') !== null;
scriptNode = node;
},
TSInterfaceDeclaration(node) {
if (node.id.name === EVENTS_TYPE_NAME) {
hasDeclaredEvents = true;
}
},
TSTypeAliasDeclaration(node) {
if (node.id.name === EVENTS_TYPE_NAME) {
hasDeclaredEvents = true;
}
},
'Program:exit'() {
if (isTs && !hasAttribute && !hasDeclaredEvents) {
context.report({
node: scriptNode,
messageId: 'missingStrictEvents'
});
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('first-attribute-linebreak', {
meta: {
docs: {
description: 'enforce the location of first attribute',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'whitespace',
schema: [
{
type: 'object',
properties: {
multiline: { enum: ['below', 'beside'] },
singleline: { enum: ['below', 'beside'] }
},
additionalProperties: false
}
],
messages: {
expected: 'Expected a linebreak before this attribute.',
unexpected: 'Expected no linebreak before this attribute.'
},
type: 'layout'
},
create(context) {
const multiline = context.options[0]?.multiline || 'below';
const singleline = context.options[0]?.singleline || 'beside';
const sourceCode = (0, compat_1.getSourceCode)(context);
function report(firstAttribute, location) {
context.report({
node: firstAttribute,
messageId: location === 'beside' ? 'unexpected' : 'expected',
fix(fixer) {
const prevToken = sourceCode.getTokenBefore(firstAttribute, {
includeComments: true
});
return fixer.replaceTextRange([prevToken.range[1], firstAttribute.range[0]], location === 'beside' ? ' ' : '\n');
}
});
}
return {
SvelteStartTag(node) {
const firstAttribute = node.attributes[0];
if (!firstAttribute)
return;
const lastAttribute = node.attributes[node.attributes.length - 1];
const location = firstAttribute.loc.start.line === lastAttribute.loc.end.line ? singleline : multiline;
if (location === 'beside') {
if (node.parent.name.loc.end.line === firstAttribute.loc.start.line) {
return;
}
}
else {
if (node.parent.name.loc.end.line < firstAttribute.loc.start.line) {
return;
}
}
report(firstAttribute, location);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('html-closing-bracket-spacing', {
meta: {
docs: {
description: "require or disallow a space before tag's closing brackets",
category: 'Stylistic Issues',
conflictWithPrettier: true,
recommended: false
},
schema: [
{
type: 'object',
properties: {
startTag: {
enum: ['always', 'never', 'ignore']
},
endTag: {
enum: ['always', 'never', 'ignore']
},
selfClosingTag: {
enum: ['always', 'never', 'ignore']
}
},
additionalProperties: false
}
],
messages: {
expectedSpace: "Expected space before '>', but not found.",
unexpectedSpace: "Expected no space before '>', but found."
},
fixable: 'whitespace',
type: 'layout'
},
create(ctx) {
const options = {
startTag: 'never',
endTag: 'never',
selfClosingTag: 'always',
...ctx.options[0]
};
const src = ctx.getSourceCode();
function containsNewline(string) {
return string.includes('\n');
}
function report(node, shouldHave) {
const tagSrc = src.getText(node);
const match = /(\s*)\/?>$/.exec(tagSrc);
const end = node.range[1];
const start = node.range[1] - match[0].length;
const loc = {
start: src.getLocFromIndex(start),
end: src.getLocFromIndex(end)
};
ctx.report({
loc,
messageId: shouldHave ? 'expectedSpace' : 'unexpectedSpace',
*fix(fixer) {
if (shouldHave) {
yield fixer.insertTextBeforeRange([start, end], ' ');
}
else {
const spaces = match[1];
yield fixer.removeRange([start, start + spaces.length]);
}
}
});
}
return {
'SvelteStartTag, SvelteEndTag'(node) {
const tagType = node.type === 'SvelteEndTag'
? 'endTag'
: node.selfClosing
? 'selfClosingTag'
: 'startTag';
if (options[tagType] === 'ignore')
return;
const tagSrc = src.getText(node);
const match = /(\s*)\/?>$/.exec(tagSrc);
if (containsNewline(match[1]))
return;
if (options[tagType] === 'always' && !match[1]) {
report(node, true);
}
else if (options[tagType] === 'never' && match[1]) {
report(node, false);
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,158 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const ast_utils_2 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
const QUOTE_CHARS = {
double: '"',
single: "'"
};
const QUOTE_NAMES = {
double: 'double quotes',
single: 'single quotes',
unquoted: 'unquoted'
};
exports.default = (0, utils_1.createRule)('html-quotes', {
meta: {
docs: {
description: 'enforce quotes style of HTML attributes',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
prefer: { enum: ['double', 'single'] },
dynamic: {
type: 'object',
properties: {
quoted: { type: 'boolean' },
avoidInvalidUnquotedInHTML: { type: 'boolean' }
},
additionalProperties: false
}
},
additionalProperties: false
}
],
messages: {
expectedEnclosed: 'Expected to be enclosed by quotes.',
expectedEnclosedBy: 'Expected to be enclosed by {{kind}}.',
unexpectedEnclosed: 'Unexpected to be enclosed by any quotes.'
},
type: 'layout'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
const preferQuote = context.options[0]?.prefer ?? 'double';
const dynamicQuote = context.options[0]?.dynamic?.quoted ? preferQuote : 'unquoted';
const avoidInvalidUnquotedInHTML = Boolean(context.options[0]?.dynamic?.avoidInvalidUnquotedInHTML);
function canBeUnquotedInHTML(text) {
return !/[\s"'<=>`]/u.test(text);
}
function verifyQuote(prefer, quoteAndRange) {
if (!quoteAndRange) {
return;
}
if (quoteAndRange.quote === prefer) {
return;
}
let messageId;
let expectedQuote = prefer;
if (quoteAndRange.quote !== 'unquoted') {
if (expectedQuote === 'unquoted') {
messageId = 'unexpectedEnclosed';
}
else {
const contentText = sourceCode.text.slice(quoteAndRange.range[0] + 1, quoteAndRange.range[1] - 1);
const needEscape = contentText.includes(QUOTE_CHARS[expectedQuote]);
if (needEscape) {
return;
}
messageId = 'expectedEnclosedBy';
}
}
else {
const contentText = sourceCode.text.slice(...quoteAndRange.range);
const needEscapeDoubleQuote = contentText.includes('"');
const needEscapeSingleQuote = contentText.includes("'");
if (needEscapeDoubleQuote && needEscapeSingleQuote) {
return;
}
if (needEscapeDoubleQuote && expectedQuote === 'double') {
expectedQuote = 'single';
messageId = 'expectedEnclosed';
}
else if (needEscapeSingleQuote && expectedQuote === 'single') {
expectedQuote = 'double';
messageId = 'expectedEnclosed';
}
else {
messageId = 'expectedEnclosedBy';
}
}
context.report({
loc: {
start: sourceCode.getLocFromIndex(quoteAndRange.range[0]),
end: sourceCode.getLocFromIndex(quoteAndRange.range[1])
},
messageId,
data: { kind: QUOTE_NAMES[expectedQuote] },
*fix(fixer) {
if (expectedQuote !== 'unquoted') {
yield fixer.insertTextBeforeRange([quoteAndRange.range[0], quoteAndRange.range[0]], QUOTE_CHARS[expectedQuote]);
}
if (quoteAndRange.quote !== 'unquoted') {
yield fixer.removeRange([quoteAndRange.range[0], quoteAndRange.range[0] + 1]);
yield fixer.removeRange([quoteAndRange.range[1] - 1, quoteAndRange.range[1]]);
}
if (expectedQuote !== 'unquoted') {
yield fixer.insertTextAfterRange([quoteAndRange.range[1], quoteAndRange.range[1]], QUOTE_CHARS[expectedQuote]);
}
}
});
}
function verifyForValues(attr) {
const quoteAndRange = (0, ast_utils_2.getAttributeValueQuoteAndRange)(attr, sourceCode);
verifyQuote(preferQuote, quoteAndRange);
}
function verifyForDynamicMustacheTag(attr, valueNode) {
const quoteAndRange = (0, ast_utils_2.getAttributeValueQuoteAndRange)(attr, sourceCode);
const text = sourceCode.text.slice(...valueNode.range);
verifyQuote(avoidInvalidUnquotedInHTML && !canBeUnquotedInHTML(text) ? preferQuote : dynamicQuote, quoteAndRange);
}
function verifyForDirective(attr) {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(attr, sourceCode);
if (!mustacheTokens) {
return;
}
const quoteAndRange = (0, ast_utils_2.getAttributeValueQuoteAndRange)(attr, sourceCode);
const text = sourceCode.text.slice(mustacheTokens.openToken.range[0], mustacheTokens.closeToken.range[1]);
verifyQuote(avoidInvalidUnquotedInHTML && !canBeUnquotedInHTML(text) ? preferQuote : dynamicQuote, quoteAndRange);
}
return {
'SvelteAttribute, SvelteStyleDirective'(node) {
if (node.value.length === 1 && node.value[0].type === 'SvelteMustacheTag') {
verifyForDynamicMustacheTag(node, node.value[0]);
}
else if (node.value.length >= 1) {
verifyForValues(node);
}
},
'SvelteDirective, SvelteSpecialDirective'(node) {
if (node.expression == null) {
return;
}
if (node.key.range[0] <= node.expression.range[0] &&
node.expression.range[1] <= node.key.range[1]) {
return;
}
verifyForDirective(node);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,154 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
const TYPE_MESSAGES = {
normal: 'HTML elements',
void: 'HTML void elements',
component: 'Svelte custom components',
svelte: 'Svelte special elements'
};
exports.default = (0, utils_1.createRule)('html-self-closing', {
meta: {
docs: {
description: 'enforce self-closing style',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
type: 'layout',
fixable: 'code',
messages: {
requireClosing: 'Require self-closing on {{type}}.',
disallowClosing: 'Disallow self-closing on {{type}}.'
},
schema: [
{
anyOf: [
{
properties: {
void: {
enum: ['never', 'always', 'ignore']
},
normal: {
enum: ['never', 'always', 'ignore']
},
component: {
enum: ['never', 'always', 'ignore']
},
svelte: {
enum: ['never', 'always', 'ignore']
}
},
additionalProperties: false
},
{
enum: ['all', 'html', 'none']
}
]
}
]
},
create(context) {
let options = {
void: 'always',
normal: 'always',
component: 'always',
svelte: 'always'
};
const option = context.options?.[0];
switch (option) {
case 'none':
options = {
void: 'never',
normal: 'never',
component: 'never',
svelte: 'never'
};
break;
case 'html':
options = {
void: 'always',
normal: 'never',
component: 'never',
svelte: 'always'
};
break;
default:
if (typeof option !== 'object' || option === null)
break;
options = {
...options,
...option
};
break;
}
function getElementType(node) {
if (node.kind === 'component')
return 'component';
if (node.kind === 'special')
return 'svelte';
if ((0, ast_utils_1.isVoidHtmlElement)(node))
return 'void';
return 'normal';
}
function isElementEmpty(node) {
if (node.children.length <= 0)
return true;
for (const child of node.children) {
if (child.type !== 'SvelteText')
return false;
if (!/^\s*$/.test(child.value))
return false;
}
return true;
}
function report(node, shouldBeClosed) {
const elementType = getElementType(node);
context.report({
node,
loc: {
start: (0, compat_1.getSourceCode)(context).getLocFromIndex(node.startTag.range[1] - (node.startTag.selfClosing ? 2 : 1)),
end: node.loc.end
},
messageId: shouldBeClosed ? 'requireClosing' : 'disallowClosing',
data: {
type: TYPE_MESSAGES[elementType]
},
*fix(fixer) {
if (shouldBeClosed) {
for (const child of node.children) {
yield fixer.removeRange(child.range);
}
yield fixer.insertTextBeforeRange([node.startTag.range[1] - 1, node.startTag.range[1]], '/');
if (node.endTag)
yield fixer.removeRange(node.endTag.range);
}
else {
yield fixer.removeRange([node.startTag.range[1] - 2, node.startTag.range[1] - 1]);
if (!(0, ast_utils_1.isVoidHtmlElement)(node))
yield fixer.insertTextAfter(node, `</${(0, ast_utils_1.getNodeName)(node)}>`);
}
}
});
}
return {
SvelteElement(node) {
if (!isElementEmpty(node))
return;
const elementType = getElementType(node);
const elementTypeOptions = options[elementType];
if (elementTypeOptions === 'ignore')
return;
const shouldBeClosed = elementTypeOptions === 'always';
if (shouldBeClosed && !node.startTag.selfClosing) {
report(node, true);
}
else if (!shouldBeClosed && node.startTag.selfClosing) {
report(node, false);
}
}
};
}
});

View File

@ -0,0 +1,6 @@
import type { AST } from 'svelte-eslint-parser';
import type { TSESTree } from '@typescript-eslint/types';
type AnyToken = AST.Token | AST.Comment;
export declare function isWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
export declare function isNotWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
export {};

View File

@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNotWhitespace = exports.isWhitespace = void 0;
function isWhitespace(token) {
return (token != null &&
((token.type === 'HTMLText' && !token.value.trim()) ||
(token.type === 'JSXText' && !token.value.trim())));
}
exports.isWhitespace = isWhitespace;
function isNotWhitespace(token) {
return (token != null &&
(token.type !== 'HTMLText' || Boolean(token.value.trim())) &&
(token.type !== 'JSXText' || Boolean(token.value.trim())));
}
exports.isNotWhitespace = isNotWhitespace;

View File

@ -0,0 +1,28 @@
import type { ASTNode, SourceCode } from '../../types';
import type { AST } from 'svelte-eslint-parser';
import type { OffsetContext } from './offset-context';
export type AnyToken = AST.Token | AST.Comment;
export type MaybeNode = {
type: string;
range: [number, number];
loc: AST.SourceLocation;
};
export type IndentOptions = {
indentChar: ' ' | '\t';
indentScript: boolean;
indentSize: number;
switchCase: number;
alignAttributesVertically: boolean;
ignoredNodes: string[];
};
export type IndentContext = {
sourceCode: SourceCode;
options: IndentOptions;
offsets: OffsetContext;
};
export declare function getFirstAndLastTokens(sourceCode: SourceCode, node: ASTNode | AnyToken | MaybeNode, borderOffset?: number): {
firstToken: AST.Token;
lastToken: AST.Token;
};
export declare function isBeginningOfLine(sourceCode: SourceCode, node: ASTNode | AnyToken | MaybeNode): boolean;
export declare function isBeginningOfElement(node: AST.SvelteText): boolean;

View File

@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isBeginningOfElement = exports.isBeginningOfLine = exports.getFirstAndLastTokens = void 0;
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const ast_1 = require("./ast");
function getFirstAndLastTokens(sourceCode, node, borderOffset = 0) {
let firstToken = sourceCode.getFirstToken(node);
let lastToken = sourceCode.getLastToken(node);
let left, right;
while ((left = sourceCode.getTokenBefore(firstToken)) != null &&
(right = sourceCode.getTokenAfter(lastToken)) != null &&
(0, eslint_utils_1.isOpeningParenToken)(left) &&
(0, eslint_utils_1.isClosingParenToken)(right) &&
borderOffset <= left.range[0]) {
firstToken = left;
lastToken = right;
}
while ((0, ast_1.isWhitespace)(firstToken) && firstToken.range[0] < lastToken.range[0]) {
firstToken = sourceCode.getTokenAfter(firstToken);
}
while ((0, ast_1.isWhitespace)(lastToken) && firstToken.range[0] < lastToken.range[0]) {
lastToken = sourceCode.getTokenBefore(lastToken);
}
return { firstToken, lastToken };
}
exports.getFirstAndLastTokens = getFirstAndLastTokens;
function isBeginningOfLine(sourceCode, node) {
const prevToken = sourceCode.getTokenBefore(node, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
return !prevToken || prevToken.loc.end.line < node.loc.start.line;
}
exports.isBeginningOfLine = isBeginningOfLine;
function isBeginningOfElement(node) {
if (node.parent.type === 'SvelteElement' ||
node.parent.type === 'SvelteAwaitCatchBlock' ||
node.parent.type === 'SvelteAwaitPendingBlock' ||
node.parent.type === 'SvelteAwaitThenBlock' ||
node.parent.type === 'SvelteEachBlock' ||
node.parent.type === 'SvelteElseBlock' ||
node.parent.type === 'SvelteIfBlock' ||
node.parent.type === 'SvelteKeyBlock' ||
node.parent.type === 'SvelteStyleElement') {
return node.parent.children[0] === node;
}
if (node.parent.type === 'Program') {
return node.parent.body[0] === node;
}
return assertNever(node.parent);
}
exports.isBeginningOfElement = isBeginningOfElement;
function assertNever(value) {
throw new Error(`This part of the code should never be reached but ${value} made it through.`);
}

View File

@ -0,0 +1,5 @@
import type { IndentContext } from './commons';
import type { ESNodeListener } from '../../types-for-node';
type NodeListener = ESNodeListener;
export declare function defineVisitor(context: IndentContext): NodeListener;
export {};

View File

@ -0,0 +1,731 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const commons_1 = require("./commons");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const ast_utils_1 = require("../../utils/ast-utils");
function defineVisitor(context) {
const { sourceCode, offsets, options } = context;
function getRootLeft(node) {
let target = node;
let parent = (0, ast_utils_1.getParent)(target);
while (parent &&
(parent.type === 'AssignmentExpression' ||
parent.type === 'AssignmentPattern' ||
parent.type === 'BinaryExpression' ||
parent.type === 'LogicalExpression')) {
const prevToken = sourceCode.getTokenBefore(target);
if (prevToken && (0, eslint_utils_1.isOpeningParenToken)(prevToken)) {
break;
}
target = parent;
parent = (0, ast_utils_1.getParent)(target);
}
return target.left;
}
const visitor = {
Program(node) {
for (const body of node.body) {
if (body.type === 'SvelteText' && !body.value.trim()) {
continue;
}
offsets.setStartOffsetToken(sourceCode.getFirstToken(body), 0);
}
},
ArrayExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getTokenAfter(node.elements[node.elements.length - 1] || firstToken, { filter: eslint_utils_1.isClosingBracketToken, includeComments: false });
offsets.setOffsetElementList(node.elements, firstToken, rightToken, 1);
},
ArrayPattern(node) {
visitor.ArrayExpression(node);
},
ArrowFunctionExpression(node) {
const [firstToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
const leftToken = node.async ? secondToken : firstToken;
const arrowToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isArrowToken,
includeComments: false
});
if (node.async) {
offsets.setOffsetToken(secondToken, 1, firstToken);
}
if ((0, eslint_utils_1.isOpeningParenToken)(leftToken)) {
const rightToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftToken, rightToken, 1);
}
offsets.setOffsetToken(arrowToken, 1, firstToken);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, firstToken);
},
AssignmentExpression(node) {
const leftNode = getRootLeft(node);
const opToken = sourceCode.getTokenAfter(node.left, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const rightToken = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.right).firstToken;
offsets.setOffsetToken([opToken, rightToken], 1, (0, commons_1.getFirstAndLastTokens)(sourceCode, leftNode).firstToken);
},
AssignmentPattern(node) {
visitor.AssignmentExpression(node);
},
BinaryExpression(node) {
visitor.AssignmentExpression(node);
},
LogicalExpression(node) {
visitor.AssignmentExpression(node);
},
AwaitExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
RestElement(node) {
visitor.AwaitExpression(node);
},
SpreadElement(node) {
visitor.AwaitExpression(node);
},
UnaryExpression(node) {
visitor.AwaitExpression(node);
},
BlockStatement(node) {
offsets.setOffsetElementList(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
ClassBody(node) {
visitor.BlockStatement(node);
},
BreakStatement(node) {
if (node.label) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
}
},
ContinueStatement(node) {
visitor.BreakStatement(node);
},
CallExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(node.typeParameters || node.callee, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
const rightParenToken = sourceCode.getLastToken(node);
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
}
for (const optionalToken of sourceCode.getTokensBetween(sourceCode.getLastToken(node.typeParameters || node.callee), leftParenToken, { filter: isOptionalToken, includeComments: false })) {
offsets.setOffsetToken(optionalToken, 1, firstToken);
}
offsets.setOffsetToken(leftParenToken, 1, firstToken);
offsets.setOffsetElementList(node.arguments, leftParenToken, rightParenToken, 1);
},
CatchClause(node) {
const catchToken = sourceCode.getFirstToken(node);
if (node.param != null) {
const leftParenToken = sourceCode.getTokenBefore(node.param);
const rightParenToken = sourceCode.getTokenAfter(node.param);
offsets.setOffsetToken(leftParenToken, 1, catchToken);
offsets.setOffsetElementList([node.param], leftParenToken, rightParenToken, 1);
}
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, catchToken);
},
ClassDeclaration(node) {
const classToken = sourceCode.getFirstToken(node);
if (node.id != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.id), 1, classToken);
}
if (node.superClass != null) {
const extendsToken = sourceCode.getTokenBefore(node.superClass);
const superClassToken = sourceCode.getTokenAfter(extendsToken);
offsets.setOffsetToken(extendsToken, 1, classToken);
offsets.setOffsetToken(superClassToken, 1, extendsToken);
}
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, classToken);
},
ClassExpression(node) {
visitor.ClassDeclaration(node);
},
ConditionalExpression(node) {
const questionToken = sourceCode.getTokenAfter(node.test, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const consequentToken = sourceCode.getTokenAfter(questionToken);
const colonToken = sourceCode.getTokenAfter(node.consequent, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const alternateToken = sourceCode.getTokenAfter(colonToken);
let baseNode = node;
let parent = (0, ast_utils_1.getParent)(baseNode);
while (parent && parent.type === 'ConditionalExpression' && parent.alternate === baseNode) {
baseNode = parent;
parent = (0, ast_utils_1.getParent)(baseNode);
}
const baseToken = sourceCode.getFirstToken(baseNode);
offsets.setOffsetToken([questionToken, colonToken], 1, baseToken);
offsets.setOffsetToken(consequentToken, 1, questionToken);
offsets.setOffsetToken(alternateToken, 1, colonToken);
},
DoWhileStatement(node) {
const doToken = sourceCode.getFirstToken(node);
const whileToken = sourceCode.getTokenAfter(node.body, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const leftParenToken = sourceCode.getTokenAfter(whileToken);
const rightParenToken = sourceCode.getTokenAfter(node.test);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, doToken);
offsets.setOffsetToken(whileToken, 0, doToken);
offsets.setOffsetToken(leftParenToken, 1, whileToken);
offsets.setOffsetElementList([node.test], leftParenToken, rightParenToken, 1);
},
ExportAllDeclaration(node) {
const exportToken = sourceCode.getFirstToken(node);
const tokens = sourceCode.getTokensBetween(exportToken, node.source);
const fromIndex = tokens.findIndex((t) => t.value === 'from');
const fromToken = tokens[fromIndex];
const beforeTokens = tokens.slice(0, fromIndex);
const afterTokens = [...tokens.slice(fromIndex + 1), sourceCode.getFirstToken(node.source)];
if (!node.exported) {
offsets.setOffsetToken(beforeTokens, 1, exportToken);
}
else {
const asIndex = beforeTokens.findIndex((t) => t.value === 'as');
offsets.setOffsetToken(beforeTokens.slice(0, asIndex), 1, exportToken);
offsets.setOffsetToken(beforeTokens.slice(asIndex), 1, beforeTokens[asIndex - 1]);
}
offsets.setOffsetToken(fromToken, 0, exportToken);
offsets.setOffsetToken(afterTokens, 1, fromToken);
const lastToken = sourceCode.getLastToken(node, {
filter: eslint_utils_1.isNotSemicolonToken,
includeComments: false
});
const assertionTokens = sourceCode.getTokensBetween(node.source, lastToken);
if (assertionTokens.length) {
const assertToken = assertionTokens.shift();
offsets.setOffsetToken(assertToken, 0, exportToken);
const assertionOpen = assertionTokens.shift();
if (assertionOpen) {
offsets.setOffsetToken(assertionOpen, 1, assertToken);
offsets.setOffsetElementList(assertionTokens, assertionOpen, lastToken, 1);
}
}
},
ExportDefaultDeclaration(node) {
const exportToken = sourceCode.getFirstToken(node);
const declarationToken = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.declaration).firstToken;
const defaultTokens = sourceCode.getTokensBetween(exportToken, declarationToken);
offsets.setOffsetToken([...defaultTokens, declarationToken], 1, exportToken);
},
ExportNamedDeclaration(node) {
const exportToken = sourceCode.getFirstToken(node);
if (node.declaration) {
const declarationToken = sourceCode.getFirstToken(node.declaration);
offsets.setOffsetToken(declarationToken, 1, exportToken);
}
else {
const firstSpecifier = node.specifiers[0];
if (!firstSpecifier || firstSpecifier.type === 'ExportSpecifier') {
const leftBraceTokens = firstSpecifier
? sourceCode.getTokensBetween(exportToken, firstSpecifier)
: [sourceCode.getTokenAfter(exportToken)];
const rightBraceToken = node.source
? sourceCode.getTokenBefore(node.source, {
filter: eslint_utils_1.isClosingBraceToken,
includeComments: false
})
: sourceCode.getLastToken(node, {
filter: eslint_utils_1.isClosingBraceToken,
includeComments: false
});
offsets.setOffsetToken(leftBraceTokens, 0, exportToken);
offsets.setOffsetElementList(node.specifiers, leftBraceTokens[leftBraceTokens.length - 1], rightBraceToken, 1);
if (node.source) {
const [fromToken, ...tokens] = sourceCode.getTokensBetween(rightBraceToken, node.source);
offsets.setOffsetToken(fromToken, 0, exportToken);
offsets.setOffsetToken([...tokens, sourceCode.getFirstToken(node.source)], 1, fromToken);
const lastToken = sourceCode.getLastToken(node, {
filter: eslint_utils_1.isNotSemicolonToken,
includeComments: false
});
const assertionTokens = sourceCode.getTokensBetween(node.source, lastToken);
if (assertionTokens.length) {
const assertToken = assertionTokens.shift();
offsets.setOffsetToken(assertToken, 0, exportToken);
const assertionOpen = assertionTokens.shift();
if (assertionOpen) {
offsets.setOffsetToken(assertionOpen, 1, assertToken);
offsets.setOffsetElementList(assertionTokens, assertionOpen, lastToken, 1);
}
}
}
}
else {
}
}
},
ExportSpecifier(node) {
const tokens = sourceCode.getTokens(node);
let firstToken = tokens.shift();
if (firstToken.value === 'type') {
const typeToken = firstToken;
firstToken = tokens.shift();
offsets.setOffsetToken(firstToken, 0, typeToken);
}
offsets.setOffsetToken(tokens, 1, firstToken);
},
ForInStatement(node) {
const forToken = sourceCode.getFirstToken(node);
const awaitToken = (node.type === 'ForOfStatement' && node.await && sourceCode.getTokenAfter(forToken)) ||
null;
const leftParenToken = sourceCode.getTokenAfter(awaitToken || forToken);
const leftToken = sourceCode.getFirstToken(node.left);
const inOrOfToken = sourceCode.getTokenAfter(node.left, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const rightToken = sourceCode.getTokenAfter(inOrOfToken);
const rightParenToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isNotOpeningParenToken,
includeComments: false
});
if (awaitToken != null) {
offsets.setOffsetToken(awaitToken, 0, forToken);
}
offsets.setOffsetToken(leftParenToken, 1, forToken);
offsets.setOffsetToken(leftToken, 1, leftParenToken);
offsets.setOffsetToken([inOrOfToken, rightToken], 1, leftToken);
offsets.setOffsetToken(rightParenToken, 0, leftParenToken);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, forToken);
},
ForOfStatement(node) {
visitor.ForInStatement(node);
},
ForStatement(node) {
const forToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(forToken);
const rightParenToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isNotOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken(leftParenToken, 1, forToken);
offsets.setOffsetElementList([node.init, node.test, node.update], leftParenToken, rightParenToken, 1);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, forToken);
},
FunctionDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenBefore(node.params[0] ||
node.returnType ||
sourceCode.getTokenBefore(node.body), {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
let bodyBaseToken = null;
if (firstToken.type === 'Punctuator') {
bodyBaseToken = sourceCode.getFirstToken((0, ast_utils_1.getParent)(node));
}
else {
let tokenOffset = 0;
for (const token of sourceCode.getTokensBetween(firstToken, leftParenToken)) {
if (token.value === '<') {
break;
}
if (token.value === '*' || (node.id && token.range[0] === node.id.range[0])) {
tokenOffset = 1;
}
offsets.setOffsetToken(token, tokenOffset, firstToken);
}
bodyBaseToken = firstToken;
}
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetToken(leftParenToken, 1, bodyBaseToken);
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, bodyBaseToken);
},
FunctionExpression(node) {
visitor.FunctionDeclaration(node);
},
IfStatement(node) {
const [ifToken, ifLeftParenToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
const ifRightParenToken = sourceCode.getTokenBefore(node.consequent, {
filter: eslint_utils_1.isClosingParenToken,
includeComments: false
});
offsets.setOffsetToken(ifLeftParenToken, 1, ifToken);
offsets.setOffsetToken(ifRightParenToken, 0, ifLeftParenToken);
const consequentFirstToken = sourceCode.getFirstToken(node.consequent);
offsets.setOffsetToken(consequentFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(consequentFirstToken) ? 0 : 1, ifToken);
if (node.alternate != null) {
const elseToken = sourceCode.getTokenAfter(node.consequent, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
offsets.setOffsetToken(elseToken, 0, ifToken);
const alternateFirstToken = sourceCode.getFirstToken(node.alternate);
offsets.setOffsetToken(alternateFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(alternateFirstToken) ? 0 : 1, elseToken);
}
},
ImportDeclaration(node) {
const importToken = sourceCode.getFirstToken(node);
const tokens = sourceCode.getTokensBetween(importToken, node.source);
const fromIndex = tokens.map((t) => t.value).lastIndexOf('from');
const { fromToken, beforeTokens, afterTokens } = fromIndex >= 0
? {
fromToken: tokens[fromIndex],
beforeTokens: tokens.slice(0, fromIndex),
afterTokens: [...tokens.slice(fromIndex + 1), sourceCode.getFirstToken(node.source)]
}
: {
fromToken: null,
beforeTokens: [...tokens, sourceCode.getFirstToken(node.source)],
afterTokens: []
};
const namedSpecifiers = [];
for (const specifier of node.specifiers) {
if (specifier.type === 'ImportSpecifier') {
namedSpecifiers.push(specifier);
}
else {
const removeTokens = sourceCode.getTokens(specifier);
removeTokens.shift();
for (const token of removeTokens) {
const i = beforeTokens.indexOf(token);
if (i >= 0) {
beforeTokens.splice(i, 1);
}
}
}
}
if (namedSpecifiers.length) {
const leftBrace = sourceCode.getTokenBefore(namedSpecifiers[0]);
const rightBrace = sourceCode.getTokenAfter(namedSpecifiers[namedSpecifiers.length - 1], {
filter: eslint_utils_1.isClosingBraceToken,
includeComments: false
});
offsets.setOffsetElementList(namedSpecifiers, leftBrace, rightBrace, 1);
for (const token of [...sourceCode.getTokensBetween(leftBrace, rightBrace), rightBrace]) {
const i = beforeTokens.indexOf(token);
if (i >= 0) {
beforeTokens.splice(i, 1);
}
}
}
if (beforeTokens.every((t) => (0, eslint_utils_1.isOpeningBraceToken)(t) || (0, eslint_utils_1.isClosingBraceToken)(t))) {
offsets.setOffsetToken(beforeTokens, 0, importToken);
}
else {
offsets.setOffsetToken(beforeTokens, 1, importToken);
}
if (fromToken) {
offsets.setOffsetToken(fromToken, 0, importToken);
offsets.setOffsetToken(afterTokens, 1, fromToken);
}
const lastToken = sourceCode.getLastToken(node, {
filter: eslint_utils_1.isNotSemicolonToken,
includeComments: false
});
const assertionTokens = sourceCode.getTokensBetween(node.source, lastToken);
if (assertionTokens.length) {
const assertToken = assertionTokens.shift();
offsets.setOffsetToken(assertToken, 0, importToken);
const assertionOpen = assertionTokens.shift();
if (assertionOpen) {
offsets.setOffsetToken(assertionOpen, 1, assertToken);
offsets.setOffsetElementList(assertionTokens, assertionOpen, lastToken, 1);
}
}
},
ImportExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getLastToken(node);
const leftToken = sourceCode.getTokenAfter(firstToken, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken(leftToken, 1, firstToken);
offsets.setOffsetElementList([node.source], leftToken, rightToken, 1);
},
ImportNamespaceSpecifier(node) {
const tokens = sourceCode.getTokens(node);
const firstToken = tokens.shift();
offsets.setOffsetToken(tokens, 1, firstToken);
},
ImportSpecifier(node) {
visitor.ExportSpecifier(node);
},
LabeledStatement(node) {
const labelToken = sourceCode.getFirstToken(node);
const colonToken = sourceCode.getTokenAfter(labelToken);
const bodyToken = sourceCode.getTokenAfter(colonToken);
offsets.setOffsetToken([colonToken, bodyToken], 1, labelToken);
},
SvelteReactiveStatement(node) {
visitor.LabeledStatement(node);
},
MemberExpression(node) {
const objectToken = sourceCode.getFirstToken(node);
if (node.type === 'MemberExpression' && node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(node.property, {
filter: eslint_utils_1.isOpeningBracketToken,
includeComments: false
});
const rightBracketToken = sourceCode.getTokenAfter(node.property, {
filter: eslint_utils_1.isClosingBracketToken,
includeComments: false
});
for (const optionalToken of sourceCode.getTokensBetween(sourceCode.getLastToken(node.object), leftBracketToken, { filter: isOptionalToken, includeComments: false })) {
offsets.setOffsetToken(optionalToken, 1, objectToken);
}
offsets.setOffsetToken(leftBracketToken, 1, objectToken);
offsets.setOffsetElementList([node.property], leftBracketToken, rightBracketToken, 1);
}
else {
const dotToken = sourceCode.getTokenBefore(node.property);
const propertyToken = sourceCode.getTokenAfter(dotToken);
offsets.setOffsetToken([dotToken, propertyToken], 1, objectToken);
}
},
MetaProperty(node) {
visitor.MemberExpression(node);
},
MethodDefinition(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.key);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
if (node.computed) {
prefixTokens.pop();
}
offsets.setOffsetToken(prefixTokens, 0, firstToken);
let lastKeyToken;
if (node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
offsets.setOffsetElementList([node.key], leftBracketToken, rightBracketToken, 1);
}
else {
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
lastKeyToken = keyTokens.lastToken;
}
if (node.value) {
const initToken = sourceCode.getFirstToken(node.value);
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
}
},
Property(node) {
visitor.MethodDefinition(node);
},
NewExpression(node) {
const newToken = sourceCode.getFirstToken(node);
const calleeTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.callee);
offsets.setOffsetToken(calleeTokens.firstToken, 1, newToken);
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, calleeTokens.firstToken);
}
const leftParenBefore = node.typeParameters || calleeTokens.lastToken;
if (node.arguments.length || leftParenBefore.range[1] < node.range[1]) {
const rightParenToken = sourceCode.getLastToken(node);
const leftParenToken = sourceCode.getTokenAfter(leftParenBefore);
offsets.setOffsetToken(leftParenToken, 1, calleeTokens.firstToken);
offsets.setOffsetElementList(node.arguments, leftParenToken, rightParenToken, 1);
}
},
ObjectExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getTokenAfter(node.properties[node.properties.length - 1] || firstToken, { filter: eslint_utils_1.isClosingBraceToken, includeComments: false });
offsets.setOffsetElementList(node.properties, firstToken, rightToken, 1);
},
ObjectPattern(node) {
visitor.ObjectExpression(node);
},
PropertyDefinition(node) {
visitor.MethodDefinition(node);
},
ReturnStatement(node) {
if (node.argument) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
}
},
ThrowStatement(node) {
visitor.ReturnStatement(node);
},
SequenceExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
offsets.setOffsetElementList(node.expressions, firstToken, null, 0);
},
SwitchCase(node) {
const caseToken = sourceCode.getFirstToken(node);
if (node.test != null) {
const testTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.test);
const colonToken = sourceCode.getTokenAfter(testTokens.lastToken);
offsets.setOffsetToken([testTokens.firstToken, colonToken], 1, caseToken);
}
else {
const colonToken = sourceCode.getTokenAfter(caseToken);
offsets.setOffsetToken(colonToken, 1, caseToken);
}
if (node.consequent.length === 1 && node.consequent[0].type === 'BlockStatement') {
offsets.setOffsetToken(sourceCode.getFirstToken(node.consequent[0]), 0, caseToken);
}
else {
for (const statement of node.consequent) {
offsets.setOffsetToken((0, commons_1.getFirstAndLastTokens)(sourceCode, statement).firstToken, 1, caseToken);
}
}
},
SwitchStatement(node) {
const switchToken = sourceCode.getFirstToken(node);
const { firstToken: leftParenToken, lastToken: rightParenToken } = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.discriminant);
const leftBraceToken = sourceCode.getTokenAfter(rightParenToken);
const rightBraceToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(leftParenToken, 1, switchToken);
offsets.setOffsetElementList([node.discriminant], leftParenToken, rightParenToken, 1);
offsets.setOffsetToken(leftBraceToken, 0, switchToken);
offsets.setOffsetElementList(node.cases, leftBraceToken, rightBraceToken, options.switchCase);
},
TaggedTemplateExpression(node) {
const tagTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.tag);
offsets.setOffsetToken(sourceCode.getFirstToken(node.quasi), 1, tagTokens.firstToken);
},
TemplateLiteral(node) {
const firstToken = sourceCode.getFirstToken(node);
const quasiTokens = node.quasis.slice(1).map((n) => sourceCode.getFirstToken(n));
const expressionToken = node.quasis.slice(0, -1).map((n) => sourceCode.getTokenAfter(n));
offsets.setOffsetToken(quasiTokens, 0, firstToken);
offsets.setOffsetToken(expressionToken, 1, firstToken);
},
TryStatement(node) {
const tryToken = sourceCode.getFirstToken(node);
const tryBlockToken = sourceCode.getFirstToken(node.block);
offsets.setOffsetToken(tryBlockToken, 0, tryToken);
if (node.handler != null) {
const catchToken = sourceCode.getFirstToken(node.handler);
offsets.setOffsetToken(catchToken, 0, tryToken);
}
if (node.finalizer != null) {
const finallyToken = sourceCode.getTokenBefore(node.finalizer);
const finallyBlockToken = sourceCode.getFirstToken(node.finalizer);
offsets.setOffsetToken([finallyToken, finallyBlockToken], 0, tryToken);
}
},
UpdateExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
VariableDeclaration(node) {
offsets.setOffsetElementList(node.declarations, sourceCode.getFirstToken(node), null, 1);
},
VariableDeclarator(node) {
if (node.init != null) {
const idToken = sourceCode.getFirstToken(node);
const eqToken = sourceCode.getTokenAfter(node.id);
const initToken = sourceCode.getTokenAfter(eqToken);
offsets.setOffsetToken([eqToken, initToken], 1, idToken);
}
},
WhileStatement(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(firstToken);
const rightParenToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isClosingParenToken,
includeComments: false
});
offsets.setOffsetToken(leftParenToken, 1, firstToken);
offsets.setOffsetToken(rightParenToken, 0, leftParenToken);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, firstToken);
},
WithStatement(node) {
visitor.WhileStatement(node);
},
YieldExpression(node) {
if (node.argument != null) {
const [yieldToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(secondToken, 1, yieldToken);
if (node.delegate) {
offsets.setOffsetToken(sourceCode.getTokenAfter(secondToken), 1, yieldToken);
}
}
},
DebuggerStatement() {
},
Identifier() {
},
ImportDefaultSpecifier() {
},
Literal() {
},
PrivateIdentifier() {
},
Super() {
},
TemplateElement() {
},
ThisExpression() {
},
ExpressionStatement() {
},
ChainExpression() {
},
EmptyStatement() {
}
};
const commonVisitor = {
':statement, PropertyDefinition'(node) {
const firstToken = sourceCode.getFirstToken(node);
const lastToken = sourceCode.getLastToken(node);
if ((0, eslint_utils_1.isSemicolonToken)(lastToken) && firstToken !== lastToken) {
const next = sourceCode.getTokenAfter(lastToken);
if (!next || lastToken.loc.start.line < next.loc.start.line) {
offsets.setOffsetToken(lastToken, 0, firstToken);
}
}
},
':expression'(node) {
let leftToken = sourceCode.getTokenBefore(node);
let rightToken = sourceCode.getTokenAfter(node);
let firstToken = sourceCode.getFirstToken(node);
while (leftToken &&
(0, eslint_utils_1.isOpeningParenToken)(leftToken) &&
rightToken &&
(0, eslint_utils_1.isClosingParenToken)(rightToken)) {
offsets.setOffsetToken(firstToken, 1, leftToken);
offsets.setOffsetToken(rightToken, 0, leftToken);
firstToken = leftToken;
leftToken = sourceCode.getTokenBefore(leftToken);
rightToken = sourceCode.getTokenAfter(rightToken);
}
}
};
const v = visitor;
return {
...v,
...commonVisitor
};
}
exports.defineVisitor = defineVisitor;
function isOptionalToken(token) {
return token.type === 'Punctuator' && token.value === '?.';
}

View File

@ -0,0 +1,3 @@
import type { RuleContext, RuleListener } from '../../types';
import type { IndentOptions } from './commons';
export declare function defineVisitor(context: RuleContext, defaultOptions: Partial<IndentOptions>): RuleListener;

View File

@ -0,0 +1,235 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const SV = __importStar(require("./svelte"));
const ES = __importStar(require("./es"));
const TS = __importStar(require("./ts"));
const ast_1 = require("./ast");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const offset_context_1 = require("./offset-context");
const compat_1 = require("../../utils/compat");
function parseOptions(options, defaultOptions) {
const ret = {
indentChar: ' ',
indentScript: true,
indentSize: 2,
switchCase: 1,
alignAttributesVertically: false,
ignoredNodes: [],
...defaultOptions
};
if (Number.isSafeInteger(options.indent)) {
ret.indentSize = Number(options.indent);
}
else if (options.indent === 'tab') {
ret.indentChar = '\t';
ret.indentSize = 1;
}
if (typeof options.indentScript === 'boolean') {
ret.indentScript = options.indentScript;
}
if (options.switchCase != null && Number.isSafeInteger(options.switchCase)) {
ret.switchCase = options.switchCase;
}
if (options.ignoredNodes != null) {
ret.ignoredNodes = options.ignoredNodes;
}
if (options.alignAttributesVertically && ret.indentChar === ' ') {
ret.alignAttributesVertically = true;
}
else if (ret.indentChar !== ' ') {
ret.alignAttributesVertically = false;
}
return ret;
}
function defineVisitor(context, defaultOptions) {
if (!(0, compat_1.getFilename)(context).endsWith('.svelte'))
return {};
const options = parseOptions(context.options[0] || {}, defaultOptions);
const sourceCode = (0, compat_1.getSourceCode)(context);
const offsets = new offset_context_1.OffsetContext({ sourceCode, options });
function getIndentText({ line, column }) {
return sourceCode.lines[line - 1].slice(0, column);
}
function validateToken(token, expectedIndent) {
const line = token.loc.start.line;
const indentText = getIndentText(token.loc.start);
if (indentText.trim() !== '') {
return;
}
const actualIndent = token.loc.start.column;
const mismatchCharIndexes = [];
for (let i = 0; i < indentText.length; ++i) {
if (indentText[i] !== options.indentChar) {
mismatchCharIndexes.push(i);
}
}
if (actualIndent !== expectedIndent) {
const loc = {
start: { line, column: 0 },
end: { line, column: actualIndent }
};
context.report({
loc,
messageId: 'unexpectedIndentation',
data: {
expectedIndent: String(expectedIndent),
actualIndent: String(actualIndent),
expectedUnit: options.indentChar === '\t' ? 'tab' : 'space',
actualUnit: mismatchCharIndexes.length
? 'whitespace'
: options.indentChar === '\t'
? 'tab'
: 'space',
expectedIndentPlural: expectedIndent === 1 ? '' : 's',
actualIndentPlural: actualIndent === 1 ? '' : 's'
},
fix(fixer) {
return fixer.replaceTextRange([sourceCode.getIndexFromLoc(loc.start), sourceCode.getIndexFromLoc(loc.end)], options.indentChar.repeat(expectedIndent));
}
});
return;
}
for (const i of mismatchCharIndexes) {
const loc = {
start: { line, column: i },
end: { line, column: i + 1 }
};
context.report({
loc,
messageId: 'unexpectedChar',
data: {
expected: JSON.stringify(options.indentChar),
actual: JSON.stringify(indentText[i])
},
fix(fixer) {
return fixer.replaceTextRange([sourceCode.getIndexFromLoc(loc.start), sourceCode.getIndexFromLoc(loc.end)], options.indentChar);
}
});
}
}
function processLine(tokens, prevComments, prevToken, calculator) {
const firstToken = tokens[0];
const actualIndent = firstToken.loc.start.column;
const expectedIndent = calculator.getExpectedIndentFromTokens(tokens);
if (expectedIndent == null) {
calculator.saveExpectedIndent(tokens, actualIndent);
return;
}
calculator.saveExpectedIndent(tokens, Math.min(...tokens
.map((t) => calculator.getExpectedIndentFromToken(t))
.filter((i) => i != null)));
let prev = prevToken;
if (prevComments.length) {
if (prev && prev.loc.end.line < prevComments[0].loc.start.line) {
validateToken(prevComments[0], expectedIndent);
}
prev = prevComments[prevComments.length - 1];
}
if (prev && prev.loc.end.line < tokens[0].loc.start.line) {
validateToken(tokens[0], expectedIndent);
}
}
const indentContext = {
sourceCode,
options,
offsets
};
const nodesVisitor = {
...ES.defineVisitor(indentContext),
...SV.defineVisitor(indentContext),
...TS.defineVisitor(indentContext)
};
const knownNodes = new Set(Object.keys(nodesVisitor));
function compositingIgnoresVisitor(visitor) {
for (const ignoreSelector of options.ignoredNodes) {
const key = `${ignoreSelector}:exit`;
if (visitor[key]) {
const handler = visitor[key];
visitor[key] = function (node, ...args) {
const ret = handler.call(this, node, ...args);
offsets.ignore(node);
return ret;
};
}
else {
visitor[key] = (node) => offsets.ignore(node);
}
}
return visitor;
}
return compositingIgnoresVisitor({
...nodesVisitor,
'*:exit'(node) {
if (!knownNodes.has(node.type)) {
offsets.ignore(node);
}
},
'Program:exit'(node) {
const calculator = offsets.getOffsetCalculator();
let prevToken = null;
for (const { prevComments, tokens } of iterateLineTokens()) {
processLine(tokens, prevComments, prevToken, calculator);
prevToken = tokens[tokens.length - 1];
}
function* iterateLineTokens() {
let line = 0;
let prevComments = [];
let bufferTokens = [];
for (const token of sourceCode.getTokens(node, {
includeComments: true,
filter: ast_1.isNotWhitespace
})) {
const thisLine = token.loc.start.line;
if (line === thisLine || bufferTokens.length === 0) {
bufferTokens.push(token);
}
else {
if ((0, eslint_utils_1.isCommentToken)(bufferTokens[0]) && bufferTokens.every(eslint_utils_1.isCommentToken)) {
prevComments.push(bufferTokens[0]);
}
else {
yield {
prevComments,
tokens: bufferTokens
};
prevComments = [];
}
bufferTokens = [token];
}
line = thisLine;
}
if (bufferTokens.length && !bufferTokens.every(eslint_utils_1.isCommentToken)) {
yield {
prevComments,
tokens: bufferTokens
};
}
}
}
});
}
exports.defineVisitor = defineVisitor;

View File

@ -0,0 +1,57 @@
import type { ASTNode, SourceCode } from '../../types';
import type { AnyToken, IndentOptions, MaybeNode } from './commons';
declare const enum OffsetDataType {
normal = 0,
align = 1,
start = 2
}
type OffsetData = {
type: OffsetDataType.normal;
base: number;
offset: number;
expectedIndent?: number;
} | {
type: OffsetDataType.align;
base: number;
alignIndent: number;
expectedIndent?: number;
} | {
type: OffsetDataType.start;
offset: number;
expectedIndent?: number;
};
export declare class OffsetContext {
private readonly sourceCode;
private readonly options;
private readonly offsets;
private readonly ignoreRanges;
constructor(arg: {
sourceCode: SourceCode;
options: IndentOptions;
});
setOffsetIndex(index: number, offset: number, base: number): void;
private setAlignIndent;
setOffsetToken(token: AnyToken | null | undefined | (AnyToken | null | undefined)[], offset: number, baseToken: AnyToken): void;
copyOffset(index: number, srcIndex: number): void;
setStartOffsetIndex(index: number, offset: number): void;
setStartOffsetToken(token: AnyToken | null | undefined | (AnyToken | null | undefined)[], offset: number): void;
setOffsetElementList(nodes: (ASTNode | AnyToken | MaybeNode | null | undefined)[], baseNodeOrToken: ASTNode | AnyToken | MaybeNode, lastNodeOrToken: ASTNode | AnyToken | MaybeNode | null, offset: number, align?: boolean): void;
private _setOffsetElementList;
ignore(node: ASTNode): void;
getOffsetCalculator(): OffsetCalculator;
}
export declare class OffsetCalculator {
private readonly options;
private readonly offsets;
private readonly ignoreRanges;
constructor(arg: {
offsets: Map<number, OffsetData>;
options: IndentOptions;
ignoreRanges: [number, number][];
});
private getExpectedIndentFromIndex;
getExpectedIndentFromToken(token: AnyToken): number | null;
getExpectedIndentFromTokens(tokens: AnyToken[]): null | number;
saveExpectedIndent(tokens: AnyToken[], expectedIndent: number): void;
}
export {};

View File

@ -0,0 +1,193 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OffsetCalculator = exports.OffsetContext = void 0;
const ast_1 = require("./ast");
const commons_1 = require("./commons");
const commons_2 = require("./commons");
class OffsetContext {
constructor(arg) {
this.offsets = new Map();
this.ignoreRanges = new Map();
this.sourceCode = arg.sourceCode;
this.options = arg.options;
}
setOffsetIndex(index, offset, base) {
if (index === base) {
return;
}
this.offsets.set(index, {
type: 0,
base,
offset
});
}
setAlignIndent(index, alignIndent, base) {
if (index === base) {
return;
}
this.offsets.set(index, {
type: 1,
base,
alignIndent
});
}
setOffsetToken(token, offset, baseToken) {
if (!token) {
return;
}
if (Array.isArray(token)) {
for (const t of token) {
this.setOffsetToken(t, offset, baseToken);
}
return;
}
this.setOffsetIndex(token.range[0], offset, baseToken.range[0]);
}
copyOffset(index, srcIndex) {
const offsetData = this.offsets.get(srcIndex);
if (!offsetData) {
return;
}
if (offsetData.type === 2) {
this.setStartOffsetIndex(index, offsetData.offset);
}
else if (offsetData.type === 1) {
this.setAlignIndent(index, offsetData.alignIndent, offsetData.base);
}
else {
this.setOffsetIndex(index, offsetData.offset, offsetData.base);
}
}
setStartOffsetIndex(index, offset) {
this.offsets.set(index, {
type: 2,
offset
});
}
setStartOffsetToken(token, offset) {
if (!token) {
return;
}
if (Array.isArray(token)) {
for (const t of token) {
this.setStartOffsetToken(t, offset);
}
return;
}
this.setStartOffsetIndex(token.range[0], offset);
}
setOffsetElementList(nodes, baseNodeOrToken, lastNodeOrToken, offset, align) {
let setIndent = (token, baseToken) => this.setOffsetToken(token, offset, baseToken);
if (align) {
for (const n of nodes) {
if (n) {
if (!(0, commons_1.isBeginningOfLine)(this.sourceCode, n)) {
const startLoc = n.loc.start;
const alignIndent = startLoc.column - /^\s*/u.exec(this.sourceCode.lines[startLoc.line - 1])[0].length;
setIndent = (token, baseToken) => this.setAlignIndent(token.range[0], alignIndent, baseToken.range[0]);
}
break;
}
}
}
this._setOffsetElementList(nodes, baseNodeOrToken, lastNodeOrToken, setIndent);
}
_setOffsetElementList(nodes, baseNodeOrToken, lastNodeOrToken, setIndent) {
const baseToken = this.sourceCode.getFirstToken(baseNodeOrToken);
let prevToken = this.sourceCode.getLastToken(baseNodeOrToken);
for (const node of nodes) {
if (node == null) {
continue;
}
const elementTokens = (0, commons_2.getFirstAndLastTokens)(this.sourceCode, node, prevToken.range[1]);
let t = prevToken;
while ((t = this.sourceCode.getTokenAfter(t, {
includeComments: true,
filter: ast_1.isNotWhitespace
})) != null &&
t.range[1] <= elementTokens.firstToken.range[0]) {
setIndent(t, baseToken);
}
setIndent(elementTokens.firstToken, baseToken);
prevToken = elementTokens.lastToken;
}
if (lastNodeOrToken) {
const lastToken = this.sourceCode.getFirstToken(lastNodeOrToken);
let t = prevToken;
while ((t = this.sourceCode.getTokenAfter(t, {
includeComments: true,
filter: ast_1.isNotWhitespace
})) != null &&
t.range[1] <= lastToken.range[0]) {
setIndent(t, baseToken);
}
this.setOffsetToken(lastToken, 0, baseToken);
}
}
ignore(node) {
const range = node.range;
const n = this.ignoreRanges.get(range[0]) ?? 0;
this.ignoreRanges.set(range[0], Math.max(n, range[1]));
}
getOffsetCalculator() {
return new OffsetCalculator({
offsets: this.offsets,
options: this.options,
ignoreRanges: [...this.ignoreRanges]
});
}
}
exports.OffsetContext = OffsetContext;
class OffsetCalculator {
constructor(arg) {
this.offsets = arg.offsets;
this.options = arg.options;
this.ignoreRanges = arg.ignoreRanges;
}
getExpectedIndentFromIndex(index) {
const offsetInfo = this.offsets.get(index);
if (offsetInfo == null) {
return null;
}
if (offsetInfo.expectedIndent != null) {
return offsetInfo.expectedIndent;
}
if (offsetInfo.type === 2) {
return offsetInfo.offset * this.options.indentSize;
}
const baseIndent = this.getExpectedIndentFromIndex(offsetInfo.base);
if (baseIndent == null) {
return null;
}
if (offsetInfo.type === 1) {
return baseIndent + offsetInfo.alignIndent;
}
return baseIndent + offsetInfo.offset * this.options.indentSize;
}
getExpectedIndentFromToken(token) {
return this.getExpectedIndentFromIndex(token.range[0]);
}
getExpectedIndentFromTokens(tokens) {
for (const token of tokens) {
const index = token.range[0];
if (this.ignoreRanges.some(([f, t]) => f <= index && index < t)) {
return null;
}
const expectedIndent = this.getExpectedIndentFromIndex(index);
if (expectedIndent != null) {
return expectedIndent;
}
}
return null;
}
saveExpectedIndent(tokens, expectedIndent) {
for (const token of tokens) {
const offsetInfo = this.offsets.get(token.range[0]);
if (offsetInfo == null) {
continue;
}
offsetInfo.expectedIndent = offsetInfo.expectedIndent ?? expectedIndent;
}
}
}
exports.OffsetCalculator = OffsetCalculator;

View File

@ -0,0 +1,5 @@
import type { SvelteNodeListener } from '../../types-for-node';
import type { IndentContext } from './commons';
type NodeListener = SvelteNodeListener;
export declare function defineVisitor(context: IndentContext): NodeListener;
export {};

View File

@ -0,0 +1,378 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const ast_1 = require("./ast");
const commons_1 = require("./commons");
const commons_2 = require("./commons");
const commons_3 = require("./commons");
const PREFORMATTED_ELEMENT_NAMES = ['pre', 'textarea', 'template'];
function defineVisitor(context) {
const { sourceCode, offsets, options } = context;
const visitor = {
SvelteScriptElement(node) {
offsets.setOffsetElementList(node.body, node.startTag, node.endTag, options.indentScript ? 1 : 0);
},
SvelteStyleElement(node) {
node.children.forEach((n) => offsets.ignore(n));
},
SvelteElement(node) {
if (node.name.type === 'Identifier' || node.name.type === 'SvelteName') {
if (PREFORMATTED_ELEMENT_NAMES.includes(node.name.name)) {
const startTagToken = sourceCode.getFirstToken(node);
const endTagToken = node.endTag && sourceCode.getFirstToken(node.endTag);
offsets.setOffsetToken(endTagToken, 0, startTagToken);
node.children.forEach((n) => offsets.ignore(n));
return;
}
if (node.name.name === 'style') {
node.children.forEach((n) => offsets.ignore(n));
return;
}
}
if (node.endTag) {
offsets.setOffsetElementList(node.children.filter(isNotEmptyTextNode), node.startTag, node.endTag, 1);
}
},
SvelteStartTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList(node.attributes, openToken, closeToken, 1, options.alignAttributesVertically);
if (node.selfClosing) {
const slash = sourceCode.getTokenBefore(closeToken);
if (slash.value === '/') {
offsets.setOffsetToken(slash, 0, openToken);
}
}
},
SvelteEndTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList([], openToken, closeToken, 1);
},
SvelteAttribute(node) {
const keyToken = sourceCode.getFirstToken(node);
const eqToken = sourceCode.getTokenAfter(node.key);
if (eqToken != null && eqToken.range[1] <= node.range[1]) {
offsets.setOffsetToken(eqToken, 1, keyToken);
const valueStartToken = sourceCode.getTokenAfter(eqToken);
if (valueStartToken != null && valueStartToken.range[1] <= node.range[1]) {
offsets.setOffsetToken(valueStartToken, 1, keyToken);
const values = node.type === 'SvelteAttribute' || node.type === 'SvelteStyleDirective'
? node.value
: [];
let processedValues = false;
if (valueStartToken.type === 'Punctuator') {
const quoted = ['"', "'"].includes(valueStartToken.value);
const mustache = !quoted && valueStartToken.value === '{';
if (quoted || mustache) {
const last = sourceCode.getLastToken(node);
if (last.type === 'Punctuator' &&
((quoted && last.value === valueStartToken.value) ||
(mustache && last.value === '}'))) {
offsets.setOffsetToken(last, 0, valueStartToken);
offsets.setOffsetElementList(values, valueStartToken, last, 1);
processedValues = true;
}
}
}
if (!processedValues) {
for (const val of values) {
const token = sourceCode.getFirstToken(val);
offsets.setOffsetToken(token, 0, valueStartToken);
}
}
}
}
},
SvelteDirective(node) {
visitor.SvelteAttribute(node);
},
SvelteStyleDirective(node) {
visitor.SvelteAttribute(node);
},
SvelteSpecialDirective(node) {
visitor.SvelteAttribute(node);
},
SvelteShorthandAttribute(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList([], openToken, closeToken, 1);
},
SvelteSpreadAttribute(node) {
visitor.SvelteShorthandAttribute(node);
},
SvelteDirectiveKey(_node) {
},
SvelteSpecialDirectiveKey(_node) {
},
SvelteText(node) {
const tokens = sourceCode.getTokens(node, {
filter: ast_1.isNotWhitespace,
includeComments: false
});
const first = tokens.shift();
if (!first) {
return;
}
offsets.setOffsetToken(tokens, (0, commons_2.isBeginningOfLine)(sourceCode, first) ? 0 : (0, commons_1.isBeginningOfElement)(node) ? 1 : 0, first);
},
SvelteLiteral(node) {
const tokens = sourceCode.getTokens(node, {
filter: ast_1.isNotWhitespace,
includeComments: false
});
const first = tokens.shift();
if (!first) {
return;
}
offsets.setOffsetToken(tokens, (0, commons_2.isBeginningOfLine)(sourceCode, first) ? 0 : 1, first);
},
SvelteMustacheTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList([node.expression], openToken, closeToken, 1);
},
SvelteDebugTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList(node.identifiers, openToken, closeToken, 1);
},
SvelteConstTag(node) {
const openToken = sourceCode.getFirstToken(node);
const constToken = sourceCode.getTokenAfter(openToken);
const declarationToken = sourceCode.getFirstToken(node.declaration);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(constToken, 1, openToken);
offsets.setOffsetToken(declarationToken, 1, openToken);
offsets.setOffsetToken(closeToken, 0, openToken);
},
SvelteIfBlock(node) {
const [openToken, ...ifTokens] = sourceCode.getFirstTokens(node, {
count: node.elseif ? 3 : 2,
includeComments: false
});
offsets.setOffsetToken(ifTokens, 1, openToken);
const exp = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.expression);
offsets.setOffsetToken(exp.firstToken, 1, ifTokens[0]);
const closeOpenTagToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
if (node.else) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.else), 0, openToken);
if (node.else.elseif) {
return;
}
}
const [openCloseTagToken, endIfToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endIfToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteElseBlock(node) {
if (node.elseif) {
return;
}
const [openToken, elseToken, closeToken] = sourceCode.getFirstTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(elseToken, 1, openToken);
offsets.setOffsetToken(closeToken, 0, openToken);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteEachBlock(node) {
const [openToken, eachToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(eachToken, 1, openToken);
offsets.setOffsetElementList([node.expression, node.context, node.index], eachToken, null, 1);
if (node.key) {
const key = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.key);
offsets.setOffsetToken(key.firstToken, 1, eachToken);
const closeOpenTagToken = sourceCode.getTokenAfter(key.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
else {
const closeOpenTagToken = sourceCode.getTokenAfter(node.index || node.context);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
if (node.else) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.else), 0, openToken);
}
const [openCloseTagToken, endEachToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endEachToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteAwaitBlock(node) {
const [openToken, awaitToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(awaitToken, 1, openToken);
const exp = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.expression);
offsets.setOffsetToken(exp.firstToken, 1, awaitToken);
if (node.pending) {
const closeOpenTagToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
offsets.setOffsetToken(sourceCode.getFirstToken(node.pending, {
includeComments: false,
filter: ast_1.isNotWhitespace
}), 1, openToken);
}
if (node.then) {
if (node.kind === 'await-then') {
const thenToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(thenToken, 1, openToken);
if (node.then.value) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.then.value), 1, thenToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.then.value || thenToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
else {
offsets.setOffsetToken(sourceCode.getFirstToken(node.then), 0, openToken);
}
}
if (node.catch) {
if (node.kind === 'await-catch') {
const catchToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(catchToken, 1, openToken);
if (node.catch.error) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.catch.error), 1, catchToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.catch.error || catchToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
else {
offsets.setOffsetToken(sourceCode.getFirstToken(node.catch), 0, openToken);
}
}
const [openCloseTagToken, endAwaitToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endAwaitToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteAwaitPendingBlock(node) {
const openToken = sourceCode.getFirstToken(node);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteAwaitThenBlock(node) {
if (!node.awaitThen) {
const [openToken, thenToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(thenToken, 1, openToken);
if (node.value) {
const valueToken = sourceCode.getFirstToken(node.value);
offsets.setOffsetToken(valueToken, 1, thenToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.value || thenToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
const openToken = sourceCode.getFirstToken(node);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteAwaitCatchBlock(node) {
if (!node.awaitCatch) {
const [openToken, catchToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(catchToken, 1, openToken);
if (node.error) {
const errorToken = sourceCode.getFirstToken(node.error);
offsets.setOffsetToken(errorToken, 1, catchToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.error || catchToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
const openToken = sourceCode.getFirstToken(node);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteKeyBlock(node) {
const [openToken, keyToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(keyToken, 1, openToken);
const exp = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.expression);
offsets.setOffsetToken(exp.firstToken, 1, keyToken);
const closeOpenTagToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
const [openCloseTagToken, endAwaitToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endAwaitToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteHTMLComment(_node) {
},
SvelteName(_node) {
},
SvelteMemberExpressionName(_node) {
}
};
return visitor;
}
exports.defineVisitor = defineVisitor;
function isNotEmptyTextNode(node) {
return !(node.type === 'SvelteText' && node.value.trim() === '');
}

View File

@ -0,0 +1,5 @@
import type { IndentContext } from './commons';
import type { TSNodeListener } from '../../types-for-node';
type NodeListener = TSNodeListener;
export declare function defineVisitor(context: IndentContext): NodeListener;
export {};

View File

@ -0,0 +1,743 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const commons_1 = require("./commons");
const commons_2 = require("./commons");
function defineVisitor(context) {
const { offsets, sourceCode } = context;
const visitor = {
TSTypeAnnotation(node) {
const [colonOrArrowToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
const baseToken = sourceCode.getFirstToken(node.parent);
offsets.setOffsetToken([colonOrArrowToken, secondToken], 1, baseToken);
const before = sourceCode.getTokenBefore(colonOrArrowToken);
if (before && before.value === '?') {
offsets.setOffsetToken(before, 1, baseToken);
}
},
TSAsExpression(node) {
const expressionTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression);
const asOrSatisfiesToken = sourceCode.getTokenAfter(expressionTokens.lastToken);
offsets.setOffsetToken([asOrSatisfiesToken, (0, commons_2.getFirstAndLastTokens)(sourceCode, node.typeAnnotation).firstToken], 1, expressionTokens.firstToken);
},
TSSatisfiesExpression(node) {
visitor.TSAsExpression(node);
},
TSTypeReference(node) {
if (node.typeParameters) {
const firstToken = sourceCode.getFirstToken(node);
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
}
},
TSInstantiationExpression(node) {
visitor.TSTypeReference(node);
},
TSTypeParameterInstantiation(node) {
offsets.setOffsetElementList(node.params, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSTypeParameterDeclaration(node) {
visitor.TSTypeParameterInstantiation(node);
},
TSTypeAliasDeclaration(node) {
const typeToken = sourceCode.getFirstToken(node);
const idToken = sourceCode.getFirstToken(node.id);
offsets.setOffsetToken(idToken, 1, typeToken);
let eqToken;
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, idToken);
eqToken = sourceCode.getTokenAfter(node.typeParameters);
}
else {
eqToken = sourceCode.getTokenAfter(node.id);
}
const initToken = sourceCode.getTokenAfter(eqToken);
offsets.setOffsetToken([eqToken, initToken], 1, idToken);
},
TSFunctionType(node) {
const firstToken = sourceCode.getFirstToken(node);
let currToken = firstToken;
if (node.type === 'TSConstructorType') {
currToken = sourceCode.getTokenAfter(currToken);
offsets.setOffsetToken(currToken, 1, firstToken);
}
if (node.typeParameters) {
currToken = sourceCode.getTokenAfter(node.typeParameters);
offsets.setOffsetToken(currToken, 1, firstToken);
}
const leftParenToken = currToken;
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
const arrowToken = sourceCode.getTokenAfter(rightParenToken);
offsets.setOffsetToken(arrowToken, 1, leftParenToken);
},
TSConstructorType(node) {
visitor.TSFunctionType(node);
},
TSTypeLiteral(node) {
offsets.setOffsetElementList(node.members, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSPropertySignature(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.key);
let keyLast;
if (node.computed) {
const closeBracket = sourceCode.getTokenAfter(keyTokens.lastToken);
offsets.setOffsetElementList([node.key], firstToken, closeBracket, 1);
keyLast = closeBracket;
}
else {
keyLast = keyTokens.lastToken;
}
if (node.typeAnnotation) {
const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, typeAnnotationToken), typeAnnotationToken], 1, firstToken);
}
else if (node.optional) {
const qToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(qToken, 1, firstToken);
}
},
TSIndexSignature(node) {
const leftBracketToken = sourceCode.getFirstToken(node);
const rightBracketToken = sourceCode.getTokenAfter(node.parameters[node.parameters.length - 1] || leftBracketToken, { filter: eslint_utils_1.isClosingBracketToken, includeComments: false });
offsets.setOffsetElementList(node.parameters, leftBracketToken, rightBracketToken, 1);
const keyLast = rightBracketToken;
if (node.typeAnnotation) {
const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, typeAnnotationToken), typeAnnotationToken], 1, leftBracketToken);
}
},
TSArrayType(node) {
const firstToken = sourceCode.getFirstToken(node);
offsets.setOffsetToken(sourceCode.getLastTokens(node, { count: 2, includeComments: false }), 0, firstToken);
},
TSTupleType(node) {
offsets.setOffsetElementList(node.elementTypes, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSQualifiedName(node) {
const objectToken = sourceCode.getFirstToken(node);
const dotToken = sourceCode.getTokenBefore(node.right);
const propertyToken = sourceCode.getTokenAfter(dotToken);
offsets.setOffsetToken([dotToken, propertyToken], 1, objectToken);
},
TSIndexedAccessType(node) {
const objectToken = sourceCode.getFirstToken(node);
const leftBracketToken = sourceCode.getTokenBefore(node.indexType, {
filter: eslint_utils_1.isOpeningBracketToken,
includeComments: false
});
const rightBracketToken = sourceCode.getTokenAfter(node.indexType, {
filter: eslint_utils_1.isClosingBracketToken,
includeComments: false
});
offsets.setOffsetToken(leftBracketToken, 1, objectToken);
offsets.setOffsetElementList([node.indexType], leftBracketToken, rightBracketToken, 1);
},
TSUnionType(node) {
const firstToken = sourceCode.getFirstToken(node);
const types = [...node.types];
if ((0, commons_2.getFirstAndLastTokens)(sourceCode, types[0]).firstToken === firstToken) {
types.shift();
}
offsets.setOffsetElementList(types, firstToken, null, (0, commons_1.isBeginningOfLine)(sourceCode, firstToken) ? 0 : 1);
},
TSIntersectionType(node) {
visitor.TSUnionType(node);
},
TSMappedType(node) {
const leftBraceToken = sourceCode.getFirstToken(node);
const leftBracketToken = sourceCode.getTokenBefore(node.typeParameter);
const rightBracketToken = sourceCode.getTokenAfter(node.nameType || node.typeParameter);
offsets.setOffsetToken([...sourceCode.getTokensBetween(leftBraceToken, leftBracketToken), leftBracketToken], 1, leftBraceToken);
offsets.setOffsetElementList([node.typeParameter, node.nameType], leftBracketToken, rightBracketToken, 1);
const rightBraceToken = sourceCode.getLastToken(node);
if (node.typeAnnotation) {
const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
offsets.setOffsetToken([
...sourceCode.getTokensBetween(rightBracketToken, typeAnnotationToken),
typeAnnotationToken
], 1, leftBraceToken);
}
else {
offsets.setOffsetToken([...sourceCode.getTokensBetween(rightBracketToken, rightBraceToken)], 1, leftBraceToken);
}
offsets.setOffsetToken(rightBraceToken, 0, leftBraceToken);
},
TSTypeParameter(node) {
const [firstToken, ...afterTokens] = sourceCode.getTokens(node);
for (const child of [node.constraint, node.default]) {
if (!child) {
continue;
}
const [, ...removeTokens] = sourceCode.getTokens(child);
for (const token of removeTokens) {
const i = afterTokens.indexOf(token);
if (i >= 0) {
afterTokens.splice(i, 1);
}
}
}
const secondToken = afterTokens.shift();
if (!secondToken) {
return;
}
offsets.setOffsetToken(secondToken, 1, firstToken);
if (secondToken.value === 'extends') {
let prevToken = null;
let token = afterTokens.shift();
while (token) {
if (token.value === '=') {
break;
}
offsets.setOffsetToken(token, 1, secondToken);
prevToken = token;
token = afterTokens.shift();
}
while (token) {
offsets.setOffsetToken(token, 1, prevToken || secondToken);
token = afterTokens.shift();
}
}
else {
offsets.setOffsetToken(afterTokens, 1, firstToken);
}
},
TSConditionalType(node) {
const checkTypeToken = sourceCode.getFirstToken(node);
const extendsToken = sourceCode.getTokenAfter(node.checkType);
const extendsTypeToken = sourceCode.getFirstToken(node.extendsType);
offsets.setOffsetToken(extendsToken, 1, checkTypeToken);
offsets.setOffsetToken(extendsTypeToken, 1, extendsToken);
const questionToken = sourceCode.getTokenAfter(node.extendsType, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const consequentToken = sourceCode.getTokenAfter(questionToken);
const colonToken = sourceCode.getTokenAfter(node.trueType, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const alternateToken = sourceCode.getTokenAfter(colonToken);
let baseNode = node;
let parent = baseNode.parent;
while (parent && parent.type === 'TSConditionalType' && parent.falseType === baseNode) {
baseNode = parent;
parent = baseNode.parent;
}
const baseToken = sourceCode.getFirstToken(baseNode);
offsets.setOffsetToken([questionToken, colonToken], 1, baseToken);
offsets.setOffsetToken(consequentToken, 1, questionToken);
offsets.setOffsetToken(alternateToken, 1, colonToken);
},
TSInterfaceDeclaration(node) {
const interfaceToken = sourceCode.getFirstToken(node);
offsets.setOffsetToken(sourceCode.getFirstToken(node.id), 1, interfaceToken);
if (node.typeParameters != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, sourceCode.getFirstToken(node.id));
}
if (node.extends != null && node.extends.length) {
const extendsToken = sourceCode.getTokenBefore(node.extends[0]);
offsets.setOffsetToken(extendsToken, 1, interfaceToken);
offsets.setOffsetElementList(node.extends, extendsToken, null, 1);
}
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, interfaceToken);
},
TSInterfaceBody(node) {
offsets.setOffsetElementList(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSClassImplements(node) {
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, sourceCode.getFirstToken(node));
}
},
TSInterfaceHeritage(node) {
visitor.TSClassImplements(node);
},
TSEnumDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const idTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.id);
const prefixTokens = sourceCode.getTokensBetween(firstToken, idTokens.firstToken);
offsets.setOffsetToken(prefixTokens, 0, firstToken);
offsets.setOffsetToken(idTokens.firstToken, 1, firstToken);
const leftBraceToken = sourceCode.getTokenAfter(idTokens.lastToken);
const rightBraceToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(leftBraceToken, 0, firstToken);
offsets.setOffsetElementList(node.members, leftBraceToken, rightBraceToken, 1);
},
TSModuleDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const idTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.id);
const prefixTokens = sourceCode.getTokensBetween(firstToken, idTokens.firstToken);
offsets.setOffsetToken(prefixTokens, 0, firstToken);
offsets.setOffsetToken(idTokens.firstToken, 1, firstToken);
if (node.body) {
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, firstToken);
}
},
TSModuleBlock(node) {
visitor.TSInterfaceBody(node);
},
TSMethodSignature(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.key);
let keyLast;
if (node.computed) {
const closeBracket = sourceCode.getTokenAfter(keyTokens.lastToken);
offsets.setOffsetElementList([node.key], firstToken, closeBracket, 1);
keyLast = closeBracket;
}
else {
keyLast = keyTokens.lastToken;
}
const leftParenToken = sourceCode.getTokenAfter(keyLast, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, leftParenToken), leftParenToken], 1, firstToken);
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
if (node.returnType) {
const typeAnnotationToken = sourceCode.getFirstToken(node.returnType);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, typeAnnotationToken), typeAnnotationToken], 1, firstToken);
}
},
TSCallSignatureDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
let currToken = firstToken;
if (node.type === 'TSConstructSignatureDeclaration') {
currToken = sourceCode.getTokenAfter(currToken);
offsets.setOffsetToken(currToken, 1, firstToken);
}
if (node.typeParameters) {
currToken = sourceCode.getTokenAfter(node.typeParameters);
offsets.setOffsetToken(currToken, 1, firstToken);
}
const leftParenToken = currToken;
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
if (node.returnType) {
const typeAnnotationToken = sourceCode.getFirstToken(node.returnType);
offsets.setOffsetToken([
...sourceCode.getTokensBetween(rightParenToken, typeAnnotationToken),
typeAnnotationToken
], 1, firstToken);
}
},
TSConstructSignatureDeclaration(node) {
visitor.TSCallSignatureDeclaration(node);
},
TSEmptyBodyFunctionExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
let leftParenToken, bodyBaseToken;
if (firstToken.type === 'Punctuator') {
leftParenToken = firstToken;
bodyBaseToken = sourceCode.getFirstToken(node.parent);
}
else {
let nextToken = sourceCode.getTokenAfter(firstToken);
let nextTokenOffset = 0;
while (nextToken && !(0, eslint_utils_1.isOpeningParenToken)(nextToken) && nextToken.value !== '<') {
if (nextToken.value === '*' || (node.id && nextToken.range[0] === node.id.range[0])) {
nextTokenOffset = 1;
}
offsets.setOffsetToken(nextToken, nextTokenOffset, firstToken);
nextToken = sourceCode.getTokenAfter(nextToken);
}
leftParenToken = nextToken;
bodyBaseToken = firstToken;
}
if (!(0, eslint_utils_1.isOpeningParenToken)(leftParenToken) && node.typeParameters) {
leftParenToken = sourceCode.getTokenAfter(node.typeParameters);
}
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetToken(leftParenToken, 1, bodyBaseToken);
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
},
TSDeclareFunction(node) {
visitor.TSEmptyBodyFunctionExpression(node);
},
TSTypeOperator(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
TSTypeQuery(node) {
visitor.TSTypeOperator(node);
},
TSInferType(node) {
visitor.TSTypeOperator(node);
},
TSTypePredicate(node) {
const firstToken = sourceCode.getFirstToken(node);
const opToken = sourceCode.getTokenAfter(node.parameterName, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const rightToken = node.typeAnnotation && (0, commons_2.getFirstAndLastTokens)(sourceCode, node.typeAnnotation).firstToken;
offsets.setOffsetToken([opToken, rightToken], 1, (0, commons_2.getFirstAndLastTokens)(sourceCode, firstToken).firstToken);
},
TSAbstractMethodDefinition(node) {
const { keyNode, valueNode } = node.type === 'TSEnumMember'
? { keyNode: node.id, valueNode: node.initializer }
: { keyNode: node.key, valueNode: node.value };
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, keyNode);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
if (node.computed) {
prefixTokens.pop();
}
offsets.setOffsetToken(prefixTokens, 0, firstToken);
let lastKeyToken;
if (node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
offsets.setOffsetElementList([keyNode], leftBracketToken, rightBracketToken, 1);
}
else {
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
lastKeyToken = keyTokens.lastToken;
}
if (valueNode != null) {
const initToken = sourceCode.getFirstToken(valueNode);
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
}
},
TSAbstractPropertyDefinition(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSEnumMember(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSAbstractAccessorProperty(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSOptionalType(node) {
offsets.setOffsetToken(sourceCode.getLastToken(node), 1, sourceCode.getFirstToken(node));
},
TSNonNullExpression(node) {
visitor.TSOptionalType(node);
},
TSJSDocNonNullableType(node) {
visitor.TSOptionalType(node);
},
TSTypeAssertion(node) {
const firstToken = sourceCode.getFirstToken(node);
const expressionToken = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression).firstToken;
offsets.setOffsetElementList([node.typeAnnotation], firstToken, sourceCode.getTokenBefore(expressionToken), 1);
offsets.setOffsetToken(expressionToken, 1, firstToken);
},
TSImportType(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(firstToken, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken(leftParenToken, 1, firstToken);
const argument = node.argument ||
node.parameter;
const rightParenToken = sourceCode.getTokenAfter(argument, {
filter: eslint_utils_1.isClosingParenToken,
includeComments: false
});
offsets.setOffsetElementList([argument], leftParenToken, rightParenToken, 1);
if (node.qualifier) {
const dotToken = sourceCode.getTokenBefore(node.qualifier);
const propertyToken = sourceCode.getTokenAfter(dotToken);
offsets.setOffsetToken([dotToken, propertyToken], 1, firstToken);
}
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
}
},
TSParameterProperty(node) {
const firstToken = sourceCode.getFirstToken(node);
const parameterToken = sourceCode.getFirstToken(node.parameter);
offsets.setOffsetToken([...sourceCode.getTokensBetween(firstToken, parameterToken), parameterToken], 1, firstToken);
},
TSImportEqualsDeclaration(node) {
const importToken = sourceCode.getFirstToken(node);
const idTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.id);
offsets.setOffsetToken(idTokens.firstToken, 1, importToken);
const opToken = sourceCode.getTokenAfter(idTokens.lastToken);
offsets.setOffsetToken([opToken, sourceCode.getFirstToken(node.moduleReference)], 1, idTokens.lastToken);
},
TSExternalModuleReference(node) {
const requireToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(requireToken, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
const rightParenToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(leftParenToken, 1, requireToken);
offsets.setOffsetElementList([node.expression], leftParenToken, rightParenToken, 1);
},
TSExportAssignment(node) {
const exportNode = sourceCode.getFirstToken(node);
const exprTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression);
const opToken = sourceCode.getTokenBefore(exprTokens.firstToken);
offsets.setOffsetToken([opToken, exprTokens.firstToken], 1, exportNode);
},
TSNamedTupleMember(node) {
const labelToken = sourceCode.getFirstToken(node);
const elementTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.elementType);
offsets.setOffsetToken([
...sourceCode.getTokensBetween(labelToken, elementTokens.firstToken),
elementTokens.firstToken
], 1, labelToken);
},
TSRestType(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
TSNamespaceExportDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const idToken = sourceCode.getFirstToken(node.id);
offsets.setOffsetToken([...sourceCode.getTokensBetween(firstToken, idToken), idToken], 1, firstToken);
},
TSTemplateLiteralType(node) {
const firstToken = sourceCode.getFirstToken(node);
const quasiTokens = node.quasis.slice(1).map((n) => sourceCode.getFirstToken(n));
const expressionToken = node.quasis.slice(0, -1).map((n) => sourceCode.getTokenAfter(n));
offsets.setOffsetToken(quasiTokens, 0, firstToken);
offsets.setOffsetToken(expressionToken, 1, firstToken);
},
Decorator(node) {
const [atToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(secondToken, 0, atToken);
const parent = node.parent;
const { decorators } = parent;
if (!decorators || decorators.length === 0) {
return;
}
if (decorators[0] === node) {
if (parent.range[0] === node.range[0]) {
const startParentToken = sourceCode.getTokenAfter(decorators[decorators?.length - 1]);
offsets.setOffsetToken(startParentToken, 0, atToken);
}
else {
const startParentToken = sourceCode.getFirstToken(parent.parent &&
(parent.parent.type === 'ExportDefaultDeclaration' ||
parent.parent.type === 'ExportNamedDeclaration') &&
node.range[0] < parent.parent.range[0]
? parent.parent
: parent);
offsets.copyOffset(atToken.range[0], startParentToken.range[0]);
}
}
else {
offsets.setOffsetToken(atToken, 0, sourceCode.getFirstToken(decorators[0]));
}
},
AccessorProperty(node) {
const keyNode = node.key;
const valueNode = node.value;
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, keyNode);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
if (node.computed) {
prefixTokens.pop();
}
offsets.setOffsetToken(prefixTokens, 0, firstToken);
let lastKeyToken;
if (node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
offsets.setOffsetElementList([keyNode], leftBracketToken, rightBracketToken, 1);
}
else {
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
lastKeyToken = keyTokens.lastToken;
}
if (valueNode != null) {
const initToken = sourceCode.getFirstToken(valueNode);
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
}
},
StaticBlock(node) {
const firstToken = sourceCode.getFirstToken(node);
let next = sourceCode.getTokenAfter(firstToken);
while (next && (0, eslint_utils_1.isNotOpeningBraceToken)(next)) {
offsets.setOffsetToken(next, 0, firstToken);
next = sourceCode.getTokenAfter(next);
}
offsets.setOffsetToken(next, 0, firstToken);
offsets.setOffsetElementList(node.body, next, sourceCode.getLastToken(node), 1);
},
ImportAttribute(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.key);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
offsets.setOffsetToken(prefixTokens, 0, firstToken);
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
const initToken = sourceCode.getFirstToken(node.value);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyTokens.lastToken, initToken), initToken], 1, keyTokens.lastToken);
},
TSAnyKeyword() {
},
TSBigIntKeyword() {
},
TSBooleanKeyword() {
},
TSNeverKeyword() {
},
TSNullKeyword() {
},
TSNumberKeyword() {
},
TSObjectKeyword() {
},
TSStringKeyword() {
},
TSSymbolKeyword() {
},
TSUndefinedKeyword() {
},
TSUnknownKeyword() {
},
TSVoidKeyword() {
},
TSAbstractKeyword() {
},
TSAsyncKeyword() {
},
TSPrivateKeyword() {
},
TSProtectedKeyword() {
},
TSPublicKeyword() {
},
TSReadonlyKeyword() {
},
TSStaticKeyword() {
},
TSDeclareKeyword() {
},
TSExportKeyword() {
},
TSIntrinsicKeyword() {
},
TSThisType() {
},
TSLiteralType() {
}
};
const commonsVisitor = {
['TSTypeAliasDeclaration, TSCallSignatureDeclaration, TSConstructSignatureDeclaration, TSImportEqualsDeclaration,' +
'TSAbstractMethodDefinition, TSAbstractPropertyDefinition, AccessorProperty, TSAbstractAccessorProperty, TSEnumMember,' +
'TSPropertySignature, TSIndexSignature, TSMethodSignature,' +
'TSAbstractClassProperty, ClassProperty'](node) {
const firstToken = sourceCode.getFirstToken(node);
const lastToken = sourceCode.getLastToken(node);
if ((0, eslint_utils_1.isSemicolonToken)(lastToken) && firstToken !== lastToken) {
const next = sourceCode.getTokenAfter(lastToken);
if (!next || lastToken.loc.start.line < next.loc.start.line) {
offsets.setOffsetToken(lastToken, 0, firstToken);
}
}
},
'*[type=/^TS/]'(node) {
if (node.type !== 'TSAnyKeyword' &&
node.type !== 'TSArrayType' &&
node.type !== 'TSBigIntKeyword' &&
node.type !== 'TSBooleanKeyword' &&
node.type !== 'TSConditionalType' &&
node.type !== 'TSConstructorType' &&
node.type !== 'TSFunctionType' &&
node.type !== 'TSImportType' &&
node.type !== 'TSIndexedAccessType' &&
node.type !== 'TSInferType' &&
node.type !== 'TSIntersectionType' &&
node.type !== 'TSIntrinsicKeyword' &&
node.type !== 'TSLiteralType' &&
node.type !== 'TSMappedType' &&
node.type !== 'TSNamedTupleMember' &&
node.type !== 'TSNeverKeyword' &&
node.type !== 'TSNullKeyword' &&
node.type !== 'TSNumberKeyword' &&
node.type !== 'TSObjectKeyword' &&
node.type !== 'TSOptionalType' &&
node.type !== 'TSRestType' &&
node.type !== 'TSStringKeyword' &&
node.type !== 'TSSymbolKeyword' &&
node.type !== 'TSTemplateLiteralType' &&
node.type !== 'TSThisType' &&
node.type !== 'TSTupleType' &&
node.type !== 'TSTypeLiteral' &&
node.type !== 'TSTypeOperator' &&
node.type !== 'TSTypePredicate' &&
node.type !== 'TSTypeQuery' &&
node.type !== 'TSTypeReference' &&
node.type !== 'TSUndefinedKeyword' &&
node.type !== 'TSUnionType' &&
node.type !== 'TSUnknownKeyword' &&
node.type !== 'TSVoidKeyword') {
return;
}
const typeNode = node;
if (typeNode.parent.type === 'TSParenthesizedType') {
return;
}
let leftToken = sourceCode.getTokenBefore(typeNode);
let rightToken = sourceCode.getTokenAfter(typeNode);
let firstToken = sourceCode.getFirstToken(typeNode);
while (leftToken &&
(0, eslint_utils_1.isOpeningParenToken)(leftToken) &&
rightToken &&
(0, eslint_utils_1.isClosingParenToken)(rightToken)) {
offsets.setOffsetToken(firstToken, 1, leftToken);
offsets.setOffsetToken(rightToken, 0, leftToken);
firstToken = leftToken;
leftToken = sourceCode.getTokenBefore(leftToken);
rightToken = sourceCode.getTokenAfter(rightToken);
}
}
};
const extendsESVisitor = {
['ClassDeclaration[implements], ClassDeclaration[typeParameters], ClassDeclaration[superTypeParameters],' +
'ClassExpression[implements], ClassExpression[typeParameters], ClassExpression[superTypeParameters]'](node) {
if (node.typeParameters != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, sourceCode.getFirstToken(node.id || node));
}
if (node.superTypeParameters != null && node.superClass != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.superTypeParameters), 1, sourceCode.getFirstToken(node.superClass));
}
if (node.implements != null && node.implements.length) {
const classToken = sourceCode.getFirstToken(node);
const implementsToken = sourceCode.getTokenBefore(node.implements[0]);
offsets.setOffsetToken(implementsToken, 1, classToken);
offsets.setOffsetElementList(node.implements, implementsToken, null, 1);
}
}
};
const deprecatedVisitor = {
TSParenthesizedType(node) {
offsets.setOffsetElementList([node.typeAnnotation], sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
ClassProperty(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSAbstractClassProperty(node) {
visitor.TSAbstractMethodDefinition(node);
}
};
const v = visitor;
return {
...v,
...commonsVisitor,
...extendsESVisitor,
...deprecatedVisitor
};
}
exports.defineVisitor = defineVisitor;

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

49
node_modules/eslint-plugin-svelte/lib/rules/indent.js generated vendored Normal file
View File

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const indent_helpers_1 = require("./indent-helpers");
exports.default = (0, utils_1.createRule)('indent', {
meta: {
docs: {
description: 'enforce consistent indentation',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'whitespace',
schema: [
{
type: 'object',
properties: {
indent: {
anyOf: [{ type: 'integer', minimum: 1 }, { enum: ['tab'] }]
},
indentScript: { type: 'boolean' },
switchCase: { type: 'integer', minimum: 0 },
alignAttributesVertically: { type: 'boolean' },
ignoredNodes: {
type: 'array',
items: {
allOf: [
{ type: 'string' },
{ not: { type: 'string', pattern: ':exit$' } },
{ not: { type: 'string', pattern: '^\\s*$' } }
]
},
uniqueItems: true,
additionalItems: false
}
},
additionalProperties: false
}
],
messages: {
unexpectedChar: 'Expected {{expected}} character, but found {{actual}} character.',
unexpectedIndentation: 'Expected indentation of {{expectedIndent}} {{expectedUnit}}{{expectedIndentPlural}} but found {{actualIndent}} {{actualUnit}}{{actualIndentPlural}}.'
},
type: 'layout'
},
create(context) {
return (0, indent_helpers_1.defineVisitor)(context, {});
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,266 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const svelte_eslint_parser_1 = require("svelte-eslint-parser");
const compat_1 = require("../utils/compat");
function extractTickReferences(context) {
const referenceTracker = new eslint_utils_1.ReferenceTracker((0, compat_1.getSourceCode)(context).scopeManager.globalScope);
const a = referenceTracker.iterateEsmReferences({
svelte: {
[eslint_utils_1.ReferenceTracker.ESM]: true,
tick: {
[eslint_utils_1.ReferenceTracker.CALL]: true
}
}
});
return Array.from(a).map(({ node, path }) => {
return {
node: node,
name: path[path.length - 1]
};
});
}
function extractTaskReferences(context) {
const referenceTracker = new eslint_utils_1.ReferenceTracker((0, compat_1.getSourceCode)(context).scopeManager.globalScope);
const a = referenceTracker.iterateGlobalReferences({
setTimeout: { [eslint_utils_1.ReferenceTracker.CALL]: true },
setInterval: { [eslint_utils_1.ReferenceTracker.CALL]: true },
queueMicrotask: { [eslint_utils_1.ReferenceTracker.CALL]: true }
});
return Array.from(a).map(({ node, path }) => {
return {
node: node,
name: path[path.length - 1]
};
});
}
function isChildNode(maybeAncestorNode, node) {
let parent = node.parent;
while (parent) {
if (parent === maybeAncestorNode)
return true;
parent = parent.parent;
}
return false;
}
function isFunctionCall(node) {
if (node.type !== 'Identifier')
return false;
const { parent } = node;
if (parent?.type !== 'CallExpression')
return false;
return parent.callee.type === 'Identifier' && parent.callee.name === node.name;
}
function isReactiveVariableNode(reactiveVariableReferences, node) {
if (node.type !== 'Identifier')
return false;
return reactiveVariableReferences.includes(node);
}
function isNodeForAssign(node) {
const { parent } = node;
if (parent?.type === 'AssignmentExpression') {
return parent.left.type === 'Identifier' && parent.left.name === node.name;
}
return (parent?.type === 'MemberExpression' &&
parent.parent?.type === 'AssignmentExpression' &&
parent.parent.left.type === 'MemberExpression' &&
parent.parent.left.object.type === 'Identifier' &&
parent.parent.left.object.name === node.name);
}
function isPromiseThenOrCatchBody(node) {
if (!getDeclarationBody(node))
return false;
const { parent } = node;
if (parent?.type !== 'CallExpression' || parent?.callee?.type !== 'MemberExpression') {
return false;
}
const { property } = parent.callee;
if (property?.type !== 'Identifier')
return false;
return ['then', 'catch'].includes(property.name);
}
function getReactiveVariableReferences(context) {
const scopeManager = (0, compat_1.getSourceCode)(context).scopeManager;
const toplevelScope = scopeManager.globalScope?.childScopes.find((scope) => scope.type === 'module') ||
scopeManager.globalScope;
if (!toplevelScope) {
return [];
}
const reactiveVariableNodes = [];
for (const variable of toplevelScope.variables) {
for (const reference of variable.references) {
if (reference.identifier.type === 'Identifier' && !isFunctionCall(reference.identifier)) {
reactiveVariableNodes.push(reference.identifier);
}
}
}
return reactiveVariableNodes;
}
function getTrackedVariableNodes(reactiveVariableReferences, ast) {
const reactiveVariableNodes = new Set();
for (const identifier of reactiveVariableReferences) {
if (ast.range[0] <= identifier.range[0] &&
identifier.range[1] <= ast.range[1]) {
reactiveVariableNodes.add(identifier);
}
}
return reactiveVariableNodes;
}
function getDeclarationBody(node, functionName) {
if (node.type === 'VariableDeclarator' &&
node.id.type === 'Identifier' &&
(!functionName || node.id.name === functionName)) {
if (node.init?.type === 'ArrowFunctionExpression' || node.init?.type === 'FunctionExpression') {
return node.init.body;
}
}
else if (node.type === 'FunctionDeclaration' &&
node.id?.type === 'Identifier' &&
(!functionName || node.id?.name === functionName)) {
return node.body;
}
else if (!functionName && node.type === 'ArrowFunctionExpression') {
return node.body;
}
return null;
}
function getFunctionDeclarationNode(context, functionCall) {
const variable = (0, ast_utils_1.findVariable)(context, functionCall);
if (!variable) {
return null;
}
for (const def of variable.defs) {
if (def.type === 'FunctionName') {
if (def.node.type === 'FunctionDeclaration') {
return def.node.body;
}
}
if (def.type === 'Variable') {
if (def.node.init &&
(def.node.init.type === 'FunctionExpression' ||
def.node.init.type === 'ArrowFunctionExpression')) {
return def.node.init.body;
}
}
}
return null;
}
function isInsideOfFunction(node) {
let parent = node;
while (parent) {
parent = parent.parent;
if (!parent)
break;
if (parent.type === 'FunctionDeclaration' && parent.async)
return true;
if (parent.type === 'VariableDeclarator' &&
(parent.init?.type === 'FunctionExpression' ||
parent.init?.type === 'ArrowFunctionExpression') &&
parent.init?.async) {
return true;
}
}
return false;
}
function doLint(context, ast, callFuncIdentifiers, tickCallExpressions, taskReferences, reactiveVariableNames, reactiveVariableReferences, pIsSameTask) {
const processed = new Set();
verifyInternal(ast, callFuncIdentifiers, pIsSameTask);
function verifyInternal(ast, callFuncIdentifiers, pIsSameTask) {
if (processed.has(ast)) {
return;
}
processed.add(ast);
let isSameMicroTask = pIsSameTask;
const differentMicroTaskEnterNodes = [];
(0, svelte_eslint_parser_1.traverseNodes)(ast, {
enterNode(node) {
if (isPromiseThenOrCatchBody(node)) {
differentMicroTaskEnterNodes.push(node);
isSameMicroTask = false;
}
for (const { node: callExpression } of [...tickCallExpressions, ...taskReferences]) {
if (isChildNode(callExpression, node)) {
differentMicroTaskEnterNodes.push(node);
isSameMicroTask = false;
}
}
if (node.parent?.type === 'AssignmentExpression' &&
node.parent?.right.type === 'AwaitExpression' &&
node.parent?.left === node) {
differentMicroTaskEnterNodes.push(node);
isSameMicroTask = false;
}
if (node.type === 'Identifier' && isFunctionCall(node)) {
const functionDeclarationNode = getFunctionDeclarationNode(context, node);
if (functionDeclarationNode) {
verifyInternal(functionDeclarationNode, [...callFuncIdentifiers, node], isSameMicroTask);
}
}
if (!isSameMicroTask) {
if (isReactiveVariableNode(reactiveVariableReferences, node) &&
reactiveVariableNames.includes(node.name) &&
isNodeForAssign(node)) {
context.report({
node,
loc: node.loc,
messageId: 'unexpected'
});
callFuncIdentifiers.forEach((callFuncIdentifier) => {
context.report({
node: callFuncIdentifier,
loc: callFuncIdentifier.loc,
messageId: 'unexpectedCall',
data: {
variableName: node.name
}
});
});
}
}
},
leaveNode(node) {
if (node.type === 'AwaitExpression') {
if (ast.parent?.type === 'SvelteReactiveStatement') {
if (!isInsideOfFunction(node)) {
isSameMicroTask = false;
}
}
else {
isSameMicroTask = false;
}
}
if (differentMicroTaskEnterNodes.includes(node)) {
isSameMicroTask = true;
}
}
});
}
}
exports.default = (0, utils_1.createRule)('infinite-reactive-loop', {
meta: {
docs: {
description: "Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent.",
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
unexpected: 'Possibly it may occur an infinite reactive loop.',
unexpectedCall: 'Possibly it may occur an infinite reactive loop because this function may update `{{variableName}}`.'
},
type: 'suggestion'
},
create(context) {
return {
['SvelteReactiveStatement']: (ast) => {
const tickCallExpressions = extractTickReferences(context);
const taskReferences = extractTaskReferences(context);
const reactiveVariableReferences = getReactiveVariableReferences(context);
const trackedVariableNodes = getTrackedVariableNodes(reactiveVariableReferences, ast);
doLint(context, ast.body, [], tickCallExpressions, taskReferences, Array.from(trackedVariableNodes).map((node) => node.name), reactiveVariableReferences, true);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
function isSingleLine(node) {
return node.loc.start.line === node.loc.end.line;
}
function groupAttributesByLine(attributes) {
const group = [];
for (const attr of attributes) {
if (group[0]?.[0]?.loc.end.line === attr.loc.start.line) {
group[0].push(attr);
}
else {
group.unshift([attr]);
}
}
return group.reverse();
}
exports.default = (0, utils_1.createRule)('max-attributes-per-line', {
meta: {
docs: {
description: 'enforce the maximum number of attributes per line',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'whitespace',
schema: [
{
type: 'object',
properties: {
multiline: {
type: 'number',
minimum: 1
},
singleline: {
type: 'number',
minimum: 1
}
},
additionalProperties: false
}
],
messages: {
requireNewline: "'{{name}}' should be on a new line."
},
type: 'layout'
},
create(context) {
const multilineMaximum = context.options[0]?.multiline ?? 1;
const singlelineMaximum = context.options[0]?.singleline ?? 1;
const sourceCode = (0, compat_1.getSourceCode)(context);
function report(attribute) {
if (!attribute) {
return;
}
let name;
if (attribute.type === 'SvelteAttribute' ||
attribute.type === 'SvelteShorthandAttribute' ||
attribute.type === 'SvelteDirective' ||
attribute.type === 'SvelteStyleDirective' ||
attribute.type === 'SvelteSpecialDirective') {
name = sourceCode.text.slice(...attribute.key.range);
}
else {
name = sourceCode.text.slice(...attribute.range);
}
context.report({
node: attribute,
loc: attribute.loc,
messageId: 'requireNewline',
data: { name },
fix(fixer) {
const prevToken = sourceCode.getTokenBefore(attribute, {
includeComments: true
});
const range = [prevToken.range[1], attribute.range[0]];
return fixer.replaceTextRange(range, '\n');
}
});
}
return {
SvelteStartTag(node) {
const numberOfAttributes = node.attributes.length;
if (!numberOfAttributes)
return;
if (isSingleLine(node)) {
if (numberOfAttributes > singlelineMaximum) {
report(node.attributes[singlelineMaximum]);
}
}
else {
for (const attrs of groupAttributesByLine(node.attributes)) {
report(attrs[multilineMaximum]);
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,256 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
const VALUE_SCHEMA = { enum: ['never', 'always'] };
function parseOptions(options) {
return {
textExpressions: options?.textExpressions || 'never',
attributesAndProps: options?.attributesAndProps || 'never',
directiveExpressions: options?.directiveExpressions || 'never',
tags: {
openingBrace: options?.tags?.openingBrace || 'never',
closingBrace: options?.tags?.closingBrace || 'never'
}
};
}
exports.default = (0, utils_1.createRule)('mustache-spacing', {
meta: {
docs: {
description: 'enforce unified spacing in mustache',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
textExpressions: VALUE_SCHEMA,
attributesAndProps: VALUE_SCHEMA,
directiveExpressions: VALUE_SCHEMA,
tags: {
type: 'object',
properties: {
openingBrace: VALUE_SCHEMA,
closingBrace: {
enum: ['never', 'always', 'always-after-expression']
}
},
additionalProperties: false
}
},
additionalProperties: false
}
],
messages: {
expectedOpening: "Expected 1 space after '{', but not found.",
expectedClosing: "Expected 1 space before '}', but not found.",
unexpectedOpening: "Expected no space after '{', but found.",
unexpectedClosing: "Expected no space before '}', but found."
},
type: 'layout'
},
create(context) {
const options = parseOptions(context.options[0]);
const sourceCode = (0, compat_1.getSourceCode)(context);
function verifyBraces(openingBrace, closingBrace, openingOption, closingOption, hasExpression) {
const firstToken = sourceCode.getTokenAfter(openingBrace, {
includeComments: true
});
if (openingOption === 'always') {
if (openingBrace.range[1] === firstToken.range[0]) {
context.report({
node: openingBrace,
messageId: 'expectedOpening',
fix: (fixer) => fixer.insertTextAfter(openingBrace, ' ')
});
}
}
else {
if (openingBrace.range[1] !== firstToken.range[0]) {
context.report({
loc: {
start: openingBrace.loc.start,
end: firstToken.loc.start
},
messageId: 'unexpectedOpening',
fix: (fixer) => fixer.removeRange([openingBrace.range[1], firstToken.range[0]])
});
}
}
if (!closingBrace) {
return;
}
const lastToken = sourceCode.getTokenBefore(closingBrace, {
includeComments: true
});
if (closingOption === 'always' ||
(closingOption === 'always-after-expression' && hasExpression)) {
if (closingBrace.range[0] === lastToken.range[1]) {
context.report({
node: closingBrace,
messageId: 'expectedClosing',
fix: (fixer) => fixer.insertTextBefore(closingBrace, ' ')
});
}
}
else {
if (closingBrace.range[0] !== lastToken.range[1]) {
context.report({
loc: {
start: lastToken.loc.end,
end: closingBrace.loc.end
},
messageId: 'unexpectedClosing',
fix: (fixer) => fixer.removeRange([lastToken.range[1], closingBrace.range[0]])
});
}
}
}
function verifyExpression(node, option) {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(node, sourceCode);
if (!mustacheTokens) {
return;
}
verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, option, option);
}
return {
SvelteMustacheTag(node) {
if (node.kind === 'raw') {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(node, sourceCode);
verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
return;
}
let option;
if (node.parent.type === 'SvelteAttribute') {
option = options.attributesAndProps;
}
else if (node.parent.type === 'SvelteStyleDirective') {
option = options.directiveExpressions;
}
else {
option = options.textExpressions;
}
verifyExpression(node, option);
},
SvelteShorthandAttribute(node) {
verifyExpression(node, options.attributesAndProps);
},
SvelteSpreadAttribute(node) {
verifyExpression(node, options.attributesAndProps);
},
SvelteDirective(node) {
verifyExpression(node, options.directiveExpressions);
},
SvelteSpecialDirective(node) {
verifyExpression(node, options.directiveExpressions);
},
SvelteDebugTag(node) {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(node, sourceCode);
verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
},
SvelteIfBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.expression, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
if (node.elseif) {
return;
}
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteElseBlock(node) {
if (node.elseif) {
return;
}
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getTokenAfter(openToken, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openToken, closeToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteEachBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.key || node.index || node.context, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteKeyBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.expression, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteAwaitBlock(node) {
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteAwaitPendingBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.parent.expression, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
},
SvelteAwaitThenBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockLast = node.value || (node.awaitThen ? node.parent.expression : null);
const openBlockClosingToken = openBlockLast
? sourceCode.getTokenAfter(openBlockLast, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
})
: null;
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, Boolean(openBlockClosingToken &&
openBlockLast &&
openBlockClosingToken === sourceCode.getTokenAfter(openBlockLast)));
},
SvelteAwaitCatchBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockLast = node.error || (node.awaitCatch ? node.parent.expression : null);
const openBlockClosingToken = openBlockLast
? sourceCode.getTokenAfter(openBlockLast, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
})
: null;
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, Boolean(openBlockClosingToken &&
openBlockLast &&
openBlockClosingToken === sourceCode.getTokenAfter(openBlockLast)));
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-at-debug-tags', {
meta: {
docs: {
description: 'disallow the use of `{@debug}`',
category: 'Best Practices',
recommended: true,
default: 'warn'
},
schema: [],
messages: {
unexpected: 'Unexpected `{@debug}`.'
},
type: 'problem'
},
create(context) {
return {
SvelteDebugTag(node) {
context.report({
node,
messageId: 'unexpected'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-at-html-tags', {
meta: {
docs: {
description: 'disallow use of `{@html}` to prevent XSS attack',
category: 'Security Vulnerability',
recommended: true
},
schema: [],
messages: {
unexpected: '`{@html}` can lead to XSS attack.'
},
type: 'suggestion'
},
create(context) {
return {
'SvelteMustacheTag[kind=raw]'(node) {
context.report({
node,
messageId: 'unexpected'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,110 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const DOM_MANIPULATING_METHODS = new Set([
'appendChild',
'insertBefore',
'normalize',
'removeChild',
'replaceChild',
'after',
'append',
'before',
'insertAdjacentElement',
'insertAdjacentHTML',
'insertAdjacentText',
'prepend',
'remove',
'replaceChildren',
'replaceWith'
]);
const DOM_MANIPULATING_PROPERTIES = new Set([
'textContent',
'innerHTML',
'outerHTML',
'innerText',
'outerText'
]);
exports.default = (0, utils_1.createRule)('no-dom-manipulating', {
meta: {
docs: {
description: 'disallow DOM manipulating',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
disallowManipulateDOM: "Don't manipulate the DOM directly. The Svelte runtime can get confused if there is a difference between the actual DOM and the DOM expected by the Svelte runtime."
},
type: 'problem'
},
create(context) {
const domVariables = new Set();
function verifyIdentifier(node) {
const member = node.parent;
if (member?.type !== 'MemberExpression' || member.object !== node) {
return;
}
const name = (0, eslint_utils_1.getPropertyName)(member);
if (!name) {
return;
}
let target = member;
let parent = target.parent;
while (parent?.type === 'ChainExpression') {
target = parent;
parent = parent.parent;
}
if (!parent) {
return;
}
if (parent.type === 'CallExpression') {
if (parent.callee !== target || !DOM_MANIPULATING_METHODS.has(name)) {
return;
}
}
else if (parent.type === 'AssignmentExpression') {
if (parent.left !== target || !DOM_MANIPULATING_PROPERTIES.has(name)) {
return;
}
}
else {
return;
}
context.report({
node: member,
messageId: 'disallowManipulateDOM'
});
}
return {
"SvelteDirective[kind='Binding']"(node) {
if (node.key.name.name !== 'this' ||
!node.expression ||
node.expression.type !== 'Identifier') {
return;
}
const element = node.parent.parent;
if (element.type !== 'SvelteElement' || !isHTMLElement(element)) {
return;
}
const variable = (0, ast_utils_1.findVariable)(context, node.expression);
if (!variable || (variable.scope.type !== 'module' && variable.scope.type !== 'global')) {
return;
}
domVariables.add(variable);
},
'Program:exit'() {
for (const variable of domVariables) {
for (const reference of variable.references) {
verifyIdentifier(reference.identifier);
}
}
}
};
function isHTMLElement(node) {
return (node.kind === 'html' || (node.kind === 'special' && (0, ast_utils_1.getNodeName)(node) === 'svelte:element'));
}
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
function splitByLogicalOperator(operator, node) {
if (node.type === 'LogicalExpression' && node.operator === operator) {
return [
...splitByLogicalOperator(operator, node.left),
...splitByLogicalOperator(operator, node.right)
];
}
return [node];
}
function splitByOr(node) {
return splitByLogicalOperator('||', node);
}
function splitByAnd(node) {
return splitByLogicalOperator('&&', node);
}
function buildOrOperands(node) {
const orOperands = splitByOr(node);
return {
node,
operands: orOperands.map((orOperand) => {
const andOperands = splitByAnd(orOperand);
return {
node: orOperand,
operands: andOperands
};
})
};
}
exports.default = (0, utils_1.createRule)('no-dupe-else-if-blocks', {
meta: {
docs: {
description: 'disallow duplicate conditions in `{#if}` / `{:else if}` chains',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: 'This branch can never execute. Its condition is a duplicate or covered by previous conditions in the `{#if}` / `{:else if}` chain.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
function equal(a, b) {
if (a.type !== b.type) {
return false;
}
if (a.type === 'LogicalExpression' &&
b.type === 'LogicalExpression' &&
(a.operator === '||' || a.operator === '&&') &&
a.operator === b.operator) {
return ((equal(a.left, b.left) && equal(a.right, b.right)) ||
(equal(a.left, b.right) && equal(a.right, b.left)));
}
return (0, ast_utils_1.equalTokens)(a, b, sourceCode);
}
function isSubset(operandsA, operandsB) {
return operandsA.operands.every((operandA) => operandsB.operands.some((operandB) => equal(operandA, operandB)));
}
function* iterateIfElseIf(node) {
let target = node;
while (target.parent.type === 'SvelteElseBlock' &&
target.parent.children.includes(target) &&
target.parent.parent.type === 'SvelteIfBlock') {
yield target.parent.parent;
target = target.parent.parent;
}
}
return {
SvelteIfBlock(node) {
const test = node.expression;
const conditionsToCheck = test.type === 'LogicalExpression' && test.operator === '&&'
? [...splitByAnd(test), test]
: [test];
const listToCheck = conditionsToCheck.map(buildOrOperands);
for (const currentIdBlock of iterateIfElseIf(node)) {
if (currentIdBlock.expression) {
const currentOrOperands = buildOrOperands(currentIdBlock.expression);
for (const condition of listToCheck) {
const operands = (condition.operands = condition.operands.filter((orOperand) => {
return !currentOrOperands.operands.some((currentOrOperand) => isSubset(currentOrOperand, orOperand));
}));
if (!operands.length) {
context.report({
node: condition.node,
messageId: 'unexpected'
});
return;
}
}
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-dupe-on-directives', {
meta: {
docs: {
description: 'disallow duplicate `on:` directives',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
duplication: 'This `on:{{type}}` directive is the same and duplicate directives in L{{lineNo}}.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
const directiveDataMap = new Map();
return {
SvelteDirective(node) {
if (node.kind !== 'EventHandler')
return;
const directiveDataList = directiveDataMap.get(node.key.name.name);
if (!directiveDataList) {
directiveDataMap.set(node.key.name.name, [
{
expression: node.expression,
nodes: [node]
}
]);
return;
}
const directiveData = directiveDataList.find((data) => {
if (!data.expression || !node.expression) {
return data.expression === node.expression;
}
return (0, ast_utils_1.equalTokens)(data.expression, node.expression, sourceCode);
});
if (!directiveData) {
directiveDataList.push({
expression: node.expression,
nodes: [node]
});
return;
}
directiveData.nodes.push(node);
},
'SvelteStartTag:exit'() {
for (const [type, directiveDataList] of directiveDataMap) {
for (const { nodes } of directiveDataList) {
if (nodes.length < 2) {
continue;
}
for (const node of nodes) {
context.report({
node,
messageId: 'duplication',
data: {
type,
lineNo: String((nodes[0] !== node ? nodes[0] : nodes[1]).loc.start.line)
}
});
}
}
}
directiveDataMap.clear();
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const css_utils_1 = require("../utils/css-utils");
exports.default = (0, utils_1.createRule)('no-dupe-style-properties', {
meta: {
docs: {
description: 'disallow duplicate style properties',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: "Duplicate property '{{name}}'."
},
type: 'problem'
},
create(context) {
return {
SvelteStartTag(node) {
const reported = new Set();
const beforeDeclarations = new Map();
for (const { decls } of iterateStyleDeclSetFromAttrs(node.attributes)) {
for (const decl of decls) {
const already = beforeDeclarations.get(decl.prop);
if (already) {
for (const report of [already, decl].filter((n) => !reported.has(n))) {
context.report({
node,
loc: report.loc,
messageId: 'unexpected',
data: { name: report.prop }
});
reported.add(report);
}
}
}
for (const decl of decls) {
beforeDeclarations.set(decl.prop, decl);
}
}
}
};
function* iterateStyleDeclSetFromAttrs(attrs) {
for (const attr of attrs) {
if (attr.type === 'SvelteStyleDirective') {
yield {
decls: [{ prop: attr.key.name.name, loc: attr.key.name.loc }]
};
}
else if (attr.type === 'SvelteAttribute') {
if (attr.key.name !== 'style') {
continue;
}
const root = (0, css_utils_1.parseStyleAttributeValue)(attr, context);
if (!root) {
continue;
}
yield* iterateStyleDeclSetFromStyleRoot(root);
}
}
}
function* iterateStyleDeclSetFromStyleRoot(root) {
for (const child of root.nodes) {
if (child.type === 'decl') {
yield {
decls: [
{
prop: child.prop.name,
get loc() {
return child.prop.loc;
}
}
]
};
}
else if (child.type === 'inline') {
const decls = [];
for (const root of child.getAllInlineStyles().values()) {
for (const set of iterateStyleDeclSetFromStyleRoot(root)) {
decls.push(...set.decls);
}
}
yield { decls };
}
}
}
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-dupe-use-directives', {
meta: {
docs: {
description: 'disallow duplicate `use:` directives',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
duplication: 'This `{{keyText}}` directive is the same and duplicate directives in L{{lineNo}}.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
const directiveDataMap = new Map();
return {
SvelteDirective(node) {
if (node.kind !== 'Action')
return;
const keyText = (0, ast_utils_1.getAttributeKeyText)(node, context);
const directiveDataList = directiveDataMap.get(keyText);
if (!directiveDataList) {
directiveDataMap.set(keyText, [
{
expression: node.expression,
nodes: [node]
}
]);
return;
}
const directiveData = directiveDataList.find((data) => {
if (!data.expression || !node.expression) {
return data.expression === node.expression;
}
return (0, ast_utils_1.equalTokens)(data.expression, node.expression, sourceCode);
});
if (!directiveData) {
directiveDataList.push({
expression: node.expression,
nodes: [node]
});
return;
}
directiveData.nodes.push(node);
},
'SvelteStartTag:exit'() {
for (const [keyText, directiveDataList] of directiveDataMap) {
for (const { nodes } of directiveDataList) {
if (nodes.length < 2) {
continue;
}
for (const node of nodes) {
context.report({
node,
messageId: 'duplication',
data: {
keyText,
lineNo: String((nodes[0] !== node ? nodes[0] : nodes[1]).loc.start.line)
}
});
}
}
}
directiveDataMap.clear();
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-dynamic-slot-name', {
meta: {
docs: {
description: 'disallow dynamic slot name',
category: 'Possible Errors',
recommended: true
},
fixable: 'code',
schema: [],
messages: {
unexpected: '`<slot>` name cannot be dynamic.',
requireValue: '`<slot>` name requires a value.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
return {
"SvelteElement[name.name='slot'] > SvelteStartTag.startTag > SvelteAttribute[key.name='name']"(node) {
if (node.value.length === 0) {
context.report({
node,
messageId: 'requireValue'
});
return;
}
for (const vNode of node.value) {
if (vNode.type === 'SvelteMustacheTag') {
context.report({
node: vNode,
messageId: 'unexpected',
fix(fixer) {
const text = getStaticText(vNode.expression);
if (text == null) {
return null;
}
if (node.value.length === 1) {
const range = (0, ast_utils_1.getAttributeValueQuoteAndRange)(node, sourceCode).range;
return fixer.replaceTextRange(range, `"${text}"`);
}
const range = vNode.range;
return fixer.replaceTextRange(range, text);
}
});
}
}
}
};
function getStaticText(node) {
const expr = findRootExpression(node);
return (0, ast_utils_1.getStringIfConstant)(expr);
}
function findRootExpression(node, already = new Set()) {
if (node.type !== 'Identifier' || already.has(node)) {
return node;
}
already.add(node);
const variable = (0, ast_utils_1.findVariable)(context, node);
if (!variable || variable.defs.length !== 1) {
return node;
}
const def = variable.defs[0];
if (def.type === 'Variable') {
if (def.parent.kind === 'const' && def.node.init) {
const init = def.node.init;
return findRootExpression(init, already);
}
}
return node;
}
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const svelte_kit_1 = require("../utils/svelte-kit");
exports.default = (0, utils_1.createRule)('no-export-load-in-svelte-module-in-kit-pages', {
meta: {
docs: {
description: 'disallow exporting load functions in `*.svelte` module in SvelteKit page components.',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
unexpected: 'disallow exporting load functions in `*.svelte` module in SvelteKit page components.'
},
type: 'problem'
},
create(context) {
if (!(0, svelte_kit_1.isKitPageComponent)(context)) {
return {};
}
let isModule = false;
return {
[`Program > SvelteScriptElement > SvelteStartTag > SvelteAttribute[key.name="context"] > SvelteLiteral[value="module"]`]: () => {
isModule = true;
},
'Program > SvelteScriptElement:exit': () => {
isModule = false;
},
[`:matches(ExportNamedDeclaration > FunctionDeclaration, ExportNamedDeclaration > VariableDeclaration > VariableDeclarator) > Identifier.id[name="load"]`]: (node) => {
if (!isModule)
return {};
return context.report({
node,
loc: node.loc,
messageId: 'unexpected'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-extra-reactive-curlies', {
meta: {
docs: {
description: 'disallow wrapping single reactive statements in curly braces',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: false
},
hasSuggestions: true,
schema: [],
messages: {
extraCurlies: `Do not wrap reactive statements in curly braces unless necessary.`,
removeExtraCurlies: `Remove the unnecessary curly braces.`
},
type: 'suggestion'
},
create(context) {
return {
[`SvelteReactiveStatement > BlockStatement[body.length=1]`]: (node) => {
const source = (0, compat_1.getSourceCode)(context);
return context.report({
node,
loc: node.loc,
messageId: 'extraCurlies',
suggest: [
{
messageId: 'removeExtraCurlies',
fix(fixer) {
const tokens = source.getTokens(node, { includeComments: true });
return [
fixer.removeRange([tokens[0].range[0], tokens[1].range[0]]),
fixer.removeRange([
tokens[tokens.length - 2].range[1],
tokens[tokens.length - 1].range[1]
])
];
}
}
]
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-ignored-unsubscribe', {
meta: {
docs: {
description: 'disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores.',
category: 'Best Practices',
recommended: false
},
fixable: undefined,
hasSuggestions: false,
messages: {
forbidden: 'Ignoring returned value of the subscribe method is forbidden.'
},
schema: [],
type: 'problem'
},
create: (context) => {
return {
"ExpressionStatement > CallExpression > MemberExpression.callee[property.name='subscribe']": (node) => {
context.report({
messageId: 'forbidden',
node: node.property
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,160 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-immutable-reactive-statements', {
meta: {
docs: {
description: "disallow reactive statements that don't reference reactive values.",
category: 'Best Practices',
recommended: false
},
schema: [],
messages: {
immutable: 'This statement is not reactive because all variables referenced in the reactive statement are immutable.'
},
type: 'suggestion'
},
create(context) {
const scopeManager = (0, compat_1.getSourceCode)(context).scopeManager;
const globalScope = scopeManager.globalScope;
const toplevelScope = globalScope?.childScopes.find((scope) => scope.type === 'module') || globalScope;
if (!globalScope || !toplevelScope) {
return {};
}
const cacheMutableVariable = new WeakMap();
function isMutableVariableReference(reference) {
if (reference.identifier.name.startsWith('$')) {
return true;
}
if (!reference.resolved) {
return true;
}
return isMutableVariable(reference.resolved);
}
function isMutableVariable(variable) {
const cache = cacheMutableVariable.get(variable);
if (cache != null) {
return cache;
}
if (variable.defs.length === 0) {
return true;
}
const isMutableDefine = variable.defs.some((def) => {
if (def.type === 'ImportBinding') {
return false;
}
if (def.node.type === 'AssignmentExpression') {
return true;
}
if (def.type === 'Variable') {
const parent = def.parent;
if (parent.kind === 'const') {
if (def.node.init &&
(def.node.init.type === 'FunctionExpression' ||
def.node.init.type === 'ArrowFunctionExpression' ||
def.node.init.type === 'Literal')) {
return false;
}
}
else {
const pp = parent.parent;
if (pp && pp.type === 'ExportNamedDeclaration' && pp.declaration === parent) {
return true;
}
}
return hasWrite(variable);
}
return false;
});
cacheMutableVariable.set(variable, isMutableDefine);
return isMutableDefine;
}
function hasWrite(variable) {
const defIds = variable.defs.map((def) => def.name);
for (const reference of variable.references) {
if (reference.isWrite() &&
!defIds.some((defId) => defId.range[0] <= reference.identifier.range[0] &&
reference.identifier.range[1] <= defId.range[1])) {
return true;
}
if (hasWriteMember(reference.identifier)) {
return true;
}
}
return false;
}
function hasWriteMember(expr) {
if (expr.type === 'JSXIdentifier')
return false;
const parent = expr.parent;
if (parent.type === 'AssignmentExpression') {
return parent.left === expr;
}
if (parent.type === 'UpdateExpression') {
return parent.argument === expr;
}
if (parent.type === 'UnaryExpression') {
return parent.operator === 'delete' && parent.argument === expr;
}
if (parent.type === 'MemberExpression') {
return parent.object === expr && hasWriteMember(parent);
}
if (parent.type === 'SvelteDirective') {
return parent.kind === 'Binding' && parent.expression === expr;
}
if (parent.type === 'SvelteEachBlock') {
return parent.expression === expr && hasWriteReference(parent.context);
}
return false;
}
function hasWriteReference(pattern) {
for (const id of (0, ast_utils_1.iterateIdentifiers)(pattern)) {
const variable = (0, ast_utils_1.findVariable)(context, id);
if (variable && hasWrite(variable))
return true;
}
return false;
}
function* iterateRangeReferences(scope, range) {
for (const variable of scope.variables) {
for (const reference of variable.references) {
if (range[0] <= reference.identifier.range[0] &&
reference.identifier.range[1] <= range[1]) {
yield reference;
}
}
}
}
return {
SvelteReactiveStatement(node) {
for (const reference of iterateRangeReferences(toplevelScope, node.range)) {
if (reference.isWriteOnly()) {
continue;
}
if (isMutableVariableReference(reference)) {
return;
}
}
for (const through of toplevelScope.through.filter((reference) => node.range[0] <= reference.identifier.range[0] &&
reference.identifier.range[1] <= node.range[1])) {
if (through.identifier.name.startsWith('$$')) {
return;
}
if (through.resolved == null) {
return;
}
}
context.report({
node: node.body.type === 'ExpressionStatement' &&
node.body.expression.type === 'AssignmentExpression' &&
node.body.expression.operator === '='
? node.body.expression.right
: node.body,
messageId: 'immutable'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-inline-styles', {
meta: {
docs: {
description: 'disallow attributes and directives that produce inline styles',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
allowTransitions: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
hasStyleAttribute: 'Found disallowed style attribute.',
hasStyleDirective: 'Found disallowed style directive.',
hasTransition: 'Found disallowed transition.'
},
type: 'suggestion'
},
create(context) {
const allowTransitions = context.options[0]?.allowTransitions ?? false;
return {
SvelteElement(node) {
if (node.kind !== 'html') {
return;
}
for (const attribute of node.startTag.attributes) {
if (attribute.type === 'SvelteStyleDirective') {
context.report({ loc: attribute.loc, messageId: 'hasStyleDirective' });
}
if (attribute.type === 'SvelteAttribute' && attribute.key.name === 'style') {
context.report({ loc: attribute.loc, messageId: 'hasStyleAttribute' });
}
if (!allowTransitions &&
attribute.type === 'SvelteDirective' &&
attribute.kind === 'Transition') {
context.report({ loc: attribute.loc, messageId: 'hasTransition' });
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const eslint_core_1 = require("../utils/eslint-core");
const coreRule = (0, eslint_core_1.getCoreRule)('no-inner-declarations');
exports.default = (0, utils_1.createRule)('no-inner-declarations', {
meta: {
docs: {
description: 'disallow variable or `function` declarations in nested blocks',
category: 'Extension Rules',
recommended: true,
extensionRule: 'no-inner-declarations'
},
fixable: coreRule.meta.fixable,
schema: coreRule.meta.schema,
messages: coreRule.meta.messages,
type: coreRule.meta.type
},
create(context) {
return (0, eslint_core_1.defineWrapperListener)(coreRule, context, {
createListenerProxy(coreListener) {
return (0, eslint_core_1.buildProxyListener)(coreListener, (node) => {
return (0, eslint_core_1.getProxyNode)(node, {
get parent() {
if (node.parent?.type === 'SvelteScriptElement') {
return node.parent.parent;
}
return node.parent;
}
});
});
}
});
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const PHRASES = {
ObjectExpression: 'object',
ArrayExpression: 'array',
ClassExpression: 'class',
Literal(node) {
if ('regex' in node) {
return 'regex value';
}
if ('bigint' in node) {
return 'bigint value';
}
if (node.value == null) {
return null;
}
return `${typeof node.value} value`;
},
TemplateLiteral: 'string value'
};
exports.default = (0, utils_1.createRule)('no-not-function-handler', {
meta: {
docs: {
description: 'disallow use of not function in event handler',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: 'Unexpected {{phrase}} in event handler.'
},
type: 'problem'
},
create(context) {
function findRootExpression(node, already = new Set()) {
if (node.type !== 'Identifier' || already.has(node)) {
return node;
}
already.add(node);
const variable = (0, ast_utils_1.findVariable)(context, node);
if (!variable || variable.defs.length !== 1) {
return node;
}
const def = variable.defs[0];
if (def.type === 'Variable') {
if (def.parent.kind === 'const' && def.node.init) {
const init = def.node.init;
return findRootExpression(init, already);
}
}
return node;
}
function verify(node) {
if (!node) {
return;
}
const expression = findRootExpression(node);
if (expression.type !== 'ObjectExpression' &&
expression.type !== 'ArrayExpression' &&
expression.type !== 'ClassExpression' &&
expression.type !== 'Literal' &&
expression.type !== 'TemplateLiteral') {
return;
}
const phraseValue = PHRASES[expression.type];
const phrase = typeof phraseValue === 'function' ? phraseValue(expression) : phraseValue;
if (phrase == null) {
return;
}
context.report({
node,
messageId: 'unexpected',
data: {
phrase
}
});
}
return {
SvelteDirective(node) {
if (node.kind !== 'EventHandler') {
return;
}
verify(node.expression);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const PHRASES = {
ObjectExpression: 'object',
ArrayExpression: 'array',
ArrowFunctionExpression: 'function',
FunctionExpression: 'function',
ClassExpression: 'class'
};
exports.default = (0, utils_1.createRule)('no-object-in-text-mustaches', {
meta: {
docs: {
description: 'disallow objects in text mustache interpolation',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: 'Unexpected {{phrase}} in text mustache interpolation.'
},
type: 'problem'
},
create(context) {
return {
SvelteMustacheTag(node) {
const { expression } = node;
if (expression.type !== 'ObjectExpression' &&
expression.type !== 'ArrayExpression' &&
expression.type !== 'ArrowFunctionExpression' &&
expression.type !== 'FunctionExpression' &&
expression.type !== 'ClassExpression') {
return;
}
if (node.parent.type === 'SvelteAttribute') {
if (node.parent.value.length === 1) {
return;
}
}
context.report({
node,
messageId: 'unexpected',
data: {
phrase: PHRASES[expression.type]
}
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-reactive-functions', {
meta: {
docs: {
description: "it's not necessary to define functions in reactive statements",
category: 'Best Practices',
recommended: false
},
hasSuggestions: true,
schema: [],
messages: {
noReactiveFns: `Do not create functions inside reactive statements unless absolutely necessary.`,
fixReactiveFns: `Move the function out of the reactive statement`
},
type: 'suggestion'
},
create(context) {
return {
[`SvelteReactiveStatement > ExpressionStatement > AssignmentExpression > :function`](node) {
const parent = node.parent?.parent?.parent;
if (!parent) {
return false;
}
const source = (0, compat_1.getSourceCode)(context);
return context.report({
node: parent,
loc: parent.loc,
messageId: 'noReactiveFns',
suggest: [
{
messageId: 'fixReactiveFns',
fix(fixer) {
const tokens = source.getFirstTokens(parent, {
includeComments: false,
count: 3
});
const noExtraSpace = source.isSpaceBetweenTokens(tokens[1], tokens[2]);
return fixer.replaceTextRange([tokens[0].range[0], tokens[1].range[1]], noExtraSpace ? 'const' : 'const ');
}
}
]
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-reactive-literals', {
meta: {
docs: {
description: "don't assign literal values in reactive statements",
category: 'Best Practices',
recommended: false
},
hasSuggestions: true,
schema: [],
messages: {
noReactiveLiterals: `Do not assign literal values inside reactive statements unless absolutely necessary.`,
fixReactiveLiteral: `Move the literal out of the reactive statement into an assignment`
},
type: 'suggestion'
},
create(context) {
return {
[`SvelteReactiveStatement > ExpressionStatement > AssignmentExpression:matches(${[
`[right.type="Literal"]`,
`[right.type="ArrayExpression"][right.elements.length=0]`,
`[right.type="ObjectExpression"][right.properties.length=0]`
].join(',')})`](node) {
const parent = node.parent?.parent;
if (!parent) {
return false;
}
const source = (0, compat_1.getSourceCode)(context);
return context.report({
node: parent,
loc: parent.loc,
messageId: 'noReactiveLiterals',
suggest: [
{
messageId: 'fixReactiveLiteral',
fix(fixer) {
return [
fixer.insertTextBefore(parent, `let ${source.getText(node)}`),
fixer.remove(parent)
];
}
}
]
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,196 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-reactive-reassign', {
meta: {
docs: {
description: 'disallow reassigning reactive values',
category: 'Possible Errors',
recommended: false
},
schema: [
{
type: 'object',
properties: {
props: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
assignmentToReactiveValue: "Assignment to reactive value '{{name}}'.",
assignmentToReactiveValueProp: "Assignment to property of reactive value '{{name}}'."
},
type: 'problem'
},
create(context) {
const props = context.options[0]?.props !== false;
const sourceCode = (0, compat_1.getSourceCode)(context);
const scopeManager = sourceCode.scopeManager;
const globalScope = scopeManager.globalScope;
const toplevelScope = globalScope?.childScopes.find((scope) => scope.type === 'module') || globalScope;
if (!globalScope || !toplevelScope) {
return {};
}
const CHECK_REASSIGN = {
UpdateExpression: ({ parent }) => ({ type: 'reassign', node: parent }),
UnaryExpression: ({ parent }) => {
if (parent.operator === 'delete') {
return { type: 'reassign', node: parent };
}
return null;
},
AssignmentExpression: ({ node, parent }) => {
if (parent.left === node) {
return { type: 'reassign', node: parent };
}
return null;
},
ForInStatement: ({ node, parent }) => {
if (parent.left === node) {
return { type: 'reassign', node: parent };
}
return null;
},
ForOfStatement: ({ node, parent }) => {
if (parent.left === node) {
return { type: 'reassign', node: parent };
}
return null;
},
CallExpression: ({ node, parent, pathNodes }) => {
if (pathNodes.length > 0 && parent.callee === node) {
const mem = pathNodes[pathNodes.length - 1];
const callName = (0, eslint_utils_1.getPropertyName)(mem);
if (callName &&
/^(?:push|pop|shift|unshift|reverse|splice|sort|copyWithin|fill)$/u.test(callName)) {
return {
type: 'reassign',
node: parent,
pathNodes: pathNodes.slice(0, -1)
};
}
}
return null;
},
MemberExpression: ({ node, parent, pathNodes }) => {
if (parent.object === node) {
return {
type: 'check',
node: parent,
pathNodes: [...pathNodes, parent]
};
}
return null;
},
ChainExpression: ({ parent }) => {
return { type: 'check', node: parent };
},
ConditionalExpression: ({ node, parent }) => {
if (parent.test === node) {
return null;
}
return { type: 'check', node: parent };
},
Property: ({ node, parent }) => {
if (parent.value === node && parent.parent && parent.parent.type === 'ObjectPattern') {
return { type: 'check', node: parent.parent };
}
return null;
},
ArrayPattern: ({ node, parent }) => {
if (parent.elements.includes(node)) {
return { type: 'check', node: parent };
}
return null;
},
RestElement: ({ node, parent }) => {
if (parent.argument === node && parent.parent) {
return {
type: 'check',
node: parent.parent
};
}
return null;
},
SvelteDirective: ({ node, parent }) => {
if (parent.kind !== 'Binding') {
return null;
}
if (parent.shorthand || parent.expression === node) {
return {
type: 'reassign',
node: parent
};
}
return null;
}
};
function getReassignData(expr) {
let pathNodes = [];
let node = expr;
let parent;
while ((parent = node.parent)) {
const check = CHECK_REASSIGN[parent.type];
if (!check) {
return null;
}
const result = check({ node, parent, pathNodes });
if (!result) {
return null;
}
pathNodes = result.pathNodes || pathNodes;
if (result.type === 'reassign') {
return {
node: result.node,
pathNodes
};
}
node = result.node;
}
return null;
}
return {
SvelteReactiveStatement(node) {
if (node.body.type !== 'ExpressionStatement' ||
node.body.expression.type !== 'AssignmentExpression' ||
node.body.expression.operator !== '=') {
return;
}
const assignment = node.body.expression;
for (const variable of toplevelScope.variables) {
if (!variable.defs.some((def) => def.node === assignment)) {
continue;
}
for (const reference of variable.references) {
const id = reference.identifier;
if ((assignment.left.range[0] <= id.range[0] &&
id.range[1] <= assignment.left.range[1]) ||
id.type === 'JSXIdentifier') {
continue;
}
const reassign = getReassignData(id);
if (!reassign) {
continue;
}
if (!props && reassign.pathNodes.length > 0)
continue;
context.report({
node: reassign.node,
messageId: reassign.pathNodes.length === 0
? 'assignmentToReactiveValue'
: 'assignmentToReactiveValueProp',
data: {
name: id.name
}
});
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-restricted-html-elements', {
meta: {
docs: {
description: 'disallow specific HTML elements',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: false
},
schema: {
type: 'array',
items: {
oneOf: [
{ type: 'string' },
{
type: 'object',
properties: {
elements: {
type: 'array',
items: {
type: ['string']
},
uniqueItems: true,
minItems: 1
},
message: { type: 'string', minLength: 1 }
},
additionalProperties: false,
minItems: 1
}
]
},
uniqueItems: true,
minItems: 1
},
messages: {},
type: 'suggestion'
},
create(context) {
return {
SvelteElement(node) {
if (node.kind !== 'html')
return;
const { name } = node;
if (name.type !== 'SvelteName')
return;
for (const option of context.options) {
const message = option.message || `Unexpected use of forbidden HTML element ${name.name}.`;
const elements = option.elements || [option];
for (const element of elements) {
if (element === name.name) {
context.report({
message,
node: node.startTag
});
}
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const css_utils_1 = require("../utils/css-utils");
exports.default = (0, utils_1.createRule)('no-shorthand-style-property-overrides', {
meta: {
docs: {
description: 'disallow shorthand style properties that override related longhand properties',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: "Unexpected shorthand '{{shorthand}}' after '{{original}}'."
},
type: 'problem'
},
create(context) {
return {
SvelteStartTag(node) {
const beforeDeclarations = new Set();
for (const { decls } of iterateStyleDeclSetFromAttrs(node.attributes)) {
for (const decl of decls) {
const normalized = (0, css_utils_1.stripVendorPrefix)(decl.prop);
const prefix = (0, css_utils_1.getVendorPrefix)(decl.prop);
const longhandProps = css_utils_1.SHORTHAND_PROPERTIES.get(normalized);
if (!longhandProps) {
continue;
}
for (const longhandProp of longhandProps) {
const longhandPropWithPrefix = prefix + longhandProp;
if (!beforeDeclarations.has(longhandPropWithPrefix)) {
continue;
}
context.report({
node,
loc: decl.loc,
messageId: 'unexpected',
data: {
shorthand: decl.prop,
original: longhandPropWithPrefix
}
});
}
}
for (const decl of decls) {
beforeDeclarations.add(decl.prop);
}
}
}
};
function* iterateStyleDeclSetFromAttrs(attrs) {
for (const attr of attrs) {
if (attr.type === 'SvelteStyleDirective') {
yield {
decls: [{ prop: attr.key.name.name, loc: attr.key.name.loc }]
};
}
else if (attr.type === 'SvelteAttribute') {
if (attr.key.name !== 'style') {
continue;
}
const root = (0, css_utils_1.parseStyleAttributeValue)(attr, context);
if (!root) {
continue;
}
yield* iterateStyleDeclSetFromStyleRoot(root);
}
}
}
function* iterateStyleDeclSetFromStyleRoot(root) {
for (const child of root.nodes) {
if (child.type === 'decl') {
yield {
decls: [
{
prop: child.prop.name,
get loc() {
return child.prop.loc;
}
}
]
};
}
else if (child.type === 'inline') {
const decls = [];
for (const root of child.getAllInlineStyles().values()) {
for (const set of iterateStyleDeclSetFromStyleRoot(root)) {
decls.push(...set.decls);
}
}
yield { decls };
}
}
}
}
});

Some files were not shown because too many files have changed in this diff Show More