diff --git a/lisp/_prepare.el b/lisp/_prepare.el
index 77915034..a929a421 100644
--- a/lisp/_prepare.el
+++ b/lisp/_prepare.el
@@ -479,10 +479,15 @@ You can pass BUFFER-OR-NAME to replace current buffer."
(with-current-buffer (or buffer-or-name (current-buffer))
(goto-char (point-min))
(while (not (eobp))
- (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position))))
- (cond ((string-match-p "[: ][Ee]rror: " line) (eask-error line))
- ((string-match-p "[: ][Ww]arning: " line) (eask-warn line))
- (t (eask-log line))))
+ (let ((line (buffer-substring-no-properties (line-beginning-position)
+ (line-end-position))))
+ ;; The variable `line' can contains format specifier, avoid it with `%s'!
+ (cond ((string-match-p "[: ][Ee]rror: " line)
+ (eask-error "%s" line))
+ ((string-match-p "[: ][Ww]arning: " line)
+ (eask-warn "%s" line))
+ (t
+ (eask-log "%s" line))))
(forward-line 1))))
(defun eask-delete-file (filename)
@@ -1821,7 +1826,8 @@ Execute forms BODY limit by the verbosity level (SYMBOL)."
(defun eask--ansi (symbol string)
"Paint STRING with color defined by log level (SYMBOL)."
(if-let* ((ansi-function (cdr (assq symbol eask-level-color))))
- (funcall ansi-function string)
+ ;; The `%s` is use to avoid `not enough arguments for string` error.
+ (funcall ansi-function "%s" string)
string))
(defun eask--format (prefix fmt &rest args)
@@ -1829,41 +1835,39 @@ Execute forms BODY limit by the verbosity level (SYMBOL)."
Argument PREFIX is a string identify the type of this messages. Arguments FMT
and ARGS are used to pass through function `format'."
- (apply #'format
- (concat (when eask-timestamps (format-time-string "%Y-%m-%d %H:%M:%S "))
- (when eask-log-level (concat prefix " "))
- fmt)
- args))
+ (concat (when eask-timestamps (format-time-string "%Y-%m-%d %H:%M:%S "))
+ (when eask-log-level (concat prefix " "))
+ (apply #'format fmt args)))
-(defun eask--msg (symbol prefix msg &rest args)
+(defun eask--msg (symbol prefix fmt &rest args)
"If level (SYMBOL) is at or below `eask-verbosity'; then, log the message.
-For arguments PREFIX, MSG and ARGS, please see funtion `eask--format' for the
+For arguments PREFIX, FMT and ARGS, please see funtion `eask--format' for the
detials."
(eask-with-verbosity symbol
- (let* ((string (apply #'eask--format prefix msg args))
- (output (eask--ansi symbol string))
+ (let* ((output (apply #'eask--format prefix fmt args))
+ (output (eask--ansi symbol output))
(output (eask--msg-displayable-kwds output)) ; Don't color, but replace it!
(func (cl-case symbol
((or error warn) symbol)
- (t #'message))))
+ (t #'message))))
(funcall func "%s" output))))
-(defun eask-debug (msg &rest args)
- "Send debug message; see function `eask--msg' for arguments MSG and ARGS."
- (apply #'eask--msg 'debug "[DEBUG]" msg args))
-(defun eask-log (msg &rest args)
- "Send log message; see function `eask--msg' for arguments MSG and ARGS."
- (apply #'eask--msg 'log "[LOG]" msg args))
-(defun eask-info (msg &rest args)
- "Send info message; see function `eask--msg' for arguments MSG and ARGS."
- (apply #'eask--msg 'info "[INFO]" msg args))
-(defun eask-warn (msg &rest args)
- "Send warn message; see function `eask--msg' for arguments MSG and ARGS."
- (apply #'eask--msg 'warn "[WARNING]" msg args))
-(defun eask-error (msg &rest args)
- "Send error message; see function `eask--msg' for arguments MSG and ARGS."
- (apply #'eask--msg 'error "[ERROR]" msg args))
+(defun eask-debug (fmt &rest args)
+ "Send debug message; see function `eask--msg' for arguments FMT and ARGS."
+ (apply #'eask--msg 'debug "[DEBUG]" fmt args))
+(defun eask-log (fmt &rest args)
+ "Send log message; see function `eask--msg' for arguments FMT and ARGS."
+ (apply #'eask--msg 'log "[LOG]" fmt args))
+(defun eask-info (fmt &rest args)
+ "Send info message; see function `eask--msg' for arguments FMT and ARGS."
+ (apply #'eask--msg 'info "[INFO]" fmt args))
+(defun eask-warn (fmt &rest args)
+ "Send warn message; see function `eask--msg' for arguments FMT and ARGS."
+ (apply #'eask--msg 'warn "[WARNING]" fmt args))
+(defun eask-error (fmt &rest args)
+ "Send error message; see function `eask--msg' for arguments FMT and ARGS."
+ (apply #'eask--msg 'error "[ERROR]" fmt args))
(defun eask--msg-char-displayable (char replacement s)
"Ensure CHAR is displayable in S; if not, we fallback to REPLACEMENT
@@ -1963,6 +1967,12 @@ Argument ARGS are direct arguments for functions `eask-error' or `eask-warn'."
(defvar eask-inhibit-error-message nil
"Non-nil to stop error/warning message.")
+(defvar eask--has-error-p nil
+ "Non-nil if an error has occurred.")
+
+(defvar eask--has-warn-p nil
+ "Non-nil if a warning has occurred.")
+
(defmacro eask-ignore-errors (&rest body)
"Execute BODY without killing the process."
(declare (indent 0) (debug t))
@@ -1981,8 +1991,8 @@ Argument ARGS are direct arguments for functions `eask-error' or `eask-warn'."
(defun eask--trigger-error ()
"Trigger error event."
(when (and (not eask--ignore-error-p)
- (not (eask-checker-p))) ; ignore when checking Eask-file
- (if (eask-allow-error-p) ; Trigger error at the right time
+ (not (eask-checker-p))) ; Ignore when checking Eask-file.
+ (if (eask-allow-error-p) ; Trigger error at the right time.
(add-hook 'eask-after-command-hook #'eask--exit)
(eask--exit))))
@@ -1990,6 +2000,7 @@ Argument ARGS are direct arguments for functions `eask-error' or `eask-warn'."
"On error.
Arguments FNC and ARGS are used for advice `:around'."
+ (setq eask--has-error-p t)
(let ((msg (eask--ansi 'error (apply #'format-message args))))
(unless eask-inhibit-error-message
(eask--unsilent (eask-msg "%s" msg)))
@@ -2001,6 +2012,7 @@ Arguments FNC and ARGS are used for advice `:around'."
"On warn.
Arguments FNC and ARGS are used for advice `:around'."
+ (setq eask--has-warn-p t)
(let ((msg (eask--ansi 'warn (apply #'format-message args))))
(unless eask-inhibit-error-message
(eask--unsilent (eask-msg "%s" msg)))
diff --git a/lisp/lint/elint.el b/lisp/lint/elint.el
index cc4edac3..278f4815 100644
--- a/lisp/lint/elint.el
+++ b/lisp/lint/elint.el
@@ -40,8 +40,14 @@
(eask-lint-first-newline)
(eask-msg "`%s` with elint" (ansi-green file))
(eask-with-verbosity 'debug (elint-file filename))
- (eask-print-log-buffer (elint-get-log-buffer))
- (kill-buffer (elint-get-log-buffer))))
+ (let ((log-buffer (elint-get-log-buffer)))
+ (eask-print-log-buffer log-buffer)
+ (kill-buffer log-buffer))))
+
+(defun eask-lint-elint--has-error-p ()
+ "Return non-nil if we should report error for exit status."
+ (and eask--has-warn-p
+ (eask-strict-p)))
(eask-start
(require 'elint)
@@ -56,7 +62,10 @@
(eask-msg "")
(eask-info "(Total of %s file%s %s checked)" (length files)
(eask--sinr files "" "s")
- (eask--sinr files "has" "have")))
+ (eask--sinr files "has" "have"))
+ ;; Report error.
+ (when (eask-lint-elint--has-error-p)
+ (eask--exit 'failure)))
;; Pattern defined, but no file found!
(patterns
(eask-info "(No files match wildcard: %s)"
diff --git a/lisp/lint/elsa.el b/lisp/lint/elsa.el
index fdc52e16..21392432 100644
--- a/lisp/lint/elsa.el
+++ b/lisp/lint/elsa.el
@@ -53,11 +53,19 @@
(if errors
(--each (reverse errors)
(let ((line (string-trim (concat file ":" (elsa-message-format it)))))
- (cond ((string-match-p "[: ][Ee]rror:" line) (eask-error line))
- ((string-match-p "[: ][Ww]arning:" line) (eask-warn line))
+ (cond ((string-match-p "[: ][Ee]rror:" line)
+ (eask-error line))
+ ((string-match-p "[: ][Ww]arning:" line)
+ (eask-warn line))
(t (eask-log line)))))
(eask-msg "No issues found"))))
+(defun eask-lint-elsa--has-error-p ()
+ "Return non-nil if we should report error for exit status."
+ (or eask--has-error-p
+ (and eask--has-warn-p
+ (eask-strict-p))))
+
(eask-start
;; Preparation
(eask-archive-install-packages '("gnu" "melpa")
@@ -77,7 +85,10 @@
(mapcar #'eask-lint-elsa--analyse-file files)
(eask-msg "")
(eask-info "(Total of %s file%s linted)" (length files)
- (eask--sinr files "" "s")))
+ (eask--sinr files "" "s"))
+ ;; Report error.
+ (when (eask-lint-elsa--has-error-p)
+ (eask--exit 'failure)))
;; Pattern defined, but no file found!
(patterns
(eask-msg "")
diff --git a/lisp/lint/indent.el b/lisp/lint/indent.el
index dc9e5467..ea6c3e96 100644
--- a/lisp/lint/indent.el
+++ b/lisp/lint/indent.el
@@ -53,9 +53,10 @@
(bs (buffer-string)))
(eask-with-temp-buffer (insert bs))
(eask--silent (indent-region (point-min) (point-max)))
- (if (/= tick (buffer-modified-tick))
+ (if-let* (((/= tick (buffer-modified-tick)))
+ (infos (eask-lint-indent--undo-infos buffer-undo-list)))
;; Indentation changed: warn for each line.
- (dolist (info (eask-lint-indent--undo-infos buffer-undo-list))
+ (dolist (info infos)
(let* ((line (nth 0 info))
(column (nth 1 info))
(current (eask-with-buffer
@@ -68,9 +69,12 @@
(let* ((patterns (eask-args))
(files (if patterns (eask-expand-file-specs (eask-args))
(eask-package-el-files))))
- (eask-install-dependencies)
- (eask-with-verbosity 'debug
- (ignore-errors (mapc #'load (eask-package-el-files))))
+ ;; XXX: Load all dependencies and elisp files to ensure
+ ;; all macros' indentation is applied.
+ (progn
+ (eask-install-dependencies)
+ (eask-with-verbosity 'debug
+ (ignore-errors (mapc #'load (eask-package-el-files)))))
(cond
;; Files found, do the action!
(files
diff --git a/lisp/lint/package.el b/lisp/lint/package.el
index 676ddcdc..9ba6d09b 100644
--- a/lisp/lint/package.el
+++ b/lisp/lint/package.el
@@ -57,6 +57,11 @@
(kill-current-buffer)))
(eask-print-log-buffer "*Package-Lint*"))
+(defun eask-lint-package--has-error-p ()
+ "Return non-nil if we should report error for exit status."
+ (and eask--has-warn-p
+ (eask-strict-p)))
+
(eask-start
;; Preparation
(eask-archive-install-packages '("gnu" "melpa")
@@ -77,7 +82,10 @@
(mapcar #'eask-lint-package--file files)
(eask-msg "")
(eask-info "(Total of %s file%s linted)" (length files)
- (eask--sinr files "" "s")))
+ (eask--sinr files "" "s"))
+ ;; Report error.
+ (when (eask-lint-package--has-error-p)
+ (eask--exit 'failure)))
;; Pattern defined, but no file found!
(patterns
(eask-msg "")
diff --git a/lisp/lint/regexps.el b/lisp/lint/regexps.el
index 9540863c..5818ef3d 100644
--- a/lisp/lint/regexps.el
+++ b/lisp/lint/regexps.el
@@ -47,12 +47,13 @@
(with-current-buffer (find-file filename)
(setq errors (relint-buffer (current-buffer)))
(dolist (err errors)
- (let* ((msg (nth 0 err))
- (error-pos (nth 2 err))
- (severity (nth 5 err))
+ (let* ((msg (seq-elt err 0))
+ (error-pos (seq-elt err 2))
+ (severity (seq-elt err 7))
(report-func (pcase severity
- (`error #'eask-error)
- (`warning #'eask-warn))))
+ (`error #'eask-error)
+ (`warning #'eask-warn)
+ (_ #'eask-info))))
(funcall report-func "%s:%s %s: %s"
file (line-number-at-pos error-pos)
(capitalize (eask-2str severity)) msg)))
@@ -60,6 +61,11 @@
(eask-msg "No issues found"))
(kill-current-buffer))))
+(defun eask-lint-regexps--has-error-p ()
+ "Return non-nil if we should report error for exit status."
+ (and eask--has-warn-p
+ (eask-strict-p)))
+
(eask-start
;; Preparation
(eask-archive-install-packages '("gnu")
@@ -79,7 +85,10 @@
(mapcar #'eask-lint-regexps--relint-file files)
(eask-msg "")
(eask-info "(Total of %s file%s linted)" (length files)
- (eask--sinr files "" "s")))
+ (eask--sinr files "" "s"))
+ ;; Report error.
+ (when (eask-lint-regexps--has-error-p)
+ (eask--exit 'failure)))
;; Pattern defined, but no file found!
(patterns
(eask-msg "")
diff --git a/test/jest/lint.test.js b/test/jest/lint.test.js
new file mode 100644
index 00000000..aeed67b5
--- /dev/null
+++ b/test/jest/lint.test.js
@@ -0,0 +1,256 @@
+const { TestContext } = require("./helpers");
+
+describe("lint", () => {
+ const ctx = new TestContext("./test/jest/lint");
+
+ beforeEach(async () => {
+ await ctx.runEask("clean elc");
+ });
+
+ afterAll(() => {
+ ctx.cleanUp();
+ });
+
+ describe("partial input", () => {
+ it("eask lint should error", async () => {
+ await expect(ctx.runEask("eask lint")).rejects.toMatchObject({ code: 1 });
+ });
+ });
+
+ describe("checkdoc", () => {
+ it("should work on declare-ok.el", async () => {
+ await expect(
+ ctx.runEask("lint checkdoc declare-ok.el"),
+ ).resolves.toMatchObject({
+ stderr: expect.stringContaining("No issues found"),
+ });
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint checkdoc --strict checkdoc-fail.el"),
+ ).rejects.toMatchObject({
+ code: 1,
+ });
+ });
+
+ it("should error given --strict and --allow-error", async () => {
+ await expect(
+ ctx.runEask("lint checkdoc --strict checkdoc-fail.el declare-ok.el"),
+ ).rejects.toMatchObject({
+ code: 1,
+ // expect that declare-ok was checked too
+ stderr: expect.stringContaining("`declare-ok.el` with checkdoc"),
+ });
+ });
+ });
+
+ describe("declare", () => {
+ it("should work on declare-ok.el", async () => {
+ await expect(
+ ctx.runEask("lint declare declare-ok.el"),
+ ).resolves.toMatchObject({
+ stderr: expect.stringContaining("No issues found"),
+ });
+ });
+
+ it("should work on declare-fail.el (warnings ignored)", async () => {
+ await ctx.runEask("lint declare declare-fail.el");
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint declare --strict declare-fail.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should error given --strict --allow-error", async () => {
+ await expect(
+ ctx.runEask("lint declare --strict --allow-error ./*.el"),
+ ).rejects.toMatchObject({
+ code: 1,
+ // expect that declare-ok was checked too
+ stderr: expect.stringContaining("`declare-ok.el` with check-declare"),
+ });
+ });
+ });
+
+ describe("elint", () => {
+ it("should work on declare-ok.el", async () => {
+ await ctx.runEask("lint elint declare-ok.el");
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint elint --strict checkdoc-fail.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should check both files given --strict --allow-error", async () => {
+ await expect(
+ ctx.runEask(
+ "lint elint --strict --allow-error checkdoc-fail.el declare-ok.el",
+ ),
+ ).rejects.toMatchObject({
+ code: 1,
+ stderr: expect.stringContaining("`declare-ok.el` with elint"),
+ });
+ });
+ });
+
+ describe("elisp-lint", () => {
+ it("should work on elisp-lint-ok.el", async () => {
+ await ctx.runEask("lint elisp-lint --strict elisp-lint-ok.el");
+ });
+
+ it("should work on declare-ok.el (warnings)", async () => {
+ await ctx.runEask("lint elisp-lint declare-ok.el");
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint elisp-lint --strict declare-ok.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should work with --strict --allow-error", async () => {
+ await expect(
+ ctx.runEask(
+ "lint elisp-lint --strict --allow-error checkdoc-fail.el elisp-lint-ok.el",
+ ),
+ ).rejects.toMatchObject({
+ stderr: expect.stringContaining("2 files linted"),
+ });
+ });
+ });
+
+ describe("elsa", () => {
+ // prints a lot of garbage
+ // likely an upstream problem, unclear how to fix
+ it("should work on elisp-lint-ok.el", async () => {
+ await ctx.runEask("lint elsa elisp-lint-ok.el");
+ });
+
+ it("should work on elsa-warn.el (warnings)", async () => {
+ await ctx.runEask("lint elsa elsa-warn.el");
+ });
+
+ it("should error on declare-ok.el", async () => {
+ await expect(
+ ctx.runEask("lint elsa declare-ok.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint elsa --strict elsa-warn.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should run all files given --allow-error", async () => {
+ await expect(
+ ctx.runEask(
+ "lint elsa --strict --allow-errors elsa-warn.el elisp-lint-ok.el",
+ ),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+ });
+
+ describe("indent", () => {
+ it("should work on indent-warn.el", async () => {
+ await ctx.runEask("lint indent indent-warn.el");
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint indent --strict indent-warn.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should work with --strict --allow-error", async () => {
+ await expect(
+ ctx.runEask(
+ "lint indent --strict --allow-error indent-warn.el declare-ok.el",
+ ),
+ ).rejects.toMatchObject({
+ code: 1,
+ stderr: expect.stringContaining("2 files linted"),
+ });
+ });
+ });
+
+ describe("keywords", () => {
+ // always errors so --strict doesn't matter
+ // checks only Eask and x-pkg.el, so --allow-error doesn't matter
+
+ it("should error in an empty project", async () => {
+ const ctxEmpty = new TestContext("./test/jest/lint");
+ await expect(ctxEmpty.runEask("lint keywords")).rejects.toThrow();
+ });
+
+ it("should work in keywords-ok", async () => {
+ const ctxOk = new TestContext("./test/jest/lint/keywords-ok");
+ await expect(ctxOk.runEask("lint keywords")).resolves.toMatchObject({
+ stderr: expect.stringContaining("No issues found"),
+ });
+ });
+
+ it("should error in keywords-bad", async () => {
+ const ctxBad = new TestContext("./test/jest/lint/keywords-bad");
+ await expect(ctxBad.runEask("lint keywords")).rejects.toMatchObject({
+ stderr: expect.stringContaining("Missing a standard keyword"),
+ });
+ });
+ });
+
+ describe("package", () => {
+ it("should work on declare-ok.el", async () => {
+ await ctx.runEask("lint package declare-ok.el");
+ });
+
+ it("should error given --strict", async () => {
+ await expect(
+ ctx.runEask("lint package --strict declare-ok.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ // note that all files are checked anyway so --allow-error has no effect
+ it("should check all files given --allow-error", async () => {
+ await expect(
+ ctx.runEask("lint package --allow-error *.el"),
+ ).rejects.toMatchObject({
+ code: 1,
+ stderr: expect.stringContaining("`declare-ok.el` with package-lint"),
+ });
+ });
+ });
+
+ describe("regexps", () => {
+ it("should work on declare-ok.el", async () => {
+ await ctx.runEask("lint regexps declare-ok.el");
+ });
+
+ it("should have warnings on regexp-warn.el", async () => {
+ await expect(
+ ctx.runEask("lint regexps regexp-warn.el"),
+ ).resolves.toMatchObject({ stderr: expect.stringContaining("Warning:") });
+ });
+
+ it("should error on regexp-warn.el with --strict", async () => {
+ await expect(
+ ctx.runEask("lint regexps --strict regexp-warn.el"),
+ ).rejects.toMatchObject({ code: 1 });
+ });
+
+ it("should work with --allow-error", async () => {
+ await expect(
+ ctx.runEask(
+ "lint regexps --allow-error --strict regexp-warn.el declare-ok.el",
+ ),
+ ).rejects.toMatchObject({
+ code: 1,
+ stderr: expect.stringContaining("2 files linted"),
+ });
+ });
+ });
+});
diff --git a/test/jest/lint/Eask b/test/jest/lint/Eask
new file mode 100644
index 00000000..4fed337f
--- /dev/null
+++ b/test/jest/lint/Eask
@@ -0,0 +1,7 @@
+(package "lint"
+ "0.0.1"
+ "Test project for lint")
+(package-file "lint-pkg.el")
+
+(source 'gnu)
+(source 'melpa)
diff --git a/test/jest/lint/checkdoc-fail.el b/test/jest/lint/checkdoc-fail.el
new file mode 100644
index 00000000..f521198d
--- /dev/null
+++ b/test/jest/lint/checkdoc-fail.el
@@ -0,0 +1,29 @@
+;;; ert-test.el --- Test the command ert -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+;;; Commentary:
+
+;; Tests for the command ert
+
+;;; Code:
+
+(defun my-foo (arg)
+ ".make a lot of checkdoc errors
+
+in this " ignore)
+
+;;; declare-ok.el ends here
diff --git a/test/jest/lint/declare-fail.el b/test/jest/lint/declare-fail.el
new file mode 100644
index 00000000..2a3207e5
--- /dev/null
+++ b/test/jest/lint/declare-fail.el
@@ -0,0 +1,24 @@
+;;; declare-fail.el --- Test lint declare -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+;;; Commentary:
+
+;;; Code:
+
+(declare-function not-a-function "subr.el" (x y z))
+
+;;; declare-fail.el ends here
diff --git a/test/jest/lint/declare-ok.el b/test/jest/lint/declare-ok.el
new file mode 100644
index 00000000..70ab1bfe
--- /dev/null
+++ b/test/jest/lint/declare-ok.el
@@ -0,0 +1,26 @@
+;;; ert-test.el --- Test the command ert -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+;;; Commentary:
+
+;; Tests for the command ert
+
+;;; Code:
+
+(declare-function ignore "subr.el" (&rest args))
+
+;;; declare-ok.el ends here
diff --git a/test/jest/lint/elisp-lint-ok.el b/test/jest/lint/elisp-lint-ok.el
new file mode 100644
index 00000000..29915e81
--- /dev/null
+++ b/test/jest/lint/elisp-lint-ok.el
@@ -0,0 +1,21 @@
+;;; elisp-lint-ok.el --- Test the linting -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;;; Version: 0.0.1
+;;; URL: https://foo.com
+;;; Package-Requires: ((emacs "28.1"))
+
+;;; Commentary:
+
+;; Tests linting with elisp-lint
+;; Also clean for packge lint
+
+;;; Code:
+
+(defun elisp-lint-ok-foo ()
+ "Nothing here."
+ (message "ok"))
+
+(provide 'elisp-lint-ok)
+;;; elisp-lint-ok.el ends here
diff --git a/test/jest/lint/elsa-warn.el b/test/jest/lint/elsa-warn.el
new file mode 100644
index 00000000..d7e9ace4
--- /dev/null
+++ b/test/jest/lint/elsa-warn.el
@@ -0,0 +1,29 @@
+;;; elsa-warn.el --- Test elsa linting -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+;;; Commentary:
+
+;; Test elsa.
+;; Should only cause warnings
+
+;;; Code:
+
+(defun elsa-warn-foo ()
+ (some-foo) ;; not declared warning
+ (message "Ok"))
+
+;;; elsa-warn.el ends here
diff --git a/test/jest/lint/indent-warn.el b/test/jest/lint/indent-warn.el
new file mode 100644
index 00000000..d2d6156e
--- /dev/null
+++ b/test/jest/lint/indent-warn.el
@@ -0,0 +1,31 @@
+;;; indent-warn.el --- Test indent linting -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+;;; Commentary:
+
+;; Test indent.
+;; Should only cause warnings
+
+;;; Code:
+
+(defun indent-warn-foo ()
+ (if 't
+ (message "Ok")
+ (message
+ "no")))
+
+;;; indent-warn.el ends here
diff --git a/test/jest/lint/keywords-bad/Eask b/test/jest/lint/keywords-bad/Eask
new file mode 100644
index 00000000..9089c7f2
--- /dev/null
+++ b/test/jest/lint/keywords-bad/Eask
@@ -0,0 +1,15 @@
+;; -*- mode: eask; lexical-binding: t -*-
+
+(package "keywords-ok"
+ "1.0.0"
+ "")
+
+(keywords "bag" "frog")
+
+(package-file "keywords-ok.el")
+
+(script "test" "echo \"Error: no test specified\" && exit 1")
+
+(source "gnu")
+
+(depends-on "emacs" "26.1")
diff --git a/test/jest/lint/keywords-bad/keywords-ok.el b/test/jest/lint/keywords-bad/keywords-ok.el
new file mode 100644
index 00000000..0d110f0b
--- /dev/null
+++ b/test/jest/lint/keywords-bad/keywords-ok.el
@@ -0,0 +1,36 @@
+;;; keywords-ok.el --- summary -*- lexical-binding: t -*-
+
+;; Author:
+;; Maintainer:
+;; Version: 1.0.0
+;; Package-Requires: (dependencies)
+;; Keywords: frog, bag
+
+
+;; This file is not part of GNU Emacs
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+
+;;; Commentary:
+
+;; commentary
+
+;;; Code:
+
+(message "Hello World!")
+
+(provide 'keywords-ok)
+
+;;; keywords-ok.el ends here
diff --git a/test/jest/lint/keywords-ok/Eask b/test/jest/lint/keywords-ok/Eask
new file mode 100644
index 00000000..a904c514
--- /dev/null
+++ b/test/jest/lint/keywords-ok/Eask
@@ -0,0 +1,15 @@
+;; -*- mode: eask; lexical-binding: t -*-
+
+(package "keywords-ok"
+ "1.0.0"
+ "")
+
+(keywords "tools")
+
+(package-file "keywords-ok.el")
+
+(script "test" "echo \"Error: no test specified\" && exit 1")
+
+(source "gnu")
+
+(depends-on "emacs" "26.1")
diff --git a/test/jest/lint/keywords-ok/keywords-ok.el b/test/jest/lint/keywords-ok/keywords-ok.el
new file mode 100644
index 00000000..4d8e9d65
--- /dev/null
+++ b/test/jest/lint/keywords-ok/keywords-ok.el
@@ -0,0 +1,36 @@
+;;; keywords-ok.el --- summary -*- lexical-binding: t -*-
+
+;; Author:
+;; Maintainer:
+;; Version: version
+;; Package-Requires: (dependencies)
+;; Keywords: tools
+
+
+;; This file is not part of GNU Emacs
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+
+;;; Commentary:
+
+;; commentary
+
+;;; Code:
+
+(message "Hello World!")
+
+(provide 'keywords-ok)
+
+;;; keywords-ok.el ends here
diff --git a/test/jest/lint/regexp-warn.el b/test/jest/lint/regexp-warn.el
new file mode 100644
index 00000000..ecfdc2b2
--- /dev/null
+++ b/test/jest/lint/regexp-warn.el
@@ -0,0 +1,28 @@
+;;; regexp-warn.el --- Test regexp linting -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 the Eask authors.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see .
+
+;;; Commentary:
+
+;; Test regexp.
+;; Should only cause warnings
+
+;;; Code:
+
+(defun regexp-warn-foo ()
+ (re-search-backward "^[.:wrod:]$"))
+
+;;; regexp-warn.el ends here