-
Notifications
You must be signed in to change notification settings - Fork 887
Implement --stdin and --stdin-filename CLI options #3816
Conversation
Thanks for your interest in palantir/tslint, @w0rp! Before we can accept your pull request, you need to sign our contributor license agreement - just visit https://cla.palantir.com/ and follow the instructions. Once you sign, I'll automatically update this pull request. |
Also, fixing code via --stdin should be considered, but I'd probably focus on getting checking for errors implemented first, and implement fixing problems automatically second. It's worth keeping it in mind while working on this. |
I'd appreciate some feedback on this if anyone wants to take a look. I imagine quite a bit more work will need to be done before this is good enough. |
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.
Changes are required to pass tests
src/runner.ts
Outdated
@@ -157,7 +167,9 @@ async function runWorker(options: Options, logger: Logger): Promise<Status> { | |||
} | |||
|
|||
async function runLinter(options: Options, logger: Logger): Promise<LintResult> { | |||
const { files, program } = resolveFilesAndProgram(options, logger); | |||
const program = resolveProgram(options); | |||
const files = await resolveFiles(options, program, logger); |
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.
You aren't returning a Promise
here.
src/runner.ts
Outdated
function resolveFilesAndProgram( | ||
{ files, project, exclude, outputAbsolutePaths }: Options, | ||
/** Read the stdin stream into a string with all of the contents. */ | ||
function readStdin(): Promise<string> { |
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.
The signature should be:
async function readStdin(): Promise<string>
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.
Sure.
src/tslint-cli.ts
Outdated
console.error("No files specified. Use --project to lint a project folder."); | ||
process.exit(1); | ||
} | ||
|
||
if (argv.stdin && !argv.stdinFilename) { |
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.
strict-boolean-expressions
forces this expression to be:
if (arg.stdin && argv.stdinFilename !== undefined) {
// code...
}
Thanks for the feedback. I'd appreciate some in-depth feedback about how to handle just |
Perhaps you should also change the subject of the commit, maybe something like:
|
Hey @w0rp thank you for your contribution! Just wanted to let you know that I'll be looking into this PR probably sometimes next week (swamped with work this week). I think that this is really interesting and can be a very powerful feature. |
Okay, sounds good. Thanks for letting me know. 👍 |
src/runner.ts
Outdated
|
||
process.stdin.on("error", (error: Error) => { | ||
reject(error); | ||
}); |
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.
indentation is wrong throughout this file. some 4 spaces, some 2 spaces.
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.
I'll fix that when I get the time. I haven't managed to get tslint running on tslint code itself yet.
src/runner.ts
Outdated
stdin?: boolean; | ||
|
||
/** | ||
* Tell TSLint where the file for some stdin data is. |
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.
this language is awkward. what is "some stdin data?" please clarify this before merging.
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.
Throw whatever string you want at me, and I'll write that.
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.
How about:
Tell TSLint where the actual file being linted through stdin is, if any.
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.
Okay, done. 👍
@suchanlee Will you have some time to look at this soon? I'm not familiar with the TSLint codebase at all, but I'm willing to do the work to get this feature done, with some guidance. I get reports of issues with TSLint integration with ALE pretty much every week. |
src/runner.ts
Outdated
stdin?: boolean; | ||
|
||
/** | ||
* Tell TSLint where the file for some stdin data is. |
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.
How about:
Tell TSLint where the actual file being linted through stdin is, if any.
if (program !== undefined) { | ||
|
||
if (resolvedFile.isStdin) { | ||
contents = await readStdin(); |
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.
is --std-filename
being ignored when actually fetching content with --std
?
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.
Essentially yes. The filename is a hint for where the file is, and the data comes from stdin.
src/tslint-cli.ts
Outdated
|| argv.project !== undefined | ||
|| commander.args.length > 0 | ||
|| argv.stdin | ||
)) { | ||
console.error("No files specified. Use --project to lint a project folder."); |
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.
might be a good idea to mention --stdin
here
src/runner.ts
Outdated
// Use a filename for shadowing stdin, if the option is set. | ||
return [{filename: path.resolve(stdinFilename), isStdin: true}]; | ||
} else { | ||
return [{filename: "", isStdin: 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.
maybe for now you should fail hard here with a good error message, until --stdin
w/o --stdinFilename
is supported
src/tslint-cli.ts
Outdated
type: "string", | ||
describe: "stdin input", | ||
description: dedent` | ||
Read and check a file via stdin.`, |
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.
would mention that stdin-filename
is currently required
the way it currently stands, it looks like if the file(s) to lint is not specified, the program would fail at One way to hack around it is to create a I am also open to incrementally developing this, with the version that requires |
Thank you for the feedback. 👍 I'll have a read through all of your comments when I get the time. I was trying to figure out how to support |
I think I'll go with the option to require |
I updated the code now to require |
@w0rp |
I'm waiting anxiously for this to be finished so I can integrate the tslint-cli into the Visual Studio Prettier extension. Any status? Anything I can help with? |
You can take what I've written so far and add to it. I don't need this any more. I just run tslint as a tsserver plugin instead. |
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.
Tests will need to pass before this is merged.
function resolveFilesAndProgram( | ||
{ files, project, exclude, outputAbsolutePaths }: Options, | ||
/** Read the stdin stream into a string with all of the contents. */ | ||
async function readStdin(): Promise<string> { |
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.
runner.ts
is getting pretty huge. Please separate this standalone utility to a different file (`src/utils.ts, maybe?).
It's taking me a bit to get used to the code base, but I'll try to get to this. It won't be too soon though. If anyone else wants to do it, it would be great. Just let me know. |
So, just to clarify what's needed now:
Anything else? |
@tommck looks like it, yes. Also a few merge conflicts now 😉 but those are probably just from a recent Prettier reformatting. |
given what @w0rp said here:
is this feature still required? what are the downsides to running tslint as a tsserver plugin? |
I would still use it in Neomake I guess, which does not has support for tsserver plugins. |
I think it's worth implementing for various purposes, including piping text into TSLint. Someone else can pick this up. I personally recommend running TSLint as a tsserver plugin, as that seems to work very well. |
Given #4534 and this PR's failing tests, merge conflicts, and lack of participation in the last few months, I'm going to go ahead and close this PR for housekeeping. Thanks so much everyone for participating in the PR! Although the changes haven't been merged in, there was still some great work that went into this. 😢 Anybody: if piping text via |
PR checklist
Overview of change:
Hello! I am the guy who created the ALE plugin for Vim, for checking for problems while you type in Vim, and I am an active JavaScript and TypeScript developer. I use ESLint in my day job, and I would like to use TSLint more. One of the key features that ESLint has, which works really well with ALE, is that you can both pass in a Vim buffer via stdin and also tell it where the file for the buffer is in your file system. This means you can check for problems before you've saved a file to disk, but still benefit from plugins which need to know where the file is for resolving modules and so on. Currently, ALE can't support all of the features of TSLint, while also checking for problems while you type, because TSLint doesn't yet support a feature like this.
I'm interested in using such a feature myself, so I thought I'd start trying to implement it myself. A new
--stdin
option ought to read a file to check from stdin, and--stdin-filename
should tell TSLint where the file you're checking will be saved to disk.Is there anything you'd like reviewers to focus on?
I'm not familiar with the TSLint codebase at all. I just quickly scanned through the codebase and modified what seemed logical to modify to me, to get anything working at all. I haven't written any tests yet, and I'm sure what I've written so far will probably cause some bugs. I'm not familiar with the coding standards, so let me know what to change there. This work certainly isn't finished yet.
One thing I know that I couldn't get working yet is that I couldn't figure out an easy way to support
--stdin
without the--stdin-filename
option, as some rules seem to depend on there being some file to actually look at in the filesystem, and I imagine this will extend to some third party rules as well. It might be that some rules will have to be modified to not throw exceptions if the file doesn't exist yet, they will probably cause problems for new files you haven't saved to disk yet, even with the--stdin-filename
option. Maybe for supporting--stdin
alone, rules will have to be modified to tolerate blank filenames, or a special filename like"-"
. Let me know your thoughts.CHANGELOG.md entry:
suggested tags: [enhancement], [api]