@@ -71,7 +71,7 @@
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
¶
- This Internet-Draft will expire on August 9, 2024.¶
+ This Internet-Draft will expire on August 22, 2024.
¶
diff -Nru xml2rfc-3.19.4/xml2rfc/__init__.py xml2rfc-3.20.0/xml2rfc/__init__.py
--- xml2rfc-3.19.4/xml2rfc/__init__.py 2024-02-06 22:37:11.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc/__init__.py 2024-02-21 22:48:47.000000000 +0000
@@ -3,7 +3,7 @@
from __future__ import unicode_literals, print_function, division
# Static values
-__version__ = '3.19.4'
+__version__ = '3.20.0'
NAME = 'xml2rfc'
VERSION = [ int(i) if i.isdigit() else i for i in __version__.split('.') ]
CACHES = ['/var/cache/xml2rfc', '~/.cache/xml2rfc'] # Ordered by priority
diff -Nru xml2rfc-3.19.4/xml2rfc/data/xml2rfc.css xml2rfc-3.20.0/xml2rfc/data/xml2rfc.css
--- xml2rfc-3.19.4/xml2rfc/data/xml2rfc.css 2024-02-06 22:36:41.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc/data/xml2rfc.css 2024-02-21 22:48:18.000000000 +0000
@@ -424,6 +424,10 @@
margin-bottom: 1.25em;
}
+.refSubseries {
+ margin-bottom: 1.25em;
+}
+
.references .ascii {
margin-bottom: 0.25em;
}
diff -Nru xml2rfc-3.19.4/xml2rfc/writers/base.py xml2rfc-3.20.0/xml2rfc/writers/base.py
--- xml2rfc-3.19.4/xml2rfc/writers/base.py 2024-02-06 22:36:41.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc/writers/base.py 2024-02-21 22:48:18.000000000 +0000
@@ -31,6 +31,12 @@
from xml2rfc.utils import namespaces, find_duplicate_ids, slugify
+SUBSERIES = {
+ 'STD': 'Internet Standard',
+ 'BCP': 'Best Current Practice',
+ 'FYI': 'For Your Information',
+}
+
DEADLY_ERRORS = [
'Element svg has extra content: script',
'Did not expect element script there',
@@ -73,6 +79,7 @@
'image_svg': False,
'indent': 2,
'info': False,
+ 'info_base_url': 'https://www.rfc-editor.org/info/',
'inline_version_info': True,
'legacy': False,
'legacy_date_format': False,
diff -Nru xml2rfc-3.19.4/xml2rfc/writers/html.py xml2rfc-3.20.0/xml2rfc/writers/html.py
--- xml2rfc-3.19.4/xml2rfc/writers/html.py 2024-02-06 22:36:41.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc/writers/html.py 2024-02-21 22:48:18.000000000 +0000
@@ -29,7 +29,7 @@
pass
from xml2rfc import log, strings
-from xml2rfc.writers.base import default_options, BaseV3Writer, RfcWriterError
+from xml2rfc.writers.base import default_options, BaseV3Writer, RfcWriterError, SUBSERIES
from xml2rfc.uniscripts import is_script
from xml2rfc.util.date import extract_date, augment_date, format_date, format_date_iso, get_expiry_date
from xml2rfc.util.name import ( full_author_name_expansion, short_author_role,
@@ -2158,18 +2158,14 @@
self.render(inner, c)
for ctag in ('title', 'refcontent', 'stream', 'seriesInfo', 'date', ):
for c in x.iterdescendants(ctag):
- if p.tag == 'referencegroup' and c.tag == 'seriesInfo' and c.get('name') == 'DOI':
- # Don't render DOI within a reference group
- continue
if len(inner):
inner[-1].tail = ', '
self.render(inner, c)
- if p.tag != 'referencegroup':
- target = x.get('target')
- if len(inner):
- inner[-1].tail = ', '
- if target:
- inner.append( build.span('<', build.a(target, href=target), '>') )
+ target = x.get('target')
+ if len(inner):
+ inner[-1].tail = ', '
+ if target:
+ inner.append( build.span('<', build.a(target, href=target), '>') )
if len(inner):
inner[-1].tail = '. '
for ctag in ('annotation', ):
@@ -2200,13 +2196,29 @@
def render_referencegroup(self, h, x):
dt = add.dt(h, x, '[%s]'%x.get('derivedAnchor'))
dd = add.dd(h, None)
+ target = x.get('target')
+ subseries = False
# workaround for weasyprint's unwillingness to break between
and
# : add an extra that is very prone to page breaks. See CSS.
add.dd(h, None, classes='break')
+ for series in x.xpath('.//seriesInfo'):
+ if series.get('name') in SUBSERIES.keys():
+ text = f"{SUBSERIES[series.get('name')]} {series.get('value')}"
+ subdiv = build.div(text, classes='refInstance')
+ if target:
+ subdiv.text += ', '
+ subdiv.append(build.span('<', build.a(target, href=target), '>'))
+ subdiv[0].tail = '.'
+ else:
+ subdiv.text += '.'
+ subdiv.append(build.br())
+ subdiv.append(build.span(f"At the time of writing, this {series.get('name')} comprises the following:"))
+ dd.append(subdiv)
+ subseries = True
+ break
for c in x.getchildren():
self.render(dd, c)
- target = x.get('target')
- if target:
+ if target and not subseries:
dd.append( build.span('<', build.a(target, href=target), '>') )
return dt, dd
diff -Nru xml2rfc-3.19.4/xml2rfc/writers/preptool.py xml2rfc-3.20.0/xml2rfc/writers/preptool.py
--- xml2rfc-3.19.4/xml2rfc/writers/preptool.py 2024-02-06 22:36:41.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc/writers/preptool.py 2024-02-21 22:48:18.000000000 +0000
@@ -263,6 +263,7 @@
'.//boilerplate;insert_copyright_notice()', # 5.4.2.3. "Copyright Notice" Insertion
'.//boilerplate//section', # 5.2.7. Section "toc" attribute
'.//reference;insert_target()', # 5.4.3. "target" Insertion
+ './/referencegroup;insert_target()', # "target" Insertion
'.//reference;insert_work_in_progress()',
'.//reference;sort_series_info()', # sort
'.//name;insert_slugified_name()', # 5.4.4. Slugification
@@ -439,9 +440,9 @@
if (c.tag, a) in latinscript_attributes:
if not is_script(v, 'Latin'):
self.err(c, 'Found non-Latin-script content in <%s> attribute value %s="%s"' % (c.tag, a, v))
- else:
+ if self.options.warn_bare_unicode:
if not isascii(v):
- self.err(c, 'Found non-ASCII content in <%s> attribute value %s="%s"' % (c.tag, a, v))
+ self.warn(c, f'Found non-ASCII content in {c.tag} attribute value {a}="{v}" that should be inspected to ensure it is intentional.')
if not (c.tag, a) in space_attributes:
vv = v.strip()
if vv != v:
@@ -1216,6 +1217,24 @@
front.insert(pos, s)
pos += 1
+ def referencegroup_insert_target(self, e, p):
+ target_pattern = {
+ "BCP": os.path.join(self.options.info_base_url, 'bcp{value}'),
+ "STD": os.path.join(self.options.info_base_url, 'std{value}'),
+ "FYI": os.path.join(self.options.info_base_url, 'fyi{value}'),
+ }
+
+ if not e.get('target'):
+ for c in e.xpath('.//seriesInfo'):
+ series_name = c.get('name')
+ if series_name in target_pattern.keys():
+ series_value=c.get('value')
+ if series_value:
+ e.set('target', target_pattern[series_name].format(value=series_value))
+ break
+ else:
+ self.err(c, 'Expected a value= attribute value for , but found none' % (series_name, ))
+
#
# 5.4.4. Slugification
#
diff -Nru xml2rfc-3.19.4/xml2rfc/writers/text.py xml2rfc-3.20.0/xml2rfc/writers/text.py
--- xml2rfc-3.19.4/xml2rfc/writers/text.py 2024-02-06 22:36:41.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc/writers/text.py 2024-02-21 22:48:18.000000000 +0000
@@ -22,7 +22,7 @@
from xml2rfc import strings
-from xml2rfc.writers.base import default_options, BaseV3Writer, RfcWriterError
+from xml2rfc.writers.base import default_options, BaseV3Writer, RfcWriterError, SUBSERIES
from xml2rfc import utils
from xml2rfc.uniscripts import is_script
from xml2rfc.util.date import extract_date, augment_date, get_expiry_date, format_date
@@ -36,6 +36,9 @@
from xml2rfc.utils import justify_inline, clean_text
+MAX_WIDTH = 72
+SPLITTER_WIDTH = 67
+
IndexItem = namedtuple('indexitem', ['item', 'subitem', 'anchor', 'page', ])
Joiner = namedtuple('joiner', ['join', 'indent', 'hang', 'overlap', 'do_outdent'])
# Joiner parts:
@@ -80,8 +83,8 @@
self.beg = beg # beginning line of block
self.end = end # ending line of block
-wrapper = utils.TextWrapper(width=72)
-splitter = utils.TextSplitter(width=67)
+wrapper = utils.TextWrapper(width=MAX_WIDTH)
+splitter = utils.TextSplitter(width=SPLITTER_WIDTH)
seen = set()
# This is not a complete list of whitespace characters, and isn't intended to be. It's
@@ -299,7 +302,7 @@
joiners = base_joiners
if self.options.pagination:
self.add_pageno_placeholders()
- lines = self.render(self.root, width=72, joiners=joiners)
+ lines = self.render(self.root, width=MAX_WIDTH, joiners=joiners)
if self.options.pagination:
lines = findblocks(lines)
@@ -321,8 +324,8 @@
sys.stderr.write(("%3d %10s [%4s] %s\n" % (i, tag, page, l.text)))
for i, l in enumerate(lines):
length = len(l.text)
- if length > 72:
- self.warn(l.elem, "Too long line found (L%s), %s characters longer than 72 characters: \n%s" %(i+1, length-72, l.text))
+ if length > MAX_WIDTH:
+ self.warn(l.elem, f"Too long line found (L{i + 1}), {length - MAX_WIDTH} characters longer than {MAX_WIDTH} characters: \n{l.text}")
text = ('\n'.join( l.text for l in lines )).rstrip(stripspace) + '\n'
@@ -505,7 +508,7 @@
else:
pass
# new toc, to be used to replace the old one
- toclines = self.render(toc, width=72, joiners=base_joiners)
+ toclines = self.render(toc, width=MAX_WIDTH, joiners=base_joiners)
if toc_start and toc_end:
j = 2
for i in range(toc_start+2, toc_end):
@@ -1811,7 +1814,7 @@
textwidth_l = textwidth(l)
textwidth_r = textwidth(r)
#assert textwidth_l+textwidth_r< 70
- w = 72-textwidth_l-textwidth_r
+ w = MAX_WIDTH-textwidth_l-textwidth_r
lines.append(l+' '*w+r)
return '\n'.join(lines).rstrip(stripspace)+'\n'
#
@@ -1819,7 +1822,7 @@
line = '%s%s%s' % (label, items, suffix)
ll = len(left)
lr = len(right)
- width = 48 if ll >= lr else min(48, 72-4-len(right[ll]))
+ width = 48 if ll >= lr else min(48, MAX_WIDTH-4-len(right[ll]))
wrapper = textwrap.TextWrapper(width=width, subsequent_indent=' '*len(label))
return wrapper.wrap(line)
#
@@ -2725,16 +2728,12 @@
elements = []
for ctag in ('title', 'refcontent', 'stream', 'seriesInfo', 'date',):
for c in e.iterdescendants(ctag):
- if p.tag == 'referencegroup' and c.tag == 'seriesInfo' and c.get('name') == 'DOI':
- # Don't render DOI within a reference group
- continue
elements.append(c)
- if p.tag != 'referencegroup':
- target = e.get('target')
- if target:
- url = self.element('refcontent')
- url.text = '<%s>' % target
- elements.append(url)
+ target = e.get('target')
+ if target:
+ url = self.element('refcontent')
+ url.text = '<%s>' % target
+ elements.append(url)
set_joiners(kwargs, {
None: Joiner(', ', 0, 0, False, False),
'annotation': Joiner(' ', 0, 0, False, False),
@@ -2746,7 +2745,8 @@
text += '.'
for ctag in ('annotation', ):
for c in e.iterdescendants(ctag):
- text = self.tjoin(text, c, width, **kwargs)
+ # use MAX_WIDTH here since text gets formatted later
+ text = self.tjoin(text, c, MAX_WIDTH, keep_url=True, **kwargs)
text = fill(text, width=width, fix_sentence_endings=False, keep_url=True, **kwargs).lstrip(stripspace)
text = indent(text, 11, 0)
@@ -2789,10 +2789,33 @@
label = self.refname_mapping[e.get('anchor')]
label = ('[%s]' % label).ljust(11)
lines = []
+ target = e.get('target')
+ subseries = False
+ for series in e.xpath('.//seriesInfo'):
+ if series.get('name') in SUBSERIES.keys():
+ kwargs['joiners'].update({
+ None: Joiner(', ', 11, 0, False, False),
+ 't': Joiner('\n', 11, 0, False, False),
+ })
+ text = f"{SUBSERIES[series.get('name')]} {series.get('value')}"
+ if target:
+ url = self.element('refcontent')
+ url.text = f'<{target}>.'
+ text = self.tjoin(text, url, width, **kwargs)
+ else:
+ text += '.'
+ subseries_width = width - 11
+ text = fill(text, width=subseries_width, fix_sentence_endings=False, keep_url=True, **kwargs).lstrip(stripspace)
+ text = indent(text, 11, 0)
+ lines = mklines(text, e)
+ t = self.element('t')
+ t.text = f"At the time of writing, this {series.get('name')} comprises the following:"
+ lines = self.ljoin(lines, t, width, **kwargs)
+ subseries = True
+ break
for c in e.getchildren():
lines = self.ljoin(lines, c, width, **kwargs)
- target = e.get('target')
- if target:
+ if target and not subseries:
t = self.element('t')
t.text = '<%s>' % target
lines = self.ljoin(lines, t, width, **kwargs)
@@ -3957,7 +3980,7 @@
Find the minimum column widths of regular cells
"""
i = 0
- splitter = utils.TextSplitter(width=67, hyphen_split=hyphen_split)
+ splitter = utils.TextSplitter(width=SPLITTER_WIDTH, hyphen_split=hyphen_split)
for p in e.iterchildren(['thead', 'tbody', 'tfoot']):
for r in list(p.iterchildren('tr')):
j = 0
diff -Nru xml2rfc-3.19.4/xml2rfc.egg-info/PKG-INFO xml2rfc-3.20.0/xml2rfc.egg-info/PKG-INFO
--- xml2rfc-3.19.4/xml2rfc.egg-info/PKG-INFO 2024-02-06 22:37:17.000000000 +0000
+++ xml2rfc-3.20.0/xml2rfc.egg-info/PKG-INFO 2024-02-21 22:48:53.000000000 +0000
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: xml2rfc
-Version: 3.19.4
+Version: 3.20.0
Summary: xml2rfc generates RFCs and IETF drafts from document source in XML according to the IETF xml2rfc v2 and v3 vocabularies.
Home-page: https://github.com/ietf-tools/xml2rfc
Download-URL: https://github.com/ietf-tools/xml2rfc/releases