asciidoctor-dita-topic 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/dita-topic.rb +704 -0
  3. metadata +66 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a78953056690681fd5bd90e2ddc9bf86fc58a97e13ef88e3493aaccfd841af38
4
+ data.tar.gz: a6f0615ccc0706a2c70411596d7d6bf535530643548b45ca3647b9763e75c289
5
+ SHA512:
6
+ metadata.gz: e4844fa7069d23b72d084a398a1d9895e1ce34c8a2a888508d9b83aefefa36cf4c56d681a6b6ffdd5f5891f7223128f5806e73fdb94624228399726d085a9253
7
+ data.tar.gz: 47bf20454de4e0b2c4ad8386ac6a4f81d5d792c3ee7ff0b73b2b2fe1cba700a3cd93f65edce4ecf082f3ea2d0954aeada3a685213005de3e49bf95dc9920736c
data/lib/dita-topic.rb ADDED
@@ -0,0 +1,704 @@
1
+ # A custom AsciiDoc converter that generates individual DITA topics
2
+ # Copyright (C) 2024 Jaromir Hradilek
3
+
4
+ # MIT License
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the "Soft-
8
+ # ware"), to deal in the Software without restriction, including without
9
+ # limitation the rights to use, copy, modify, merge, publish, distribute,
10
+ # sublicense, and/or sell copies of the Software, and to permit persons to
11
+ # whom the Software is furnished to do so, subject to the following condi-
12
+ # tions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included
15
+ # in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABI-
19
+ # LITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
20
+ # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
21
+ # OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ # OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ # frozen_string_literal: true
26
+
27
+ module Asciidoctor
28
+ class DitaConverter < Asciidoctor::Converter::Base
29
+ NAME = 'dita-topic'
30
+ register_for NAME
31
+
32
+ def initialize *args
33
+ super
34
+ outfilesuffix '.dita'
35
+ end
36
+
37
+ def convert_document node
38
+ # Check if the modular documentation content type is specified:
39
+ content_type = (node.attr? '_mod-docs-content-type') ? %( outputclass="#{(node.attr '_mod-docs-content-type').downcase}") : ''
40
+
41
+ # Return the XML output:
42
+ <<~EOF.chomp
43
+ <?xml version='1.0' encoding='utf-8' ?>
44
+ <!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
45
+ <topic#{compose_id (node.id or node.attributes['docname'])}#{content_type}>
46
+ <title>#{node.doctitle}</title>
47
+ <body>
48
+ #{node.content}
49
+ </body>
50
+ </topic>
51
+ EOF
52
+ end
53
+
54
+ def convert_admonition node
55
+ # NOTE: Unlike admonitions in AsciiDoc, the <note> element in DITA
56
+ # cannot have its own <title>. Admonition titles are therefore not
57
+ # preserved.
58
+
59
+ # Issue a warning if the admonition has a title:
60
+ if node.title?
61
+ logger.warn "#{NAME}: Admonition title not supported in DITA: #{node.title}"
62
+ end
63
+
64
+ # Return the XML output:
65
+ <<~EOF.chomp
66
+ <note type="#{node.attr 'name'}">
67
+ #{node.content}
68
+ </note>
69
+ EOF
70
+ end
71
+
72
+ def convert_audio node
73
+ # Issue a warning if audio content is present:
74
+ logger.warn "#{NAME}: Audio macro not supported"
75
+ return ''
76
+ end
77
+
78
+ # FIXME: Figure out how to handle this along with convert_inline_callout.
79
+ # A definition list looks like a reasonable option.
80
+ def convert_colist node
81
+ # Issue a warning if a callout list is present:
82
+ logger.warn "#{NAME}: Callout list support not implemented"
83
+ return ''
84
+ end
85
+
86
+ # FIXME: Add support for a title.
87
+ def convert_dlist node
88
+ # Check if a different list style is set:
89
+ return compose_horizontal_dlist node if node.style == 'horizontal'
90
+ return compose_qanda_dlist node if node.style == 'qanda'
91
+
92
+ # Open the definition list:
93
+ result = ['<dl>']
94
+
95
+ # Process individual list items:
96
+ node.items.each do |terms, description|
97
+ # Open the definition entry:
98
+ result << %(<dlentry>)
99
+
100
+ # Process individual terms:
101
+ terms.each do |item|
102
+ result << %(<dt>#{item.text}</dt>)
103
+ end
104
+
105
+ # Check if the term description is specified:
106
+ if description
107
+ # Check if the description contains multiple block elements:
108
+ if description.blocks?
109
+ result << %(<dd>)
110
+ result << %(<p>#{description.text}</p>) if description.text?
111
+ result << description.content
112
+ result << %(</dd>)
113
+ else
114
+ result << %(<dd>#{description.text}</dd>)
115
+ end
116
+ end
117
+
118
+ # Close the definition entry:
119
+ result << %(</dlentry>)
120
+ end
121
+
122
+ # Close the definition list:
123
+ result << '</dl>'
124
+
125
+ # Return the XML output:
126
+ result.join LF
127
+ end
128
+
129
+ def convert_example node
130
+ <<~EOF.chomp
131
+ <example#{compose_id node.id}>
132
+ #{compose_title node.title}#{node.content}
133
+ </example>
134
+ EOF
135
+ end
136
+
137
+ def convert_floating_title node
138
+ compose_floating_title node.title, node.level
139
+ end
140
+
141
+ # FIXME: Add support for additional attributes.
142
+ def convert_image node
143
+ # Check if the image has a title specified:
144
+ if node.title?
145
+ <<~EOF.chomp
146
+ <fig>
147
+ <title>#{node.title}</title>
148
+ <image href="#{node.image_uri(node.attr 'target')}" placement="break">
149
+ <alt>#{node.alt}</alt>
150
+ </image>
151
+ </fig>
152
+ EOF
153
+ else
154
+ <<~EOF.chomp
155
+ <image href="#{node.image_uri(node.attr 'target')}" placement="break">
156
+ <alt>#{node.alt}</alt>
157
+ </image>
158
+ EOF
159
+ end
160
+ end
161
+
162
+ def convert_inline_anchor node
163
+ # Determine the type of the anchor:
164
+ case node.type
165
+ when :link
166
+ # Compose an external link:
167
+ %(<xref href="#{node.target}" scope="external">#{node.text}</xref>)
168
+ when :xref
169
+ # NOTE: While AsciiDoc is happy to reference an ID that is not
170
+ # defined in the same AsciiDoc file, DITA requires the topic ID as
171
+ # part of the reference. As this script does not have direct access
172
+ # to the topic IDs of external files and to avoid performance issues
173
+ # I do not want to process them from this script, I choose to issue a
174
+ # warning so that the user can resolve the problem.
175
+
176
+ # Determine whether the cross reference links to a file path or an ID:
177
+ if (path = node.attributes['path'])
178
+ # Issue a warning if the cross reference includes an ID:
179
+ logger.warn "#{NAME}: Possible invalid reference: #{node.target}" if node.target.include? '#'
180
+
181
+ # Compose a cross reference:
182
+ %(<xref href="#{node.target}">#{node.text || path}</xref>)
183
+ else
184
+ # Issue a warning as the cross reference is unlikely to work:
185
+ logger.warn "#{NAME}: Possible invalid reference: #{node.target}"
186
+
187
+ # Compose the cross reference:
188
+ node.text ? %(<xref href="#{node.target}">#{node.text}</xref>) : %(<xref href="#{node.target}" />)
189
+ end
190
+ when :ref
191
+ # NOTE: DITA does not have a dedicated element for inline anchors or
192
+ # a direct equivalent of the <span> element from HTML. The solution
193
+ # below is the least invasive way I could find to achieve the
194
+ # equivalent behavior.
195
+
196
+ # Compose an inline anchor:
197
+ %(<i id="#{node.id}" />)
198
+ when :bibref
199
+ # NOTE: DITA does not have a dedicated element for inline anchors or
200
+ # a direct equivalent of the <span> element from HTML. The solution
201
+ # below is the least invasive way I could find to achieve the
202
+ # equivalent behavior.
203
+
204
+ # Compose a bibliographic reference:
205
+ %(<i id="#{node.id}" />[#{node.reftext || node.id}])
206
+ else
207
+ # Issue a warning if an unknown anchor type is present:
208
+ logger.warn "#{NAME}: Unknown anchor type: #{node.type}"
209
+ ''
210
+ end
211
+ end
212
+
213
+ def convert_inline_break node
214
+ # NOTE: Unlike AsciiDoc, DITA does not support inline line breaks.
215
+
216
+ # Issue a warning if an inline line break is present:
217
+ logger.warn "#{NAME}: Inline breaks not supported in DITA"
218
+
219
+ # Return the XML output:
220
+ %(#{node.text}<!-- break -->)
221
+ end
222
+
223
+ def convert_inline_button node
224
+ %(<uicontrol outputclass="button">#{node.text}</uicontrol>)
225
+ end
226
+
227
+ def convert_inline_callout node
228
+ # Issue a warning if an inline callout is present:
229
+ logger.warn "#{NAME}: Inline callout support not implemented"
230
+ return ''
231
+ end
232
+
233
+ # FIXME: Add support for footnoteref equivalent.
234
+ def convert_inline_footnote node
235
+ %(<fn>#{node.text}</fn>)
236
+ end
237
+
238
+ # FIXME: Add support for additional attributes.
239
+ def convert_inline_image node
240
+ %(<image href="#{node.image_uri node.target}" placement="inline"><alt>#{node.alt}</alt></image>)
241
+ end
242
+
243
+ def convert_inline_indexterm node
244
+ # Issue a warning if an inline index term is present:
245
+ logger.warn "#{NAME}: Inline index terms not implemented"
246
+ return ''
247
+ end
248
+
249
+ # FIXME: Investigate if there is an equivalent of <span> in DITA that
250
+ # would group individual <uicontrol> elements together.
251
+ def convert_inline_kbd node
252
+ # Check if there is more than one key:
253
+ if (keys = node.attr 'keys').size == 1
254
+ %(<uicontrol outputclass="key">#{keys[0]}</uicontrol>)
255
+ else
256
+ %(<uicontrol outputclass="key">#{keys.join '</uicontrol>+<uicontrol outputclass="key">'}</uicontrol>)
257
+ end
258
+ end
259
+
260
+ def convert_inline_menu node
261
+ # Compose the markup for the menu:
262
+ menu = %(<uicontrol>#{node.attr 'menu'}</uicontrol>)
263
+
264
+ # Compose the markup for possible submenus:
265
+ submenus = (not (node.attr 'submenus').empty?) ? %(<uicontrol>#{(node.attr 'submenus').join '</uicontrol><uicontrol>'}</uicontrol>) : ''
266
+
267
+ # Compose the markup for the menu item:
268
+ menuitem = (node.attr 'menuitem') ? %(<uicontrol>#{node.attr 'menuitem'}</uicontrol>) : ''
269
+
270
+ # Return the XML output:
271
+ %(<menucascade>#{menu}#{submenus}#{menuitem}</menucascade>)
272
+ end
273
+
274
+ def convert_inline_quoted node
275
+ # Determine the inline markup type:
276
+ case node.type
277
+ when :emphasis
278
+ %(<i>#{node.text}</i>)
279
+ when :strong
280
+ %(<b>#{node.text}</b>)
281
+ when :monospaced
282
+ %(<tt>#{node.text}</tt>)
283
+ when :superscript
284
+ %(<sup>#{node.text}</sup>)
285
+ when :subscript
286
+ %(<sub>#{node.text}</sub>)
287
+ when :double
288
+ %(&#8220;#{node.text}&#8221;)
289
+ when :single
290
+ %(&#8216;#{node.text}&#8217;)
291
+ else
292
+ node.text
293
+ end
294
+ end
295
+
296
+ def convert_listing node
297
+ # Check the listing style:
298
+ if node.style == 'source'
299
+ # Check whether the source language is defined:
300
+ language = (node.attributes.key? 'language') ? %( outputclass="language-#{node.attributes['language']}") : ''
301
+
302
+ # Return the XML output:
303
+ <<~EOF.chomp
304
+ <codeblock#{language}>
305
+ #{node.content}
306
+ </codeblock>
307
+ EOF
308
+ else
309
+ # Return the XML output:
310
+ <<~EOF.chomp
311
+ <screen>
312
+ #{node.content}
313
+ </screen>
314
+ EOF
315
+ end
316
+ end
317
+
318
+ def convert_literal node
319
+ <<~EOF.chomp
320
+ <pre>
321
+ #{node.content}
322
+ </pre>
323
+ EOF
324
+ end
325
+
326
+ # FIXME: Add support for titles.
327
+ def convert_olist node
328
+ # Open the ordered list:
329
+ result = ['<ol>']
330
+
331
+ # Process individual list items:
332
+ node.items.each do |item|
333
+ # Check if the list item contains multiple block elements:
334
+ if item.blocks?
335
+ result << %(<li>)
336
+ result << %(<p>#{item.text}</p>)
337
+ result << item.content
338
+ result << %(</li>)
339
+ else
340
+ result << %(<li>#{item.text}</li>)
341
+ end
342
+ end
343
+
344
+ # Close the ordered list:
345
+ result << '</ol>'
346
+
347
+ # Return the XML output:
348
+ result.join LF
349
+ end
350
+
351
+ # FIXME: This is not the top priority.
352
+ def convert_open node
353
+ ''
354
+ end
355
+
356
+ def convert_page_break node
357
+ # NOTE: Unlike AsciiDoc, DITA does not support page breaks.
358
+
359
+ # Issue a warning if a page break is present:
360
+ logger.warn "#{NAME}: Page breaks not supported in DITA"
361
+
362
+ # Return the XML output:
363
+ %(<p outputclass="page-break"></p>)
364
+ end
365
+
366
+ def convert_paragraph node
367
+ # Check if the paragraph has a title assigned:
368
+ if node.title?
369
+ <<~EOF.chomp
370
+ <div outputclass="paragraph">
371
+ #{compose_floating_title node.title}<p>#{node.content}</p>
372
+ </div>
373
+ EOF
374
+ else
375
+ %(<p>#{node.content}</p>)
376
+ end
377
+ end
378
+
379
+ def convert_preamble node
380
+ node.content
381
+ end
382
+
383
+ def convert_quote node
384
+ # Check if the author is defined:
385
+ author = (node.attr? 'attribution') ? %(\n<p>&#8212; #{node.attr 'attribution'}</p>) : ''
386
+
387
+ # Check if the citation source is defined:
388
+ source = (node.attr? 'citetitle') ? %(\n<cite>#{node.attr 'citetitle'}</cite>) : ''
389
+
390
+ # Check if the content contains multiple block elements:
391
+ if node.content_model == :compound
392
+ <<~EOF.chomp
393
+ <lq>
394
+ #{compose_floating_title node.title}#{node.content}#{author}#{source}
395
+ </lq>
396
+ EOF
397
+ else
398
+ <<~EOF.chomp
399
+ <lq>
400
+ #{compose_floating_title node.title}<p>#{node.content}</p>#{author}#{source}
401
+ </lq>
402
+ EOF
403
+ end
404
+ end
405
+
406
+ def convert_section node
407
+ # NOTE: Unlike sections in AsciiDoc, the <section> element in DITA
408
+ # cannot be nested. Consequently, converting AsciiDoc files that do
409
+ # contain nested subsections will result in invalid markup.
410
+ #
411
+ # I explored the possibility to use the <topic> element instead as it
412
+ # can be nested, but that presents a problem with closing the <body>
413
+ # element of the parent <topic>. As only a very small number of
414
+ # AsciiDoc modules contain nested subsections, I chose the simple
415
+ # markup.
416
+
417
+ # Issue a warning if there are nested sections:
418
+ logger.warn "#{NAME}: Nesting of sections not supported in DITA" if node.level > 1
419
+
420
+ # Return the XML output:
421
+ <<~EOF.chomp
422
+ <section#{compose_id node.id}>
423
+ <title>#{node.title}</title>
424
+ #{node.content}
425
+ </section>
426
+ EOF
427
+ end
428
+
429
+ def convert_sidebar node
430
+ # NOTE: Unlike AsciiDoc, DITA does not provide markup for a sidebar. As
431
+ # a workaround, I decided to use a div with the outputclass attribute.
432
+
433
+ # Check if the content contains multiple block elements:
434
+ if node.content_model == :compound
435
+ <<~EOF.chomp
436
+ <div outputclass="sidebar">
437
+ #{compose_floating_title node.title}#{node.content}
438
+ </div>
439
+ EOF
440
+ else
441
+ <<~EOF.chomp
442
+ <div outputclass="sidebar">
443
+ #{compose_floating_title node.title}<p>#{node.content}</p>
444
+ </div>
445
+ EOF
446
+ end
447
+ end
448
+
449
+ def convert_stem node
450
+ # Issue a warning if a STEM content is present:
451
+ logger.warn "#{NAME}: STEM support not implemented"
452
+ return ''
453
+ end
454
+
455
+ def convert_table node
456
+ # Open the table:
457
+ result = ['<table>']
458
+
459
+ # Check if the title is specified:
460
+ result << %(<title>#{node.title}</title>) if node.title?
461
+
462
+ # Define the table properties and open the tgroup:
463
+ result << %(<tgroup cols="#{node.attr 'colcount'}">)
464
+
465
+ # Define column properties:
466
+ node.columns.each do |column|
467
+ result << %(<colspec colname="col_#{column.attr 'colnumber'}" colwidth="#{column.attr ((node.attr? 'width') ? 'colabswidth' : 'colpcwidth')}*"/>)
468
+ end
469
+
470
+ # Process each table section (header, body, and footer):
471
+ node.rows.to_h.each do |type, rows|
472
+ # Skip empty sections:
473
+ next if rows.empty?
474
+
475
+ # Issue a warning if a table footer is present:
476
+ if type == :foot
477
+ logger.warn "#{NAME}: Table footers not supported in DITA"
478
+ next
479
+ end
480
+
481
+ # Open the section:
482
+ result << %(<t#{type}>)
483
+
484
+ # Process each row:
485
+ rows.each do |row|
486
+ # Open the row:
487
+ result <<%(<row>)
488
+
489
+ # Process each cell:
490
+ row.each do |cell|
491
+ # Check if the cell spans multiple columns:
492
+ colspan = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{column + cell.colspan - 1}") : ''
493
+
494
+ # Check if the cell spans multiple rows:
495
+ rowspan = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
496
+
497
+ # Compose the entry tag:
498
+ entry_tag = %(entry#{colspan}#{rowspan})
499
+
500
+ # Determine the formatting of the entry:
501
+ if type == :head
502
+ result << %(<#{entry_tag}>#{cell.text}</entry>)
503
+ next
504
+ end
505
+ case cell.style
506
+ when :asciidoc
507
+ result << %(<#{entry_tag}>#{cell.content}</entry>)
508
+ when :literal
509
+ result << %(<#{entry_tag}><pre>#{cell.text}</pre></entry>)
510
+ else
511
+ result << %(<#{entry_tag}>)
512
+ cell.content.each do |line|
513
+ result << %(<p>#{line}</p>)
514
+ end
515
+ result << %(</entry>)
516
+ end
517
+ end
518
+
519
+ # Close the row:
520
+ result <<%(</row>)
521
+ end
522
+
523
+ # Close the section:
524
+ result << %(</t#{type}>)
525
+ end
526
+
527
+ # Close the table:
528
+ result << %(</tgroup>)
529
+ result << %(</table>)
530
+
531
+ # Return the XML output:
532
+ result.join LF
533
+ end
534
+
535
+ def convert_thematic_break node
536
+ # NOTE: Unlike AsciiDoc, DITA does not support thematic breaks.
537
+
538
+ # Issue a warning if a thematic break is present:
539
+ logger.warn "#{NAME}: Thematic breaks not supported in DITA"
540
+
541
+ # Return the XML output:
542
+ %(<p outputclass="thematic-break"></p>)
543
+ end
544
+
545
+ # FIXME: Add support for titles.
546
+ def convert_ulist node
547
+ # Open the unordered list:
548
+ result = ['<ul>']
549
+
550
+ # Process individual list items:
551
+ node.items.each do |item|
552
+ # Check if the list item is part of a checklist:
553
+ unless item.attr? 'checkbox'
554
+ check_box = ''
555
+ else
556
+ check_box = (item.attr? 'checked') ? '&#10003; ' : '&#10063; '
557
+ end
558
+
559
+ # Check if the list item contains multiple block elements:
560
+ if item.blocks?
561
+ result << %(<li>)
562
+ result << %(<p>#{check_box}#{item.text}</p>)
563
+ result << item.content
564
+ result << %(</li>)
565
+ else
566
+ result << %(<li>#{check_box}#{item.text}</li>)
567
+ end
568
+ end
569
+
570
+ # Close the unordered list:
571
+ result << '</ul>'
572
+
573
+ # Returned the XML output:
574
+ result.join LF
575
+ end
576
+
577
+ def convert_verse node
578
+ # Check if the author is defined:
579
+ author = (node.attr? 'attribution') ? %(\n&#8212; #{node.attr 'attribution'}) : ''
580
+
581
+ # Check if the citation source is defined:
582
+ source = (node.attr? 'citetitle') ? %(\n<cite>#{node.attr 'citetitle'}</cite>) : ''
583
+
584
+ # Return the XML output:
585
+ <<~EOF.chomp
586
+ <lines>
587
+ #{node.content}#{author}#{source}
588
+ </lines>
589
+ EOF
590
+ end
591
+
592
+ def convert_video node
593
+ # Issue a warning if video content is present:
594
+ logger.warn "#{NAME}: Video macro not supported"
595
+ return ''
596
+ end
597
+
598
+ def compose_qanda_dlist node
599
+ # Open the ordered list:
600
+ result = ['<ol>']
601
+
602
+ # Process individual list items:
603
+ node.items.each do |terms, description|
604
+ # Open the list item:
605
+ result << %(<li>)
606
+
607
+ # Process individual terms:
608
+ terms.each do |item|
609
+ result << %(<p outputclass="question"><i>#{item.text}</i></p>)
610
+ end
611
+
612
+ # Check if the term description is specified:
613
+ if description
614
+ result << %(<p>#{description.text}</p>)
615
+ result << description.content if description.blocks?
616
+ end
617
+
618
+ # Close the list item:
619
+ result << %(</li>)
620
+ end
621
+
622
+ # Close the ordered list:
623
+ result << '</ol>'
624
+
625
+ # Return the XML output:
626
+ result.join LF
627
+ end
628
+
629
+ def compose_horizontal_dlist node
630
+ # Open the table:
631
+ result = ['<table>']
632
+
633
+ # Define the table properties and open the tgroup:
634
+ result << %(<tgroup cols="2">)
635
+ result << %(<colspec colwidth="#{node.attr 'labelwidth', 15}*" />)
636
+ result << %(<colspec colwidth="#{node.attr 'itemwidth', 85}*" />)
637
+
638
+ # Open the table body:
639
+ result << %(<tbody>)
640
+
641
+ # Process individual list items:
642
+ node.items.each do |terms, description|
643
+ # Open the table row:
644
+ result << %(<row>)
645
+
646
+ # Check the number of terms to process:
647
+ if terms.count == 1
648
+ result << %(<entry><b>#{terms[0].text}</b></entry>)
649
+ else
650
+ # Process individual terms:
651
+ result << %(<entry>)
652
+ terms.each do |item|
653
+ result << %(<p><b>#{item.text}</b></p>)
654
+ end
655
+ result << %(</entry>)
656
+ end
657
+
658
+ # Check if the term description is specified:
659
+ if description
660
+ # Check if the description contains multiple block elements:
661
+ if description.blocks?
662
+ result << %(<entry>)
663
+ result << %(<p>#{description.text}</p>) if description.text?
664
+ result << description.content
665
+ result << %(</entry>)
666
+ else
667
+ result << %(<entry>#{description.text}</entry>) if description.text?
668
+ end
669
+ end
670
+
671
+ # Close the table row:
672
+ result << %(</row>)
673
+ end
674
+
675
+ # Close the table:
676
+ result << %(</tbody>)
677
+ result << %(</tgroup>)
678
+ result << %(</table>)
679
+
680
+ # Return the XML output:
681
+ result.join LF
682
+ end
683
+
684
+ def compose_floating_title title, section_level=false
685
+ # NOTE: Unlike AsciiDoc, DITA does not support floating titles or
686
+ # titles assigned to certain block elements. As a workaround, I decided
687
+ # to use a paragraph with the outputclass attribute.
688
+
689
+ # Check whether the section level is defined:
690
+ level = section_level ? %( sect#{section_level}) : ''
691
+
692
+ # Return the XML output:
693
+ title ? %(<p outputclass="title#{level}"><b>#{title}</b></p>\n) : ''
694
+ end
695
+
696
+ def compose_id id
697
+ id ? %( id="#{id}") : ''
698
+ end
699
+
700
+ def compose_title title
701
+ title ? %(<title>#{title}</title>\n) : ''
702
+ end
703
+ end
704
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asciidoctor-dita-topic
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jaromir Hradilek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-06-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: asciidoctor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ description: An extension for AsciiDoctor that converts a single AsciiDoc file to
34
+ a DITA topic.
35
+ email: jhradilek@gmail.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - lib/dita-topic.rb
41
+ homepage: https://github.com/jhradilek/asciidoctor-dita-topic
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ homepage_uri: https://github.com/jhradilek/asciidoctor-dita-topic
46
+ bug_tracker_uri: https://github.com/jhradilek/asciidoctor-dita-topic/issues
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.5.9
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: A custom AsciiDoc converter that generates individual DITA topics
66
+ test_files: []