-
Notifications
You must be signed in to change notification settings - Fork 889
Add import-spacing rule #1935
Add import-spacing rule #1935
Changes from 13 commits
7883f69
4fc6bd6
e9be547
3652af3
659ecb1
9a3c767
2bb92f5
3be5f03
9d22b21
e1e1c4e
8e055db
ce6a1d3
afc57ad
8854c0a
3c5e081
9a53021
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--- | ||
ruleName: import-spacing | ||
description: Ensures proper spacing between import statement keywords | ||
optionsDescription: '' | ||
options: {} | ||
optionExamples: [] | ||
type: style | ||
typescriptOnly: false | ||
layout: rule | ||
title: 'Rule: import-spacing' | ||
optionsJSON: '{}' | ||
--- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* @license | ||
* Copyright 2013 Palantir Technologies, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import * as ts from "typescript"; | ||
|
||
import * as Lint from "../index"; | ||
|
||
const LINE_BREAK_REGEX = /\n|\r\n/; | ||
|
||
export class Rule extends Lint.Rules.AbstractRule { | ||
/* tslint:disable:object-literal-sort-keys */ | ||
public static metadata: Lint.IRuleMetadata = { | ||
ruleName: "import-spacing", | ||
description: "Ensures proper spacing between import statement keywords", | ||
optionsDescription: "", | ||
options: {}, | ||
optionExamples: [], | ||
type: "style", | ||
typescriptOnly: false, | ||
}; | ||
|
||
public static ADD_SPACE_AFTER_IMPORT = "Add space after import"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please feel free to correct my error wordings here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about some quotes: |
||
public static TOO_MANY_SPACES_AFTER_IMPORT = "Too many spaces after import"; | ||
public static ADD_SPACE_AFTER_STAR = "Add space after *"; | ||
public static TOO_MANY_SPACES_AFTER_STAR = "Too many spaces after *"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
public static ADD_SPACE_AFTER_FROM = "Add space after from"; | ||
public static TOO_MANY_SPACES_AFTER_FROM = "Too many spaces after from"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
public static ADD_SPACE_BEFORE_FROM = "Add space before from"; | ||
public static TOO_MANY_SPACES_BEFORE_FROM = "Too many spaces before from"; | ||
public static NO_LINE_BREAKS = "No line breaks are allowed in import declaration"; | ||
|
||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
const comparisonWalker = new ImportStatementWalker(sourceFile, this.getOptions()); | ||
return this.applyWithWalker(comparisonWalker); | ||
} | ||
} | ||
|
||
class ImportStatementWalker extends Lint.RuleWalker { | ||
private static IMPORT_KEYWORD_LENGTH = 6; // "import".length; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can just define it as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't it more performance friendly to do this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The perf difference is not measurable. See the jsperf run https://jsperf.com/str-length |
||
|
||
public visitImportDeclaration(node: ts.ImportDeclaration) { | ||
if (!node.importClause) { | ||
this.checkModuleWithSideEffect(node); | ||
} else { | ||
const nodeStart = node.getStart(); | ||
const importKeywordEnd = node.getStart() + ImportStatementWalker.IMPORT_KEYWORD_LENGTH; | ||
const moduleSpecifierStart = node.moduleSpecifier.getStart(); | ||
const importClauseEnd = node.importClause.getEnd(); | ||
const importClauseStart = node.importClause.getStart(); | ||
|
||
if (importKeywordEnd === importClauseStart) { | ||
this.addFailure(this.createFailure(nodeStart, ImportStatementWalker.IMPORT_KEYWORD_LENGTH, Rule.ADD_SPACE_AFTER_IMPORT)); | ||
} else if (importClauseStart > (importKeywordEnd + 1)) { | ||
this.addFailure(this.createFailure(nodeStart, importClauseStart - nodeStart, Rule.TOO_MANY_SPACES_AFTER_IMPORT)); | ||
} | ||
|
||
const fromString = node.getText().substring(importClauseEnd - nodeStart, moduleSpecifierStart - nodeStart); | ||
|
||
if (/from$/.test(fromString)) { | ||
this.addFailure(this.createFailure(importClauseEnd, fromString.length, Rule.ADD_SPACE_AFTER_FROM)); | ||
} | ||
if (/from\s{2,}$/.test(fromString)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
this.addFailure(this.createFailure(importClauseEnd, fromString.length, Rule.TOO_MANY_SPACES_AFTER_FROM)); | ||
} | ||
if (/^\s{2,}from/.test(fromString)) { | ||
this.addFailure(this.createFailure(importClauseEnd, fromString.length, Rule.TOO_MANY_SPACES_BEFORE_FROM)); | ||
} | ||
if (/^from/.test(fromString)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
this.addFailure(this.createFailure(importClauseEnd, fromString.length, Rule.ADD_SPACE_BEFORE_FROM)); | ||
} | ||
|
||
const text = node.getText(); | ||
const beforeImportClauseText = text.substring(0, importClauseStart - nodeStart); | ||
const afterImportClauseText = text.substring(importClauseEnd - nodeStart); | ||
if (LINE_BREAK_REGEX.test(beforeImportClauseText)) { | ||
this.addFailure(this.createFailure(nodeStart, importClauseStart - nodeStart - 1, Rule.NO_LINE_BREAKS)); | ||
} | ||
if (LINE_BREAK_REGEX.test(afterImportClauseText)) { | ||
this.addFailure(this.createFailure(importClauseEnd, node.getEnd() - importClauseEnd, Rule.NO_LINE_BREAKS)); | ||
} | ||
} | ||
super.visitImportDeclaration(node); | ||
} | ||
|
||
public visitNamespaceImport(node: ts.NamespaceImport) { | ||
const text = node.getText(); | ||
if (text.indexOf("*as") > -1) { | ||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.ADD_SPACE_AFTER_STAR)); | ||
} else if (/\*\s{2,}as/.test(text)) { | ||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.TOO_MANY_SPACES_AFTER_STAR)); | ||
} else if (LINE_BREAK_REGEX.test(text)) { | ||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.NO_LINE_BREAKS)); | ||
} | ||
super.visitNamespaceImport(node); | ||
} | ||
|
||
private checkModuleWithSideEffect(node: ts.ImportDeclaration) { | ||
const moduleSpecifierStart = node.moduleSpecifier.getStart(); | ||
const nodeStart = node.getStart(); | ||
if ((nodeStart + ImportStatementWalker.IMPORT_KEYWORD_LENGTH + 1) < moduleSpecifierStart) { | ||
this.addFailure(this.createFailure(nodeStart, moduleSpecifierStart - nodeStart, Rule.TOO_MANY_SPACES_AFTER_IMPORT)); | ||
} | ||
if ((nodeStart + ImportStatementWalker.IMPORT_KEYWORD_LENGTH) === moduleSpecifierStart) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
this.addFailure(this.createFailure(nodeStart, ImportStatementWalker.IMPORT_KEYWORD_LENGTH, Rule.ADD_SPACE_AFTER_IMPORT)); | ||
} | ||
if (LINE_BREAK_REGEX.test(node.getText())) { | ||
this.addFailure(this.createFailure(nodeStart, node.getWidth(), Rule.NO_LINE_BREAKS)); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// --------------------------------------------------------------------------------------------------------------------- | ||
// Module with side effect import | ||
// --------------------------------------------------------------------------------------------------------------------- | ||
// good | ||
import "styles.css"; | ||
|
||
// bad | ||
import"styles.css"; | ||
~~~~~~ [Add space after import] | ||
import "styles.css"; | ||
~~~~~~~~ [Too many spaces after import] | ||
import "styles.css"; | ||
~~~~~~~~~ [Too many spaces after import] | ||
|
||
import | ||
~~~~~~ | ||
"styles.css"; | ||
~~~~~~~~~~~~~ [No line breaks are allowed in import declaration] | ||
// --------------------------------------------------------------------------------------------------------------------- | ||
// Namespace import | ||
// --------------------------------------------------------------------------------------------------------------------- | ||
// good | ||
import * as ts from "typescript"; | ||
|
||
// bad | ||
import*as ts from "typescript"; | ||
~~~~~~ [Add space after import] | ||
~~~~~~ [Add space after *] | ||
import *as ts from "typescript"; | ||
~~~~~~ [Add space after *] | ||
import * as ts from "typescript"; | ||
~~~~~~~~ [Too many spaces after *] | ||
import * as ts from "typescript"; | ||
~~~~~~~~~ [Too many spaces after *] | ||
import* as ts from "typescript"; | ||
~~~~~~ [Add space after import] | ||
import * as ts from"typescript"; | ||
~~~~~ [Add space after from] | ||
import * as ts from "typescript"; | ||
~~~~~~~~ [Too many spaces after import] | ||
import * as ts from "typescript"; | ||
~~~~~~~~~~ [Too many spaces after import] | ||
import * as ts from "typescript"; | ||
~~~~~~~ [Too many spaces after from] | ||
import | ||
~~~~~~ [No line breaks are allowed in import declaration] | ||
* as ts from "typescript"; | ||
|
||
import * | ||
~ | ||
as ts from "typescript"; | ||
~~~~~ [No line breaks are allowed in import declaration] | ||
|
||
import * as | ||
~~~~ | ||
ts from "typescript"; | ||
~~ [No line breaks are allowed in import declaration] | ||
|
||
import * as ts | ||
~nil | ||
from "typescript"; | ||
~~~~~~~~~~~~~~~~~~ [No line breaks are allowed in import declaration] | ||
|
||
|
||
// --------------------------------------------------------------------------------------------------------------------- | ||
// Single-line import | ||
// --------------------------------------------------------------------------------------------------------------------- | ||
// good | ||
import {Expression} from "typescript"; | ||
|
||
// bad | ||
import{Expression}from"typescript"; | ||
~~~~~~ [Add space after import] | ||
~~~~ [Add space after from] | ||
~~~~ [Add space before from] | ||
import {Expression}from"typescript"; | ||
~~~~ [Add space after from] | ||
~~~~ [Add space before from] | ||
import {Expression} from"typescript"; | ||
~~~~~ [Add space after from] | ||
import {Expression} from "typescript"; | ||
~~~~~~~~ [Too many spaces after import] | ||
import {Expression} from "typescript"; | ||
~~~~~~~ [Too many spaces before from] | ||
import {Expression} from "typescript"; | ||
~~~~~~~ [Too many spaces after from] | ||
import {Expression} from "typescript"; | ||
~~~~~~~~ [Too many spaces after import] | ||
import {Expression} from "typescript"; | ||
~~~~~~~~~ [Too many spaces after import] | ||
|
||
import | ||
~~~~~~ [No line breaks are allowed in import declaration] | ||
{Expression} from "typescript"; | ||
|
||
import {Expression} | ||
~nil | ||
from "typescript"; | ||
~~~~~~~~~~~~~~~~~~ [No line breaks are allowed in import declaration] | ||
|
||
import {Expression} from | ||
~~~~~ | ||
"typescript"; | ||
~~~~~~~~~~~~~ [No line breaks are allowed in import declaration] | ||
|
||
// --------------------------------------------------------------------------------------------------------------------- | ||
// Multi-line import | ||
// --------------------------------------------------------------------------------------------------------------------- | ||
// good | ||
import { | ||
Expression | ||
} from "typescript"; | ||
|
||
// bad | ||
import{ | ||
~~~~~~ [Add space after import] | ||
Expression | ||
} from "typescript"; | ||
|
||
import {Expression | ||
}from "typescript"; | ||
~~~~~ [Add space before from] | ||
|
||
import { | ||
Expression | ||
} from"typescript"; | ||
~~~~~ [Add space after from] | ||
|
||
import { | ||
~~~~~~~~ [Too many spaces after import] | ||
Expression | ||
} from "typescript"; | ||
|
||
import { | ||
~~~~~~~~ [Too many spaces after import] | ||
Expression | ||
} from "typescript"; | ||
|
||
import { | ||
Expression | ||
} | ||
~nil | ||
from "typescript"; | ||
~~~~~~~~~~~~~~~~~~ [No line breaks are allowed in import declaration] | ||
|
||
import { | ||
Expression | ||
} from | ||
~~~~~ | ||
"typescript"; | ||
~~~~~~~~~~~~~ [No line breaks are allowed in import declaration] | ||
|
||
import | ||
~~~~~~ [No line breaks are allowed in import declaration] | ||
{ | ||
Expression | ||
} from "typescript" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"rules": { | ||
"import-spacing": true | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2016 (or 2017 if applicable)