@markuplint/types 4.7.6 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ import type { CustomSyntaxChecker } from '../types.js';
2
+ /**
3
+ * Link Type
4
+ * @see https://html.spec.whatwg.org/multipage/links.html#linkTypes
5
+ */
6
+ export declare const checkLinkType: CustomSyntaxChecker<{
7
+ el: 'link' | 'body link' | 'a, area' | 'form';
8
+ }>;
@@ -0,0 +1,568 @@
1
+ import { checkList } from '../list.js';
2
+ import { TokenCollection } from '../token/token-collection.js';
3
+ /**
4
+ * @see https://html.spec.whatwg.org/multipage/links.html#linkTypes
5
+ *
6
+ * Scraping:
7
+ * ```js
8
+ * JSON.stringify(document.querySelectorAll('#table-link-relations tbody tr').values().toArray().map((el) => {
9
+ * const keyword = el.querySelector('td').textContent.trim();
10
+ * const link = el.querySelector('td:nth-child(2)').textContent.trim();
11
+ * const a = el.querySelector('td[colspan="3"]:nth-child(2)')?.textContent.trim() ?? el.querySelector('td[colspan="2"]:nth-child(2)')?.textContent.trim() ?? el.querySelector('td:nth-child(3)')?.textContent.trim();
12
+ * const form = el.querySelector('td[colspan="3"]:nth-child(2)')?.textContent.trim() ?? el.querySelector('td[colspan="2"]:nth-child(3)')?.textContent.trim() ?? el.querySelector('td[colspan="2"]:nth-child(2) + td')?.textContent.trim() ?? el.querySelector('td:nth-child(4)')?.textContent.trim();
13
+ * const bodyOk = el.querySelector('td[colspan="3"]:nth-child(2) + td')?.textContent.trim() ?? el.querySelector('td[colspan="2"]:nth-child(3) + td')?.textContent.trim() ?? el.querySelector('td[colspan="2"]:nth-child(2) + td + td')?.textContent.trim() ?? el.querySelector('td:nth-child(5)')?.textContent.trim();
14
+ * return { keyword, link, a, form, bodyOk }
15
+ * }));
16
+ * ```
17
+ */
18
+ const DEF_LINK_TYPE_WHATWG = [
19
+ { keyword: 'alternate', link: 'Hyperlink', a: 'Hyperlink', form: 'not allowed', bodyOk: '·' },
20
+ { keyword: 'canonical', link: 'Hyperlink', a: 'not allowed', form: 'not allowed', bodyOk: '·' },
21
+ { keyword: 'author', link: 'Hyperlink', a: 'Hyperlink', form: 'not allowed', bodyOk: '·' },
22
+ { keyword: 'bookmark', link: 'not allowed', a: 'Hyperlink', form: 'not allowed', bodyOk: '·' },
23
+ { keyword: 'dns-prefetch', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
24
+ { keyword: 'expect', link: 'Internal Resource', a: 'not allowed', form: 'not allowed', bodyOk: '·' },
25
+ { keyword: 'external', link: 'not allowed', a: 'Annotation', form: 'Annotation', bodyOk: '·' },
26
+ { keyword: 'help', link: 'Hyperlink', a: 'Hyperlink', form: 'Hyperlink', bodyOk: '·' },
27
+ { keyword: 'icon', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: '·' },
28
+ { keyword: 'manifest', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: '·' },
29
+ { keyword: 'modulepreload', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
30
+ { keyword: 'license', link: 'Hyperlink', a: 'Hyperlink', form: 'Hyperlink', bodyOk: '·' },
31
+ { keyword: 'next', link: 'Hyperlink', a: 'Hyperlink', form: 'Hyperlink', bodyOk: '·' },
32
+ { keyword: 'nofollow', link: 'not allowed', a: 'Annotation', form: 'Annotation', bodyOk: '·' },
33
+ { keyword: 'noopener', link: 'not allowed', a: 'Annotation', form: 'Annotation', bodyOk: '·' },
34
+ { keyword: 'noreferrer', link: 'not allowed', a: 'Annotation', form: 'Annotation', bodyOk: '·' },
35
+ { keyword: 'opener', link: 'not allowed', a: 'Annotation', form: 'Annotation', bodyOk: '·' },
36
+ { keyword: 'pingback', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
37
+ { keyword: 'preconnect', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
38
+ { keyword: 'prefetch', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
39
+ { keyword: 'preload', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
40
+ { keyword: 'prev', link: 'Hyperlink', a: 'Hyperlink', form: 'Hyperlink', bodyOk: '·' },
41
+ { keyword: 'privacy-policy', link: 'Hyperlink', a: 'Hyperlink', form: 'not allowed', bodyOk: '·' },
42
+ { keyword: 'search', link: 'Hyperlink', a: 'Hyperlink', form: 'Hyperlink', bodyOk: '·' },
43
+ { keyword: 'stylesheet', link: 'External Resource', a: 'not allowed', form: 'not allowed', bodyOk: 'Yes' },
44
+ { keyword: 'tag', link: 'not allowed', a: 'Hyperlink', form: 'not allowed', bodyOk: '·' },
45
+ { keyword: 'terms-of-service', link: 'Hyperlink', a: 'Hyperlink', form: 'not allowed', bodyOk: '·' },
46
+ ];
47
+ /**
48
+ * @see https://microformats.org/wiki/existing-rel-values#formats
49
+ *
50
+ * Scraping:
51
+ * ```js
52
+ * JSON.stringify($("h2:has('#formats') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
53
+ * const $tr = $(el);
54
+ * const keyword = $tr.find('td')[0].textContent.trim();
55
+ * const link = !/not allow/i.test($tr.find('td')[1].textContent);
56
+ * const a = !/not allow/i.test($tr.find('td')[2].textContent);
57
+ * return { keyword, link, a }
58
+ * }));
59
+ * ```
60
+ */
61
+ const DEF_LINK_TYPE_MICROFORMATS_FORMATS = [
62
+ { keyword: 'acquaintance', link: false, a: true },
63
+ { keyword: 'alternate', link: true, a: true },
64
+ { keyword: 'appendix', link: true, a: true },
65
+ { keyword: 'bookmark', link: false, a: true },
66
+ { keyword: 'chapter', link: true, a: true },
67
+ { keyword: 'child', link: true, a: true },
68
+ { keyword: 'colleague', link: false, a: true },
69
+ { keyword: 'contact', link: false, a: true },
70
+ { keyword: 'contents', link: true, a: true },
71
+ { keyword: 'copyright', link: true, a: true },
72
+ { keyword: 'co-resident', link: false, a: true },
73
+ { keyword: 'co-worker', link: false, a: true },
74
+ { keyword: 'crush', link: false, a: true },
75
+ { keyword: 'date', link: false, a: true },
76
+ { keyword: 'friend', link: false, a: true },
77
+ { keyword: 'glossary', link: true, a: true },
78
+ { keyword: 'help', link: true, a: true },
79
+ { keyword: 'its-rules', link: true, a: false },
80
+ { keyword: 'kin', link: false, a: true },
81
+ { keyword: 'license', link: true, a: true },
82
+ { keyword: 'me', link: true, a: true },
83
+ { keyword: 'met', link: false, a: true },
84
+ { keyword: 'muse', link: false, a: true },
85
+ { keyword: 'neighbor', link: false, a: true },
86
+ { keyword: 'next', link: true, a: true },
87
+ { keyword: 'nofollow', link: false, a: true },
88
+ { keyword: 'parent', link: true, a: true },
89
+ { keyword: 'prev', link: true, a: true },
90
+ { keyword: 'previous', link: true, a: true },
91
+ { keyword: 'section', link: true, a: true },
92
+ { keyword: 'sibling', link: false, a: true },
93
+ { keyword: 'spouse', link: false, a: true },
94
+ { keyword: 'start', link: true, a: true },
95
+ { keyword: 'stylesheet', link: true, a: false },
96
+ { keyword: 'subsection', link: true, a: true },
97
+ { keyword: 'sweetheart', link: false, a: true },
98
+ { keyword: 'tag', link: false, a: true },
99
+ { keyword: 'toc', link: true, a: true },
100
+ { keyword: 'transformation', link: true, a: true },
101
+ ];
102
+ /**
103
+ * @see https://microformats.org/wiki/existing-rel-values#proposals
104
+ *
105
+ * Scraping:
106
+ * ```js
107
+ * JSON.stringify($("h2:has('#proposals') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
108
+ * const $tr = $(el);
109
+ * const keyword = $tr.find('td')[0].textContent.trim();
110
+ * return { keyword, link: true, a: true }
111
+ * }));
112
+ * ```
113
+ */
114
+ const DEF_LINK_TYPE_MICROFORMATS_PROPOSALS = [
115
+ { keyword: 'pronunciation', link: true, a: true },
116
+ { keyword: 'directory', link: true, a: true },
117
+ { keyword: 'enclosure', link: true, a: true },
118
+ { keyword: 'home', link: true, a: true },
119
+ { keyword: 'payment', link: true, a: true },
120
+ { keyword: 'vcs-*', link: true, a: true },
121
+ ];
122
+ /**
123
+ * @see https://microformats.org/wiki/existing-rel-values#HTML5_link_type_extensions
124
+ *
125
+ * Scraping:
126
+ * ```js
127
+ * JSON.stringify($("h2:has('#HTML5_link_type_extensions') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
128
+ * const $tr = $(el);
129
+ * const keyword = $tr.find('td')[0].textContent.trim();
130
+ * const link = !/not allow/i.test($tr.find('td')[1].textContent);
131
+ * const a = !/not allow/i.test($tr.find('td')[2].textContent);
132
+ * return { keyword, link, a }
133
+ * }));
134
+ * ```
135
+ */
136
+ const DEF_LINK_TYPE_MICROFORMATS_HTML5_LINK_TYPE_EXTENSIONS = [
137
+ { keyword: 'about', link: true, a: true },
138
+ { keyword: 'amphtml', link: true, a: true },
139
+ { keyword: 'apple-touch-icon', link: true, a: false },
140
+ { keyword: 'apple-touch-icon-precomposed', link: true, a: false },
141
+ { keyword: 'apple-touch-startup-image', link: true, a: false },
142
+ { keyword: 'archived', link: true, a: true },
143
+ { keyword: 'attachment', link: true, a: true },
144
+ { keyword: 'authorization_endpoint', link: true, a: false },
145
+ { keyword: 'canonical', link: true, a: true },
146
+ { keyword: 'category', link: true, a: true },
147
+ { keyword: 'code-repository', link: true, a: true },
148
+ { keyword: 'code-license', link: true, a: true },
149
+ { keyword: 'component', link: true, a: false },
150
+ { keyword: 'chrome-webstore-item', link: true, a: false },
151
+ { keyword: 'content-repository', link: true, a: true },
152
+ { keyword: 'content-license', link: true, a: true },
153
+ { keyword: 'DCTERMS.conformsTo', link: true, a: false }, // cspell:disable-line
154
+ { keyword: 'DCTERMS.contributor', link: true, a: false }, // cspell:disable-line
155
+ { keyword: 'DCTERMS.creator', link: true, a: false }, // cspell:disable-line
156
+ { keyword: 'DCTERMS.description', link: true, a: false }, // cspell:disable-line
157
+ { keyword: 'DCTERMS.hasFormat', link: true, a: false }, // cspell:disable-line
158
+ { keyword: 'DCTERMS.hasPart', link: true, a: false }, // cspell:disable-line
159
+ { keyword: 'DCTERMS.hasVersion', link: true, a: false }, // cspell:disable-line
160
+ { keyword: 'DCTERMS.isFormatOf', link: true, a: false }, // cspell:disable-line
161
+ { keyword: 'DCTERMS.isPartOf', link: true, a: false }, // cspell:disable-line
162
+ { keyword: 'DCTERMS.isReferencedBy', link: true, a: false }, // cspell:disable-line
163
+ { keyword: 'DCTERMS.isReplacedBy', link: true, a: false }, // cspell:disable-line
164
+ { keyword: 'DCTERMS.isRequiredBy', link: true, a: false }, // cspell:disable-line
165
+ { keyword: 'DCTERMS.isVersionOf', link: true, a: false }, // cspell:disable-line
166
+ { keyword: 'DCTERMS.license', link: true, a: false }, // cspell:disable-line
167
+ { keyword: 'DCTERMS.mediator', link: true, a: false }, // cspell:disable-line
168
+ { keyword: 'DCTERMS.publisher', link: true, a: false }, // cspell:disable-line
169
+ { keyword: 'DCTERMS.references', link: true, a: false }, // cspell:disable-line
170
+ { keyword: 'DCTERMS.relation', link: true, a: false }, // cspell:disable-line
171
+ { keyword: 'DCTERMS.replaces', link: true, a: false }, // cspell:disable-line
172
+ { keyword: 'DCTERMS.requires', link: true, a: false }, // cspell:disable-line
173
+ { keyword: 'DCTERMS.rightsHolder', link: true, a: false }, // cspell:disable-line
174
+ { keyword: 'DCTERMS.source', link: true, a: false }, // cspell:disable-line
175
+ { keyword: 'DCTERMS.subject', link: true, a: false }, // cspell:disable-line
176
+ { keyword: 'disclosure', link: false, a: true },
177
+ { keyword: 'discussion', link: true, a: true },
178
+ { keyword: 'donation', link: true, a: true },
179
+ { keyword: 'dns-prefetch', link: true, a: false },
180
+ { keyword: 'edit', link: true, a: true },
181
+ { keyword: 'EditURI', link: true, a: false },
182
+ { keyword: 'enclosure', link: true, a: true },
183
+ { keyword: 'entry-content', link: false, a: true },
184
+ { keyword: 'external', link: false, a: true },
185
+ { keyword: 'first', link: true, a: true },
186
+ { keyword: 'gbfs', link: true, a: false }, // cspell:disable-line
187
+ { keyword: 'gtfs-static', link: true, a: false }, // cspell:disable-line
188
+ { keyword: 'gtfs-realtime', link: true, a: false }, // cspell:disable-line
189
+ { keyword: 'home', link: true, a: true },
190
+ { keyword: 'hub', link: true, a: true },
191
+ { keyword: 'import', link: true, a: false },
192
+ { keyword: 'in-reply-to', link: true, a: true },
193
+ { keyword: 'root', link: true, a: true },
194
+ { keyword: 'index', link: true, a: true },
195
+ { keyword: 'issues', link: true, a: true },
196
+ { keyword: 'jslicense', link: true, a: true }, // cspell:disable-line
197
+ { keyword: 'last', link: true, a: true },
198
+ { keyword: 'lightbox', link: false, a: true },
199
+ { keyword: 'lightvideo', link: false, a: true },
200
+ { keyword: 'main', link: true, a: true },
201
+ { keyword: 'manifest', link: true, a: false },
202
+ { keyword: 'mask-icon', link: true, a: false },
203
+ { keyword: 'meta', link: true, a: false },
204
+ { keyword: 'micropub', link: true, a: false },
205
+ { keyword: 'noopener', link: false, a: true },
206
+ { keyword: 'openid.delegate', link: true, a: false },
207
+ { keyword: 'openid.server', link: true, a: false },
208
+ { keyword: 'openid2.local_id', link: true, a: false },
209
+ { keyword: 'openid2.provider', link: true, a: false },
210
+ { keyword: 'p3pv1', link: true, a: false },
211
+ { keyword: 'pgpkey', link: true, a: false },
212
+ { keyword: 'pingback', link: true, a: false },
213
+ { keyword: 'preconnect', link: true, a: false },
214
+ { keyword: 'prerender', link: true, a: true },
215
+ { keyword: 'profile', link: true, a: true },
216
+ { keyword: 'publisher', link: true, a: true },
217
+ { keyword: 'radioepg', link: true, a: true }, // cspell:disable-line
218
+ { keyword: 'rendition', link: true, a: true },
219
+ { keyword: 'reply-to', link: true, a: true },
220
+ { keyword: 'schema.DCTERMS', link: true, a: false }, // cspell:disable-line
221
+ { keyword: 'service', link: true, a: false },
222
+ { keyword: 'shortlink', link: true, a: false },
223
+ { keyword: 'sidebar', link: true, a: true },
224
+ { keyword: 'sitemap', link: true, a: false },
225
+ { keyword: 'subresource', link: true, a: false },
226
+ { keyword: 'sword', link: true, a: false },
227
+ { keyword: 'syndication', link: true, a: true },
228
+ { keyword: 'timesheet', link: true, a: false },
229
+ { keyword: 'token_endpoint', link: true, a: false },
230
+ { keyword: 'webmention', link: true, a: true },
231
+ { keyword: 'widget', link: true, a: true },
232
+ { keyword: 'wlwmanifest', link: true, a: false }, // cspell:disable-line
233
+ { keyword: 'image_src', link: true, a: false },
234
+ { keyword: 'http://docs.oasis-open.org/ns/cmis/link/200908/acl', link: true, a: true },
235
+ { keyword: 'stylesheet/less', link: true, a: false },
236
+ { keyword: 'yandex-tableau-widget', link: true, a: false },
237
+ ];
238
+ /**
239
+ * @see https://microformats.org/wiki/existing-rel-values#brainstorming
240
+ *
241
+ * Scraping:
242
+ * ```js
243
+ * JSON.stringify($("h2:has('#brainstorming') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
244
+ * const $tr = $(el);
245
+ * const keyword = $tr.find('td')[0].textContent.trim();
246
+ * return { keyword, link: true, a: true }
247
+ * }));
248
+ * ```
249
+ */
250
+ const DEF_LINK_TYPE_MICROFORMATS_BRAINSTORMING = [
251
+ { keyword: 'accessibility', link: true, a: true },
252
+ { keyword: 'author', link: true, a: true },
253
+ { keyword: 'bibliography', link: true, a: true },
254
+ { keyword: 'cite', link: true, a: true },
255
+ { keyword: 'embed', link: true, a: true },
256
+ { keyword: 'group', link: true, a: true },
257
+ { keyword: 'longdesc', link: true, a: true },
258
+ { keyword: 'map', link: true, a: true },
259
+ { keyword: 'member', link: true, a: true },
260
+ { keyword: 'm_PageScroll2id', link: true, a: true },
261
+ { keyword: 'prefetch', link: true, a: true },
262
+ { keyword: 'preload', link: true, a: true },
263
+ { keyword: 'prerender', link: true, a: true },
264
+ { keyword: 'profile', link: true, a: true },
265
+ { keyword: 'shortlink', link: true, a: true },
266
+ { keyword: 'source', link: true, a: true },
267
+ { keyword: 'vcalendar-parent', link: true, a: true }, // cspell:disable-line
268
+ { keyword: 'vcalendar-child', link: true, a: true }, // cspell:disable-line
269
+ { keyword: 'vcalendar-sibling', link: true, a: true }, // cspell:disable-line
270
+ { keyword: 'status', link: true, a: true },
271
+ { keyword: 'https://api.w.org/', link: true, a: true },
272
+ ];
273
+ /**
274
+ * @see https://microformats.org/wiki/existing-rel-values#POSH_usage
275
+ *
276
+ * Scraping:
277
+ * ```js
278
+ * JSON.stringify($("h2:has('#POSH_usage') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
279
+ * const $tr = $(el);
280
+ * const keyword = $tr.find('td')[0].textContent.trim();
281
+ * return { keyword, link: true, a: true }
282
+ * }));
283
+ * ```
284
+ */
285
+ const DEF_LINK_TYPE_MICROFORMATS_POSH_USAGE = [
286
+ { keyword: 'archive', link: true, a: true },
287
+ { keyword: 'archives', link: true, a: true },
288
+ { keyword: 'author', link: true, a: true },
289
+ { keyword: 'canonical', link: true, a: true },
290
+ { keyword: 'comment', link: true, a: true },
291
+ { keyword: 'contribution', link: true, a: true },
292
+ { keyword: 'EditURI', link: true, a: true },
293
+ { keyword: 'endorsed', link: true, a: true },
294
+ { keyword: 'fan', link: true, a: true },
295
+ { keyword: 'feed', link: true, a: true },
296
+ { keyword: 'footnote', link: true, a: true },
297
+ { keyword: 'icon', link: true, a: true },
298
+ { keyword: 'kinetic-stylesheet', link: true, a: true },
299
+ { keyword: 'lightbox', link: true, a: true },
300
+ { keyword: 'made', link: true, a: true },
301
+ { keyword: 'meta', link: true, a: true },
302
+ { keyword: 'microsummary', link: true, a: true },
303
+ { keyword: 'noreferrer', link: true, a: true },
304
+ { keyword: 'openid.delegate', link: true, a: true },
305
+ { keyword: 'openid.server', link: true, a: true },
306
+ { keyword: 'permalink', link: true, a: true },
307
+ { keyword: 'pgpkey', link: true, a: true },
308
+ { keyword: 'pingback', link: true, a: true },
309
+ { keyword: 'popover', link: true, a: true },
310
+ { keyword: 'prefetch', link: true, a: true },
311
+ { keyword: 'privacy', link: true, a: true },
312
+ { keyword: 'publickey', link: true, a: true },
313
+ { keyword: 'referral', link: true, a: true },
314
+ { keyword: 'related', link: true, a: true },
315
+ { keyword: 'replies', link: true, a: true },
316
+ { keyword: 'respond-proxy', link: true, a: true },
317
+ { keyword: 'respond-redirect', link: true, a: true },
318
+ { keyword: 'resource', link: true, a: true },
319
+ { keyword: 'search', link: true, a: true },
320
+ { keyword: 'sitemap', link: true, a: true },
321
+ { keyword: 'sponsor', link: true, a: true },
322
+ { keyword: 'tooltip', link: true, a: true },
323
+ { keyword: 'trackback', link: true, a: true },
324
+ { keyword: 'unendorsed', link: true, a: true },
325
+ { keyword: 'user', link: true, a: true },
326
+ { keyword: 'wlwmanifest', link: true, a: true }, // cspell:disable-line
327
+ ];
328
+ /**
329
+ * @see https://microformats.org/wiki/existing-rel-values#Dublin_Core
330
+ *
331
+ * > **only use invisible <link href> element.**
332
+ *
333
+ * Scraping:
334
+ * ```js
335
+ * JSON.stringify($("h2:has('#Dublin_Core') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
336
+ * const $tr = $(el);
337
+ * const keyword = $tr.find('td')[0].textContent.trim();
338
+ * return { keyword, link: true, a: false }
339
+ * }));
340
+ */
341
+ const DEF_LINK_TYPE_MICROFORMATS_DUBLIN_CORE = [
342
+ { keyword: 'schema.DC', link: true, a: false },
343
+ { keyword: 'schema.DCTERMS', link: true, a: false }, // cspell:disable-line
344
+ ];
345
+ /**
346
+ * @see https://microformats.org/wiki/existing-rel-values#non_HTML_rel_values
347
+ *
348
+ * Scraping:
349
+ * ```js
350
+ * JSON.stringify($("h2:has('#non_HTML_rel_values') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
351
+ * const $tr = $(el);
352
+ * const keyword = $tr.find('td')[0].textContent.trim();
353
+ * return { keyword, link: true, a: true }
354
+ * }));
355
+ */
356
+ const DEF_LINK_TYPE_MICROFORMATS_NON_HTML_REL_VALUES = [
357
+ { keyword: 'self' },
358
+ { keyword: 'http://gdata.youtube.com/schemas/2007#in-reply-to' },
359
+ { keyword: 'collection' },
360
+ { keyword: 'compensatingtx' }, // cspell:disable-line
361
+ { keyword: 'east' },
362
+ { keyword: 'events' },
363
+ { keyword: 'exit' },
364
+ { keyword: 'north' },
365
+ { keyword: 'south' },
366
+ { keyword: 'via' },
367
+ { keyword: 'west' },
368
+ { keyword: 'item' },
369
+ { keyword: 'create-form' },
370
+ { keyword: 'edit-form' },
371
+ { keyword: 'lightframe' },
372
+ { keyword: 'superbox[image]' },
373
+ { keyword: 'wp-video-lightbox' },
374
+ { keyword: 'youtube' },
375
+ { keyword: 'shadowbox' },
376
+ { keyword: 'permission' },
377
+ { keyword: 'sub' },
378
+ { keyword: 'unsub' }, // cspell:disable-line
379
+ { keyword: 'version-history' },
380
+ { keyword: 'latest-version' },
381
+ { keyword: 'working-copy' },
382
+ { keyword: 'working-copy-of' },
383
+ { keyword: 'predecessor-version' },
384
+ { keyword: 'successor-version' },
385
+ ];
386
+ /**
387
+ * @see https://microformats.org/wiki/existing-rel-values#dropped
388
+ *
389
+ * Scraping:
390
+ * ```js
391
+ * JSON.stringify($("h2:has('#dropped') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
392
+ * const $tr = $(el);
393
+ * const keyword = $tr.find('td')[0].textContent.split(' ')[0]?.trim();
394
+ * return { keyword }
395
+ * }));
396
+ */
397
+ const DEF_LINK_TYPE_MICROFORMATS_DROPPED = [
398
+ { keyword: 'banner' },
399
+ { keyword: 'begin' },
400
+ { keyword: 'biblioentry' }, // cspell:disable-line
401
+ { keyword: 'bibliography' },
402
+ { keyword: 'child' },
403
+ { keyword: 'citation' },
404
+ { keyword: 'collection' },
405
+ { keyword: 'definition' },
406
+ { keyword: 'disclaimer' },
407
+ { keyword: 'editor' },
408
+ { keyword: 'end' },
409
+ { keyword: 'footnote' },
410
+ { keyword: 'navigate' },
411
+ { keyword: 'origin' },
412
+ { keyword: 'parent' },
413
+ { keyword: 'pointer' },
414
+ { keyword: 'publisher' },
415
+ { keyword: 'sibling' },
416
+ { keyword: 'top' },
417
+ { keyword: 'trademark' },
418
+ { keyword: 'translation' },
419
+ { keyword: 'urc' },
420
+ ];
421
+ /**
422
+ * @see https://microformats.org/wiki/existing-rel-values#dropped_without_prejudice
423
+ *
424
+ * Scraping:
425
+ * ```js
426
+ * JSON.stringify($("h2:has('#dropped_without_prejudice') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
427
+ * const $tr = $(el);
428
+ * const keyword = $tr.find('td')[0].textContent.split(' ')[0]?.trim();
429
+ * return { keyword }
430
+ * }));
431
+ * ```
432
+ */
433
+ const DEF_LINK_TYPE_MICROFORMATS_DROPPED_WITHOUT_PREJUDICE = [
434
+ { keyword: 'first' },
435
+ { keyword: 'index' },
436
+ { keyword: 'last' },
437
+ { keyword: 'up' },
438
+ ];
439
+ /**
440
+ * @see https://microformats.org/wiki/existing-rel-values#rejected
441
+ *
442
+ * Scraping:
443
+ * ```js
444
+ * JSON.stringify($("h2:has('#rejected') ~ table").eq(0).find('tr:has(td)').toArray().map((el) => {
445
+ * const $tr = $(el);
446
+ * const keyword = $tr.find('td')[0].textContent.split(' ')[0]?.trim();
447
+ * return { keyword }
448
+ * }));
449
+ * ```
450
+ */
451
+ const DEF_LINK_TYPE_MICROFORMATS_REJECTED = [
452
+ { keyword: 'logo' },
453
+ { keyword: 'pavatar' }, // cspell:disable-line
454
+ ];
455
+ const ALLOWED_LINK_TYPE_MICROFORMATS = [
456
+ ...DEF_LINK_TYPE_MICROFORMATS_FORMATS,
457
+ ...DEF_LINK_TYPE_MICROFORMATS_PROPOSALS,
458
+ ...DEF_LINK_TYPE_MICROFORMATS_HTML5_LINK_TYPE_EXTENSIONS,
459
+ ...DEF_LINK_TYPE_MICROFORMATS_BRAINSTORMING,
460
+ ...DEF_LINK_TYPE_MICROFORMATS_POSH_USAGE,
461
+ ...DEF_LINK_TYPE_MICROFORMATS_DUBLIN_CORE,
462
+ ].filter(def => !DEF_LINK_TYPE_WHATWG.some(whatwg => whatwg.keyword === def.keyword));
463
+ /**
464
+ * Link Type
465
+ * @see https://html.spec.whatwg.org/multipage/links.html#linkTypes
466
+ */
467
+ export const checkLinkType = options => value => {
468
+ if (!options) {
469
+ throw new Error('options is required on `checkLinkType`');
470
+ }
471
+ const tokens = new TokenCollection(value, {
472
+ separator: 'space',
473
+ caseInsensitive: true,
474
+ unique: true,
475
+ });
476
+ for (const def of DEF_LINK_TYPE_MICROFORMATS_NON_HTML_REL_VALUES) {
477
+ const searched = tokens.search(def.keyword);
478
+ if (searched) {
479
+ return searched.unmatched({
480
+ reason: 'unexpected-token',
481
+ expects: [
482
+ {
483
+ type: 'common',
484
+ value: 'valid Link Type',
485
+ },
486
+ ],
487
+ });
488
+ }
489
+ }
490
+ for (const def of DEF_LINK_TYPE_MICROFORMATS_DROPPED) {
491
+ const searched = tokens.search(def.keyword);
492
+ if (searched) {
493
+ return searched.unmatched({
494
+ reason: 'unexpected-token',
495
+ expects: [
496
+ {
497
+ type: 'common',
498
+ value: 'valid Link Type',
499
+ },
500
+ ],
501
+ });
502
+ }
503
+ }
504
+ for (const def of DEF_LINK_TYPE_MICROFORMATS_DROPPED_WITHOUT_PREJUDICE) {
505
+ const searched = tokens.search(def.keyword);
506
+ if (searched) {
507
+ return searched.unmatched({
508
+ reason: 'unexpected-token',
509
+ expects: [
510
+ {
511
+ type: 'common',
512
+ value: 'valid Link Type',
513
+ },
514
+ ],
515
+ });
516
+ }
517
+ }
518
+ for (const def of DEF_LINK_TYPE_MICROFORMATS_REJECTED) {
519
+ const searched = tokens.search(def.keyword);
520
+ if (searched) {
521
+ return searched.unmatched({
522
+ reason: 'unexpected-token',
523
+ expects: [
524
+ {
525
+ type: 'common',
526
+ value: 'valid Link Type',
527
+ },
528
+ ],
529
+ });
530
+ }
531
+ }
532
+ const enumList = [];
533
+ for (const def of DEF_LINK_TYPE_WHATWG) {
534
+ if (options.el === 'link' && def.link !== 'not allowed') {
535
+ enumList.push(def.keyword);
536
+ }
537
+ if (options.el === 'body link' && def.link !== 'not allowed' && def.bodyOk === 'Yes') {
538
+ enumList.push(def.keyword);
539
+ }
540
+ if (options.el === 'a, area' && def.a !== 'not allowed') {
541
+ enumList.push(def.keyword);
542
+ }
543
+ if (options.el === 'form' && def.form !== 'not allowed') {
544
+ enumList.push(def.keyword);
545
+ }
546
+ }
547
+ for (const def of ALLOWED_LINK_TYPE_MICROFORMATS) {
548
+ if (def.link && options.el === 'link') {
549
+ enumList.push(def.keyword);
550
+ }
551
+ if (def.a && options.el === 'a, area') {
552
+ enumList.push(def.keyword);
553
+ }
554
+ }
555
+ if (enumList.length === 0) {
556
+ throw new Error(`enumList is empty on \`checkLinkType\`, \`options\`: ${JSON.stringify(options)}`);
557
+ }
558
+ return checkList(value, {
559
+ token: {
560
+ enum: enumList,
561
+ caseInsensitive: true,
562
+ },
563
+ separator: 'space',
564
+ caseInsensitive: true,
565
+ unique: true,
566
+ number: 'oneOrMore',
567
+ }, {}, 'https://html.spec.whatwg.org/multipage/links.html#linkTypes');
568
+ };
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@markuplint/types",
3
- "version": "4.7.6",
3
+ "version": "4.8.0",
4
4
  "description": "Type declaration and value checker",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
7
7
  "license": "MIT",
8
- "private": false,
9
8
  "type": "module",
10
9
  "exports": {
11
10
  ".": {
@@ -22,24 +21,24 @@
22
21
  "scripts": {
23
22
  "build": "tsc --project tsconfig.build.json",
24
23
  "dev": "tsc --watch --project tsconfig.build.json",
25
- "clean": "tsc --build --clean",
24
+ "clean": "tsc --build --clean tsconfig.build.json",
26
25
  "schema": "run-s schema:types schema:schema build schema:prettier schema:eslint schema:prettier",
27
26
  "schema:types": "tsx \"./gen/types.ts\"",
28
- "schema:schema": "json2ts \"./types.schema.json\" > \"./src/types.schema.ts\"",
29
- "schema:eslint": "eslint --fix \"./src/types.schema.ts\"",
30
- "schema:prettier": "prettier --write \"./src/types.schema.ts\" \"./types.schema.json\" --log-level warn"
27
+ "schema:schema": "npx json2ts \"./types.schema.json\" > \"./src/types.schema.ts\"",
28
+ "schema:eslint": "npx eslint --fix \"./src/types.schema.ts\"",
29
+ "schema:prettier": "npx prettier --write \"./src/types.schema.ts\" \"./types.schema.json\" --log-level warn"
31
30
  },
32
31
  "dependencies": {
33
- "@markuplint/shared": "4.4.11",
32
+ "@markuplint/shared": "4.4.12",
34
33
  "@types/css-tree": "2.3.10",
35
34
  "@types/debug": "4.1.12",
36
35
  "@types/whatwg-mimetype": "3.0.2",
37
36
  "bcp-47": "2.1.0",
38
37
  "css-tree": "3.1.0",
39
- "debug": "4.4.0",
38
+ "debug": "4.4.1",
40
39
  "leven": "4.0.0",
41
- "type-fest": "4.39.1",
40
+ "type-fest": "4.41.0",
42
41
  "whatwg-mimetype": "4.0.0"
43
42
  },
44
- "gitHead": "eb36d59f7e13d4e59ff3f3c4eabb5ec06c070eb0"
43
+ "gitHead": "ae97eb2d31ecedf4f0800fbbf18588aad4ebca04"
45
44
  }
package/types.schema.json CHANGED
@@ -1167,6 +1167,10 @@
1167
1167
  "Int",
1168
1168
  "ItemProp",
1169
1169
  "JSON",
1170
+ "LinkTypeForAnchorAndAreaElement",
1171
+ "LinkTypeForFormElement",
1172
+ "LinkTypeForLinkElement",
1173
+ "LinkTypeForLinkElementInBody",
1170
1174
  "MIMEType",
1171
1175
  "NavigableTargetName",
1172
1176
  "NavigableTargetNameOrKeyword",