kramdown-respec 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []