Batch: keep an existing artboard file of a one-artboard Separate Artboards save

A save in the native, template or .ai formats with separateArtboards writes an
artboard file even when the document has one artboard, so an existing file with
that name now gives the data set the next free suffix too.
This commit is contained in:
dotCooCoo
2026-11-01 01:22:06 +07:00
committed by bflatastic
parent 5dcc65d69a
commit 89ca9d9a25
2 changed files with 66 additions and 30 deletions
+62 -27
View File
@@ -292,8 +292,9 @@ struct DatasetOutput {
joiner: &'static str,
}
/// Lists step output extensions and reserves artboard file names when the document has multiple artboards.
/// Per-artboard names count for vectorcraft, template, AI and AIT saves and SVG, SVGZ, EPS, raster, DXF, EMF, WMF and AI exports.
/// Lists step output extensions and reserves artboard file names for saves with any artboard or
/// exports with multiple artboards. Per-artboard names count for vectorcraft, template, AI and AIT
/// saves and SVG, SVGZ, EPS, raster, DXF, EMF, WMF and AI exports.
#[cfg(not(target_arch = "wasm32"))]
fn dataset_output_extensions(run: &Run<'_>, doc: &vectorcraft_doc::Document) -> Vec<DatasetOutput> {
let mut outputs = Vec::new();
@@ -314,31 +315,31 @@ fn dataset_output_extensions(run: &Run<'_>, doc: &vectorcraft_doc::Document) ->
if safe_extension(&ext) {
let format_id = format.and_then(super::format).map(|f| f.id).unwrap_or("vectorcraft");
let is_save = matches!(id, "document.save" | "file.save" | "file.saveAs");
let artboards = doc.artboards.len() > 1
&& if is_save {
matches!(format_id, "vectorcraft" | "template" | "ai" | "ait")
} else {
id == "document.export"
&& matches!(
format_id,
"svg"
| "svgz"
| "eps"
| "png"
| "jpg"
| "webp"
| "gif"
| "png8"
| "tiff"
| "bmp"
| "tga"
| "psd"
| "dxf"
| "emf"
| "wmf"
| "ai"
)
};
let artboards = if is_save {
!doc.artboards.is_empty() && matches!(format_id, "vectorcraft" | "template" | "ai" | "ait")
} else {
doc.artboards.len() > 1
&& id == "document.export"
&& matches!(
format_id,
"svg"
| "svgz"
| "eps"
| "png"
| "jpg"
| "webp"
| "gif"
| "png8"
| "tiff"
| "bmp"
| "tga"
| "psd"
| "dxf"
| "emf"
| "wmf"
| "ai"
)
};
outputs.push(DatasetOutput { ext, artboards, joiner: if format_id == "eps" { "_" } else { "-" } });
}
}
@@ -952,6 +953,40 @@ mod tests {
);
}
#[test]
fn batch_single_artboard_save_keeps_existing_artboard_file() {
let source = tmp("choice-single-artboard-source");
let dest = tmp("choice-single-artboard-dest");
let mut s = Session::new();
s.execute("file.new", &json!({"width": 20, "height": 20, "artboards": 1})).unwrap();
s.execute(
"document.save",
&json!({
"path": source.join("source.vectorcraft").to_string_lossy(),
"separateArtboards": true
}),
)
.unwrap();
assert!(source.join("source-Artboard-1.vectorcraft").exists());
let existing = dest.join("Alpha-Artboard-1.vectorcraft");
std::fs::write(&existing, b"keep").unwrap();
s.execute("dataset.new", &json!({"name": "Alpha"})).unwrap();
let r = s
.execute(
"action.batch",
&json!({
"source": "datasets", "datasetFileNaming": "dataSetName",
"destinationFolder": dest.to_string_lossy(),
"commands": [{"command": "document.save", "params": {"separateArtboards": true}}]
}),
)
.unwrap();
assert_eq!(r["failed"], 0, "{r}");
assert_eq!(std::fs::read(existing).unwrap(), b"keep");
assert_eq!(file_names(&dest), ["Alpha-2-Artboard-1.vectorcraft", "Alpha-2.vectorcraft", "Alpha-Artboard-1.vectorcraft"]);
}
#[test]
fn batch_pdf_export_ignores_artboard_named_file() {
let dest = tmp("choice-pdf-artboard-name");
+4 -3
View File
@@ -2971,9 +2971,10 @@ destination and overridden Save/Export paths use the chosen stem with the output
set name under Data Set Name falls back to the document stem plus its three-digit ordinal. Batch writes `/`, `\`,
`:`, `<`, `>`, `"`, `|`, `?`, `*` and control characters in the data set's name as `-`, and adds the next free `-2`,
`-3` suffix to a stem already used in the batch (compared without case). An output already in a destination folder
gets the next free suffix only when the batch may read and write that folder before it starts. When a step can write
one file per artboard and the document has several artboards, a file with one of those artboard file names for the
stem counts too. Under Data Set Name, VectorCraft makes Windows device names safe (`CON` becomes `CON-`). This is
gets the next free suffix only when the batch may read and write that folder before it starts. A save in VectorCraft,
template, AI or AIT format counts artboard file names when the document has any artboard; a per-artboard export
counts them when the document has several artboards.
Under Data Set Name, VectorCraft makes Windows device names safe (`CON` becomes `CON-`). This is
VectorCraft's naming behavior. Caps: 500
files or data sets, 8 folder levels, 256 steps. An action recorded in the Actions panel leaves the artboard out,
and its steps of these commands get the artboard that is active when the action plays. A press with the Selection,