Skip to content
This repository was archived by the owner on Jan 19, 2019. It is now read-only.

Commit

Permalink
[FIX] [indent] Add more indent cases + tests (#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher authored Jan 9, 2019
1 parent 08124d4 commit f612bdf
Show file tree
Hide file tree
Showing 3 changed files with 858 additions and 39 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ When adding or changing a rule, you must:
- (if any) outline the settings; how to configure them and what each one does
- have clear examples of valid and invalid code when using the rule. Bonus points for extra cases showing what each setting does.

When adding a rule, you must also add a link to the rule in the README.md.
When adding a rule, you must also add a link to the rule in the README.md (`yarn docs` will help you with this).

## Submitting Issues

Expand Down
246 changes: 208 additions & 38 deletions lib/rules/indent.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,68 @@ const util = require("../util");
const KNOWN_NODES = new Set([
// Class properties aren't yet supported by eslint...
"ClassProperty",

// ts keywords
"TSAbstractKeyword",
"TSAnyKeyword",
"TSBooleanKeyword",
"TSNeverKeyword",
"TSNumberKeyword",
"TSStringKeyword",
"TSSymbolKeyword",
"TSUndefinedKeyword",
"TSUnknownKeyword",
"TSVoidKeyword",
"TSNullKeyword",

// ts specific nodes we want to support
"TSAbstractClassDeclaration",
"TSAbstractClassProperty",
"TSAbstractMethodDefinition",
"TSArrayType",
"TSAsExpression",
"TSConditionalType",
"TSConstructorType",
"TSConstructSignature",
"TSEmptyBodyDeclareFunction",
"TSEmptyBodyFunctionExpression",
"TSEnumDeclaration",
"TSEnumMember",
"TSExportAssignment",
"TSExternalModuleReference",
"TSFunctionType",
"TSImportType",
"TSIndexedAccessType",
"TSIndexSignature",
"TSInferType",
"TSInterfaceBody",
"TSInterfaceDeclaration",
"TSInterfaceHeritage",
"TSIntersectionType",
"TSImportEqualsDeclaration",
"TSLiteralType",
"TSMappedType",
"TSMethodSignature",
"TSMinusToken",
"TSModuleBlock",
"TSModuleDeclaration",
"TSNonNullExpression",
"TSParameterProperty",
"TSParenthesizedType",
"TSPlusToken",
"TSPropertySignature",
"TSQualifiedName",
"TSQuestionToken",
"TSRestType",
"TSThisType",
"TSTupleType",
"TSTypeAnnotation",
"TSTypeLiteral",
"TSTypeOperator",
"TSTypeParameter",
"TSTypeParameterDeclaration",
"TSTypeReference",
"TSUnionType",
]);

const defaultOptions = [
Expand All @@ -43,22 +86,7 @@ const defaultOptions = [
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-8.html#example-4
SwitchCase: 1,
flatTernaryExpressions: false,
// list derived from https://github.com/benjamn/ast-types/blob/HEAD/def/jsx.js
ignoredNodes: [
"JSXElement",
"JSXElement > *",
"JSXAttribute",
"JSXIdentifier",
"JSXNamespacedName",
"JSXMemberExpression",
"JSXSpreadAttribute",
"JSXExpressionContainer",
"JSXOpeningElement",
"JSXClosingElement",
"JSXText",
"JSXEmptyExpression",
"JSXSpreadChild",
],
ignoredNodes: [],
},
];

Expand Down Expand Up @@ -124,11 +152,14 @@ module.exports = Object.assign({}, baseRule, {
}
},

"TSTypeLiteral, TSEnumDeclaration"(node) {
// transform it to an ObjectExpression
return rules["ObjectExpression, ObjectPattern"]({
type: "ObjectExpression",
properties: node.members.map(TSPropertySignatureToProperty),
TSAsExpression(node) {
// transform it to a BinaryExpression
return rules["BinaryExpression, LogicalExpression"]({
type: "BinaryExpression",
operator: "as",
left: node.expression,
// the first typeAnnotation includes the as token
right: node.typeAnnotation.typeAnnotation,

// location data
parent: node.parent,
Expand All @@ -137,29 +168,41 @@ module.exports = Object.assign({}, baseRule, {
});
},

// handle the interface extends clause
"TSInterfaceDeclaration[heritage.length > 0]"(node) {
return rules[
"ClassDeclaration[superClass], ClassExpression[superClass]"
]({
type: "ClassDeclaration",
body: node.body,
superClass: node.heritage[0].id,
TSConditionalType(node) {
// transform it to a ConditionalExpression
return rules.ConditionalExpression({
type: "ConditionalExpression",
test: {
type: "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,
});
},
// handle the interface body
TSInterfaceBody(node) {
// transform it to an ClassBody
return rules["BlockStatement, ClassBody"]({
type: "ClassBody",
body: node.body.map(p =>
TSPropertySignatureToProperty(p, "ClassProperty")
),

"TSEnumDeclaration, TSTypeLiteral"(node) {
// transform it to an ObjectExpression
return rules["ObjectExpression, ObjectPattern"]({
type: "ObjectExpression",
properties: node.members.map(TSPropertySignatureToProperty),

// location data
parent: node.parent,
Expand Down Expand Up @@ -220,8 +263,89 @@ module.exports = Object.assign({}, baseRule, {
});
},

TSIndexedAccessType(node) {
// convert to a MemberExpression
return rules[
"MemberExpression, JSXMemberExpression, MetaProperty"
]({
type: "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: "ClassBody",
body: node.body.map(p =>
TSPropertySignatureToProperty(p, "ClassProperty")
),

// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},

"TSInterfaceDeclaration[heritage.length > 0]"(node) {
// transform it to a ClassDeclaration
return rules[
"ClassDeclaration[superClass], ClassExpression[superClass]"
]({
type: "ClassDeclaration",
body: node.body,
superClass: node.heritage[0].id,

// 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: "ObjectExpression",
properties: [
{
type: "Property",
key: node.typeParameter,
value: node.typeAnnotation,

// location data
range: [
squareBracketStart.range[0],
node.typeAnnotation.range[1],
],
loc: {
start: squareBracketStart.loc.start,
end: node.typeAnnotation.loc.end,
},
},
],

// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},

TSModuleBlock(node) {
// transform it to a block statement
// transform it to a BlockStatement
return rules["BlockStatement, ClassBody"]({
type: "BlockStatement",
body: node.body,
Expand All @@ -232,6 +356,52 @@ module.exports = Object.assign({}, baseRule, {
loc: node.loc,
});
},

TSQualifiedName(node) {
return rules[
"MemberExpression, JSXMemberExpression, MetaProperty"
]({
type: "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: "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: "JSXOpeningElement",
selfClosing: false,
name,
attributes,

// location data
parent: node.parent,
range: node.range,
loc: node.loc,
});
},
});
},
});
Loading

0 comments on commit f612bdf

Please sign in to comment.