1// use `deno run --allow-read --allow-write ./fixtures/testgen.js ./commonmark.rs` to run this script
2
3if (Deno.args.length !== 1) {
4 console.error(`
5Usage: deno run --allow-read --allow-write ./fixtures/testgen.js ./commonmark.rs
6`)
7 Deno.exit(1)
8}
9
10import testgen from 'npm:markdown-it-testgen@^0.1.6'
11
12function rust_escape(s) {
13 if (s.match(/( $|\t)/m)) {
14 return '"' + s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/ $/mg, '\\x20').replace(/\t/g, '\\t') + '"'
15 }
16
17 if (s.match(/#"|"#/)) return 'r##"' + s + '"##'
18 return 'r#"' + s + '"#'
19}
20
21let identmap = new Set()
22function ident(str) {
23 str = str.toLowerCase()
24 .replace(/[^a-z0-9]+/g, '_')
25 .replace(/^_+|_+$/g, '')
26
27 if (!str) str = 'unnamed'
28
29 let result = str
30 let idx = 0
31 while (identmap.has(result)) {
32 result = str + '_' + (++idx)
33 }
34
35 identmap.add(result)
36 return result
37}
38
39function generate(fixture) {
40 return `
41#[test]
42fn ${ident(fixture.header)}() {
43 let input = ${rust_escape(fixture.first.text.replace(/\n$/, ''))};
44 let output = ${rust_escape(fixture.second.text.replace(/\n$/, ''))};
45 run(input, output);
46}
47`.trim()
48}
49
50let input_raw = await Deno.readFile(Deno.args[0])
51let input = new TextDecoder().decode(input_raw)
52let lines = []
53let state = 'passthrough'
54
55for (let line of input.split('\n')) {
56 switch (state) {
57 case 'passthrough':
58 lines.push(line)
59 if (line.match(/^\/{4,}$/)) {
60 state = 'maybeheader'
61 }
62 break
63 case 'skipping':
64 if (line.match(/^\/{4,}$/)) {
65 lines.push(line)
66 state = 'maybeheader'
67 }
68 break
69 case 'maybeheader':
70 lines.push(line)
71 let match = line.match(/^\/{2,}\s+TESTGEN:\s*(.+)\s*$/)
72 if (match) {
73 let has_data = false
74 lines.push('#[rustfmt::skip]')
75 lines.push(`mod ${ident(match[1])} {`)
76 lines.push('use super::run;')
77 lines.push('// this part of the file is auto-generated')
78 lines.push('// don\'t edit it, otherwise your changes might be lost')
79 testgen.load(match[1], data => {
80 data.fixtures.forEach((data, idx) => {
81 has_data = true
82 if (idx++ > 0) lines.push('')
83 let generated = generate(data).replace(/\r?\n$/, '')
84 lines = lines.concat(generated.split('\n'))
85 })
86 })
87 lines.push('// end of auto-generated module')
88 lines.push('}')
89 if (!has_data) throw new Error(`no data found for ${match[1]}`)
90 state = 'skipping'
91 }
92 break
93 default:
94 throw Error('unknown state')
95 }
96}
97
98await Deno.rename(Deno.args[0], Deno.args[0] + '.old')
99await Deno.writeFile(Deno.args[0], new TextEncoder().encode(lines.join('\n') + '\n'))