From 195b862036985d014c88ccbf64d2af7e9dc144b2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 12:58:15 +0000 Subject: [PATCH] =?UTF-8?q?Text:=20layer.setText's=20schema=20accepts=20di?= =?UTF-8?q?scretionaryLigatures=20and=20ss01=E2=80=93ss20=20under=20checke?= =?UTF-8?q?d=20execution=20(#521=20follow-up)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The params parser reads ':' as the start of a value, so 'OpenType?: discretionaryLigatures?' declared a bogus OpenType key and hid discretionaryLigatures, and 'ss01?…ss20?' declared only ss01. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f --- crates/engine/src/commands/layer.rs | 2 +- crates/engine/src/tests_text_edit.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/commands/layer.rs b/crates/engine/src/commands/layer.rs index 7be56a9e..11dcb4dc 100644 --- a/crates/engine/src/commands/layer.rs +++ b/crates/engine/src/commands/layer.rs @@ -1548,7 +1548,7 @@ pub fn specs() -> Vec { "Edit Text", [], None, - "{layer?, range?: [start, end] (characters; default all), text?, font?, style?, size?, fill?, stroke?, applyFill?, applyStroke?, strokeWidth?, tracking?, leading?: px|\"auto\", baselineShift? px, hScale? %, vScale? %, tsume? %, fauxBold?, fauxItalic?, allCaps?, smallCaps?, baseline?: normal|superscript|subscript, superscript?, subscript?, kerning?: metrics|optical|number, ligatures?, OpenType?: discretionaryLigatures?, contextualAlternates?, stylisticAlternates?, stylisticSets?: [1–20], ss01?…ss20?, swash?, titling?, ordinals?, fractions?, allSmallCaps?, figureStyle?: default|lining|oldStyle, figureWidth?: default|proportional|tabular, figures?, variations?: {tag: value} (variable font axes; null resets), justify?: left|center|right|justifyLeft|justifyCenter|justifyRight|justifyAll, indentLeft?, indentRight?, indentFirst?, spaceBefore?, spaceAfter?, direction?: ltr|rtl, composer?: everyLine|singleLine, hangingPunctuation?, strokeOverFill?, box?: [x,y,w,h]|null (layer space), vertical?}", + "{layer?, range?: [start, end] (characters; default all), text?, font?, style?, size?, fill?, stroke?, applyFill?, applyStroke?, strokeWidth?, tracking?, leading?: px|\"auto\", baselineShift? px, hScale? %, vScale? %, tsume? %, fauxBold?, fauxItalic?, allCaps?, smallCaps?, baseline?: normal|superscript|subscript, superscript?, subscript?, kerning?: metrics|optical|number, ligatures?, discretionaryLigatures? (OpenType), contextualAlternates?, stylisticAlternates?, stylisticSets?: [1–20], ss01?, ss02?, ss03?, ss04?, ss05?, ss06?, ss07?, ss08?, ss09?, ss10?, ss11?, ss12?, ss13?, ss14?, ss15?, ss16?, ss17?, ss18?, ss19?, ss20?, swash?, titling?, ordinals?, fractions?, allSmallCaps?, figureStyle?: default|lining|oldStyle, figureWidth?: default|proportional|tabular, figures?, variations?: {tag: value} (variable font axes; null resets), justify?: left|center|right|justifyLeft|justifyCenter|justifyRight|justifyAll, indentLeft?, indentRight?, indentFirst?, spaceBefore?, spaceAfter?, direction?: ltr|rtl, composer?: everyLine|singleLine, hangingPunctuation?, strokeOverFill?, box?: [x,y,w,h]|null (layer space), vertical?}", has_layers, set_text ), diff --git a/crates/engine/src/tests_text_edit.rs b/crates/engine/src/tests_text_edit.rs index d543fc9a..ef87bf86 100644 --- a/crates/engine/src/tests_text_edit.rs +++ b/crates/engine/src/tests_text_edit.rs @@ -259,3 +259,19 @@ fn fonts_lists_bundled_and_installed_families() { assert_eq!(crate::font_styles("NOTO SERIF"), styles); assert_eq!(crate::font_styles("No Such Family").len(), 5); } + +/// `layer.setText`'s schema lists every OpenType key as optional, so checked execution (control +/// channel, MCP) accepts them and requires none (#520). +#[test] +fn set_text_schema_accepts_every_opentype_key_and_requires_none() { + let spec = crate::commands::find("layer.setText").unwrap(); + let schema = crate::commands::params_schema(spec); + assert_eq!(schema["required"], json!([])); + for key in ["discretionaryLigatures", "ss01", "ss02", "ss20", "swash"] { + assert!(schema["properties"].get(key).is_some(), "{key} is not in the schema"); + } + assert!(schema["properties"].get("OpenType").is_none()); + let (mut s, t) = session("Office 1/2"); + s.execute_checked("layer.setText", json!({"layer": t, "discretionaryLigatures": true, "ss02": true, "ss20": true})).unwrap(); + assert!(doc(&s, t).style_at(0).opentype.stylistic_set(20)); +}