laporan-generator 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.agents/skills/laporan-generator/SKILL.md +132 -0
  2. package/.agents/skills/laporan-generator/agents/openai.yaml +3 -0
  3. package/.agents/skills/laporan-generator/references/campus-guide.md +120 -0
  4. package/.agents/skills/laporan-generator/references/metadata-schema.md +76 -0
  5. package/.agents/skills/laporan-generator/references/preset-schema.md +79 -0
  6. package/.agents/skills/laporan-generator/references/syntax-cheatsheet.md +122 -0
  7. package/.agents/skills/laporan-generator/references/template-guide.md +100 -0
  8. package/.agents/skills/laporan-generator/references/troubleshooting.md +105 -0
  9. package/.agents/skills/laporan-generator/resources/Makefile +90 -0
  10. package/.agents/skills/laporan-generator/resources/apa.csl +2273 -0
  11. package/.agents/skills/laporan-generator/resources/build-docx.sh +122 -0
  12. package/.agents/skills/laporan-generator/resources/build.sh +102 -0
  13. package/.agents/skills/laporan-generator/resources/chapters/bab1-pendahuluan.md +60 -0
  14. package/.agents/skills/laporan-generator/resources/chapters/bab2-tinjauan-pustaka.md +83 -0
  15. package/.agents/skills/laporan-generator/resources/chapters/bab3-metodologi.md +116 -0
  16. package/.agents/skills/laporan-generator/resources/chapters/bab4-hasil-dan-pembahasan.md +93 -0
  17. package/.agents/skills/laporan-generator/resources/chapters/bab5-penutup.md +27 -0
  18. package/.agents/skills/laporan-generator/resources/cover.md +50 -0
  19. package/.agents/skills/laporan-generator/resources/docx.lua +416 -0
  20. package/.agents/skills/laporan-generator/resources/laporan +464 -0
  21. package/.agents/skills/laporan-generator/resources/laporan.ps1 +552 -0
  22. package/.agents/skills/laporan-generator/resources/logo.jpg +0 -0
  23. package/.agents/skills/laporan-generator/resources/metadata.yml +35 -0
  24. package/.agents/skills/laporan-generator/resources/presets/itb-ta.yml +27 -0
  25. package/.agents/skills/laporan-generator/resources/presets/its-skripsi.yml +26 -0
  26. package/.agents/skills/laporan-generator/resources/presets/skripsi-4433.yml +26 -0
  27. package/.agents/skills/laporan-generator/resources/presets/standard.yml +26 -0
  28. package/.agents/skills/laporan-generator/resources/presets/ugm-skripsi.yml +26 -0
  29. package/.agents/skills/laporan-generator/resources/presets/ui-skripsi.yml +26 -0
  30. package/.agents/skills/laporan-generator/resources/presets/unpad-skripsi.yml +27 -0
  31. package/.agents/skills/laporan-generator/resources/reference.docx +0 -0
  32. package/.agents/skills/laporan-generator/resources/references.bib +115 -0
  33. package/.agents/skills/laporan-generator/resources/scripts/bundle.py +75 -0
  34. package/.agents/skills/laporan-generator/resources/scripts/docx-pagenum.py +192 -0
  35. package/.agents/skills/laporan-generator/resources/scripts/finalize-docx.py +291 -0
  36. package/.agents/skills/laporan-generator/resources/scripts/make-reference-docx.py +670 -0
  37. package/.agents/skills/laporan-generator/resources/scripts/report-doctor.py +211 -0
  38. package/.agents/skills/laporan-generator/resources/scripts/report-stats.py +149 -0
  39. package/.agents/skills/laporan-generator/resources/scripts/scan-preset.py +311 -0
  40. package/.agents/skills/laporan-generator/resources/scripts/setup-deps.ps1 +152 -0
  41. package/.agents/skills/laporan-generator/resources/scripts/setup-deps.sh +113 -0
  42. package/.agents/skills/laporan-generator/resources/scripts/test_scripts.py +128 -0
  43. package/.agents/skills/laporan-generator/resources/scripts/validate-preset.py +166 -0
  44. package/.agents/skills/laporan-generator/resources/template.typ +394 -0
  45. package/.agents/skills/laporan-generator/scripts/build.sh +78 -0
  46. package/.agents/skills/laporan-generator/scripts/bundle.py +75 -0
  47. package/.agents/skills/laporan-generator/scripts/docx-pagenum.py +192 -0
  48. package/.agents/skills/laporan-generator/scripts/finalize-docx.py +152 -0
  49. package/.agents/skills/laporan-generator/scripts/laporan +447 -0
  50. package/.agents/skills/laporan-generator/scripts/laporan.ps1 +529 -0
  51. package/.agents/skills/laporan-generator/scripts/make-reference-docx.py +630 -0
  52. package/.agents/skills/laporan-generator/scripts/report-doctor.py +211 -0
  53. package/.agents/skills/laporan-generator/scripts/report-stats.py +149 -0
  54. package/.agents/skills/laporan-generator/scripts/scan-preset.py +311 -0
  55. package/.agents/skills/laporan-generator/scripts/setup-deps.ps1 +152 -0
  56. package/.agents/skills/laporan-generator/scripts/setup-deps.sh +113 -0
  57. package/.agents/skills/laporan-generator/scripts/test_scripts.py +103 -0
  58. package/.agents/skills/laporan-generator/scripts/validate-preset.py +166 -0
  59. package/.agents/workflows/laporan-generator.md +8 -0
  60. package/LICENSE +21 -0
  61. package/Makefile +90 -0
  62. package/README.md +389 -0
  63. package/apa.csl +2273 -0
  64. package/bin/laporan-generator.js +71 -0
  65. package/build-docx.sh +122 -0
  66. package/build.sh +102 -0
  67. package/chapters/bab1-pendahuluan.md +60 -0
  68. package/chapters/bab2-tinjauan-pustaka.md +83 -0
  69. package/chapters/bab3-metodologi.md +116 -0
  70. package/chapters/bab4-hasil-dan-pembahasan.md +93 -0
  71. package/chapters/bab5-penutup.md +27 -0
  72. package/cover.md +50 -0
  73. package/docs/campus-guide.md +120 -0
  74. package/docs/metadata-schema.md +76 -0
  75. package/docs/preset-schema.md +79 -0
  76. package/docs/syntax-cheatsheet.md +122 -0
  77. package/docs/template-guide.md +100 -0
  78. package/docs/troubleshooting.md +105 -0
  79. package/docx.lua +416 -0
  80. package/laporan +464 -0
  81. package/laporan.ps1 +552 -0
  82. package/lib/init.js +118 -0
  83. package/lib/setup.js +33 -0
  84. package/lib/sync-hosts.js +194 -0
  85. package/lib/uninstall.js +123 -0
  86. package/logo.jpg +0 -0
  87. package/metadata.yml +35 -0
  88. package/package.json +65 -0
  89. package/presets/itb-ta.yml +27 -0
  90. package/presets/its-skripsi.yml +26 -0
  91. package/presets/skripsi-4433.yml +26 -0
  92. package/presets/standard.yml +26 -0
  93. package/presets/ugm-skripsi.yml +26 -0
  94. package/presets/ui-skripsi.yml +26 -0
  95. package/presets/unpad-skripsi.yml +27 -0
  96. package/reference.docx +0 -0
  97. package/references.bib +115 -0
  98. package/scripts/bundle.py +75 -0
  99. package/scripts/docx-pagenum.py +192 -0
  100. package/scripts/finalize-docx.py +291 -0
  101. package/scripts/make-reference-docx.py +670 -0
  102. package/scripts/report-doctor.py +211 -0
  103. package/scripts/report-stats.py +149 -0
  104. package/scripts/scan-preset.py +311 -0
  105. package/scripts/setup-deps.ps1 +152 -0
  106. package/scripts/setup-deps.sh +113 -0
  107. package/scripts/test_scripts.py +128 -0
  108. package/scripts/validate-preset.py +166 -0
  109. package/template.typ +394 -0
@@ -0,0 +1,50 @@
1
+ # KATA PENGANTAR {-}
2
+
3
+ Puji syukur kehadirat Tuhan Yang Maha Esa atas segala rahmat dan karunia-Nya sehingga laporan yang berjudul **"Otomatisasi Pembuatan Dokumen Laporan Akademik menggunakan Pandoc, Typst, dan Markdown"** dapat diselesaikan dengan baik.
4
+
5
+ Laporan ini disusun sebagai dokumentasi pipeline otomatisasi dokumen akademik yang dibangun menggunakan kombinasi teknologi Markdown, Pandoc, Typst, ImageMagick, dan Bash. Pipeline ini memungkinkan penulisan konten laporan dalam format Markdown yang sederhana, yang kemudian dikonversi menjadi PDF dengan format profesional melalui Pandoc dan Typst.
6
+
7
+ Penulis menyadari bahwa laporan ini tidak dapat terselesaikan tanpa bantuan dari berbagai pihak. Oleh karena itu, penulis mengucapkan terima kasih kepada semua pihak yang telah memberikan dukungan dalam penyelesaian laporan ini.
8
+
9
+ Penulis menyadari bahwa laporan ini masih jauh dari sempurna. Oleh karena itu, kritik dan saran yang membangun sangat diharapkan untuk perbaikan di masa mendatang. Semoga laporan ini dapat memberikan manfaat bagi pembaca dalam memahami konsep otomatisasi dokumen akademik.
10
+
11
+ ```{=typst}
12
+ #v(0.8cm)
13
+ #align(right)[
14
+ Agustus 2026
15
+
16
+ #v(1cm)
17
+ Tim Penyusun
18
+ ]
19
+ #pagebreak()
20
+ #outline(
21
+ title: [#align(center)[#text(size: 14pt, weight: "bold")[DAFTAR ISI]]],
22
+ depth: 3,
23
+ )
24
+ #context {
25
+ let imgs = query(figure.where(kind: image))
26
+ if imgs.len() > 0 {
27
+ pagebreak()
28
+ outline(
29
+ title: align(center)[#text(size: 14pt, weight: "bold")[DAFTAR GAMBAR]],
30
+ target: figure.where(kind: image),
31
+ )
32
+ }
33
+ let tbls = query(figure.where(kind: table))
34
+ if tbls.len() > 0 {
35
+ pagebreak()
36
+ outline(
37
+ title: align(center)[#text(size: 14pt, weight: "bold")[DAFTAR TABEL]],
38
+ target: figure.where(kind: table),
39
+ )
40
+ }
41
+ }
42
+ #pagebreak()
43
+ #set page(numbering: "1")
44
+ #counter(page).update(1)
45
+ ```
46
+
47
+ ```{=openxml}
48
+ <w:p><w:pPr><w:jc w:val="right"/><w:spacing w:before="454"/></w:pPr><w:r><w:t>Agustus 2026</w:t></w:r></w:p>
49
+ <w:p><w:pPr><w:jc w:val="right"/><w:spacing w:before="567"/></w:pPr><w:r><w:t>Tim Penyusun</w:t></w:r></w:p>
50
+ ```
@@ -0,0 +1,416 @@
1
+ -- docx.lua: penomoran heading dan cover page untuk output DOCX.
2
+ -- - Heading 1: "BAB I PENDAHULUAN" (huruf kapital, angka romawi)
3
+ -- - Heading 2: "1.1. Sub Bab" (titik di akhir nomor)
4
+ -- - Heading 3: "1.1.1 Sub Sub Bab"
5
+ -- - Heading dengan atribut {-} (unnumbered) dilewati tanpa penomoran.
6
+ -- - Cover page dibangun dari metadata (logo, judul, penulis, institusi)
7
+ -- meniru cover PDF, menggantikan title block bawaan pandoc.
8
+ --
9
+ -- Dipakai lewat `pandoc ... --lua-filter=docx.lua --reference-doc=reference.docx`.
10
+
11
+ local bab = 0
12
+ local sub = 0
13
+ local subsub = 0
14
+ local toc_entries = {}
15
+ local chapter_prefix = "BAB "
16
+ local chapter_num_fmt = "roman"
17
+
18
+ local function is_unnumbered(el)
19
+ for _, cls in ipairs(el.attr.classes or {}) do
20
+ if cls == "unnumbered" then
21
+ return true
22
+ end
23
+ end
24
+ return false
25
+ end
26
+
27
+ local function roman(n)
28
+ local map = {
29
+ {1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"},
30
+ {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"},
31
+ {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"},
32
+ }
33
+ local out = ""
34
+ for _, pair in ipairs(map) do
35
+ while n >= pair[1] do
36
+ out = out .. pair[2]
37
+ n = n - pair[1]
38
+ end
39
+ end
40
+ return out
41
+ end
42
+
43
+ local function balance_title(text)
44
+ local words = {}
45
+ for w in text:gmatch("%S+") do
46
+ words[#words + 1] = w
47
+ end
48
+ local n = #words
49
+ if n <= 1 or #text <= 55 then
50
+ return { text }
51
+ end
52
+ local function count_words(s)
53
+ local c = 0
54
+ for _ in s:gmatch("%S+") do
55
+ c = c + 1
56
+ end
57
+ return c
58
+ end
59
+ local function best_for(k)
60
+ local best, best_cost = nil, math.huge
61
+ local function rec(i, kk, cur, mx, single)
62
+ if kk == 1 then
63
+ local line = table.concat(words, " ", i, n)
64
+ local lines = {}
65
+ for _, l in ipairs(cur) do
66
+ lines[#lines + 1] = l
67
+ end
68
+ lines[#lines + 1] = line
69
+ local m = math.max(mx, #line)
70
+ local s = single + (count_words(line) <= 1 and 1 or 0)
71
+ local cost = m + 100 * s
72
+ if cost < best_cost then
73
+ best, best_cost = lines, cost
74
+ end
75
+ return
76
+ end
77
+ for j = i, n - kk + 1 do
78
+ local line = table.concat(words, " ", i, j)
79
+ local nxt = {}
80
+ for _, l in ipairs(cur) do
81
+ nxt[#nxt + 1] = l
82
+ end
83
+ nxt[#nxt + 1] = line
84
+ rec(
85
+ j + 1,
86
+ kk - 1,
87
+ nxt,
88
+ math.max(mx, #line),
89
+ single + (count_words(line) <= 1 and 1 or 0)
90
+ )
91
+ end
92
+ end
93
+ rec(1, k, {}, 0, 0)
94
+ return best
95
+ end
96
+ local function mx_of(lines)
97
+ local m = 0
98
+ for _, l in ipairs(lines) do
99
+ m = math.max(m, #l)
100
+ end
101
+ return m
102
+ end
103
+ local function orphan(lines)
104
+ for _, l in ipairs(lines) do
105
+ if count_words(l) <= 1 then
106
+ return true
107
+ end
108
+ end
109
+ return false
110
+ end
111
+ local two = best_for(2)
112
+ if not orphan(two) and mx_of(two) <= 50 then
113
+ return two
114
+ end
115
+ return best_for(3)
116
+ end
117
+
118
+ local function para(content, style)
119
+ return pandoc.Div(
120
+ { pandoc.Para(content) },
121
+ pandoc.Attr("", {}, { ["custom-style"] = style })
122
+ )
123
+ end
124
+
125
+ local function pagebreak()
126
+ return pandoc.RawBlock("openxml", '<w:p><w:r><w:br w:type="page"/></w:r></w:p>')
127
+ end
128
+
129
+ local function spacer(before)
130
+ return pandoc.RawBlock(
131
+ "openxml",
132
+ '<w:p><w:pPr><w:spacing w:before="' .. before .. '"/></w:pPr></w:p>'
133
+ )
134
+ end
135
+
136
+ local function meta_str(meta, key)
137
+ local v = meta[key]
138
+ if v == nil then
139
+ return ""
140
+ end
141
+ return pandoc.utils.stringify(v)
142
+ end
143
+
144
+ local function format_chapter_number(n)
145
+ if chapter_num_fmt == "arabic" then
146
+ return tostring(n)
147
+ else
148
+ return roman(n)
149
+ end
150
+ end
151
+
152
+ local function Meta(meta)
153
+ if meta["heading_chapter_prefix"] ~= nil then
154
+ local pfx = meta_str(meta, "heading_chapter_prefix")
155
+ if pfx == "" then
156
+ chapter_prefix = ""
157
+ else
158
+ if not pfx:match("%s$") then
159
+ pfx = pfx .. " "
160
+ end
161
+ chapter_prefix = pfx
162
+ end
163
+ end
164
+ local fmt = meta_str(meta, "heading_chapter_num_format")
165
+ if fmt ~= "" then
166
+ chapter_num_fmt = fmt
167
+ end
168
+ end
169
+
170
+ function Header(el)
171
+ if FORMAT ~= "docx" then
172
+ return nil
173
+ end
174
+ local title = pandoc.utils.stringify(el.content)
175
+ if is_unnumbered(el) then
176
+ if el.level == 1 then
177
+ toc_entries[#toc_entries + 1] = {
178
+ level = 1,
179
+ id = el.identifier,
180
+ text = string.upper(title),
181
+ }
182
+ end
183
+ return nil
184
+ end
185
+ if el.level == 1 then
186
+ bab = bab + 1
187
+ sub = 0
188
+ subsub = 0
189
+ local bnum = format_chapter_number(bab)
190
+ local full_bab = chapter_prefix .. bnum
191
+ if chapter_prefix == "" then
192
+ full_bab = bnum .. "."
193
+ toc_entries[#toc_entries + 1] = {
194
+ level = 1,
195
+ id = el.identifier,
196
+ text = full_bab .. " " .. string.upper(title),
197
+ }
198
+ el.content = pandoc.List{
199
+ pandoc.Str(full_bab .. " " .. string.upper(title)),
200
+ }
201
+ else
202
+ toc_entries[#toc_entries + 1] = {
203
+ level = 1,
204
+ id = el.identifier,
205
+ text = full_bab .. " " .. string.upper(title),
206
+ }
207
+ el.content = pandoc.List{
208
+ pandoc.Str(full_bab),
209
+ pandoc.LineBreak(),
210
+ pandoc.Str(string.upper(title)),
211
+ }
212
+ end
213
+ elseif el.level == 2 then
214
+ sub = sub + 1
215
+ subsub = 0
216
+ toc_entries[#toc_entries + 1] = {
217
+ level = 2,
218
+ id = el.identifier,
219
+ text = bab .. "." .. sub .. ". " .. title,
220
+ }
221
+ el.content = pandoc.Str(bab .. "." .. sub .. ". " .. title)
222
+ elseif el.level == 3 then
223
+ subsub = subsub + 1
224
+ toc_entries[#toc_entries + 1] = {
225
+ level = 3,
226
+ id = el.identifier,
227
+ text = bab .. "." .. sub .. "." .. subsub .. " " .. title,
228
+ }
229
+ el.content = pandoc.Str(bab .. "." .. sub .. "." .. subsub .. " " .. title)
230
+ end
231
+ return el
232
+ end
233
+
234
+ local function toc_entry(e)
235
+ local style, ind, bold, spacing = "TOC1", 0, "<w:rPr><w:b/></w:rPr>", '<w:spacing w:before="120" w:after="40" w:line="260" w:lineRule="auto"/>'
236
+ if e.level == 2 then
237
+ style, ind, bold, spacing = "TOC2", 360, "", '<w:spacing w:before="20" w:after="20" w:line="240" w:lineRule="auto"/>'
238
+ elseif e.level == 3 then
239
+ style, ind, bold, spacing = "TOC3", 720, "", '<w:spacing w:before="0" w:after="0" w:line="240" w:lineRule="auto"/>'
240
+ end
241
+ return '<w:p><w:pPr><w:pStyle w:val="' .. style .. '"/>' ..
242
+ spacing ..
243
+ '<w:tabs><w:tab w:val="right" w:leader="dot" w:pos="9072"/></w:tabs>' ..
244
+ '<w:ind w:left="' .. ind .. '" w:right="0"/></w:pPr>' ..
245
+ '<w:hyperlink w:anchor="' .. e.id .. '" w:history="1">' ..
246
+ '<w:r>' .. bold .. '<w:t xml:space="preserve">' .. e.text .. '</w:t></w:r>' ..
247
+ '</w:hyperlink>' ..
248
+ '<w:r><w:tab/></w:r>' ..
249
+ '<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
250
+ '<w:r><w:instrText xml:space="preserve"> PAGEREF ' .. e.id .. ' \\h </w:instrText></w:r>' ..
251
+ '<w:r><w:fldChar w:fldCharType="separate"/></w:r>' ..
252
+ '<w:r><w:t>0</w:t></w:r>' ..
253
+ '<w:r><w:fldChar w:fldCharType="end"/></w:r>' ..
254
+ '</w:p>'
255
+ end
256
+
257
+ local function daftar_isi()
258
+ local out = pandoc.List{}
259
+ out[#out + 1] = pagebreak()
260
+ out[#out + 1] = pandoc.RawBlock(
261
+ "openxml",
262
+ '<w:p><w:pPr><w:pStyle w:val="TOCHeading"/><w:jc w:val="center"/><w:outlineLvl w:val="9"/></w:pPr>' ..
263
+ '<w:r><w:rPr><w:b/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr><w:t>DAFTAR ISI</w:t></w:r></w:p>'
264
+ )
265
+ out[#out + 1] = pandoc.RawBlock(
266
+ "openxml",
267
+ '<w:p><w:pPr><w:pStyle w:val="TOC1"/></w:pPr>' ..
268
+ '<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
269
+ '<w:r><w:instrText xml:space="preserve"> TOC \\o "1-3" \\h \\z \\u </w:instrText></w:r>' ..
270
+ '<w:r><w:fldChar w:fldCharType="separate"/></w:r></w:p>'
271
+ )
272
+ for _, e in ipairs(toc_entries) do
273
+ out[#out + 1] = pandoc.RawBlock("openxml", toc_entry(e))
274
+ end
275
+ out[#out + 1] = pandoc.RawBlock(
276
+ "openxml",
277
+ '<w:p><w:pPr><w:pStyle w:val="TOC1"/></w:pPr>' ..
278
+ '<w:r><w:fldChar w:fldCharType="end"/></w:r></w:p>'
279
+ )
280
+ return out
281
+ end
282
+
283
+ function Pandoc(doc)
284
+ if FORMAT ~= "docx" then
285
+ return doc
286
+ end
287
+ local meta = doc.meta
288
+ local title = meta_str(meta, "title")
289
+ local subtitle = meta_str(meta, "subtitle")
290
+ local course = meta_str(meta, "course")
291
+ local lecturer = meta_str(meta, "lecturer")
292
+ local faculty = meta_str(meta, "faculty")
293
+ local institution = meta_str(meta, "institution")
294
+ local year = meta_str(meta, "year")
295
+
296
+ local blocks = pandoc.List{}
297
+
298
+ if title ~= "" then
299
+ local tlines = balance_title(string.upper(title))
300
+ local content = {}
301
+ for i, l in ipairs(tlines) do
302
+ if i > 1 then
303
+ content[#content + 1] = pandoc.LineBreak()
304
+ end
305
+ content[#content + 1] = pandoc.Str(l)
306
+ end
307
+ blocks[#blocks + 1] = para(content, "CoverTitle")
308
+ if subtitle ~= "" then
309
+ blocks[#blocks + 1] = para({ pandoc.Str(string.upper(subtitle)) }, "CoverSubtitle")
310
+ end
311
+ if course ~= "" then
312
+ blocks[#blocks + 1] = para({ pandoc.Strong(pandoc.Str(course)) }, "CoverCourse")
313
+ end
314
+ local hide_lecturer = meta_str(meta, "cover_hide_lecturer") == "true" or meta_str(meta, "cover_show_lecturer") == "false"
315
+ if lecturer ~= "" and not hide_lecturer then
316
+ local lecturer_lbl = meta_str(meta, "lecturer_label")
317
+ if lecturer_lbl == "" then
318
+ lecturer_lbl = "Dosen Pengampu: "
319
+ else
320
+ if not lecturer_lbl:match(":%s*$") then
321
+ lecturer_lbl = lecturer_lbl .. ": "
322
+ elseif not lecturer_lbl:match("%s$") then
323
+ lecturer_lbl = lecturer_lbl .. " "
324
+ end
325
+ end
326
+ blocks[#blocks + 1] = para(
327
+ { pandoc.Str(lecturer_lbl), pandoc.Strong(pandoc.Str(lecturer)) },
328
+ "CoverLecturer"
329
+ )
330
+ end
331
+ local logo_width = meta_str(meta, "cover_logo_width")
332
+ if logo_width == "" then
333
+ logo_width = "4cm"
334
+ end
335
+ blocks[#blocks + 1] = spacer(640)
336
+ blocks[#blocks + 1] = pandoc.Div(
337
+ { pandoc.Para({ pandoc.Image({}, "logo.jpg", "", pandoc.Attr("", {}, { width = logo_width })) }) },
338
+ pandoc.Attr("", {}, { ["custom-style"] = "CoverImage" })
339
+ )
340
+ blocks[#blocks + 1] = spacer(640)
341
+ end
342
+
343
+ local authors = meta["author"]
344
+ if authors ~= nil then
345
+ local author_list = {}
346
+ if authors[1] ~= nil then
347
+ for _, a in ipairs(authors) do
348
+ author_list[#author_list + 1] = a
349
+ end
350
+ else
351
+ author_list[#author_list + 1] = authors
352
+ end
353
+ if #author_list > 0 then
354
+ blocks[#blocks + 1] = para({ pandoc.Str("Disusun oleh:") }, "CoverLine")
355
+ for _, a in ipairs(author_list) do
356
+ local name = pandoc.utils.stringify(a["name"] or a)
357
+ local nim = pandoc.utils.stringify(a["nim"] or "")
358
+ blocks[#blocks + 1] = para({ pandoc.Strong(pandoc.Str(name)) }, "CoverName")
359
+ if nim ~= "" then
360
+ blocks[#blocks + 1] = para({ pandoc.Str(nim) }, "CoverLine")
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ if faculty ~= "" or institution ~= "" or year ~= "" then
367
+ blocks[#blocks + 1] = spacer(640)
368
+ if faculty ~= "" then
369
+ blocks[#blocks + 1] = para({ pandoc.Str(string.upper(faculty)) }, "CoverInstitution")
370
+ end
371
+ if institution ~= "" then
372
+ blocks[#blocks + 1] = para({ pandoc.Str(string.upper(institution)) }, "CoverInstitution")
373
+ end
374
+ if year ~= "" then
375
+ blocks[#blocks + 1] = para({ pandoc.Str(string.upper(year)) }, "CoverInstitution")
376
+ end
377
+ end
378
+
379
+ -- Section break (Next Page) penutup cover: tanpa footer/nomor halaman
380
+ blocks[#blocks + 1] = pandoc.RawBlock(
381
+ "openxml",
382
+ '<w:p><w:pPr><w:sectPr><w:footnotePr><w:numRestart w:val="eachSect"/></w:footnotePr><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1134" w:right="1417" w:bottom="1701" w:left="1417" w:header="720" w:footer="720" w:gutter="0"/></w:sectPr></w:pPr></w:p>'
383
+ )
384
+
385
+ meta.title = nil
386
+ meta.subtitle = nil
387
+ meta.date = nil
388
+ meta.author = nil
389
+ meta.abstract = nil
390
+ meta["abstract-title"] = nil
391
+
392
+ local body = pandoc.List{}
393
+ local inserted = false
394
+ for _, blk in ipairs(doc.blocks) do
395
+ if
396
+ not inserted
397
+ and blk.tag == "Header"
398
+ and blk.level == 1
399
+ and not is_unnumbered(blk)
400
+ then
401
+ for _, b in ipairs(daftar_isi()) do
402
+ body[#body + 1] = b
403
+ end
404
+ inserted = true
405
+ end
406
+ body[#body + 1] = blk
407
+ end
408
+
409
+ doc.blocks = blocks .. body
410
+ return doc
411
+ end
412
+
413
+ return {
414
+ { Meta = Meta },
415
+ { Header = Header, Pandoc = Pandoc }
416
+ }