app/lib/text-fragment.mjs
29 lines and 2 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| encodePart | 14 to 14 | 1 | 100% | OkCRAP 1 | No data: no mutants in this code |
| textFragment | 20 to 35 | 5 | 100% | OkCRAP 5 | No data: no mutants in this code |
Imports
It imports no other module of this repo. Imported by app/enhance/blog.ts.
Source
// The directive matches the first occurrence, so a short phrase can land on the wrong paragraph.
export const FRAGMENT_MIN_CHARS = 12;
export const FRAGMENT_MAX_CHARS = 200;
export const FRAGMENT_EDGE_WORDS = 6;
/**
* `encodeURIComponent` leaves the hyphen, which the directive reserves: an unescaped one turns the
* rest of the passage into a suffix match.
*
* @param {string} text
*/
const encodePart = (text) => encodeURIComponent(text).replace(/-/g, "%2D");
/**
* @param {string} selected raw selected text, as `Selection.toString()` yields it
* @returns {string | null} the value for `#:~:text=`, or null when the selection is too short
*/
export function textFragment(selected) {
const text = selected.trim().replace(/[^\S\n]+/g, " ");
if (text.length < FRAGMENT_MIN_CHARS) return null;
const words = text.split(/\s+/);
const edge = Math.min(FRAGMENT_EDGE_WORDS, words.length >> 1);
/*
* A selection crossing a block boundary (a newline from `Selection`) never matches as one exact
* string, and long passages are fragile against whitespace differences, so both use the range form.
*/
if (edge > 0 && (text.length > FRAGMENT_MAX_CHARS || text.includes("\n"))) {
return `${encodePart(words.slice(0, edge).join(" "))},${encodePart(words.slice(-edge).join(" "))}`;
}
return encodePart(text);
}