blob: 266d11cc6c7cab6ee52318483e39f94fce91e3fb [file] [log] [blame]
"use strict";
/**
* Note this file is rather type-unsafe in its current state.
* This is due to some really funky type conversions between different node types.
* This is done intentionally based on the internal implementation of the base indent rule.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const experimental_utils_1 = require("@typescript-eslint/experimental-utils");
const indent_1 = __importDefault(require("eslint/lib/rules/indent"));
const util = __importStar(require("../util"));
const KNOWN_NODES = new Set([
// Class properties aren't yet supported by eslint...
experimental_utils_1.AST_NODE_TYPES.ClassProperty,
// ts keywords
experimental_utils_1.AST_NODE_TYPES.TSAbstractKeyword,
experimental_utils_1.AST_NODE_TYPES.TSAnyKeyword,
experimental_utils_1.AST_NODE_TYPES.TSBooleanKeyword,
experimental_utils_1.AST_NODE_TYPES.TSNeverKeyword,
experimental_utils_1.AST_NODE_TYPES.TSNumberKeyword,
experimental_utils_1.AST_NODE_TYPES.TSStringKeyword,
experimental_utils_1.AST_NODE_TYPES.TSSymbolKeyword,
experimental_utils_1.AST_NODE_TYPES.TSUndefinedKeyword,
experimental_utils_1.AST_NODE_TYPES.TSUnknownKeyword,
experimental_utils_1.AST_NODE_TYPES.TSVoidKeyword,
experimental_utils_1.AST_NODE_TYPES.TSNullKeyword,
// ts specific nodes we want to support
experimental_utils_1.AST_NODE_TYPES.TSAbstractClassProperty,
experimental_utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition,
experimental_utils_1.AST_NODE_TYPES.TSArrayType,
experimental_utils_1.AST_NODE_TYPES.TSAsExpression,
experimental_utils_1.AST_NODE_TYPES.TSCallSignatureDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSConditionalType,
experimental_utils_1.AST_NODE_TYPES.TSConstructorType,
experimental_utils_1.AST_NODE_TYPES.TSConstructSignatureDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSDeclareFunction,
experimental_utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression,
experimental_utils_1.AST_NODE_TYPES.TSEnumDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSEnumMember,
experimental_utils_1.AST_NODE_TYPES.TSExportAssignment,
experimental_utils_1.AST_NODE_TYPES.TSExternalModuleReference,
experimental_utils_1.AST_NODE_TYPES.TSFunctionType,
experimental_utils_1.AST_NODE_TYPES.TSImportType,
experimental_utils_1.AST_NODE_TYPES.TSIndexedAccessType,
experimental_utils_1.AST_NODE_TYPES.TSIndexSignature,
experimental_utils_1.AST_NODE_TYPES.TSInferType,
experimental_utils_1.AST_NODE_TYPES.TSInterfaceBody,
experimental_utils_1.AST_NODE_TYPES.TSInterfaceDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSInterfaceHeritage,
experimental_utils_1.AST_NODE_TYPES.TSIntersectionType,
experimental_utils_1.AST_NODE_TYPES.TSImportEqualsDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSLiteralType,
experimental_utils_1.AST_NODE_TYPES.TSMappedType,
experimental_utils_1.AST_NODE_TYPES.TSMethodSignature,
'TSMinusToken',
experimental_utils_1.AST_NODE_TYPES.TSModuleBlock,
experimental_utils_1.AST_NODE_TYPES.TSModuleDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSNonNullExpression,
experimental_utils_1.AST_NODE_TYPES.TSParameterProperty,
experimental_utils_1.AST_NODE_TYPES.TSParenthesizedType,
'TSPlusToken',
experimental_utils_1.AST_NODE_TYPES.TSPropertySignature,
experimental_utils_1.AST_NODE_TYPES.TSQualifiedName,
experimental_utils_1.AST_NODE_TYPES.TSQuestionToken,
experimental_utils_1.AST_NODE_TYPES.TSRestType,
experimental_utils_1.AST_NODE_TYPES.TSThisType,
experimental_utils_1.AST_NODE_TYPES.TSTupleType,
experimental_utils_1.AST_NODE_TYPES.TSTypeAnnotation,
experimental_utils_1.AST_NODE_TYPES.TSTypeLiteral,
experimental_utils_1.AST_NODE_TYPES.TSTypeOperator,
experimental_utils_1.AST_NODE_TYPES.TSTypeParameter,
experimental_utils_1.AST_NODE_TYPES.TSTypeParameterDeclaration,
experimental_utils_1.AST_NODE_TYPES.TSTypeParameterInstantiation,
experimental_utils_1.AST_NODE_TYPES.TSTypeReference,
experimental_utils_1.AST_NODE_TYPES.TSUnionType,
]);
exports.default = util.createRule({
name: 'indent',
meta: {
type: 'layout',
docs: {
description: 'Enforce consistent indentation',
category: 'Stylistic Issues',
recommended: 'error',
},
fixable: 'whitespace',
schema: indent_1.default.meta.schema,
messages: indent_1.default.meta.messages,
},
defaultOptions: [
// typescript docs and playground use 4 space indent
4,
{
// typescript docs indent the case from the switch
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-8.html#example-4
SwitchCase: 1,
flatTernaryExpressions: false,
ignoredNodes: [],
},
],
create(context, optionsWithDefaults) {
// because we extend the base rule, have to update opts on the context
// the context defines options as readonly though...
const contextWithDefaults = Object.create(context, {
options: {
writable: false,
configurable: false,
value: optionsWithDefaults,
},
});
const rules = indent_1.default.create(contextWithDefaults);
/**
* Converts from a TSPropertySignature to a Property
* @param node a TSPropertySignature node
* @param [type] the type to give the new node
* @returns a Property node
*/
function TSPropertySignatureToProperty(node, type = experimental_utils_1.AST_NODE_TYPES.Property) {
const base = {
// indent doesn't actually use these
key: null,
value: null,
// Property flags
computed: false,
method: false,
kind: 'init',
// this will stop eslint from interrogating the type literal
shorthand: true,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
};
if (type === experimental_utils_1.AST_NODE_TYPES.Property) {
return Object.assign({ type }, base);
}
else {
return Object.assign({ type, static: false, readonly: false }, base);
}
}
return Object.assign({}, rules, {
// overwrite the base rule here so we can use our KNOWN_NODES list instead
'*:exit'(node) {
// For nodes we care about, skip the default handling, because it just marks the node as ignored...
if (!KNOWN_NODES.has(node.type)) {
rules['*:exit'](node);
}
},
VariableDeclaration(node) {
// https://github.com/typescript-eslint/typescript-eslint/issues/441
if (node.declarations.length === 0) {
return;
}
return rules.VariableDeclaration(node);
},
TSAsExpression(node) {
// transform it to a BinaryExpression
return rules['BinaryExpression, LogicalExpression']({
type: experimental_utils_1.AST_NODE_TYPES.BinaryExpression,
operator: 'as',
left: node.expression,
// the first typeAnnotation includes the as token
right: node.typeAnnotation,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSConditionalType(node) {
// transform it to a ConditionalExpression
return rules.ConditionalExpression({
type: experimental_utils_1.AST_NODE_TYPES.ConditionalExpression,
test: {
type: experimental_utils_1.AST_NODE_TYPES.BinaryExpression,
operator: 'extends',
left: node.checkType,
right: node.extendsType,
// location data
range: [node.checkType.range[0], node.extendsType.range[1]],
loc: {
start: node.checkType.loc.start,
end: node.extendsType.loc.end,
},
},
consequent: node.trueType,
alternate: node.falseType,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
'TSEnumDeclaration, TSTypeLiteral'(node) {
// transform it to an ObjectExpression
return rules['ObjectExpression, ObjectPattern']({
type: experimental_utils_1.AST_NODE_TYPES.ObjectExpression,
properties: node.members.map(member => TSPropertySignatureToProperty(member)),
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSImportEqualsDeclaration(node) {
// transform it to an VariableDeclaration
// use VariableDeclaration instead of ImportDeclaration because it's essentially the same thing
const { id, moduleReference } = node;
return rules.VariableDeclaration({
type: experimental_utils_1.AST_NODE_TYPES.VariableDeclaration,
kind: 'const',
declarations: [
{
type: experimental_utils_1.AST_NODE_TYPES.VariableDeclarator,
range: [id.range[0], moduleReference.range[1]],
loc: {
start: id.loc.start,
end: moduleReference.loc.end,
},
id: id,
init: {
type: experimental_utils_1.AST_NODE_TYPES.CallExpression,
callee: {
type: experimental_utils_1.AST_NODE_TYPES.Identifier,
name: 'require',
range: [
moduleReference.range[0],
moduleReference.range[0] + 'require'.length,
],
loc: {
start: moduleReference.loc.start,
end: {
line: moduleReference.loc.end.line,
column: moduleReference.loc.start.line + 'require'.length,
},
},
},
arguments: 'expression' in moduleReference
? [moduleReference.expression]
: [],
// location data
range: moduleReference.range,
loc: moduleReference.loc,
},
},
],
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSIndexedAccessType(node) {
// convert to a MemberExpression
return rules['MemberExpression, JSXMemberExpression, MetaProperty']({
type: experimental_utils_1.AST_NODE_TYPES.MemberExpression,
object: node.objectType,
property: node.indexType,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSInterfaceBody(node) {
// transform it to an ClassBody
return rules['BlockStatement, ClassBody']({
type: experimental_utils_1.AST_NODE_TYPES.ClassBody,
body: node.body.map(p => TSPropertySignatureToProperty(p, experimental_utils_1.AST_NODE_TYPES.ClassProperty)),
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
'TSInterfaceDeclaration[extends.length > 0]'(node) {
// transform it to a ClassDeclaration
return rules['ClassDeclaration[superClass], ClassExpression[superClass]']({
type: experimental_utils_1.AST_NODE_TYPES.ClassDeclaration,
body: node.body,
id: undefined,
// TODO: This is invalid, there can be more than one extends in interface
superClass: node.extends[0].expression,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSMappedType(node) {
const sourceCode = context.getSourceCode();
const squareBracketStart = sourceCode.getTokenBefore(node.typeParameter);
// transform it to an ObjectExpression
return rules['ObjectExpression, ObjectPattern']({
type: experimental_utils_1.AST_NODE_TYPES.ObjectExpression,
properties: [
{
type: experimental_utils_1.AST_NODE_TYPES.Property,
key: node.typeParameter,
value: node.typeAnnotation,
// location data
range: [
squareBracketStart.range[0],
node.typeAnnotation
? node.typeAnnotation.range[1]
: squareBracketStart.range[0],
],
loc: {
start: squareBracketStart.loc.start,
end: node.typeAnnotation
? node.typeAnnotation.loc.end
: squareBracketStart.loc.end,
},
kind: 'init',
computed: false,
method: false,
shorthand: false,
},
],
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSModuleBlock(node) {
// transform it to a BlockStatement
return rules['BlockStatement, ClassBody']({
type: experimental_utils_1.AST_NODE_TYPES.BlockStatement,
body: node.body,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSQualifiedName(node) {
return rules['MemberExpression, JSXMemberExpression, MetaProperty']({
type: experimental_utils_1.AST_NODE_TYPES.MemberExpression,
object: node.left,
property: node.right,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSTupleType(node) {
// transform it to an ArrayExpression
return rules['ArrayExpression, ArrayPattern']({
type: experimental_utils_1.AST_NODE_TYPES.ArrayExpression,
elements: node.elementTypes,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
TSTypeParameterDeclaration(node) {
const [name, ...attributes] = node.params;
// JSX is about the closest we can get because the angle brackets
// it's not perfect but it works!
return rules.JSXOpeningElement({
type: experimental_utils_1.AST_NODE_TYPES.JSXOpeningElement,
selfClosing: false,
name: name,
attributes: attributes,
// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
});
},
});
//# sourceMappingURL=indent.js.map