initial release
[squeep-web-linking] / lib / rfc8288-web-linking.peggy
1 {{
2 /* Generated code is not pretty, ignore a lot of this horrorstyle. */
3 /* eslint-disable quotes */
4 /* eslint-disable vars-on-top */
5 /* eslint-disable no-control-regex */
6 /* eslint-disable security/detect-object-injection */
7 /* eslint-disable vars-on-top */
8 /* eslint-disable brace-style */
9 /* eslint-disable comma-dangle */
10 /* eslint-disable no-unused-vars */
11
12 function makeString(o) {
13 return o.join('');
14 }
15
16 const onlyFirstAttributes = [
17 'media',
18 'rel',
19 'title',
20 'title*',
21 'type',
22 ];
23
24 }}
25
26 {
27 // Per-parsing tracking of attributes which should be ignored after first occurrence.
28 let seenAttributes = [];
29 }
30
31 links 'links'
32 = links:linkValue+ {
33 return links;
34 }
35
36 linkValue 'link-value'
37 = uriReference:uriReference OWS attributes:attributes ','? OWS {
38 seenAttributes = [];
39 return {
40 target: uriReference,
41 attributes,
42 };
43 }
44
45 uriReference 'uri-reference'
46 = '<' uri:uri '>' ';' {
47 return uri;
48 }
49
50 uri 'uri'
51 = uri:[^>]+ {
52 return makeString(uri);
53 }
54
55 attributes 'attributes'
56 = attrs:linkParam+ {
57 return attrs.filter((a) => a);
58 }
59
60 linkParam 'link-param'
61 = name:name BWS '=' BWS value:value ';'? OWS {
62 if (onlyFirstAttributes.includes(name.name)) {
63 if (seenAttributes.includes(name.name)) {
64 // Repeat of singleton attribute, ignore it.
65 return;
66 }
67 seenAttributes.push(name.name);
68 }
69 return {
70 ...name,
71 ...value,
72 };
73 }
74 / name:name BWS ';'? OWS {
75 return {
76 ...name,
77 value: null,
78 }
79 }
80
81 name 'name'
82 = name:[a-zA-Z]+ extended:'*'? {
83 return {
84 name: makeString(name.concat(extended)).toLowerCase(),
85 extended: !!extended,
86 };
87 }
88
89 value 'value'
90 = ["] value:[^"]+ ["] {
91 return {
92 value: makeString(value),
93 };
94 }
95 / value:[^";,]+ {
96 return {
97 value: makeString(value),
98 };
99 }
100
101 OWS 'whitespace'
102 = spaces:[ ]*
103
104 BWS 'bad whitespace'
105 = OWS
106
107 // This is also an alternate startRule.
108 extendedValue 'extended-value'
109 = encoding:[^']* ['] language:[^']* ['] value:.* {
110 return {
111 encoding: encoding.length ? makeString(encoding) : 'UTF-8',
112 language: language.length ? makeString(language) : null,
113 value: decodeURIComponent(makeString(value)),
114 };
115 }
116 / value:.* {
117 return {
118 encoding: null,
119 language: null,
120 value: makeString(value),
121 };
122 }