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

Add deno lint support #728

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ jobs:
if: startsWith(matrix.os, 'macos')
run: brew install clang-format

# Deno

- name: Set up Deno
uses: denoland/setup-deno@v1

# Go

- name: Set up Go
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ _**Note:** The behavior of actions like this one is currently limited in the con
- [SwiftLint](https://github.com/realm/SwiftLint)
- **TypeScript:**
- [tsc](https://www.typescriptlang.org/docs/handbook/compiler-options.html)
- [deno lint](https://deno.land/manual/tools/linter)
- **VB.NET:**
- [dotnet-format](https://github.com/dotnet/format)

Expand Down Expand Up @@ -386,7 +387,7 @@ With `auto_fix` set to `true`, by default the action will try and fix code issue

### Linter-specific options

`[linter]` can be one of `autopep8`, `black`, `clang_format`, `dotnet_format`, `erblint`, `eslint`, `flake8`, `gofmt`, `golint`, `mypy`, `oitnb`, `php_codesniffer`, `prettier`, `pylint`, `rubocop`, `stylelint`, `swift_format_official`, `swift_format_lockwood`, `swiftlint` and `xo`:
`[linter]` can be one of `autopep8`, `black`, `clang_format`, `deno_lint`, `dotnet_format`, `erblint`, `eslint`, `flake8`, `gofmt`, `golint`, `mypy`, `oitnb`, `php_codesniffer`, `prettier`, `pylint`, `rubocop`, `stylelint`, `swift_format_official`, `swift_format_lockwood`, `swiftlint` and `xo`:

- **`[linter]`:** Enables the linter in your repository. Default: `false`
- **`[linter]_args`**: Additional arguments to pass to the linter. Example: `eslint_args: "--max-warnings 0"` if ESLint checks should fail even if there are no errors and only warnings. Default: `""`
Expand Down Expand Up @@ -431,6 +432,7 @@ Some options are not available for specific linters:
| black | ✅ | ✅ |
| clang_format | ✅ | ✅ |
| clippy | ✅ | ❌ (rs) |
| deno_lint | ❌ | ✅ |
| dotnet_format | ✅ | ❌ (cs) |
| erblint | ❌ | ❌ (erb) |
| eslint | ✅ | ✅ |
Expand Down
24 changes: 24 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,30 @@ inputs:
required: false
default: "false"

deno_lint:
description: Enable or disable deno lint checks
required: false
default: "false"
deno_lint_args:
description: Additional arguments to pass to the linter
required: false
default: ""
deno_lint_dir:
description: Directory where the deno lint command should be run
required: false
deno_lint_extensions:
description: Extensions of files to check with deno lint
required: false
default: "*"
Copy link
Author

Choose a reason for hiding this comment

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

deno lint checks all supported files if the [files]... argument is not provided. This default value "*" is interpreted as not passing the [files]... argument.

deno_lint_command_prefix:
description: Shell command to prepend to the linter command
required: false
default: ""
deno_lint_auto_fix:
description: Whether this linter should try to fix code style issues automatically. If set to `true`, it will only work if "auto_fix" is set to `true` as well
required: false
default: "false"

# PHP

php_codesniffer:
Expand Down
111 changes: 111 additions & 0 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

102 changes: 102 additions & 0 deletions src/linters/deno-lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const core = require("@actions/core");

const { run } = require("../utils/action");
const commandExists = require("../utils/command-exists");
const { initLintResult } = require("../utils/lint-result");
const { removeTrailingPeriod } = require("../utils/string");

/** @typedef {import('../utils/lint-result').LintResult} LintResult */

/**
* https://docs.deno.com/runtime/manual/tools/linter
*/
class DenoLint {
static get name() {
return "deno_lint";
}

/**
* Verifies that all required programs are installed. Throws an error if programs are missing
* @param {string} dir - Directory to run the linting program in
* @param {string} prefix - Prefix to the lint command
*/
static async verifySetup(dir, prefix = "") {
// Verify that deno is installed
if (!(await commandExists("deno"))) {
throw new Error("deno is not installed");
}
}

/**
* Runs the linting program and returns the command output
* @param {string} dir - Directory to run the linter in
* @param {string[]} extensions - File extensions which should be linted
* @param {string} args - Additional arguments to pass to the linter
* @param {boolean} fix - Whether the linter should attempt to fix code style issues automatically
* @param {string} prefix - Prefix to the lint command
* @returns {{status: number, stdout: string, stderr: string}} - Output of the lint command
*/
static lint(dir, extensions, args = "", fix = false, prefix = "") {
if (fix) {
core.warning(`${this.name} does not support auto-fixing`);
}

let targets;
switch (extensions.length) {
case 0:
targets = "";
break;
case 1:
if (extensions[0] === "*") {
targets = ""; // all files supported by deno lint
} else {
targets = `./**/*.${extensions[0]}`;
}
break;
default:
targets = `./**/*.{${extensions.map((ext) => ext).join(",")}}`;
break;
}

return run(`${prefix} deno lint ${targets} --json ${args}`, {
dir,
ignoreErrors: true,
});
}

/**
* Parses the output of the lint command. Determines the success of the lint process and the
* severity of the identified code style violations
* @param {string} dir - Directory in which the linter has been run
* @param {{status: number, stdout: string, stderr: string}} output - Output of the lint command
* @returns {LintResult} - Parsed lint result
*/
static parseOutput(dir, output) {
const lintResult = initLintResult();
lintResult.isSuccess = output.status === 0;

let outputJson;
try {
outputJson = JSON.parse(output.stdout);
} catch (err) {
throw new Error(
`Error parsing ${this.name} JSON output: ${err.message}. Output: "${output.stdout}"`,
);
}

for (const diagnostics of outputJson.diagnostics) {
const { filename, range, code, message, hint } = diagnostics;
const path = filename.substring(dir.length + 1);
const entry = {
path,
firstLine: range.start.line,
lastLine: range.end.line,
message: `${removeTrailingPeriod(message)} (${code}, ${hint})`,
};
lintResult.warning.push(entry);
}
return lintResult;
}
}

module.exports = DenoLint;
2 changes: 2 additions & 0 deletions src/linters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const Autopep8 = require("./autopep8");
const Black = require("./black");
const ClangFormat = require("./clang-format");
const Clippy = require("./clippy");
const DenoLint = require("./deno-lint");
const DotnetFormat = require("./dotnet-format");
const Erblint = require("./erblint");
const ESLint = require("./eslint");
Expand All @@ -25,6 +26,7 @@ const XO = require("./xo");
const linters = {
// Linters
clippy: Clippy,
deno_lint: DenoLint,
erblint: Erblint,
eslint: ESLint,
flake8: Flake8,
Expand Down
2 changes: 2 additions & 0 deletions test/linters/linters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const autopep8Params = require("./params/autopep8");
const blackParams = require("./params/black");
const clangFormatParams = require("./params/clang-format");
const clippyParams = require("./params/clippy");
const denoLintParams = require("./params/deno-lint");
const dotnetFormatParams = require("./params/dotnet-format");
const erblintParams = require("./params/erblint");
const eslintParams = require("./params/eslint");
Expand All @@ -32,6 +33,7 @@ const linterParams = [
blackParams,
clangFormatParams,
clippyParams,
denoLintParams,
dotnetFormatParams,
erblintParams,
eslintParams,
Expand Down
62 changes: 62 additions & 0 deletions test/linters/params/deno-lint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const DenoLint = require("../../../src/linters/deno-lint");
const { joinDoubleBackslash } = require("../../test-utils");

const testName = "deno-lint";
const linter = DenoLint;
const args = "";
const commandPrefex = "";
const extensions = ["*"];

// Linting without auto-fixing
function getLintParams(dir) {
const stdoutStr = `{
"diagnostics": [
{
"range": {
"start": {
"line": 1,
"col": 31,
"bytePos": 31
},
"end": {
"line": 1,
"col": 35,
"bytePos": 35
}
},
"filename": "${joinDoubleBackslash(dir, "file.ts")}",
"message": "\`arg1\` is never used",
"code": "no-unused-vars",
"hint": "If this is intentional, prefix it with an underscore like \`_arg1\`"
}
],
"errors": []
}`;
return {
// Expected output of the linting function
cmdOutput: {
status: 1,
stdOutParts: stdoutStr,
stdout: stdoutStr,
},
// Expected output of the parsing function
lintResult: {
isSuccess: false,
warning: [
{
firstLine: 1,
lastLine: 1,
message:
"`arg1` is never used (no-unused-vars, If this is intentional, prefix it with an underscore like `_arg1`)",
path: "file.ts",
},
],
error: [],
},
};
}

// Linting with auto-fixing
const getFixParams = getLintParams; // Does not support auto-fixing -> option has no effect

module.exports = [testName, linter, commandPrefex, extensions, args, getLintParams, getFixParams];
Loading
Loading