-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathox-11ty.el
More file actions
276 lines (246 loc) · 11.4 KB
/
Copy pathox-11ty.el
File metadata and controls
276 lines (246 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
;;; ox-11ty.el --- Eleventy export for Emacs Org Mode -*- lexical-binding: t -*-
;; Copyright (C) 2021 Sacha Chua
;; Author: Sacha Chua <sacha@sachachua.com>
;; Version: 2.17.3
;; Package-Requires: ((emacs "27"))
;; Keywords: org, eleventy, 11ty
;; Homepage: https://github.com/sachac/ox-11ty
;; 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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;; A very rough starting point for exporting to 11ty from Org Mode.
;;
;;; Code:
(require 'ox-html)
(defgroup org-export-11ty nil
"Options for exporting Org mode files to 11ty."
:tag "Org Export 11ty"
:group 'org-export)
(defcustom org-11ty-toplevel-hlevel 3
"The <H> level for level 1 headings in 11ty export.
This is also important for the classes that will be wrapped around headlines
and outline structure. If this variable is 1, the top-level headlines will
be <h1>, and the corresponding classes will be outline-1, section-number-1,
and outline-text-1. If this is 2, all of these will get a 2 instead.
The default for this variable is 3, because your layout might use <h2>
for formatting the post title."
:group 'org-export-11ty
:type 'integer)
(defcustom org-11ty-skip-private-files-regexp "gpg\\|private\\|secret\\|authinfo\\|ssh"
"Regular expression matching linked files that should cause an error when exporting."
:group 'org-export-11ty
:type 'string)
(defvar org-11ty-front-matter-functions nil
"Functions to call with the current front matter plist and info.")
(defun org-11ty--front-matter (info)
"Return front matter for INFO."
(let* ((date (plist-get info :date))
(title (plist-get info :title))
(modified (plist-get info :modified))
(permalink (plist-get info :permalink))
(categories (plist-get info :categories))
(collections (plist-get info :collections))
(extra (if (plist-get info :extra) (json-parse-string
(plist-get info :extra)
:object-type 'plist))))
(seq-reduce
(lambda (prev val)
(funcall val prev info))
org-11ty-front-matter-functions
(append
extra
(list :permalink permalink
:date (if (listp date) (car date) date)
:modified (if (listp modified) (car modified) modified)
:title (if (listp title) (car title) title)
:categories (if (stringp categories) (split-string categories) categories)
:tags (if (stringp collections) (split-string collections) collections))))))
(defun org-11ty-template (contents info)
(format
"module.exports = class {
data() {
return %s;
}
render() {
return %s;
}
}"
(json-encode (org-11ty--front-matter info))
(json-encode-string contents)))
(defun org-11ty-export-as-11ty (&optional async subtreep visible-only body-only ext-plist)
"Export current buffer as 11ty file."
(interactive)
(org-export-to-buffer '11ty "*org 11ty export*" async subtreep visible-only body-only ext-plist))
(defun org-11ty--get-info (subtreep visible-only)
(let ((info (org-combine-plists
(org-export--get-export-attributes '11ty subtreep visible-only)
(org-export--get-buffer-attributes)
(org-export-get-environment '11ty subtreep))))
(unless (plist-get info :categories)
(plist-put info :categories (let ((org-use-tag-inheritance t)) (org-get-tags))))
(unless (plist-get info :permalink)
(error "No permalink set")
;; (plist-put info :permalink (concat "/" (plist-get info :file-name)))
)
info))
(defun org-11ty-skip-private-files (filename)
"Filter out `org-11ty-skip-private-files-regexp' from FILENAME."
(if (string-match org-11ty-skip-private-files-regexp filename)
(error "Tried to link to %s" filename)
t))
(defvar org-11ty-copy-file-test-function #'org-11ty-skip-private-files
"Function to use to check whether a file is okay to copy.
If specified, this function is called with the filename and the file is
copied only if the function returns non-nil.")
(defun org-11ty--copy-files-and-replace-links (info &optional destination-dir)
(let ((file-regexp "\\(?:src\\|href\\|poster\\)=\"\\(\\(file:\\)?.*?\\)\"")
(destination-dir (or destination-dir (file-name-directory (plist-get info :file-path))))
file-all-urls file-name beg
new-file file-re
unescaped)
(save-excursion
(goto-char (point-min))
(while (re-search-forward file-regexp nil t)
(setq file-name (or (match-string 1) (match-string 2)))
(unless (or (string-match "^#" file-name)
(get-text-property 0 'changed file-name)
(and org-11ty-copy-file-test-function
(not (funcall org-11ty-copy-file-test-function file-name))))
(setq file-name
(replace-regexp-in-string
"\\?.+" ""
(save-match-data (if (string-match "^file:" file-name)
(substring file-name 7)
file-name))))
(setq unescaped
(replace-regexp-in-string
"%23" "#"
file-name))
(setq new-file (concat
(if info (plist-get info :permalink) "")
(file-name-nondirectory unescaped)))
(unless (org-url-p file-name)
(let ((new-file-name (expand-file-name (file-name-nondirectory unescaped)
destination-dir)))
(unless (file-directory-p destination-dir)
(make-directory destination-dir t))
(condition-case err
(when (and (file-exists-p unescaped)
(or (not (file-exists-p new-file-name))
(file-newer-than-file-p unescaped new-file-name)))
(copy-file unescaped destination-dir t))
(error nil))
(when (file-exists-p new-file-name)
(save-excursion
(goto-char (point-min))
(setq file-re (concat "\\(?: src=\"\\| href=\"\\| poster=\"\\)\\(\\(?:file://\\)?" (regexp-quote file-name) "\\)"))
(while (re-search-forward file-re nil t)
(replace-match
(propertize
(save-match-data (replace-regexp-in-string "#" "%23" new-file))
'changed t)
t t nil 1)))))))))))
(defun org-11ty--base-file-name (subtreep visible-only)
"Return the path to the output file, sans extension."
(let* ((info (org-11ty--get-info subtreep visible-only))
(base-file-name
(or
(and (plist-get info :file-name)
(if (string= (file-name-base (plist-get info :file-name)) "")
(concat (plist-get info :file-name) "index")
(plist-get info :file-name)))
(org-export-output-file-name "" subtreep))))
(if (plist-get info :base-dir)
(expand-file-name base-file-name (plist-get info :base-dir))
base-file-name)))
(defun org-11ty-export-to-11tydata (&optional async subtreep visible-only body-only ext-plist)
(let* ((info (org-11ty--get-info subtreep visible-only))
(file (org-11ty--base-file-name subtreep visible-only)))
(plist-put info :file-path file)
(when (file-name-directory file)
(make-directory (file-name-directory file) :parents))
(with-temp-file (concat file ".11tydata.json")
(insert (json-encode (org-11ty--front-matter info))))))
(defvar org-11ty-process-export-functions '(org-11ty--copy-files-and-replace-links)
"List of functions to run after exporting.
They will be called with the org-11ty--get-info info.")
(defun org-11ty-export-to-11tydata-and-html (&optional async subtreep visible-only body-only ext-plist)
(interactive)
(let* ((info (org-11ty--get-info subtreep visible-only))
(file (org-11ty--base-file-name subtreep visible-only))
(front-matter (org-11ty--front-matter info)))
(plist-put info :file-path file)
(when (file-name-directory file) (make-directory (file-name-directory file) :parents))
(with-temp-file (concat file ".11tydata.json") (insert (json-encode front-matter)))
(let ((body (org-export-as '11ty subtreep visible-only t ext-plist)))
(with-temp-file (concat file ".html")
(insert body)
(run-hook-with-args 'org-11ty-process-export-functions info)))))
(defun org-11ty-export-to-org (&optional async subtreep visible-only body-only ext-plist)
"Export this post as an Org file in the output directory."
(interactive)
(let* ((info (org-11ty--get-info subtreep visible-only))
(file (org-11ty--base-file-name subtreep visible-only))
(front-matter (org-11ty--front-matter info)))
(plist-put info :file-path file)
(when (file-name-directory file) (make-directory (file-name-directory file) :parents))
(with-temp-file (concat file ".11tydata.json") (insert (json-encode front-matter)))
(let ((body (org-export-as 'org subtreep visible-only t ext-plist)))
(with-temp-file (concat file ".org")
(save-excursion
(insert body))))))
(defun org-11ty-export-block (export-block _contents _info)
"Transcode a EXPORT-BLOCK element from Org to 11ty.
CONTENTS is nil. INFO is a plist holding contextual information."
(when (or (string= (org-element-property :type export-block) "11TY")
(string= (org-element-property :type export-block) "HTML"))
(org-remove-indentation (org-element-property :value export-block))))
(defun org-11ty-export-snippet (export-snippet _contents _info)
"Transcode a EXPORT-SNIPPET object from Org to 11ty.
CONTENTS is nil. INFO is a plist holding contextual
information."
(when (member (org-export-snippet-backend export-snippet) '(11ty html))
(org-element-property :value export-snippet)))
(defun org-11ty-link (link desc info)
"Transcode a LINK object from Org to HTML.
DESC is the description part of the link, or the empty string.
INFO is a plist holding contextual information. See
`org-export-data'."
(or (org-export-custom-protocol-maybe link desc '11ty info)
;; handle file links
(org-html-link link desc info)))
(defun org-11ty-src-block (src-block contents info)
"Wrap source blocks in raw directives."
(format "{%% raw %%}\n%s\n{%% endraw %%}\n"
(org-html-src-block src-block contents info)))
(org-export-define-derived-backend '11ty 'html
:menu-entry
'(?1 "Export to 11ty JS"
((?1 "To 11tydata.json and HTML file" org-11ty-export-to-11tydata-and-html)
(?o "To Org file" org-11ty-export-to-org)
(?b "As buffer" org-11ty-export-as-11ty) ))
:translate-alist '((export-block . org-11ty-export-block)
(export-snippet . org-11ty-export-snippet)
(src-block . org-11ty-src-block)
(link . org-11ty-link))
;; '((template . org-11ty-template))
:options-alist
'((:permalink "ELEVENTY_PERMALINK" nil nil)
(:categories "ELEVENTY_CATEGORIES" nil nil split)
(:base-dir "ELEVENTY_BASE_DIR" nil nil)
(:base-url "ELEVENTY_BASE_URL" nil nil)
(:modified "MODIFIED" nil nil)
(:file-name "ELEVENTY_FILE_NAME" nil nil)
(:extra "ELEVENTY_EXTRA" nil nil)
(:collections "ELEVENTY_COLLECTIONS" nil nil split)
(:html-toplevel-hlevel nil nil org-11ty-toplevel-hlevel)))
(provide 'ox-11ty)
;;; ox-11ty.el ends here