@hhkaos/webmentions-widget 0.3.0 → 0.4.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.
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/core.js +81 -1
package/README.md
CHANGED
|
@@ -210,6 +210,10 @@ assigns remote HTML.
|
|
|
210
210
|
folds them together, so only ever branch on `mention-of`.
|
|
211
211
|
- Bridgy mangles emoji into runs of `?` and `U+FFFD` when extracting plain text.
|
|
212
212
|
`stripMojibake` removes the debris — the emoji is not recoverable.
|
|
213
|
+
- Responses are sometimes **invalid JSON**: source content is copied into string
|
|
214
|
+
literals unescaped, so a backslash or a raw newline in a mention's content
|
|
215
|
+
makes the whole payload unparseable. `parseWebmentionJson` repairs those two
|
|
216
|
+
cases; valid payloads pass through untouched.
|
|
213
217
|
|
|
214
218
|
## Development
|
|
215
219
|
|
package/package.json
CHANGED
package/src/core.js
CHANGED
|
@@ -461,6 +461,86 @@ export function mergeSnapshot(existing, incoming) {
|
|
|
461
461
|
};
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
const VALID_JSON_ESCAPES = new Set(['"', '\\', '/', 'b', 'f', 'n', 'r', 't', 'u']);
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Repair the malformed JSON webmention.io sometimes serves.
|
|
468
|
+
*
|
|
469
|
+
* Its serializer copies source-page content into string literals without
|
|
470
|
+
* escaping it, so a mention whose content contains a backslash (a shell example
|
|
471
|
+
* ending in `\`, say) or a raw newline produces a payload that `JSON.parse`
|
|
472
|
+
* rejects outright. The mention is then invisible — not because the API was
|
|
473
|
+
* down, but because its response could not be read at all.
|
|
474
|
+
*
|
|
475
|
+
* Walks the text tracking whether it is inside a string literal, escaping only
|
|
476
|
+
* the offending characters and leaving valid escapes untouched.
|
|
477
|
+
*/
|
|
478
|
+
export function repairJson(text) {
|
|
479
|
+
let out = '';
|
|
480
|
+
let inString = false;
|
|
481
|
+
|
|
482
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
483
|
+
const char = text[index];
|
|
484
|
+
|
|
485
|
+
if (!inString) {
|
|
486
|
+
if (char === '"') {
|
|
487
|
+
inString = true;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
out += char;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (char === '"') {
|
|
495
|
+
inString = false;
|
|
496
|
+
out += char;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (char === '\\') {
|
|
501
|
+
const next = text[index + 1];
|
|
502
|
+
|
|
503
|
+
if (VALID_JSON_ESCAPES.has(next)) {
|
|
504
|
+
out += char + next;
|
|
505
|
+
index += 1;
|
|
506
|
+
} else {
|
|
507
|
+
out += '\\\\';
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const code = char.charCodeAt(0);
|
|
514
|
+
|
|
515
|
+
if (code < 0x20) {
|
|
516
|
+
if (code === 0x0a) {
|
|
517
|
+
out += '\\n';
|
|
518
|
+
} else if (code === 0x0d) {
|
|
519
|
+
out += '\\r';
|
|
520
|
+
} else if (code === 0x09) {
|
|
521
|
+
out += '\\t';
|
|
522
|
+
} else {
|
|
523
|
+
out += `\\u${code.toString(16).padStart(4, '0')}`;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
out += char;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return out;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/** Parse a webmention.io response, repairing it only if it will not parse. */
|
|
536
|
+
export function parseWebmentionJson(text) {
|
|
537
|
+
try {
|
|
538
|
+
return JSON.parse(text);
|
|
539
|
+
} catch {
|
|
540
|
+
return JSON.parse(repairJson(text));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
464
544
|
export class WebmentionFetchError extends Error {
|
|
465
545
|
constructor(message, {status, attempts, cause} = {}) {
|
|
466
546
|
super(message, {cause});
|
|
@@ -612,7 +692,7 @@ export async function fetchWebmentions({
|
|
|
612
692
|
continue;
|
|
613
693
|
}
|
|
614
694
|
|
|
615
|
-
const data = await response.
|
|
695
|
+
const data = parseWebmentionJson(await response.text());
|
|
616
696
|
|
|
617
697
|
return endpoint.json
|
|
618
698
|
? normalizeJsonFeed(data)
|