diff --git a/CHANGELOG.md b/CHANGELOG.md index b12838e..e9b1e72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Change Log v2.1.0 --- * [new-fixer] `jasmine-no-lambda-expression-callbacks` +* [new-fixer] `import-barrels` +* [new-rule-option] `fixWithExplicitBarrelImport` added to `import-barrels` * [enhancement] Added preliminary checks for `jasmine-no-lambda-expression-callbacks` rule to skip walking file if there are no jasmine top-level statements. diff --git a/README.md b/README.md index 91fdce8..72d691d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ An argument object may be optionally provided, with the following properties: * `noExplicitBarrels = false`: disallows usage of explicitly named barrels in import statements (`import foo from './foo/index'`) * `fileExtensions = ['ts', 'js']`: uses the provided file extensions for module and barrel file lookup +* `fixWithExplicitBarrelImport`: uses the provided string to replace non-barrel imports in `--fix` mode + (i.e. when set to `'index'`, `import foo from './foo/some-module'` becomes `import foo from './foo/index'`) ## `jasmine-no-lambda-expression-callbacks` diff --git a/package.json b/package.json index a660b57..1d57c39 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "tslint": "^4.2.0", "tslint-microsoft-contrib": "^4.0.0", "typescript": "~2.1.4", - "yargs": "^6.0.0" + "yargs": "^6.6.0" }, "peerDependencies": { "tslint": "^4.0.0" diff --git a/runTests.js b/runTests.js index fe319d4..0d7d4ce 100644 --- a/runTests.js +++ b/runTests.js @@ -34,6 +34,7 @@ glob('src/tests/**/*.ts.lint', (error, files) => { const pathToBuildDir = path.resolve(dir, buildDir); const pathToCoverageDir = path.resolve(dir, coverageDir); + console.log(`=> running tests from: ${dir}`); child_process.execSync(getTestCommand(pathToBuildDir, pathToCoverageDir), { cwd: dir, stdio: 'inherit' diff --git a/src/importBarrelsRule.ts b/src/importBarrelsRule.ts index 02dc455..2689c83 100644 --- a/src/importBarrelsRule.ts +++ b/src/importBarrelsRule.ts @@ -1,10 +1,11 @@ import * as fs from 'fs'; import * as path from 'path'; -import { IRuleMetadata, RuleFailure, Rules, RuleWalker, Utils } from 'tslint/lib'; +import { Fix, IOptions, IRuleMetadata, Replacement, RuleFailure, Rules, RuleWalker, Utils } from 'tslint/lib'; import { Expression, ImportDeclaration, SourceFile, StringLiteral, SyntaxKind } from 'typescript'; +import { CachedStat } from './utils/cachedStat'; export class Rule extends Rules.AbstractRule { - public static metadata:IRuleMetadata = { + public static readonly metadata:IRuleMetadata = { ruleName: 'import-barrels', description: Utils.dedent` Enforces usage of barrels (\`index.ts\`) when importing from a directory that has a barrel file.`, @@ -17,7 +18,9 @@ export class Rule extends Rules.AbstractRule { An argument object may be optionally provided, with the following properties: * \`noExplicitBarrels = false\`: disallows usage of explicitly named barrels in import statements (\`import foo from './foo/index'\`) - * \`fileExtensions = ['ts', 'js']\`: uses the provided file extensions for module and barrel file lookup`, + * \`fileExtensions = ['ts', 'js']\`: uses the provided file extensions for module and barrel file lookup + * \`fixWithExplicitBarrelImport\`: uses the provided string to replace non-barrel imports in \`--fix\` mode + (i.e. when set to \`'index'\`, \`import foo from './foo/some-module'\` becomes \`import foo from './foo/index'\`)`, optionExamples: ['[true, {"noExplicitBarrels": false, "fileExtensions": ["ts", "js"]}]'], options: { type: 'array', @@ -34,6 +37,9 @@ export class Rule extends Rules.AbstractRule { }, minLength: 1, }, + fixWithExplicitBarrelImport: { + type: 'string', + }, }, }, minLength: 1, @@ -43,38 +49,66 @@ export class Rule extends Rules.AbstractRule { typescriptOnly: false, }; - public static USE_BARREL_FAILURE_STRING = 'Use barrel (index) files for imports if they are available for path: '; - public static NO_EXPLICIT_BARRELS_FAILURE_STRING = "Don't import barrel files by name, import containing directory instead for path: "; + public static readonly USE_BARREL_FAILURE_STRING = 'Use barrel (index) files for imports if they are available for path: '; + public static readonly NO_EXPLICIT_BARRELS_FAILURE_STRING = + "Don't import barrel files by name, import containing directory instead for path: "; + + public static readonly DEFAULT_OPTIONS = { + fileExtensions: ['ts', 'js'], + noExplicitBarrels: false, + fixWithExplicitBarrelImport: '' + }; public apply(sourceFile:SourceFile):RuleFailure[] { return this.applyWithWalker(new ImportBarrelsWalker(sourceFile, this.getOptions())); } } +enum CheckResult { + OK, + ExplicitBarrelsForbidden, + NonBarrelImport +} + class ImportBarrelsWalker extends RuleWalker { - private statCache = new Map(); + private static readonly resultErrorMap = { + [CheckResult.NonBarrelImport]: Rule.USE_BARREL_FAILURE_STRING, + [CheckResult.ExplicitBarrelsForbidden]: Rule.NO_EXPLICIT_BARRELS_FAILURE_STRING, + }; + private readonly cachedStat = new CachedStat(); + private readonly ruleOptions:typeof Rule.DEFAULT_OPTIONS; + + constructor(sourceFile:SourceFile, options:IOptions) { + super(sourceFile, options); + + this.ruleOptions = Object.assign({}, Rule.DEFAULT_OPTIONS, this.getOptions()[0] || {}); + } protected visitImportDeclaration(node:ImportDeclaration) { const moduleExpression = node.moduleSpecifier; - const moduleExpressionError = this.getModuleExpressionErrorMessage(moduleExpression); - - if (moduleExpressionError) { - this.addFailureAtNode(moduleExpression, moduleExpressionError); + const expressionCheckResult = this.checkModuleExpression(moduleExpression); + + if (expressionCheckResult !== CheckResult.OK) { + this.addFailureAtNode( + moduleExpression, + ImportBarrelsWalker.resultErrorMap[expressionCheckResult] + moduleExpression.getText(), + this.getFix(moduleExpression, expressionCheckResult) + ); } super.visitImportDeclaration(node); } - private getModuleExpressionErrorMessage(expression:Expression):string|null { + private checkModuleExpression(expression:Expression):CheckResult { if (expression.kind !== SyntaxKind.StringLiteral) { - return null; + return CheckResult.OK; } const modulePathText = (expression).text; // check only relative paths if (!modulePathText.startsWith('.')) { - return null; + return CheckResult.OK; } const sourceFileRelative = this.getSourceFile().path; @@ -85,80 +119,49 @@ class ImportBarrelsWalker extends RuleWalker { // enforce barrel usage only on files that are not in the same directory or in one of the sub-directories // of the module if (sourceFileDirAbsolute.startsWith(moduleDirAbsolute)) { - return null; + return CheckResult.OK; } const moduleStats = this.getModuleStats(moduleAbsolute); // only file imports are of interest if (!moduleStats || moduleStats.isDirectory()) { - return null; + return CheckResult.OK; } // if module's name is 'index', it must be an explicit barrel import, dirs were excluded earlier if (path.parse(moduleAbsolute).name === 'index') { - return this.getExplicitBarrelsAllowed() ? null : Rule.NO_EXPLICIT_BARRELS_FAILURE_STRING + expression.getText(); + return this.ruleOptions.noExplicitBarrels ? CheckResult.ExplicitBarrelsForbidden : CheckResult.OK; } - return this.getModuleFileExtensions() + const dirHasBarrelFile = this.ruleOptions.fileExtensions .map(ext => path.join(moduleDirAbsolute, `index.${ext}`)) - .some(file => this.isFile(file)) ? Rule.USE_BARREL_FAILURE_STRING + expression.getText() : null; + .some(file => this.cachedStat.isFile(file)); + + return dirHasBarrelFile ? CheckResult.NonBarrelImport : CheckResult.OK; } private getModuleStats(modulePath:string):fs.Stats|null { - let stats = this.cachedStatSync(modulePath); + const modulePathCandidates = [modulePath, ...this.ruleOptions.fileExtensions.map(suffix => `${modulePath}.${suffix}`)]; - if (!stats) { - this.getModuleFileExtensions().some(suffix => { - stats = this.cachedStatSync(`${modulePath}.${suffix}`); - return stats !== null; - }); - } + let stats:fs.Stats|null = null; + modulePathCandidates.some(modulePathCandidate => { + stats = this.cachedStat.statSync(modulePathCandidate); + return stats !== null; + }); return stats; } - private getModuleFileExtensions():string[] { - let extensions = this.getOptionsObject().fileExtensions || []; - - if (!extensions.length) { - extensions = ['ts', 'js']; - } - return extensions; - } - - private getExplicitBarrelsAllowed():boolean { - const {noExplicitBarrels = false} = this.getOptionsObject(); - - return !noExplicitBarrels; - } - - private getOptionsObject():{fileExtensions?:string[], noExplicitBarrels?:boolean} { - return this.getOptions()[0] || {}; - } + private getFix(moduleSpecifier:StringLiteral, checkResult:CheckResult):Fix { + let replacement = path.dirname(moduleSpecifier.text); - private isFile(path:string):boolean { - const stats = this.cachedStatSync(path); - return stats != null && stats.isFile(); - } - - private cachedStatSync(path:string):fs.Stats|null { - if (this.statCache.has(path)) { - return this.statCache.get(path); - } - - const stat = this.statSync(path); - if (stat !== null) { - this.statCache.set(path, stat); + if (checkResult === CheckResult.NonBarrelImport && this.ruleOptions.fixWithExplicitBarrelImport) { + replacement += `/${this.ruleOptions.fixWithExplicitBarrelImport}`; } - return stat; - } - private statSync(path:string):fs.Stats|null { - try { - return fs.statSync(path); - } catch (e) { - return null; - } + return new Fix(Rule.metadata.ruleName, [ + // account for quotes + new Replacement(moduleSpecifier.getStart() + 1, moduleSpecifier.getWidth() - `''`.length, replacement)]); } } diff --git a/src/jasmineNoLambdaExpressionCallbacksRule.ts b/src/jasmineNoLambdaExpressionCallbacksRule.ts index d2821e7..b610d94 100644 --- a/src/jasmineNoLambdaExpressionCallbacksRule.ts +++ b/src/jasmineNoLambdaExpressionCallbacksRule.ts @@ -4,7 +4,7 @@ import { isJasmineDescribe, isJasmineIt, isJasmineSetupTeardown, isJasmineTest } import find = require('lodash/find'); export class Rule extends Rules.AbstractRule { - public static metadata:IRuleMetadata = { + public static readonly metadata:IRuleMetadata = { ruleName: 'jasmine-no-lambda-expression-callbacks', description: Utils.dedent` Disallows usage of ES6-style lambda expressions as callbacks to Jasmine BDD functions.`, @@ -32,7 +32,7 @@ export class Rule extends Rules.AbstractRule { typescriptOnly: false, }; - public static FAILURE_STRING = "Don't use lambda expressions as callbacks to jasmine functions"; + public static readonly FAILURE_STRING = "Don't use lambda expressions as callbacks to jasmine functions"; public apply(sourceFile:SourceFile):RuleFailure[] { return this.applyWithWalker(new JasmineNoLambdaExpressionCallbacksWalker(sourceFile, this.getOptions())); diff --git a/src/tests/importBarrels/default/default.ts.fix b/src/tests/importBarrels/default/default.ts.fix new file mode 100644 index 0000000..602c02d --- /dev/null +++ b/src/tests/importBarrels/default/default.ts.fix @@ -0,0 +1,10 @@ +import relativeFromNonBarrel from './dir-with-barrel'; +import relativeFromNonBarrelWithIndexLikeName from './dir-with-barrel'; + +// following should be OK +import relativeFromBarrel from './dir-with-barrel'; +import relativeFromBarrelExplicit from './dir-with-barrel/index'; +import relativeFromDirWithoutBarrel from './dir-without-barrel/some-module'; +import relativeFromSameDirWithBarrel from './some-module'; +import relativeFromSameDirWithBarrelExplicit from './index'; +import absoluteFromLib from 'lib'; diff --git a/src/tests/importBarrels/default/importBarrelsRuleDefault.ts.lint b/src/tests/importBarrels/default/default.ts.lint similarity index 97% rename from src/tests/importBarrels/default/importBarrelsRuleDefault.ts.lint rename to src/tests/importBarrels/default/default.ts.lint index 3a82be7..27fd21d 100644 --- a/src/tests/importBarrels/default/importBarrelsRuleDefault.ts.lint +++ b/src/tests/importBarrels/default/default.ts.lint @@ -2,6 +2,8 @@ import relativeFromNonBarrel from './dir-with-barrel/some-module'; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Use barrel (index) files for imports if they are available for path: './dir-with-barrel/some-module'] import relativeFromNonBarrelWithIndexLikeName from './dir-with-barrel/some-module-index'; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Use barrel (index) files for imports if they are available for path: './dir-with-barrel/some-module-index'] + +// following should be OK import relativeFromBarrel from './dir-with-barrel'; import relativeFromBarrelExplicit from './dir-with-barrel/index'; import relativeFromDirWithoutBarrel from './dir-without-barrel/some-module'; diff --git a/src/tests/importBarrels/fixWithExplicitBarrelImport/dir-with-barrel/index.ts b/src/tests/importBarrels/fixWithExplicitBarrelImport/dir-with-barrel/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/importBarrels/fixWithExplicitBarrelImport/dir-with-barrel/some-module-index.ts b/src/tests/importBarrels/fixWithExplicitBarrelImport/dir-with-barrel/some-module-index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/importBarrels/fixWithExplicitBarrelImport/dir-with-barrel/some-module.ts b/src/tests/importBarrels/fixWithExplicitBarrelImport/dir-with-barrel/some-module.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/importBarrels/fixWithExplicitBarrelImport/fixWithExplicitBarrelImport.ts.fix b/src/tests/importBarrels/fixWithExplicitBarrelImport/fixWithExplicitBarrelImport.ts.fix new file mode 100644 index 0000000..f284c3a --- /dev/null +++ b/src/tests/importBarrels/fixWithExplicitBarrelImport/fixWithExplicitBarrelImport.ts.fix @@ -0,0 +1,2 @@ +import relativeFromNonBarrel from './dir-with-barrel/index.ts'; +import relativeFromNonBarrelWithIndexLikeName from './dir-with-barrel/index.ts'; diff --git a/src/tests/importBarrels/fixWithExplicitBarrelImport/fixWithExplicitBarrelImport.ts.lint b/src/tests/importBarrels/fixWithExplicitBarrelImport/fixWithExplicitBarrelImport.ts.lint new file mode 100644 index 0000000..8c9d52e --- /dev/null +++ b/src/tests/importBarrels/fixWithExplicitBarrelImport/fixWithExplicitBarrelImport.ts.lint @@ -0,0 +1,4 @@ +import relativeFromNonBarrel from './dir-with-barrel/some-module'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Use barrel (index) files for imports if they are available for path: './dir-with-barrel/some-module'] +import relativeFromNonBarrelWithIndexLikeName from './dir-with-barrel/some-module-index'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Use barrel (index) files for imports if they are available for path: './dir-with-barrel/some-module-index'] diff --git a/src/tests/importBarrels/fixWithExplicitBarrelImport/tslint.json b/src/tests/importBarrels/fixWithExplicitBarrelImport/tslint.json new file mode 100644 index 0000000..23d7a67 --- /dev/null +++ b/src/tests/importBarrels/fixWithExplicitBarrelImport/tslint.json @@ -0,0 +1,13 @@ +{ + "rulesDirectory": [ + "../../../../dist" + ], + "rules": { + "import-barrels": [ + true, + { + "fixWithExplicitBarrelImport": "index.ts" + } + ] + } +} diff --git a/src/tests/importBarrels/no-explicit-barrels/noExplicitBarrels.ts.fix b/src/tests/importBarrels/no-explicit-barrels/noExplicitBarrels.ts.fix new file mode 100644 index 0000000..7ebad40 --- /dev/null +++ b/src/tests/importBarrels/no-explicit-barrels/noExplicitBarrels.ts.fix @@ -0,0 +1,5 @@ +import relativeFromBarrelExplicit from './dir-with-barrel'; + +// following should be OK +import relativeFromBarrel from './dir-with-barrel'; +import relativeFromNonBarrelWithIndexLikeName from './dir-without-barrel/some-module-index'; diff --git a/src/tests/importBarrels/no-explicit-barrels/importBarrelRulesNoExplicitBarrels.ts.lint b/src/tests/importBarrels/no-explicit-barrels/noExplicitBarrels.ts.lint similarity index 93% rename from src/tests/importBarrels/no-explicit-barrels/importBarrelRulesNoExplicitBarrels.ts.lint rename to src/tests/importBarrels/no-explicit-barrels/noExplicitBarrels.ts.lint index 3ffb052..796628e 100644 --- a/src/tests/importBarrels/no-explicit-barrels/importBarrelRulesNoExplicitBarrels.ts.lint +++ b/src/tests/importBarrels/no-explicit-barrels/noExplicitBarrels.ts.lint @@ -1,5 +1,6 @@ import relativeFromBarrelExplicit from './dir-with-barrel/index'; ~~~~~~~~~~~~~~~~~~~~~~~~~ [Don't import barrel files by name, import containing directory instead for path: './dir-with-barrel/index'] +// following should be OK import relativeFromBarrel from './dir-with-barrel'; import relativeFromNonBarrelWithIndexLikeName from './dir-without-barrel/some-module-index'; diff --git a/src/tests/importBarrels/with-extension-list/withExtensionList.ts.fix b/src/tests/importBarrels/with-extension-list/withExtensionList.ts.fix new file mode 100644 index 0000000..7e277aa --- /dev/null +++ b/src/tests/importBarrels/with-extension-list/withExtensionList.ts.fix @@ -0,0 +1,4 @@ +import relativeFromNonBarrel from './dir-with-barrel'; + +// following should be OK +import relativeFromNonBarrelWithIndexName from './dir-with-barrel/some-module-index'; diff --git a/src/tests/importBarrels/with-extension-list/importBarrelRulesWithExtensionList.ts.lint b/src/tests/importBarrels/with-extension-list/withExtensionList.ts.lint similarity index 92% rename from src/tests/importBarrels/with-extension-list/importBarrelRulesWithExtensionList.ts.lint rename to src/tests/importBarrels/with-extension-list/withExtensionList.ts.lint index 4ae3e81..94fa19d 100644 --- a/src/tests/importBarrels/with-extension-list/importBarrelRulesWithExtensionList.ts.lint +++ b/src/tests/importBarrels/with-extension-list/withExtensionList.ts.lint @@ -1,3 +1,5 @@ import relativeFromNonBarrel from './dir-with-barrel/some-module'; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Use barrel (index) files for imports if they are available for path: './dir-with-barrel/some-module'] + +// following should be OK import relativeFromNonBarrelWithIndexName from './dir-with-barrel/some-module-index'; diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefault.ts.fix b/src/tests/jasmineNoLambdaExpressionCallbacks/default/default.ts.fix similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefault.ts.fix rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/default.ts.fix diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefault.ts.lint b/src/tests/jasmineNoLambdaExpressionCallbacks/default/default.ts.lint similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefault.ts.lint rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/default.ts.lint diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE1.ts.fix b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE1.ts.fix similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE1.ts.fix rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE1.ts.fix diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE1.ts.lint b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE1.ts.lint similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE1.ts.lint rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE1.ts.lint diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE2.ts.fix b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE2.ts.fix similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE2.ts.fix rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE2.ts.fix diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE2.ts.lint b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE2.ts.lint similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE2.ts.lint rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE2.ts.lint diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE3.ts.fix b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE3.ts.fix similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE3.ts.fix rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE3.ts.fix diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE3.ts.lint b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE3.ts.lint similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultIIFE3.ts.lint rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWithIIFE3.ts.lint diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultWrapped.ts.fix b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWrapped.ts.fix similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultWrapped.ts.fix rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWrapped.ts.fix diff --git a/src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultWrapped.ts.lint b/src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWrapped.ts.lint similarity index 100% rename from src/tests/jasmineNoLambdaExpressionCallbacks/default/jasmineNoLambdaExpressionCallbacksRuleDefaultWrapped.ts.lint rename to src/tests/jasmineNoLambdaExpressionCallbacks/default/defaultWrapped.ts.lint diff --git a/src/utils/cachedStat.ts b/src/utils/cachedStat.ts new file mode 100644 index 0000000..cb09bdc --- /dev/null +++ b/src/utils/cachedStat.ts @@ -0,0 +1,30 @@ +import * as fs from 'fs'; + +export class CachedStat { + private readonly statCache = new Map(); + + public statSync(path:string):fs.Stats|null { + if (this.statCache.has(path)) { + return this.statCache.get(path); + } + + const stat = this.statSyncUncached(path); + if (stat !== null) { + this.statCache.set(path, stat); + } + return stat; + } + + public isFile(path:string):boolean { + const stats = this.statSync(path); + return stats != null && stats.isFile(); + } + + private statSyncUncached(path:string):fs.Stats|null { + try { + return fs.statSync(path); + } catch (e) { + return null; + } + } +} diff --git a/src/utils/languageUtils.ts b/src/utils/languageUtils.ts index 95f9cfe..c05c00d 100644 --- a/src/utils/languageUtils.ts +++ b/src/utils/languageUtils.ts @@ -1,11 +1,5 @@ import { unwrapParentheses } from 'tslint'; -import { - Block, - CallExpression, - Expression, - FunctionExpression, - SyntaxKind -} from 'typescript'; +import { Block, CallExpression, Expression, FunctionExpression, SyntaxKind } from 'typescript'; export function getIIFEExpressionBody(expression:Expression):Block|null { if (expression.kind === SyntaxKind.CallExpression) { diff --git a/yarn.lock b/yarn.lock index b1181df..f20783d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -277,8 +277,8 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" diff@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.1.0.tgz#9406c73a401e6c2b3ba901c5e2c44eb6a60c5385" + version "3.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" dot-prop@^3.0.0: version "3.0.0" @@ -340,8 +340,8 @@ extsprintf@1.0.2: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" fast-levenshtein@~2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" filled-array@^1.0.0: version "1.1.0" @@ -650,8 +650,8 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" jsonpointer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jsprim@^1.2.2: version "1.3.1" @@ -709,8 +709,8 @@ load-json-file@^1.0.0: strip-bom "^2.0.0" lodash@^4.17.3: - version "4.17.3" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.3.tgz#557ed7d2a9438cac5fd5a43043ca60cb455e01f7" + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" log-driver@1.2.5: version "1.2.5" @@ -1131,8 +1131,8 @@ supports-color@^3.1.0: has-flag "^1.0.0" timed-out@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.0.tgz#43b98b14bb712c9161c28f4dc1f3068d67a04ec2" + version "3.1.3" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217" tough-cookie@~2.3.0: version "2.3.2" @@ -1260,10 +1260,6 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -1315,9 +1311,9 @@ yargs-parser@^4.2.0: dependencies: camelcase "^3.0.0" -yargs@^6.0.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.5.0.tgz#a902e23a1f0fe912b2a03f6131b7ed740c9718ff" +yargs@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" dependencies: camelcase "^3.0.0" cliui "^3.2.0" @@ -1330,7 +1326,6 @@ yargs@^6.0.0: set-blocking "^2.0.0" string-width "^1.0.2" which-module "^1.0.0" - window-size "^0.2.0" y18n "^3.2.1" yargs-parser "^4.2.0"