-
-
Notifications
You must be signed in to change notification settings - Fork 120
/
tables.cljc
110 lines (99 loc) · 3.53 KB
/
tables.cljc
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
(ns markdown.tables
(:require [clojure.string :as string]))
(defn parse-table-row [text]
(->> text
(#(if (= (first %) \|)
(apply str (rest %))
%))
(string/trim)
(#(string/split % #"\|"))
(map string/trim)
(map #(identity {:text %}))))
(defn table-row->str [row-data is-header?]
(reduce
(fn [row col]
(let [alignment-str (when (:alignment col)
(str " style='text-align:" (name (:alignment col)) "'"))]
(if is-header?
(str row "<th" alignment-str ">" (:text col) "</th>")
(str row "<td" alignment-str ">" (:text col) "</td>"))))
""
row-data))
(defn table->str [table]
(let [table-data (map-indexed vector (:data table))
alignment-seq (:alignment-seq table)]
(str "<table>"
(reduce
(fn [table-acc row]
(let [row-idx (first row)
row-data (mapv merge (second row) alignment-seq)
is-header? (= row-idx 0)
is-first-row? (= row-idx 1)
is-last-row? (= row-idx (dec (count table-data)))]
(str
table-acc
(cond
is-header?
"<thead>"
is-first-row?
"<tbody>")
"<tr>"
(table-row->str row-data is-header?)
"</tr>"
(cond
is-header?
"</thead>"
is-last-row?
"</tbody>"))))
""
table-data)
"</table>")))
(defn divider-seq->alignment [divider-seq]
(mapv (fn [divider]
(cond
(= (re-find #"^:-+" (:text divider))
(:text divider))
(identity {:alignment :left})
(= (re-find #"^-+:" (:text divider))
(:text divider))
(identity {:alignment :right})
(= (re-find #"^:-+:" (:text divider))
(:text divider))
(identity {:alignment :center})
:else
nil))
divider-seq))
(defn table [text state]
(let [table-row-re (re-find #"\|(?: [\S ]+ \|)+" text)
table-divider-re (re-find #"\|(?: ?:?-+:? ?\|)+" text)
is-table-row? (= table-row-re text)
is-table-header?
(and is-table-row?
(not (get-in state [:table :in-table-body?])))
is-table-divider?
(and (= table-divider-re text)
(get-in state [:table :in-table-body?])
(get-in state [:table :is-prev-header?]))]
(cond
is-table-header?
(let [header-seq (parse-table-row text)]
["" (-> state
(assoc-in [:table :is-prev-header?] true)
(assoc-in [:table :in-table-body?] true)
(update-in [:table :data] (fnil conj []) (vec header-seq)))])
is-table-divider?
(let [divider-seq (parse-table-row text)]
["" (-> state
(assoc-in [:table :is-prev-header?] false)
(assoc-in [:table :alignment-seq]
(divider-seq->alignment divider-seq)))])
is-table-row?
(let [row-seq (parse-table-row text)]
["" (-> state
(assoc-in [:table :is-prev-header?] false)
(update-in [:table :data] (fnil conj []) (vec row-seq)))])
:else
(let [out (if (empty? (get-in state [:table :data]))
text
(str (table->str (:table state)) text))]
[out (dissoc state :table)]))))