Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add spectral #530

Merged
merged 3 commits into from
Jun 26, 2024
Merged

Conversation

luispflamminger
Copy link
Contributor

Hi @mfussenegger,

thanks for this great plugin.
I would like to add the Spectral linter for OpenAPI specifications.

There is a slight problem in that the linter takes a required parameter --ruleset that takes either a file path or a URL.
Without this parameter, the linter will error out.

I have implemented it in a way, where the user would have to do something like this, which is a bit awkward 😄

require('lint').linters.spectral = require('lint').linters.spectral("path/to/ruleset")

Another approach would be to not specify the ruleset parameter by default, let the linter error and let the user figure out how to override the linters args. This is also pretty inconvenient.

I would appreciate your feedback on which of the options you would prefer, or if you maybe have a better idea.
I could also contribute some better documentation so users would know how to configure this specific linter.

If it's not a good fit for the project because of this constraint, I obviously understand.

@luispflamminger luispflamminger force-pushed the master branch 2 times, most recently from a6e6a8e to 16317d8 Compare February 7, 2024 21:31
@SirAppSec
Copy link

SirAppSec commented Feb 8, 2024

Thank you so much, I was about to create a PR for this.

A few checks before merging this PR.

  1. Would extending Spectral with npm packages work out of the box? (Should the plugin warn the user of missing dependencies in rules?)
  2. Should a user install Spectral dependencies for this to work? (Should the plugin warn the user when Spectral is not in the path?)

Edit: .spectral.yaml should allow for spectral to just work on a file, with the file name as the command argument:
So if the user have an existing .spectral.yaml the command would be spectral lint swagger.json

Edit #2: I've noticed that vscode extension also have issues with allowing custom npm packages and suggested a workaround we can use here. stoplightio/vscode-spectral#214

@luispflamminger
Copy link
Contributor Author

Thanks for the feedback @SirAppSec!

I don't think having specific logic for dependency issues is in scope for this plugin. We simply want to execute the linter as it is configured on the users system.

I will build some basic error handling when I find the time, because right now there is no way of knowing whether the linter errored, which is pretty confusing. I would also like to throw an error when spectral is not in PATH.

Your point about .spectral.yaml is good, I didn't think about that. I will change it as suggested.
Users will then have the option to override the ruleset using custom args.

@luispflamminger luispflamminger marked this pull request as draft February 9, 2024 12:53
@luispflamminger luispflamminger marked this pull request as ready for review February 11, 2024 19:35
@luispflamminger
Copy link
Contributor Author

luispflamminger commented Feb 11, 2024

I removed the --ruleset option. Spectral will now look for a .spectral.* file by default, as specified in the docs. This also means users can now use this like they would any other linter in this plugin.

I also improved error handling so users get notified if no ruleset was found (WARN) or if Spectral didn't return valid JSON (ERROR), which happens when Spectral itself ran into an error. You can test this by specifying an invalid .spectral.yaml, for example.

The case that Spectral can't be found on PATH is already handled by the plugin itself, so nothing to do here.

@SirAppSec: Please feel free to take another look and give feedback 🙂

Comment on lines 25 to 30
-- attempt to decode linter result
local success, result = pcall(vim.json.decode, output)
if not success then
vim.notify("Spectral exited with an error:\n" .. output, vim.log.levels.ERROR)
return {}
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- attempt to decode linter result
local success, result = pcall(vim.json.decode, output)
if not success then
vim.notify("Spectral exited with an error:\n" .. output, vim.log.levels.ERROR)
return {}
end
result = vim.json.decode(output)

You can just let it fail, there is default error handling:

local ok, diagnostics = pcall(parse, output, bufnr, linter_cwd)
if not ok then
local err = diagnostics
diagnostics = {
{
bufnr = bufnr,
lnum = 0,
col = 0,
message = string.format(parse_failure_msg, err, output),
severity = vim.diagnostic.severity.ERROR
}
}
end

@mfussenegger
Copy link
Owner

Could you address the suggestion?

@luispflamminger
Copy link
Contributor Author

@mfussenegger Sorry it took so long. I addressed your suggestion and rebased the branch.

@mfussenegger mfussenegger merged commit 4dc548e into mfussenegger:master Jun 26, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants