kramdown-respec 0.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2ba63912c12fd783b548da579f41ccff5eaab6f46ad1e5c0fcde594d15eb2cbe
4
+ data.tar.gz: c796124e266be7c4353394daf20f49dd6563de213088654af8f9dd9ed0aa723d
5
+ SHA512:
6
+ metadata.gz: 349070d5fb6f509747ba3e1cdf29b6bfb854de03608a1df388ab9897a3a335f29ee65deec5c6061516c01cf596f3961cbff555d7797be92a57aeb5e5e46a41f8
7
+ data.tar.gz: cdb905cdb4d0af314e0e28ee36dc736c18e8c6a896691d464e74953d4183195928cfe53710ce7b59e79a453edbe7d5ce31556fdc270f4e70730b68af0b4d4ff4
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2020 CoSMo Software <ludovic.roux@cosmosoftware.io>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,600 @@
1
+ # kramdown-respec
2
+
3
+ [kramdown][] is a [markdown][] parser by Thomas Leitner, which has a
4
+ number of backends for generating HTML, LaTeX, and markdown again.
5
+
6
+ **kramdown-respec** is an additional backend to that: It allows the
7
+ generation of W3C/ReSpec markup ([https://respec.org/docs/][]).
8
+
9
+ Who would care? Anybody who is writing Internet-Drafts and RFCs in
10
+ the [IETF][] and prefers (or has co-authors who prefer) to do part of
11
+ their work in markdown.
12
+
13
+ # Usage
14
+
15
+ Start by installing the kramdown-rfc2629 gem (this automatically
16
+ installs appropriate versions of referenced gems such as kramdown as
17
+ well):
18
+
19
+ gem install kramdown-rfc2629
20
+
21
+ (Add a `sudo` and a space in front of that command if you don't have
22
+ all the permissions needed.)
23
+
24
+ The guts of kramdown-rfc2629 are in one Ruby file,
25
+ `lib/kramdown-rfc2629.rb` --- this melds nicely into the extension
26
+ structure provided by kramdown. `bin/kramdown-rfc2629` started out as
27
+ a simple command-line program showing how to use this, but can now do
28
+ much more (see below).
29
+
30
+ To use kramdown-rfc2629, you'll need a Ruby 2.x, and maybe
31
+ [XML2RFC][] if you want to see the fruits of your work.
32
+
33
+ kramdown-rfc2629 mydraft.mkd >mydraft.xml
34
+ xml2rfc mydraft.xml
35
+
36
+ (The most popular file name extension that IETF people have for
37
+ markdown is .md -- for those who tend to think about GNU machine
38
+ descriptions here, any extension such as .mkd will do, too.)
39
+
40
+ A more brief interface for both calling kramdown-rfc2629 and XML2RFC
41
+ is provided by `kdrfc`:
42
+
43
+ kdrfc mydraft.mkd
44
+
45
+ `kdrfc` can also use a remote installation of XML2RFC if needed:
46
+
47
+ kdrfc -r mydraft.mkd
48
+
49
+ # Examples
50
+
51
+ For historical interest
52
+ `stupid.mkd` was an early markdown version of an actual Internet-Draft
53
+ (for a protocol called [STuPiD][] \[sic!]). This demonstrated some,
54
+ but not all features of kramdown-rfc2629. Since markdown/kramdown
55
+ does not cater for all the structure of an RFC 7749 style document,
56
+ some of the markup is in XML, and the example switches between XML and
57
+ markdown using kramdown's `{::nomarkdown}` and `{:/nomarkdown}` (this
58
+ is ugly, but works well enough). `stupid.xml` and `stupid.txt` show
59
+ what kramdown-rfc2629 and xml2rfc make out of this.
60
+
61
+ `stupid-s.mkd` is the same document in the new sectionized format
62
+ supported by kramdown-rfc2629. The document metadata are in a short
63
+ piece of YAML at the start, and from there, `abstract`, `middle`,
64
+ references (`normative` and `informative`) and `back` are sections
65
+ delimited in the markdown file. See the example for how this works.
66
+ The sections `normative` and `informative` can be populated right from
67
+ the metadata, so there is never a need to write XML any more.
68
+ Much less scary, and no `{:/nomarkdown}` etc. is needed any more.
69
+ Similarly, `stupid-s.xml` and `stupid-s.txt` show what
70
+ kramdown-rfc2629 and xml2rfc make out of this.
71
+
72
+ `draft-ietf-core-block-xx.mkd` is a real-world example of a current
73
+ Internet-Draft done this way. For RFC and Internet-Draft references,
74
+ it uses document prolog entities instead of caching the references in
75
+ the XML (i.e., not standalone mode, this is easier to handle when
76
+ collaborating with XML-only co-authors). See the `bibxml` metadata.
77
+
78
+ # The YAML header
79
+
80
+ Please consult the examples for the structure of the YAML header, this should be mostly
81
+ obvious. The `stand_alone` attribute controls whether the RFC/I-D
82
+ references are inserted into the document (yes) or entity-referenced
83
+ (no), the latter leads to increased build time, but may be more
84
+ palatable for a final XML conversion.
85
+ The author entry can be a single hash or a list, as in:
86
+
87
+ author:
88
+ ins: C. Bormann
89
+ name: Carsten Bormann
90
+ org: Universität Bremen TZI
91
+ abbrev: TZI
92
+ street: Bibliothekstr. 1
93
+ city: Bremen
94
+ code: D-28359
95
+ country: Germany
96
+ phone: +49-421-218-63921
97
+ email: cabo@tzi.org
98
+
99
+ or
100
+
101
+ author:
102
+ -
103
+ ins: C. Bormann
104
+ name: Carsten Bormann
105
+ org: Universität Bremen TZI
106
+ email: cabo@tzi.org
107
+ -
108
+ ins: Z. Shelby
109
+ name: Zach Shelby
110
+ org: Sensinode
111
+ role: editor
112
+ street: Kidekuja 2
113
+ city: Vuokatti
114
+ code: 88600
115
+ country: Finland
116
+ phone: "+358407796297"
117
+ email: zach@sensinode.com
118
+ -
119
+ role: editor
120
+ ins: P. Thubert
121
+ name: Pascal Thubert
122
+ org: Cisco Systems
123
+ abbrev: Cisco
124
+ street:
125
+ - Village d'Entreprises Green Side
126
+ - 400, Avenue de Roumanille
127
+ - Batiment T3
128
+ city: Biot - Sophia Antipolis
129
+ code: '06410'
130
+ country: FRANCE
131
+ phone: "+33 4 97 23 26 34"
132
+ email: pthubert@cisco.com
133
+
134
+ (the hash keys are the XML GIs from RFC 7749, with a flattened
135
+ structure. As RFC 7749 requires giving both the full name and
136
+ surname/initials, we use `ins` as an abbreviation for
137
+ "initials/surname". Yes, the toolchain is Unicode-capable, even if
138
+ the final RFC output is still in ASCII.)
139
+
140
+ Note that the YAML header needs to be syntactically valid YAML.
141
+ Where there is a potential for triggering some further YAML feature, a
142
+ string should be put in quotes (like the "+358407796297" above, which
143
+ might otherwise be interpreted as a number, losing the + sign).
144
+
145
+ ## References
146
+
147
+ The references section is built from the references listed in the YAML
148
+ header and from references made inline to RFCs and I-Ds in the
149
+ markdown text. Since kramdown-rfc2629 cannot know whether a reference
150
+ is normative or informative, no entry is generated by default in the
151
+ references section. By indicating a normative reference as in
152
+ `{{!RFC2119}}` or an informative one as in `{{?RFC1925}}`, you can
153
+ completely automate the referencing, without the need to write
154
+ anything in the header. Alternatively, you can write something like:
155
+
156
+ informative:
157
+ RFC1925:
158
+ normative:
159
+ RFC2119:
160
+
161
+ and then just write `{{RFC2119}}` or `{{RFC1925}}`. (Yes, there is a
162
+ colon in the YAML, because this is a hash that could provide other
163
+ information.)
164
+
165
+ Since version 1.1, references imported from the [XML2RFC][] databases
166
+ can be supplied with a replacement label (anchor name). E.g., RFC 793
167
+ could be referenced as `{{!TCP=RFC0793}}`, further references then just
168
+ can say `{{TCP}}`; both will get `[TCP]` as the label. In the
169
+ YAML, the same replacement can be expressed as in the first example:
170
+
171
+ normative:
172
+ TCP: RFC0793
173
+ informative:
174
+ SST: DOI.10.1145/1282427.1282421
175
+
176
+ Notes about this feature:
177
+
178
+ * Thank you, Martin Thomson, for supplying an implementation and
179
+ insisting this be done.
180
+ * While this feature is now available, you are not forced to use it
181
+ for everything: readers of documents often benefit from not having
182
+ to look up references, so continuing to use the draft names and RFC
183
+ numbers as labels may be the preferable style in many cases.
184
+ * As a final caveat, renaming anchors does not work in the
185
+ `stand_alone: no` mode (except for IANA and DOI), as there is no
186
+ such mechanism in XML entity referencing; exporting to XML while
187
+ maintaining live references then may require some manual editing to
188
+ get rid of the custom anchors.
189
+
190
+ If your references are not in the [XML2RFC][] databases and do not
191
+ have a DOI (that also happens to have correct data) either, you need
192
+ to spell it out like in the examples below:
193
+
194
+ informative:
195
+ RFC1925:
196
+ WEI:
197
+ title: "6LoWPAN: the Wireless Embedded Internet"
198
+ # see the quotes above? Needed because of the embedded colon.
199
+ author:
200
+ -
201
+ ins: Z. Shelby
202
+ name: Zach Shelby
203
+ -
204
+ ins: C. Bormann
205
+ name: Carsten Bormann
206
+ date: 2009
207
+ seriesinfo:
208
+ ISBN: 9780470747995
209
+ ann: This is a really good reference on 6LoWPAN.
210
+ ASN.1:
211
+ title: >
212
+ Information Technology — ASN.1 encoding rules:
213
+ Specification of Basic Encoding Rules (BER), Canonical Encoding
214
+ Rules (CER) and Distinguished Encoding Rules (DER)
215
+ # YAML's ">" syntax used above is a good way to write longer titles
216
+ author:
217
+ org: International Telecommunications Union
218
+ date: 1994
219
+ seriesinfo:
220
+ ITU-T: Recommendation X.690
221
+ REST:
222
+ target: http://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf
223
+ title: Architectural Styles and the Design of Network-based Software Architectures
224
+ author:
225
+ ins: R. Fielding
226
+ name: Roy Thomas Fielding
227
+ org: University of California, Irvine
228
+ date: 2000
229
+ seriesinfo:
230
+ "Ph.D.": "Dissertation, University of California, Irvine"
231
+ format:
232
+ PDF: http://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf
233
+ COAP:
234
+ title: "CoAP: An Application Protocol for Billions of Tiny Internet Nodes"
235
+ seriesinfo:
236
+ DOI: 10.1109/MIC.2012.29
237
+ date: 2012
238
+ author:
239
+ -
240
+ ins: C. Bormann
241
+ name: Carsten Bormann
242
+ -
243
+ ins: A. P. Castellani
244
+ name: Angelo P. Castellani
245
+ -
246
+ ins: Z. Shelby
247
+ name: Zach Shelby
248
+ IPSO:
249
+ title: IP for Smart Objects (IPSO)
250
+ author:
251
+ - org:
252
+ date: false
253
+ seriesinfo:
254
+ Web: http://ipso-alliance.github.io/pub/
255
+ normative:
256
+ ECMA262:
257
+ author:
258
+ org: European Computer Manufacturers Association
259
+ title: ECMAScript Language Specification 5.1 Edition
260
+ date: 2011-06
261
+ target: http://www.ecma-international.org/publications/files/ecma-st/ECMA-262.pdf
262
+ seriesinfo:
263
+ ECMA: Standard ECMA-262
264
+ RFC2119:
265
+ RFC6690:
266
+
267
+ (as in the author list, `ins` is an abbreviation for
268
+ "initials/surname"; note that the first title had to be put in double
269
+ quotes as it contains a colon which is special syntax in YAML.)
270
+ Then you can simply reference `{{ASN.1}}` and
271
+ `{{ECMA262}}` in the text. (Make sure the reference keys are valid XML
272
+ names, though.)
273
+
274
+ # Experimental features
275
+
276
+ Most of the [kramdown syntax][kdsyntax] is supported and does
277
+ something useful; with the exception of the math syntax (math has no
278
+ special support in XML2RFC), and HTML syntax of course.
279
+
280
+ A number of more esoteric features have recently been added.
281
+ (The minimum required version for each full feature is indicated.)
282
+
283
+ (1.2.9:)
284
+ The YAML header now allows specifying [kramdown_options][].
285
+
286
+ [kramdown_options]: https://kramdown.gettalong.org/options.html
287
+
288
+ This was added specifically to provide easier access to the kramdown
289
+ `auto_id_prefix` feature, which prefixes by some distinguishing string
290
+ the anchors that are auto-generated for sections, avoiding conflicts:
291
+
292
+ ```yaml
293
+ kramdown_options:
294
+ auto_id_prefix: sec-
295
+ ```
296
+
297
+ (1.2.8:)
298
+ An experimental feature was added to include [BCP 14] boilerplate:
299
+
300
+ ```markdown
301
+ {::boilerplate bcp14}
302
+ ```
303
+
304
+ which saves some typing. Saying "bcp14+" instead of "bcp14" adds some
305
+ random clarifications at the end of the [standard boilerplate text][] that
306
+ you may or may not want to have. (Do we need other boilerplate items
307
+ beyond BCP14?)
308
+
309
+ [BCP 14]: https://www.rfc-editor.org/info/bcp14
310
+
311
+ [standard boilerplate text]: https://tools.ietf.org/html/rfc8174#page-3
312
+
313
+ (1.0.35:)
314
+ An experimental command `doilit` has been added. It can be used to
315
+ convert DOIs given on the command line into references entries for
316
+ kramdown-rfc YAML, saving a lot of typing. Note that the DOI database
317
+ is not of very consistent quality, so you likely have to hand-edit the
318
+ result before including it into the document (use `-v` to see raw JSON
319
+ data from the DOI database, made somewhat readable by converting it
320
+ into YAML). Use `-c` to enable caching (requires `open-uri-cached`
321
+ gem). Use `-h=handle` in front of a DOI to set a handle different
322
+ from the default `a`, `b`, etc. Similarly, use `-x=handle` to
323
+ generate XML2RFCv2 XML instead of kramdown-rfc YAML.
324
+
325
+ (1.0.31:)
326
+ The kramdown `smart_quotes` feature can be controlled better.
327
+ By default, it is on (with default kramdown settings), unless `coding:
328
+ us-ascii` is in effect, when it is off by default.
329
+ It also can be explicitly set on (`true`) or off (`false`) in the YAML
330
+ header, or to a specific value (an array of four kramdown entity names
331
+ or character numbers). E.g., for a German text (that is not intended
332
+ to become an Internet-Draft), one might write:
333
+
334
+ ```yaml
335
+ smart_quotes: [sbquo, lsquo, bdquo, ldquo]
336
+ pi:
337
+ topblock: no
338
+ private: yes
339
+ ```
340
+
341
+ (1.0.30:)
342
+ kramdown-rfc now uses kramdown 1.10, which leads to two notable updates:
343
+
344
+ * Support for empty link texts in the standard markdown
345
+ reference syntax, as in `[](#RFC7744)`.
346
+ * Language names in fenced code blocks now support all characters
347
+ except whitespace, so you can go wild with `asn.1` and `C#`.
348
+
349
+ A heuristic generates missing initials/surname from the `name` entry
350
+ in author information. This should save a lot of redundant typing.
351
+ You'll need to continue using the `ins` entry as well if that
352
+ heuristic fails (e.g., for Spanish names).
353
+
354
+ Also, there is some rather experimental support for markdown display
355
+ math (blocks between `$$` pairs) if the `tex2mail` tool is available.
356
+
357
+ (1.0.23:)
358
+ Move up to kramdown 1.6.0. This inherits a number of fixes and one
359
+ nice feature:
360
+ Markdown footnote definitions that turn into `cref`s can have their
361
+ attributes in the footnote definition:
362
+
363
+ ```markdown
364
+ {:cabo: source="cabo"}
365
+
366
+ (This section to be removed by the RFC editor.)[^1]
367
+
368
+ [^1]: here is my editorial comment: warble warble.
369
+ {:cabo}
370
+
371
+ Another questionable paragraph.[^2]
372
+
373
+ [^2]: so why not delete it?
374
+ {: source="observer"}
375
+ ```
376
+
377
+ (1.0.23:)
378
+ As before, IAL attributes on a codeblock go to the figure element.
379
+ Language attributes on the code block now become the artwork type, and any
380
+ attribute with a name that starts "artwork-" is moved over to the artwork.
381
+ So this snippet now does the obvious things:
382
+
383
+ ```markdown
384
+ ~~~ abnf
385
+ a = b / %s"foo" / %x0D.0A
386
+ ~~~
387
+ {: artwork-align="center" artwork-name="syntax"}
388
+ ```
389
+
390
+ (1.0.22:)
391
+ Index entries can be created with `(((item)))` or
392
+ `(((item, subitem)))`; use quotes for weird entries: `(((",", comma)))`.
393
+ If the index entry is to be marked "primary", prefix an (unquoted) `!`
394
+ as in `(((!item)))`.
395
+
396
+ In addition, auto-indexing is supported by hijacking the kramdown
397
+ "abbrev" syntax:
398
+
399
+ *[IANA]:
400
+ *[MUST]: BCP14
401
+ *[CBOR]: (((Object Representation, Concise Binary))) (((CBOR)))
402
+
403
+ The word in square brackets (which must match exactly,
404
+ case-sensitively) is entered into the index automatically for each
405
+ place where it occurs. If no title is given, just the word is entered
406
+ (first example). If one is given, that becomes the main item (the
407
+ auto-indexed word becomes the subitem, second example). If full
408
+ control is desired (e.g., for multiple entries per occurrence), just
409
+ write down the full index entries instead (third example).
410
+
411
+ (1.0.20:)
412
+ As an alternative referencing syntax for references with text,
413
+ `{{ref}}` can be expressed as `[text](#ref)`. As a special case, a
414
+ simple `[ref]` is interpreted as `[](#ref)` (except that the latter
415
+ syntax is not actually allowed by kramdown). This syntax does not
416
+ allow for automatic entry of items as normative/informative.
417
+
418
+ (1.0.16:) Markdown footnotes are converted into `cref`s (XML2RFC formal
419
+ comments; note that these are only visible if the pi "comments" is set to yes).
420
+ The anchor is taken from the markdown footnote name. The source, if
421
+ needed, can be supplied by an IAD, as in (first example with
422
+ ALD):
423
+
424
+ ```markdown
425
+ {:cabo: source="cabo"}
426
+
427
+ (This section to be removed by the RFC editor.)[^1]{:cabo}
428
+
429
+ [^1]: here is my editorial comment
430
+
431
+ Another questionable paragraph.[^2]{: source="observer"}
432
+
433
+ [^2]: so why not delete it
434
+ ```
435
+
436
+ Note that XML2RFC v2 doesn't allow structure in crefs. If you put any,
437
+ you get the escaped verbatim XML...
438
+
439
+ (1.0.11:) Allow overriding "style" attribute (via IAL =
440
+ [inline attribute list][kdsyntax-ial]) in lists and spans
441
+ as in:
442
+
443
+ ```markdown
444
+ {:req: counter="bar" style="format R(%d)"}
445
+
446
+ {: req}
447
+ * Foo
448
+ * Bar
449
+ * Bax
450
+
451
+ Text outside the list, so a new IAL is needed.
452
+
453
+ * Foof
454
+ * Barf
455
+ * Barx
456
+ {: req}
457
+ ```
458
+
459
+ (1.0.5:) An IAL attribute "cols" can be added to tables to override
460
+ the column layout. For example, `cols="* 20 30c r"` sets the width attributes to
461
+ 20 and 30 for the middle columns and sets the right two columns to
462
+ center and right alignment, respectively. The alignment from `cols`
463
+ overrides that from the kramdown table, if present.
464
+
465
+ (1.0.2:) An IAL attribute "vspace" can be added to a definition list
466
+ to break after the definition term:
467
+
468
+ ```markdown
469
+ {: vspace="0"}
470
+ word:
471
+ : definition
472
+
473
+ anotherword:
474
+ : another definition
475
+ ```
476
+
477
+ (0.x:) Files can be included with the syntax `{::include fn}` (needs
478
+ to be in column 1 since 1.0.22; can be suppressed for use in servers
479
+ by setting environment variable KRAMDOWN_SAFE since 1.0.22). A
480
+ typical example from a recent RFC, where the contents of a figure was
481
+ machine-generated:
482
+
483
+ ```markdown
484
+ ~~~~~~~~~~
485
+ {::include ../ghc/packets-new/p4.out}
486
+ ~~~~~~~~~~
487
+ {: #example2 title="A longer RPL example"}
488
+ ```
489
+
490
+ (0.x:) A page break can be forced by adding a horizontal rule (`----`,
491
+ note that this creates ugly blank space in some HTML converters).
492
+
493
+ # Risks and Side-Effects
494
+
495
+ The code is not very polished, but now quite stable; it has been successfully used for a
496
+ number of non-trivial Internet-Drafts and RFCs. You probably still need to
497
+ skim [RFC 7749][] if you want to write an Internet-Draft, but you
498
+ don't really need to understand XML very much. Knowing the basics of
499
+ YAML helps with the metadata (but you'll understand it from the
500
+ examples).
501
+
502
+ Occasionally, you do need to reach through to the XML arcana, e.g. by
503
+ setting attribute values using kramdown's ["IAL" syntax][IAL].
504
+ This can for instance be used to obtain unnumbered appendices:
505
+
506
+ ```markdown
507
+ Acknowledgements
508
+ ================
509
+ {: numbered="no"}
510
+
511
+ John Mattsson was nice enough to point out the need for this being documented.
512
+ ```
513
+
514
+ [IAL]: https://kramdown.gettalong.org/syntax.html#inline-attribute-lists
515
+
516
+ # Upconversion
517
+
518
+ If you have an old RFC and want to convert it to markdown, try just
519
+ using that RFC, it is 80 % there. It may be possible to automate the
520
+ remaining 20 % some more, but that hasn't been done.
521
+
522
+ If you have XML, there is an experimental upconverter that does 99 %
523
+ of the work. Please [contact the
524
+ author](mailto:cabo@tzi.org?subject=Markdown for RFCXML) if you want
525
+ to try it.
526
+
527
+ Actually, if the XML was generated by kramdown-rfc2629, you can simply
528
+ extract the input markdown from that XML file (but will of course lose
529
+ any edits that have been made to the XML file after generation):
530
+
531
+ kramdown-rfc-extract-markdown myfile.xml >myfile.md
532
+
533
+
534
+ # Tools
535
+
536
+ Joe Hildebrand has a
537
+ [grunt][] plugin for kramdown-rfc2629 at:
538
+ https://github.com/hildjj/grunt-kramdown-rfc2629
539
+ .
540
+ Get started with it at:
541
+ https://github.com/hildjj/grunt-init-rfc
542
+ .
543
+ This provides a self-refreshing web page with the
544
+ kramdown-rfc2629/xml2rfc rendition of the draft you are editing.
545
+
546
+ [grunt]: http://gruntjs.com
547
+
548
+ Martin Thomson has an [I-D Template][] for github repositories that enable
549
+ collaboration on draft development.
550
+ This supports kramdown-rfc2629 out of the
551
+ box. Just name your draft like `draft-ietf-unicorn-protocol-latest.md` and
552
+ follow the installation instructions.
553
+
554
+ [I-D Template]: https://github.com/martinthomson/i-d-template
555
+
556
+ # Related Work
557
+
558
+ Moving from XML to Markdown for RFC writing apparently is a
559
+ no-brainer, so I'm not the only one who has written code for this.
560
+
561
+ [Miek Gieben][] has done a [similar thing][pandoc2rfc] employing
562
+ pandoc, now documented in [RFC 7328][]. He uses multiple input files instead of
563
+ kramdown-rfc2629's sectionized input format. He keeps the metadata in
564
+ a separate XML file, similar to the way the previous version of
565
+ kramdown-rfc2629 stored (and still can store) the metadata in XML in
566
+ the markdown document. He also uses a slightly different referencing
567
+ syntax, which is closer to what markdown does elsewhere but more
568
+ verbose (this syntax is now also supported in kramdown-rfc2629).
569
+ (Miek now also has a new thing going on with mostly different syntax,
570
+ see [mmark][] and its [github repository][mmark-git].)
571
+
572
+ Other human-oriented markup input languages that are being used for authoring RFCXML include:
573
+
574
+ * [asciidoc][], with the [asciidoctor-rfc][] tool, as documented in [draft-ribose-asciirfc][].
575
+ * [orgmode][] (please help supply a more specific link here).
576
+
577
+ # License
578
+
579
+ Since kramdown version 1.0, kramdown itself is MIT licensed, which
580
+ made it possible to license kramdown-rfc2629 under the same license.
581
+
582
+ [kramdown]: http://kramdown.rubyforge.org/
583
+ [kdsyntax]: http://kramdown.gettalong.org/syntax.html
584
+ [kdsyntax-ial]: http://kramdown.gettalong.org/syntax.html#inline-attribute-lists
585
+ [stupid]: http://tools.ietf.org/id/draft-hartke-xmpp-stupid-00
586
+ [RFC 2629]: http://xml.resource.org/public/rfc/html/rfc2629.html
587
+ [RFC 7749]: http://tools.ietf.org/html/rfc7749
588
+ [markdown]: http://en.wikipedia.org/wiki/Markdown
589
+ [IETF]: http://www.ietf.org
590
+ [Miek Gieben]: http://www.miek.nl/
591
+ [pandoc2rfc]: https://github.com/miekg/pandoc2rfc/
592
+ [XML2RFC]: http://xml.resource.org
593
+ [RFC 7328]: http://tools.ietf.org/html/rfc7328
594
+ [mmark-git]: https://github.com/miekg/mmark
595
+ [mmark]: https://mmark.nl
596
+ [YAML]: http://www.yaml.org/spec/1.2/spec.html
597
+ [draft-ribose-asciirfc]: https://tools.ietf.org/html/draft-ribose-asciirfc
598
+ [asciidoctor-rfc]: https://github.com/metanorma/asciidoctor-rfc
599
+ [asciidoc]: http://www.methods.co.nz/asciidoc/
600
+ [orgmode]: http://orgmode.org
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'kramdown-respec'
4
+
5
+ require 'optparse'
6
+ require 'ostruct'
7
+
8
+ $options = OpenStruct.new
9
+ op = OptionParser.new do |opts|
10
+ opts.banner = "Usage: kramdown-respec [options] file.md > file.html"
11
+ end
12
+ op.parse!
13
+
14
+ doc = Kramdown::Document.new(input, options)
15
+ $stderr.puts doc.warnings.to_yaml unless doc.warnings.empty?
16
+ puts doc.to_htmlRESPEC
@@ -0,0 +1,15 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'kramdown-respec'
3
+ s.version = '0.0.0'
4
+ s.summary = "Kramdown extension for generating respec HTML."
5
+ s.description = %{A respec HTML generating backend for Thomas Leitner's "kramdown" markdown parser. Mostly useful for RFC writers.}
6
+ s.add_dependency('kramdown', '~> 1.14')
7
+ s.files = Dir['lib/*.rb'] + %w(README.md LICENSE kramdown-respec.gemspec)
8
+ s.require_path = 'lib'
9
+ s.executables = ['kramdown-respec']
10
+ s.required_ruby_version = '>= 2.3.0'
11
+ s.authors = ['Ludovic Roux']
12
+ s.email = "ludovic.roux@cosmosoftware.io"
13
+ s.homepage = "http://github.com/ludocosmo/kramdown-respec"
14
+ s.license = 'MIT'
15
+ end
@@ -0,0 +1,362 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ # Copyright (C) 2020 CoSMo Software, Ludovic Roux <ludovic.roux@cosmosoftware.io>
6
+ #
7
+ # This file was derived from a part of the kramdown gem which is licensed under the MIT license.
8
+ # This derived work is also licensed under the MIT license, see LICENSE.
9
+ #++
10
+ #
11
+
12
+ raise "sorry, 1.8 was last decade" unless RUBY_VERSION >= '1.9'
13
+
14
+ gem 'kramdown', '~> 1.14'
15
+ require 'kramdown'
16
+ require 'kramdown/parser'
17
+ require 'kramdown/converter'
18
+ require 'kramdown/utils'
19
+
20
+ module Kramdown
21
+
22
+ # Re-open class Document
23
+ #
24
+ # The main interface to kramdown-respec.
25
+ #
26
+ # This class provides a one-stop-shop for using kramdown-respec to convert text into various output
27
+ # formats. Use it like this:
28
+ #
29
+ # require 'kramdown-respec'
30
+ # doc = KramdownRespec::Document.new('This *is* some kramdown-respec text')
31
+ # puts doc.to_html
32
+ #
33
+ # The #to_html method is a shortcut for using the Converter::Html class. See #method_missing for
34
+ # more information.
35
+ #
36
+ # The second argument to the ::new method is an options hash for customizing the behaviour of the
37
+ # used parser and the converter. See ::new for more information!
38
+ class Document
39
+
40
+ # Redfine method initialize()
41
+ #
42
+ # Create a new KramdownRespec document from the string +source+ and use the provided +options+.
43
+ # The options that can be used are defined in the Options module.
44
+ #
45
+ # The special options key :input can be used to select the parser that should parse the
46
+ # +source+. It has to be the name of a class in the KramdownRespec::Parser module. For example, to
47
+ # select the kramdown-respec parser, one would set the :input key to +KramdownRespec+. If this key
48
+ # is not set, it defaults to +KramdownRespec+.
49
+ #
50
+ # The +source+ is immediately parsed by the selected parser so that the root element is
51
+ # immediately available and the output can be generated.
52
+ def initialize(source, options = {})
53
+ @options = Options.merge(options).freeze
54
+ # parser = (@options[:input] || 'kramdown-respec').to_s
55
+ parser = (@options[:input] || 'kramdown').to_s
56
+ parser = parser[0..0].upcase + parser[1..-1]
57
+ try_require('parser', parser)
58
+ if Parser.const_defined?(parser)
59
+ @root, @warnings = Parser.const_get(parser).parse(source, @options)
60
+ else
61
+ raise Kramdown::Error.new("kramdown-respec has no parser to handle the specified input format: #{@options[:input]}")
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+
68
+ module Parser
69
+
70
+ # class KramdownRespec < Kramdown::Parser::Kramdown
71
+
72
+ class Kramdown < Base
73
+
74
+ include ::Kramdown
75
+
76
+ # Create a new Kramdown parser object with the given +options+.
77
+ def initialize(source, options)
78
+ super
79
+
80
+ reset_env
81
+
82
+ @alds = {}
83
+ @footnotes = {}
84
+ @link_defs = {}
85
+ update_link_definitions(@options[:link_defs])
86
+
87
+ @block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header,
88
+ :horizontal_rule, :list, :definition_list, :block_html, :setext_header,
89
+ :block_math, :table, :footnote_definition, :link_definition, :abbrev_definition,
90
+ :block_extensions, :eob_marker, :paragraph, :respectests]
91
+ @span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, :smart_quotes, :inline_math,
92
+ :span_extensions, :html_entity, :typographic_syms, :line_break, :escaped_chars,
93
+ :respectests]
94
+
95
+ end
96
+ # def initialize(source, options)
97
+ # super
98
+ # @span_parsers.unshift(:respectests)
99
+ # @block_parsers.unshift(:respectests)
100
+ # end
101
+
102
+ # List of possible annotations
103
+ # If annotation is not in the list, then it should be a reference to a test
104
+ RESPECTESTS_ANNOTATIONS = ["untestable", "informative", "note", "no-test-needed", "needs-test"]
105
+
106
+ RESPECTESTS = /\{:&(.*)\}/
107
+ RESPECTESTS_START = /^#{OPT_SPACE}#{RESPECTESTS}/
108
+
109
+ # Parse one of the block extensions (ALD, block IAL or generic extension) at the current
110
+ # location.
111
+ def parse_block_extensions
112
+ # Parse the string +str+ and extract the annotation or the list of tests
113
+ if @src.scan(RESPECTESTS_START)
114
+ last_child = @tree.children.last
115
+ if last_child.type == :header
116
+ parse_respec_tests_list(@src[1], last_child.options[:respec_section] ||= {})
117
+ @tree.children << new_block_el(:eob, :respec_section)
118
+ else
119
+ parse_respec_tests_list(@src[1], last_child.options[:ial] ||= {})
120
+ @tree.children << new_block_el(:eob, :ial)
121
+ end
122
+ # Original parser of block extensions
123
+ elsif @src.scan(ALD_START)
124
+ parse_attribute_list(@src[2], @alds[@src[1]] ||= Utils::OrderedHash.new)
125
+ @tree.children << new_block_el(:eob, :ald)
126
+ true
127
+ elsif @src.check(EXT_BLOCK_START)
128
+ parse_extension_start_tag(:block)
129
+ elsif @src.scan(IAL_BLOCK_START)
130
+ if @tree.children.last && @tree.children.last.type != :blank &&
131
+ (@tree.children.last.type != :eob || [:link_def, :abbrev_def, :footnote_def].include?(@tree.children.last.value))
132
+ parse_attribute_list(@src[1], @tree.children.last.options[:ial] ||= Utils::OrderedHash.new)
133
+ @tree.children << new_block_el(:eob, :ial) unless @src.check(IAL_BLOCK_START)
134
+ else
135
+ parse_attribute_list(@src[1], @block_ial ||= Utils::OrderedHash.new)
136
+ end
137
+ true
138
+ else
139
+ false
140
+ end
141
+ end
142
+ # Parse the string +str+ and extract the annotation or the list of tests
143
+ # def parse_block_extensions
144
+ # if @src.scan(RESPECTESTS_START)
145
+ # last_child = @tree.children.last
146
+ # if last_child.type == :header
147
+ # parse_respec_tests_list(@src[1], last_child.options[:respec_section] ||= {})
148
+ # @tree.children << new_block_el(:eob, :respec_section)
149
+ # else
150
+ # parse_respec_tests_list(@src[1], last_child.options[:ial] ||= {})
151
+ # @tree.children << new_block_el(:eob, :ial)
152
+ # end
153
+ # else
154
+ # super
155
+ # end
156
+ # end
157
+
158
+ # Parse the string +str+ and extract the annotation or the list of tests
159
+ def parse_respec_tests_list(str, opts)
160
+ str = str.strip
161
+ if RESPECTESTS_ANNOTATIONS.include?(str)
162
+ opts['class'] = "#{str}"
163
+ else
164
+ opts['data-tests'] = "#{str}"
165
+ end
166
+ end
167
+
168
+ def parse_respectests
169
+ last_child = @tree.children.last
170
+ if last_child.type == :header
171
+ parse_respec_tests_list(@src[1], last_child.options[:respec_section] ||= {})
172
+ @tree.children << new_block_el(:eob, :respec_section)
173
+ else
174
+ parse_respec_tests_list(@src[1], last_child.options[:ial] ||= {})
175
+ @tree.children << new_block_el(:eob, :ial)
176
+ end
177
+ end
178
+
179
+ # Parse the extension span at the current location.
180
+ def parse_span_extensions
181
+ if @src.check(RESPECTESTS_START)
182
+ if (last_child = @tree.children.last) && last_child.type != :text
183
+ @src.pos += @src.matched_size
184
+ attr = {}
185
+ parse_respec_tests_list(@src[1], attr)
186
+ update_ial_with_ial(last_child.options[:ial] ||= {}, attr)
187
+ update_attr_with_ial(last_child.attr, attr)
188
+ else
189
+ warning("Found span respec-test after text - ignoring it")
190
+ add_text(@src.getch)
191
+ end
192
+ # Original parser of span extension
193
+ elsif @src.check(EXT_SPAN_START)
194
+ parse_extension_start_tag(:span)
195
+ elsif @src.check(IAL_SPAN_START)
196
+ if @tree.children.last && @tree.children.last.type != :text
197
+ @src.pos += @src.matched_size
198
+ attr = Utils::OrderedHash.new
199
+ parse_attribute_list(@src[1], attr)
200
+ update_ial_with_ial(@tree.children.last.options[:ial] ||= Utils::OrderedHash.new, attr)
201
+ update_attr_with_ial(@tree.children.last.attr, attr)
202
+ else
203
+ warning("Found span IAL after text - ignoring it")
204
+ add_text(@src.getch)
205
+ end
206
+ else
207
+ add_text(@src.getch)
208
+ end
209
+ end
210
+ # Parse the extension span at the current location.
211
+ # def parse_span_extensions
212
+ # if @src.check(RESPECTESTS_START)
213
+ # if (last_child = @tree.children.last) && last_child.type != :text
214
+ # @src.pos += @src.matched_size
215
+ # attr = {}
216
+ # parse_respec_tests_list(@src[1], attr)
217
+ # update_ial_with_ial(last_child.options[:ial] ||= {}, attr)
218
+ # update_attr_with_ial(last_child.attr, attr)
219
+ # else
220
+ # warning("Found span respec-test after text - ignoring it")
221
+ # add_text(@src.getch)
222
+ # end
223
+ # else
224
+ # super
225
+ # end
226
+ # end
227
+
228
+ define_parser(:respectests, RESPECTESTS_START, '{:&')
229
+
230
+ end
231
+
232
+ end
233
+
234
+ module Converter
235
+
236
+ # Converts an element tree to the kramdown-respec format.
237
+ # class KramdownRespec < Kramdown
238
+ # end
239
+
240
+
241
+ # class HtmlRESPEC < Html
242
+ class Html < Base
243
+
244
+ # Initialize the HTML converter with the given Kramdown document +doc+.
245
+ def initialize(root, options)
246
+ super
247
+ @footnote_counter = @footnote_start = @options[:footnote_nr]
248
+ @footnotes = []
249
+ @footnotes_by_name = {}
250
+ @footnote_location = nil
251
+ @toc = []
252
+ @toc_code = nil
253
+ @indent = 2
254
+ @stack = []
255
+ @respec_first_section = true
256
+ @respec_last_header_level = 0
257
+ end
258
+ # Initialize the HTML converter with the given Kramdown document +doc+.
259
+ # def initialize(root, options)
260
+ # super
261
+ # @respec_first_section = true
262
+ # @respec_last_header_level = 0
263
+ # end
264
+
265
+ def convert_root(el, indent)
266
+ result = inner(el, indent)
267
+ if @footnote_location
268
+ result.sub!(/#{@footnote_location}/, footnote_content.gsub(/\\/, "\\\\\\\\"))
269
+ else
270
+ result << footnote_content
271
+ end
272
+ if @toc_code
273
+ toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {})
274
+ text = if toc_tree.children.size > 0
275
+ convert(toc_tree, 0)
276
+ else
277
+ ''
278
+ end
279
+ result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\"))
280
+ end
281
+ # Close the last sections that remain opened
282
+ current_header_level = 2
283
+ while @respec_last_header_level > current_header_level
284
+ result += "</section>\n\n"
285
+ @respec_last_header_level -= 1
286
+ end
287
+ result + "</section>\n\n"
288
+ result
289
+ end
290
+ # def convert_root(el, indent)
291
+ # result = super
292
+ # # Close the last sections that remain opened
293
+ # current_header_level = 2
294
+ # while @respec_last_header_level > current_header_level
295
+ # result += "</section>\n\n"
296
+ # @respec_last_header_level -= 1
297
+ # end
298
+ # result + "</section>\n\n"
299
+ # end
300
+
301
+ def convert_header(el, indent)
302
+ res = ""
303
+ current_header_level = el.options[:level]
304
+ if @respec_first_section
305
+ @respec_first_section = false
306
+ @respec_last_header_level = current_header_level
307
+ else
308
+ if @respec_last_header_level < current_header_level
309
+ @respec_last_header_level = current_header_level
310
+ else
311
+ while @respec_last_header_level > current_header_level
312
+ res += "#{' ' * indent}</section>\n\n"
313
+ @respec_last_header_level -= 1
314
+ end
315
+ res += "#{' ' * indent}</section>\n\n"
316
+ end
317
+ end
318
+ if el.options[:respec_section]
319
+ res += "#{' ' * indent}<section#{html_attributes(el.options[:respec_section])}>\n"
320
+ else
321
+ res += "#{' ' * indent}<section>\n"
322
+ end
323
+ # res + super
324
+
325
+ attr = el.attr.dup
326
+ if @options[:auto_ids] && !attr['id']
327
+ attr['id'] = generate_id(el.options[:raw_text])
328
+ end
329
+ @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el)
330
+ level = output_header_level(el.options[:level])
331
+ res + format_as_block_html("h#{level}", attr, inner(el, indent), indent)
332
+ end
333
+ # def convert_header(el, indent)
334
+ # res = ""
335
+ # current_header_level = el.options[:level]
336
+ # if @respec_first_section
337
+ # @respec_first_section = false
338
+ # @respec_last_header_level = current_header_level
339
+ # else
340
+ # if @respec_last_header_level < current_header_level
341
+ # @respec_last_header_level = current_header_level
342
+ # else
343
+ # while @respec_last_header_level > current_header_level
344
+ # res += "#{' ' * indent}</section>\n\n"
345
+ # @respec_last_header_level -= 1
346
+ # end
347
+ # res += "#{' ' * indent}</section>\n\n"
348
+ # end
349
+ # end
350
+ # if el.options[:respec_section]
351
+ # res += "#{' ' * indent}<section#{html_attributes(el.options[:respec_section])}>\n"
352
+ # else
353
+ # res += "#{' ' * indent}<section>\n"
354
+ # end
355
+ # res + super
356
+ # end
357
+
358
+ end
359
+
360
+ end
361
+
362
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kramdown-respec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ludovic Roux
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kramdown
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ description: A respec HTML generating backend for Thomas Leitner's "kramdown" markdown
28
+ parser. Mostly useful for RFC writers.
29
+ email: ludovic.roux@cosmosoftware.io
30
+ executables:
31
+ - kramdown-respec
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - LICENSE
36
+ - README.md
37
+ - bin/kramdown-respec
38
+ - kramdown-respec.gemspec
39
+ - lib/kramdown-respec.rb
40
+ homepage: http://github.com/ludocosmo/kramdown-respec
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.3.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.1.2
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Kramdown extension for generating respec HTML.
63
+ test_files: []