Review #997: one anchor-reference parser, for Reshape area type too

`text.reshapeArea` read its anchors with the lenient `parse_refs`, so a
malformed reference among good ones moved only the good ones. It now
uses `checked_refs` as well, and `parse_refs` (no other user) goes.
Test: a mixed list fails without moving anything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-11 01:48:17 +07:00
parent 2f984f2e7a
commit 93cadc8994
3 changed files with 7 additions and 10 deletions

View File

@ -294,15 +294,9 @@ fn key(s: &mut Session, p: &Value) -> Result<Value> {
ok()
}
/// `[[subpath, anchor]…]` anchor references (malformed entries are left out).
pub(crate) fn parse_refs(v: Option<&Value>) -> Vec<(usize, usize)> {
v.and_then(Value::as_array)
.map(|a| a.iter().filter_map(|x| Some((x.get(0)?.as_u64()? as usize, x.get(1)?.as_u64()? as usize))).collect())
.unwrap_or_default()
}
/// Parse an explicitly supplied anchor list without dropping invalid entries.
fn checked_refs(v: Option<&Value>, cmd: &str) -> Result<Vec<(usize, usize)>> {
/// `[[subpath, anchor]…]` anchor references of `cmd`: a malformed entry fails rather than being
/// left out, which would act on other anchors than the ones given.
pub(crate) fn checked_refs(v: Option<&Value>, cmd: &str) -> Result<Vec<(usize, usize)>> {
let refs = v.and_then(Value::as_array).ok_or_else(|| bad(cmd, "`anchors` must be an array of [subpath, anchor] pairs"))?;
refs.iter()
.map(|v| {

View File

@ -628,7 +628,7 @@ fn area_options(s: &mut Session, p: &Value) -> Result<Value> {
fn reshape_area(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "text.reshapeArea";
let id = id_param(p, "id").ok_or_else(|| bad(C, "missing id"))?;
let mut refs = super::select::parse_refs(p.get("anchors"));
let mut refs = super::select::checked_refs(p.get("anchors"), C)?;
refs.sort_unstable();
refs.dedup();
if refs.is_empty() {

View File

@ -236,6 +236,9 @@ fn reshape_area_takes_untrusted_params() {
json!({"id": id.0, "dx": 1, "dy": 1}),
json!({"id": id.0, "anchors": [], "dx": 1, "dy": 1}),
json!({"id": id.0, "anchors": [["a", 1], [0], "x"], "dx": 1, "dy": 1}),
// A malformed reference among good ones fails rather than moving only the good ones.
json!({"id": id.0, "anchors": [[0, 2], [0, "3"]], "dx": 1, "dy": 1}),
json!({"id": id.0, "anchors": [[0, 2], [0, 3, 1]], "dx": 1, "dy": 1}),
json!({"id": id.0, "anchors": [[0, 9]], "dx": 1, "dy": 1}),
json!({"id": id.0, "anchors": [[0, 1], [7, 0]], "dx": 1, "dy": 1}),
json!({"id": id.0, "anchors": [[0, 2]], "dy": 1}),