From 197fbd38d0fe1eb8ad3e5e9d167bf5c53b7e12e9 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Tue, 2 May 2017 14:21:22 -0400 Subject: [PATCH 1/7] Add `outputAbsolutePaths` option fixes #1794 fixes #2462 --- docs/usage/cli/index.md | 4 +++ package.json | 1 + src/runner.ts | 25 ++++++++++++++++--- src/tslint-cli.ts | 6 +++++ test/runner/runnerTests.ts | 50 ++++++++++++++++++++++++++++++++++++++ test/utils.ts | 2 +- yarn.lock | 33 ++++++++++++++++++++++++- 7 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 test/runner/runnerTests.ts diff --git a/docs/usage/cli/index.md b/docs/usage/cli/index.md index af4e603c775..f6896f04f24 100644 --- a/docs/usage/cli/index.md +++ b/docs/usage/cli/index.md @@ -40,6 +40,7 @@ Options: -h, --help display detailed help -i, --init generate a tslint.json config file in the current working directory -o, --out output file +--outputAbsolutePaths whether or not outputted file paths are absolute -p, --project tsconfig.json file -r, --rules-dir rules directory -s, --formatters-dir formatters directory @@ -89,6 +90,9 @@ tslint accepts the following command-line options: A filename to output the results to. By default, tslint outputs to stdout, which is usually the console where you're running it from. +--outputAbsolutePaths: + Indicates whether or not outputted file paths are absolute paths. + -r, --rules-dir: An additional rules directory, for user-created rules. tslint will always check its default rules directory, in diff --git a/package.json b/package.json index 2ca4cc088e6..48f15e355df 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "github": "^8.1.1", "js-yaml": "^3.7.0", "json-stringify-pretty-compact": "^1.0.3", + "memory-streams": "^0.1.2", "mocha": "^3.2.0", "npm-run-all": "^3.1.0", "nyc": "^10.2.0", diff --git a/src/runner.ts b/src/runner.ts index 264fc64a657..b9fec636778 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -76,6 +76,11 @@ export interface IRunnerOptions { */ out?: string; + /** + * Whether to output absolute paths + */ + outputAbsolutePaths?: boolean; + /** * tsconfig.json file. */ @@ -159,8 +164,15 @@ export class Runner { // emit any error messages let message = ts.DiagnosticCategory[diag.category]; if (diag.file) { - const {line, character} = diag.file.getLineAndCharacterOfPosition(diag.start); - message += ` at ${diag.file.fileName}:${line + 1}:${character + 1}:`; + const { line, character } = diag.file.getLineAndCharacterOfPosition(diag.start); + let file: string; + const currentDirectory = program!.getCurrentDirectory(); + if (this.options.outputAbsolutePaths) { + file = path.resolve(currentDirectory, diag.file.fileName); + } else { + file = path.relative(currentDirectory, diag.file.fileName); + } + message += ` at ${file}:${line + 1}:${character + 1}:`; } message += " " + ts.flattenDiagnosticMessageText(diag.messageText, "\n"); return message; @@ -188,7 +200,14 @@ export class Runner { // remove single quotes which break matching on Windows when glob is passed in single quotes .map(Runner.trimSingleQuotes) .map((file: string) => glob.sync(file, { ignore: ignorePatterns, nodir: true })) - .reduce((a: string[], b: string[]) => a.concat(b), []); + .reduce((a: string[], b: string[]) => a.concat(b), []) + .map((file: string) => { + // tslint:disable + if (this.options.outputAbsolutePaths) { + return path.resolve(file); + } + return path.relative(process.cwd(), file); + }); try { this.processFiles(onComplete, files, program); diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index ab88b32073f..4249cef3543 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -33,6 +33,7 @@ interface Argv { init?: boolean; o?: string; out?: string; + outputAbsolutePaths?: boolean; p?: string; project?: string; r?: string; @@ -93,6 +94,10 @@ const processed = optimist describe: "output file", type: "string", }, + "outputAbsolutePaths": { + describe: "whether or not outputted file paths are absolute", + type: "boolean", + }, "p": { alias: "project", describe: "tsconfig.json file", @@ -237,6 +242,7 @@ const options: IRunnerOptions = { formattersDirectory: argv.s, init: argv.init, out: argv.out, + outputAbsolutePaths: argv.outputAbsolutePaths, project: argv.p, rulesDirectory: argv.r, test: argv.test, diff --git a/test/runner/runnerTests.ts b/test/runner/runnerTests.ts new file mode 100644 index 00000000000..145c83a7ace --- /dev/null +++ b/test/runner/runnerTests.ts @@ -0,0 +1,50 @@ +/* + * 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 { assert } from "chai"; +import * as streams from "memory-streams"; +import { Runner } from "../../src/runner"; +import { IRunnerOptions } from "./../../src/runner"; + +const customRulesOptions: IRunnerOptions = { + config: "./test/config/tslint-custom-rules.json", + files: ["src/test.ts"], + rulesDirectory: "./test/files/custom-rules", +}; + +describe("Runner Tests", () => { + it("outputs absolute path with --outputAbsolutePaths", () => { + const output = runLint({ ...customRulesOptions, outputAbsolutePaths: true }); + assert.include(output, "ERROR: /"); + }); + + it("outputs relative path without --outputAbsolutePaths", () => { + const output = runLint(customRulesOptions); + assert.include(output, "ERROR: src/"); + }); +}); + +function runLint(options: IRunnerOptions, callback?: (status: number) => void) { + const output = new streams.WritableStream(); + const runner = new Runner(options, output); + if (callback === undefined) { + callback = () => { + // do nothing + }; + } + runner.run(callback); + return output.toString(); +} diff --git a/test/utils.ts b/test/utils.ts index fecf7456b6c..feaf60346ab 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -45,7 +45,7 @@ export function createTempFile(extension: string) { if (tmpfile == null) { throw new Error("Couldn't create temp file"); } - return tmpfile; + return path.relative(process.cwd(), tmpfile); } // converts Windows normalized paths (with backwards slash `\`) to paths used by TypeScript (with forward slash `/`) diff --git a/yarn.lock b/yarn.lock index ca7552ddd0d..305be9e1778 100644 --- a/yarn.lock +++ b/yarn.lock @@ -331,6 +331,10 @@ core-js@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + cross-spawn@^4, cross-spawn@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" @@ -656,7 +660,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -756,6 +760,10 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -951,6 +959,12 @@ md5-o-matic@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" +memory-streams@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" + dependencies: + readable-stream "~1.0.2" + merge-source-map@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.3.tgz#da1415f2722a5119db07b14c4f973410863a2abf" @@ -1226,6 +1240,15 @@ read-pkg@^1.0.0, read-pkg@^1.1.0: normalize-package-data "^2.3.2" path-type "^1.0.0" +readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + regenerator-runtime@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" @@ -1389,6 +1412,10 @@ string.prototype.padend@^3.0.0: es-abstract "^1.4.3" function-bind "^1.0.2" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -1433,6 +1460,10 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +tslib@^1.6.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.6.1.tgz#b77b09abc5fa4935e157d838b80e36dad47152c4" + "tslint-test-config-non-relative@file:test/external/tslint-test-config-non-relative": version "0.0.1" From b9fe6b72afd5ed434d75f68097af7ea1e459f071 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 5 May 2017 09:15:38 -0700 Subject: [PATCH 2/7] fix test for windows --- test/runner/runnerTests.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/runner/runnerTests.ts b/test/runner/runnerTests.ts index 145c83a7ace..f5dd3300980 100644 --- a/test/runner/runnerTests.ts +++ b/test/runner/runnerTests.ts @@ -28,7 +28,9 @@ const customRulesOptions: IRunnerOptions = { describe("Runner Tests", () => { it("outputs absolute path with --outputAbsolutePaths", () => { const output = runLint({ ...customRulesOptions, outputAbsolutePaths: true }); - assert.include(output, "ERROR: /"); + + // match either a path starting with `/` or something like `C:\` + assert.isTrue(/ERROR: (\/|\w+:\\)/.test(output)); }); it("outputs relative path without --outputAbsolutePaths", () => { From 7fadda1e3aada9925c603462672f3d51af4601a2 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 5 May 2017 09:34:59 -0700 Subject: [PATCH 3/7] don't include slash in regex --- src/runner.ts | 1 - test/runner/runnerTests.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/runner.ts b/src/runner.ts index b9fec636778..872ec609c27 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -202,7 +202,6 @@ export class Runner { .map((file: string) => glob.sync(file, { ignore: ignorePatterns, nodir: true })) .reduce((a: string[], b: string[]) => a.concat(b), []) .map((file: string) => { - // tslint:disable if (this.options.outputAbsolutePaths) { return path.resolve(file); } diff --git a/test/runner/runnerTests.ts b/test/runner/runnerTests.ts index f5dd3300980..cfc2926935d 100644 --- a/test/runner/runnerTests.ts +++ b/test/runner/runnerTests.ts @@ -29,8 +29,8 @@ describe("Runner Tests", () => { it("outputs absolute path with --outputAbsolutePaths", () => { const output = runLint({ ...customRulesOptions, outputAbsolutePaths: true }); - // match either a path starting with `/` or something like `C:\` - assert.isTrue(/ERROR: (\/|\w+:\\)/.test(output)); + // match either a path starting with `/` or something like `C:` + assert.isTrue(/ERROR: (\/|\w:)/.test(output)); }); it("outputs relative path without --outputAbsolutePaths", () => { From 29772730f9a334fc96934287e67ba9d1fb4d0a5f Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 5 May 2017 09:55:57 -0700 Subject: [PATCH 4/7] attempt windows test fix --- test/executable/executableTests.ts | 2 +- test/utils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index ed63721a2f0..afddb89a64d 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -156,7 +156,7 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { fs.unlinkSync(tempFile); assert.strictEqual(content, "import * as y from \"a_long_module\";\nimport * as x from \"b\";\n"); assert.isNull(err, "process should exit without an error"); - assert.strictEqual(stdout, `Fixed 2 error(s) in ${denormalizedFileName}`); + assert.strictEqual(stdout, `Fixed 2 error(s) in ${path.relative(process.cwd(), denormalizedFileName)}`); done(); }); }); diff --git a/test/utils.ts b/test/utils.ts index feaf60346ab..fecf7456b6c 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -45,7 +45,7 @@ export function createTempFile(extension: string) { if (tmpfile == null) { throw new Error("Couldn't create temp file"); } - return path.relative(process.cwd(), tmpfile); + return tmpfile; } // converts Windows normalized paths (with backwards slash `\`) to paths used by TypeScript (with forward slash `/`) From cd296fcf42ecf490572f05b189f4d280ab5dad60 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 5 May 2017 15:07:36 -0700 Subject: [PATCH 5/7] try to fix for windows --- src/linter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linter.ts b/src/linter.ts index e85eb77fd8c..40994777980 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -186,7 +186,7 @@ class Linter { let source = fs.readFileSync(currentFileName, { encoding: "utf-8" }); source = Replacement.applyFixes(source, fixesForFile); fs.writeFileSync(currentFileName, source, { encoding: "utf-8" }); - if (sourceFilePath === currentFileName) { + if (path.resolve(sourceFilePath) === path.resolve(currentFileName)) { result = source; } }); From 07377b29147907a7082881d847b29c2c8d1cb3b3 Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 5 May 2017 20:46:37 -0700 Subject: [PATCH 6/7] attempt # 928 to fix the windows test --- test/executable/executableTests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index afddb89a64d..d97a03e763b 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -146,7 +146,7 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { describe("--fix flag", () => { it("fixes multiple rules without overwriting each other", (done) => { - const tempFile = createTempFile("ts"); + const tempFile = path.relative(process.cwd(), createTempFile("ts")); fs.createReadStream("test/files/multiple-fixes-test/multiple-fixes.test.ts").pipe(fs.createWriteStream(tempFile)); execCli(["-c", "test/files/multiple-fixes-test/tslint.json", tempFile, "--fix"], (err, stdout) => { @@ -156,7 +156,7 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { fs.unlinkSync(tempFile); assert.strictEqual(content, "import * as y from \"a_long_module\";\nimport * as x from \"b\";\n"); assert.isNull(err, "process should exit without an error"); - assert.strictEqual(stdout, `Fixed 2 error(s) in ${path.relative(process.cwd(), denormalizedFileName)}`); + assert.strictEqual(stdout, `Fixed 2 error(s) in ${denormalizedFileName}`); done(); }); }); From e79cb237f6062468af90bee2fb868af92c3a758f Mon Sep 17 00:00:00 2001 From: Noah Chen Date: Fri, 5 May 2017 21:02:40 -0700 Subject: [PATCH 7/7] Update runnerTests.ts --- test/runner/runnerTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runner/runnerTests.ts b/test/runner/runnerTests.ts index cfc2926935d..5036b6bc735 100644 --- a/test/runner/runnerTests.ts +++ b/test/runner/runnerTests.ts @@ -1,5 +1,5 @@ /* - * Copyright 2013 Palantir Technologies, Inc. + * Copyright 2017 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.