summaryrefslogtreecommitdiff
path: root/ftt-docgen
blob: 6dd7ee9270a7901eb9a62d0fe67a1a2c75d7fa51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/bin/env python3

import copy
import re
import sys

import CommonMark_bkrs as CommonMark
import yaml

def format_keyword(line):
    words = line.split(' ')
    keyword = words[0]
    return '**{}** '.format(keyword) + line[len(keyword):]

def format_scenario_step(bind, line):
    for b in bind:
        m = re.match(b['pattern'], line, re.I)
        if m and m.end() == len(line):
            n = len(m.groups())
            if n > 0:
                end = 0
                parts = []
                for i in range(1, n+1):
                    parts.append(line[end:m.start(i)])
                    thispart = line[m.start(i) : m.end(i)]
                    parts.append('_{}_'.format(thispart))
                    end = m.end(i)
                line = ''.join(parts) + line[m.end(n):]

    if not line.strip():
        return line
    return format_keyword(line)

def format_fable_snippet(bind, lines):
    return [format_scenario_step(bind, line) for line in lines]

def is_fable_snippet(o):
    prefix = "```fable\n"
    return o.t == 'FencedCode' and o.info == 'fable'

def is_heading(o):
    return o.t =='ATXHeader'

def write_document(bind, f, o):
    pass

def write_atxheader(bind, f, o):
    f.write('{} {}\n\n'.format('#' * o.level, ' '.join(o.strings)))

def write_setextheader(bind, f, o):
    chars = {
        1: '=',
        2: '-',
    }
    c = chars[o.level]
    f.write('{}\n{}\n\n'.format(' '.join(o.strings), c * 72))

def write_paragraph(bind, f, o):
    for s in o.strings:
        f.write('{}\n'.format(s))
    f.write('\n')

def write_fable_snippet(bind, f, o):
    for line in format_fable_snippet(bind, o.strings[1:]):
        f.write('> {}  \n'.format(line))
    f.write('\n')

def write_not_fable_snippet(bind, f, o):
    fence = o.fence_char * o.fence_length
    lang = o.strings[0]
    f.write('{}{}\n'.format(fence, lang))
    for line in o.strings[1:]:
        f.write('{}\n'.format(line))
    f.write('{}\n'.format(fence))
    f.write('\n')

def write_fencedcode(bind, f, o):
    if is_fable_snippet(o):
        write_fable_snippet(bind, f, o)
    else:
        write_not_fable_snippet(bind, f, o)

def write_horizontalrule(bind, f, o):
    f.write('---\n')

writers = {
    'Document': write_document,
    'ATXHeader': write_atxheader,
    'SetextHeader': write_setextheader,
    'Paragraph': write_paragraph,
    'FencedCode': write_fencedcode,
    'HorizontalRule': write_horizontalrule,
}

def write(bind, f, o):
    if o.t not in writers:
        debug('{} not known'.format(repr(o.t)))
        return
    writer = writers[o.t]
    writer(bind, f, o)

def walk(o, func):
    func(o)
    for c in o.children:
        walk(c, func)

def debug(msg):
    sys.stderr.write('DEBUG: {}\n'.format(msg))
    sys.stderr.flush()

debug('reading bindings')
bindings = yaml.safe_load(open(sys.argv[1]))

debug('reading inputs')
text = ''.join(open(filename).read() for filename in sys.argv[2:])

debug('parse')
parser = CommonMark.DocParser()
ast = parser.parse(text)

debug('output')
walk(ast, lambda o: write(bindings, sys.stdout, o))

debug('ok')