diff --git a/CHANGELOG.md b/CHANGELOG.md
index 592b1fb1..927c0752 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
* fix(lisp/extern): Clean up `compat` (2b41f5db4b5bbe145c9671f95850f79a00dcbd48)
* fix(lisp): Paint keywords with nested ansi codes (#323)
* feat(create): Add new command for `el-project` (#325)
+* feat(lint): Add command for `org-lint` (#328)
## 0.11.x
> Released Apr 03, 2025
diff --git a/cmds/lint/org.js b/cmds/lint/org.js
new file mode 100644
index 00000000..9f0da30e
--- /dev/null
+++ b/cmds/lint/org.js
@@ -0,0 +1,31 @@
+/**
+ * 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, 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 .
+ */
+
+"use strict";
+
+exports.command = ['org [files..]'];
+exports.desc = `Run org-lint on Org files`;
+exports.builder = yargs => yargs
+ .positional(
+ '[files..]', {
+ description: 'files you want org-lint to run on',
+ type: 'array',
+ });
+
+exports.handler = async (argv) => {
+ await UTIL.e_call(argv, 'lint/org', argv.files);
+};
diff --git a/docs/content/Getting-Started/Commands-and-options/_index.en.md b/docs/content/Getting-Started/Commands-and-options/_index.en.md
index 3bc6cb6e..3ec1a6f8 100644
--- a/docs/content/Getting-Started/Commands-and-options/_index.en.md
+++ b/docs/content/Getting-Started/Commands-and-options/_index.en.md
@@ -808,38 +808,46 @@ Run indent-lint.
eask [GLOBAL-OPTIONS] lint indent [FILES..]
```
-## π eask lint keywords
+## π eask lint declare
-Run keywords checker (built-in).
+Run check-declare (built-in).
```sh
-eask [GLOBAL-OPTIONS] lint keywords
+eask [GLOBAL-OPTIONS] lint declare [FILES..]
```
-## π eask lint license
+## π eask lint regexps
-Run license check.
+Run [relint](https://github.com/mattiase/relint).
+
+Alias: `lint relint`
```sh
-eask [GLOBAL-OPTIONS] lint license
+eask [GLOBAL-OPTIONS] lint regexps [FILES..]
```
-## π eask lint declare
+## π eask lint keywords
-Run check-declare (built-in).
+Run keywords checker (built-in).
```sh
-eask [GLOBAL-OPTIONS] lint declare [FILES..]
+eask [GLOBAL-OPTIONS] lint keywords
```
-## π eask lint regexps
+## π eask lint license
-Run [relint](https://github.com/mattiase/relint).
+Run license check.
-Alias: `lint relint`
+```sh
+eask [GLOBAL-OPTIONS] lint license
+```
+
+## π eask lint org
+
+Run `org-lint` on Org files.
```sh
-eask [GLOBAL-OPTIONS] lint regexps [FILES..]
+eask [GLOBAL-OPTIONS] lint org
```
# π© Testing
diff --git a/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md b/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md
index 60a023ee..da15bd13 100644
--- a/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md
+++ b/docs/content/Getting-Started/Commands-and-options/_index.zh-tw.md
@@ -754,7 +754,7 @@ eask [GLOBAL-OPTIONS] lint package [FILES..]
## π eask lint checkdoc
-ιθ‘ checkdoc (θͺεΈΆ).
+ιθ‘ checkdoc (θͺεΈΆ)γ
```sh
eask [GLOBAL-OPTIONS] lint checkdoc [FILES..]
@@ -762,7 +762,7 @@ eask [GLOBAL-OPTIONS] lint checkdoc [FILES..]
## π eask lint elint
-ιθ‘ elint (θͺεΈΆ).
+ιθ‘ elint (θͺεΈΆ)γ
```sh
eask [GLOBAL-OPTIONS] lint elint [FILES..]
@@ -794,38 +794,46 @@ eask [GLOBAL-OPTIONS] lint lint elsa [FILES..]
eask [GLOBAL-OPTIONS] lint indent [FILES..]
```
-## π eask lint keywords
+## π eask lint declare
-ιθ‘ keywords checker (θͺεΈΆ).
+ιθ‘ check-declare (θͺεΈΆ)γ
```sh
-eask [GLOBAL-OPTIONS] lint keywords
+eask [GLOBAL-OPTIONS] lint declare [FILES..]
```
-## π eask lint license
+## π eask lint regexps
-ιθ‘ license check.
+Run [relint](https://github.com/mattiase/relint).
+
+ε₯ε: `lint relint`
```sh
-eask [GLOBAL-OPTIONS] lint license
+eask [GLOBAL-OPTIONS] lint regexps [FILES..]
```
-## π eask lint declare
+## π eask lint keywords
-ιθ‘ check-declare (θͺεΈΆ).
+ιθ‘ keywords checker (θͺεΈΆ).
```sh
-eask [GLOBAL-OPTIONS] lint declare [FILES..]
+eask [GLOBAL-OPTIONS] lint keywords
```
-## π eask lint regexps
+## π eask lint license
-Run [relint](https://github.com/mattiase/relint).
+ιθ‘ license ζͺ’ζ₯ε¨γ
-ε₯ε: `lint relint`
+```sh
+eask [GLOBAL-OPTIONS] lint license
+```
+
+## π eask lint org
+
+ε¨ Org ζͺζ‘δΈιθ‘ `org-lint`γ
```sh
-eask [GLOBAL-OPTIONS] lint regexps [FILES..]
+eask [GLOBAL-OPTIONS] lint org
```
# π© 測試ζ‘ζΆ
diff --git a/lisp/help/lint/org b/lisp/help/lint/org
new file mode 100644
index 00000000..068fc891
--- /dev/null
+++ b/lisp/help/lint/org
@@ -0,0 +1,8 @@
+
+π‘ You need to specify pattern(s) you want to check
+
+ $ eask lint org [FILES..]
+
+For example,
+
+ $ eask lint org README.org docs/*.org
diff --git a/lisp/lint/org.el b/lisp/lint/org.el
new file mode 100644
index 00000000..583f5fc6
--- /dev/null
+++ b/lisp/lint/org.el
@@ -0,0 +1,78 @@
+;;; lint/org.el --- Run org-lint on Org files -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;;
+;; Commmand use to run `org-lint' for all files
+;;
+;; $ eask lint org [files..]
+;;
+;;
+;; Positionals:
+;;
+;; [files..] files you want org-lint to run on
+;;
+
+;;; Code:
+
+(let ((dir (file-name-directory (nth 1 (member "-scriptload" command-line-args)))))
+ (load (expand-file-name "_prepare.el"
+ (locate-dominating-file dir "_prepare.el"))
+ nil t))
+
+;;
+;;; Flags
+
+(advice-add #'eask-allow-error-p :override #'eask-always)
+
+;;
+;;; Core
+
+(defun eask-lint-org--print-error (file result)
+ "Print the error RESULT from FILE."
+ (let* ((data (cl-second result))
+ (filename (file-name-nondirectory file))
+ (line (elt data 0))
+ (text (elt data 2))
+ (msg (concat filename ":" line ": " text)))
+ (if (eask-strict-p) (error msg) (warn msg))))
+
+(defun eask-lint-org--file (file)
+ "Run `org-lint' on FILE."
+ (eask-msg "`%s` with org-lint" (ansi-green file))
+ (with-temp-buffer
+ (insert-file-contents file)
+ (org-mode)
+ (if-let* ((results (org-lint)))
+ (mapc (lambda (result)
+ (eask-lint-org--print-error file result))
+ results)
+ (eask-msg "No issues found"))))
+
+(eask-start
+ ;; Preparation
+ (eask-archive-install-packages '("gnu")
+ 'org)
+
+ ;; Start Linting
+ (require 'org-lint)
+ (let* ((patterns (eask-args))
+ (files (eask-expand-file-specs patterns)))
+ (cond
+ ;; Files found, do the action!
+ (files
+ (mapcar #'eask-lint-org--file files)
+ (eask-msg "")
+ (eask-info "(Total of %s file%s linted)" (length files)
+ (eask--sinr files "" "s")))
+ ;; Pattern defined, but no file found!
+ (patterns
+ (eask-msg "")
+ (eask-info "(No files match wildcard: %s)"
+ (mapconcat #'identity patterns " ")))
+ ;; Default, print help!
+ (t
+ (eask-msg "")
+ (eask-info "(No files have been linted)")
+ (eask-help "lint/org")))))
+
+;;; lint/org.el ends here
diff --git a/test/jest/local.test.js b/test/jest/local.test.js
index 32100073..5803c0ae 100644
--- a/test/jest/local.test.js
+++ b/test/jest/local.test.js
@@ -198,6 +198,7 @@ describe("local", () => {
describe("Linting", () => {
// some lint commands may fail if packages are missing
beforeAll(async () => await ctx.runEask("install-deps"));
+
it.each([
"lint checkdoc",
"lint declare",
@@ -210,15 +211,21 @@ describe("local", () => {
])("eask %s", async (cmd) => {
await ctx.runEask(cmd);
});
+
it("lint regexps", async () => {
if ((await emacsVersion()) >= "27.1") {
await ctx.runEask("lint regexps");
}
});
+
// XXX: Elsa is not stable, ignore it for now
test.skip("lint elsa", async () => {
await ctx.runEask("lint elsa");
});
+
+ it("lint org *.org", async () => {
+ await ctx.runEask("lint org *.org");
+ });
});
describe("Testing", () => {
diff --git a/test/jest/local/Eask b/test/jest/local/Eask
index 10e9b56f..91d8bb6d 100644
--- a/test/jest/local/Eask
+++ b/test/jest/local/Eask
@@ -1,7 +1,7 @@
;; -*- mode: eask; lexical-binding: t -*-
(package "mini.pkg.1"
- "5.5.6"
+ "9.9.10"
"Minimal test package")
(website-url "https://github.com/emacs-eask/cli/tree/master/test/fixtures/mini.pkg.1")
diff --git a/test/jest/local/README.org b/test/jest/local/README.org
new file mode 100644
index 00000000..ab5c45c0
--- /dev/null
+++ b/test/jest/local/README.org
@@ -0,0 +1,19 @@
+* Test Org File
+This is a test org file used for Emacs behavior checking.
+
+** TODO Broken heading without space
+***BROKEN Heading
+
+** Code Block
+#+BEGIN_SRC emacs-lisp
+(message "Hello, Emacs!")
+(1+ ) ; Intentional syntax error
+#+END_SRC
+
+** Bad Property
+:PROPERTIES:
+:WRONGPROP without value
+:END:
+
+** Notes
+Unclosed *bold and /italic text.
diff --git a/test/jest/local/mini.pkg.1.el b/test/jest/local/mini.pkg.1.el
index 5438f83c..fd474bcc 100644
--- a/test/jest/local/mini.pkg.1.el
+++ b/test/jest/local/mini.pkg.1.el
@@ -5,7 +5,7 @@
;; Author: Shen, Jen-Chieh
;; URL: https://github.com/emacs-eask/cli/tree/master/test/fixtures/mini.pkg.1
-;; Version: 5.5.6
+;; Version: 9.9.10
;; Package-Requires: ((emacs "24.3") (s "1.12.0") (fringe-helper "1.0.1"))
;; Keywords: test local