MCP: document.json names linked JavaScript files outside the read roots by file name

With automation read roots in force, document.json returned each entry of
svg_scripts unchanged, so a JavaScript file linked from outside the read
roots kept its full path in the reply. The reply copy now names such a
file by its file name alone. An entry given as a URL is kept, and the
stored document is not changed.
This commit is contained in:
dotCooCoo
2026-11-12 13:18:17 -08:00
parent 80f909a162
commit a670c3072b
4 changed files with 19 additions and 4 deletions
+1 -1
View File
@@ -50,7 +50,7 @@ pub fn specs() -> Vec<CommandSpec> {
has_doc,
doc_compare
),
cmd!(query "document.json", "Document JSON", [], None, "{} → complete document model (with automation read roots, a linked or placed file outside them is named by its file name alone, without its relative path, size or date, in brush art too, and so is a data set's image value outside them; a relative path that leads outside them is left out; a stored brush entry that does not read as a brush is left out; a folder outside them is left out of export_settings)", has_doc, |s, _| {
cmd!(query "document.json", "Document JSON", [], None, "{} → complete document model (with automation read roots, a linked or placed file outside them is named by its file name alone, without its relative path, size or date, in brush art too, and so are a data set's image value and a linked JavaScript file in svg_scripts outside them (a URL is kept); a relative path that leads outside them is left out; a stored brush entry that does not read as a brush is left out; a folder outside them is left out of export_settings)", has_doc, |s, _| {
let st = s.doc()?;
let d = super::links::with_hidden_paths_named(&st.doc, super::links::LinkBase::of(st));
Ok(serde_json::to_value(&*d).unwrap_or(Value::Null))
+6 -1
View File
@@ -1200,7 +1200,8 @@ pub(crate) fn with_found_paths(d: &mut Document, base: LinkBase) {
/// `d`, a document saved at `doc_path`, as a reply to the caller asking now may show it: without
/// read roots in force, `d` itself; with them, a copy in which each link [`path_shown`] does not
/// allow names its file alone, without its relative path or the size and date kept of its file,
/// and each data set's image value it does not allow names its file alone too. The folder Export
/// and each data set's image value and linked JavaScript file (`svg_scripts`) it does not allow
/// names its file alone too, while a JavaScript file given as a URL stays as it is. The folder Export
/// for Screens last wrote to is left out of the export settings when it is outside the read roots.
/// A link whose path is allowed but whose relative path leads outside the read roots loses its
/// relative path. Links in the layers, symbols, graph designs, patterns, the pattern being edited
@@ -1266,6 +1267,10 @@ pub(crate) fn with_hidden_paths_named<'a>(d: &'a Document, base: LinkBase) -> Co
}
}
}
let script_hidden = |f: &str| !path_shown(f, doc_path) && !matches!(fileio::document_path(f, doc_path), Err(craft_docpath::Refused::Url));
for f in d.svg_scripts.iter_mut().filter(|f| script_hidden(f)) {
*f = LinkInfo::new(f.as_str()).name().to_string();
}
Cow::Owned(d)
}
+10 -1
View File
@@ -1102,6 +1102,13 @@ fn document_replies_leave_out_paths_outside_the_read_roots() {
s.execute("variable.define", &json!({"name": "Photo", "kind": "image"})).unwrap();
s.execute("dataset.new", &json!({"name": "Row", "values": {"Photo": pic}})).unwrap();
let image = r["ids"][0].as_u64().unwrap();
// A linked JavaScript file outside the read roots, and one given as a URL.
let script = away.file("menu.js");
write(&script, b"void 0;");
let url = "https://example.com/scripts/menu.js";
for file in [script.as_str(), url] {
s.execute("svgInteractivity.addFile", &json!({"file": file})).unwrap();
}
let poster = away.file("poster.vectorcraft");
save(&mut s, &poster);
// The folder Export for Screens wrote to, and a pattern of the linked image being edited: its
@@ -1124,11 +1131,13 @@ fn document_replies_leave_out_paths_outside_the_read_roots() {
assert!(model.contains(&format!("\"path\":\"{name}\"")), "{name}: {model}");
}
assert!(model.contains("{\"image\":\"photo.png\"}"), "{model}");
assert!(model.contains(&format!("\"svg_scripts\":[\"menu.js\",\"{url}\"]")), "{model}");
// The document keeps its links, and a caller whose read roots hold the files sees every path.
assert_eq!(placed(&s, id).link.path, src);
assert_eq!(s.doc().unwrap().doc.svg_scripts, [script.as_str(), url]);
for model in [ask(&mut s, &away.0, "document.json"), s.execute("document.json", &json!({})).unwrap()] {
let model = model.to_string();
for path in [&src, &pic, &out] {
for path in [&src, &pic, &out, &script] {
assert!(model.contains(&json!(path).to_string()), "{path}: {model}");
}
}
+2 -1
View File
@@ -227,7 +227,8 @@ the suite) keep the agent to the folders you give it:
leaves out the link's `relative`, `size` and `modified`. This covers the art of the brushes in `unknown.brushes`
too. A link whose file is inside them keeps its `path` but leaves out a `relative` that leads outside them. A
stored brush entry that does not read as a brush is left out of `unknown.brushes`. `document.json` also names a data set's image
value outside them by its file name alone, and leaves out the `folder` of `export_settings` (the settings Export
value and a linked JavaScript file in `svg_scripts` outside them by its file name alone (a JavaScript file given
as a URL is kept), and leaves out the `folder` of `export_settings` (the settings Export
for Screens last used) when that folder is outside them. The document itself is not changed.
- `plugin.list`, `plugin.safeMode`, `file.recovery.*` and `ui_inspect`'s `scriptReport` leave out the paths
outside the read roots, also those the person or an earlier request put there. In `plugin.list`, the plug-in