Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 3x 3x 3x 2x 2x 1x 3x 3x 1x 1x 4x 4x 4x 5x 5x 5x 5x 5x 9x 1x 1x 8x 3x 5x 5x 8x 4x 5x 1x 4x 2x 2x 2x 8x 8x 8x 10x 10x 10x 8x | import { downloadBlob } from "../view/download.js";
/**
* Reads a parameter JSON file and returns the parsed content.
* Restores composition parameters (theta) from a previously exported JSON file.
* @param {File|Blob} file - Source containing serialized parameters (theta) as JSON text.
* @return {Promise<Object>} Parsed parameter object (theta).
* @throws {Error} If the file cannot be read or the content is not valid JSON.
*/
export function importParameters(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
try {
resolve(JSON.parse(e.target.result));
} catch {
reject(new Error("Could not parse the JSON file."));
}
};
reader.onerror = () => reject(new Error("Could not read the file."));
reader.readAsText(file);
});
}
/**
* Exports the composition parameters (theta) as a JSON file download.
* @param {Object} parameters - Top-level parameters (theta) to serialize as JSON.
*/
export function exportParameters(parameters) {
const blob = new Blob([JSON.stringify(parameters, null, 2)], {
type: "application/json",
});
downloadBlob(blob, "parameters.json");
}
/**
* Builds the initial composition parameters (theta) for a list of steps by calling schema() on each.
* @param {Step[]} steps - Step instances.
* @return {Promise<{steps: Step[], schemas: Object<string, Object[]>, parameters: Object}>}
* Step instances unchanged plus a schemas-by-step.id map and the parameters object.
*/
export async function buildParameters(steps) {
const schemas = {};
const parameters = {};
for (const step of steps) {
const schema = await step.schema();
schemas[step.id] = schema;
parameters[step.id] = {};
const filled = parameters[step.id];
for (const param of schema) {
if (param.type === "checkboxes") {
for (const cb of param.items) {
filled[cb.name] = cb.default;
}
} else if (param.type !== "nested") {
filled[param.name] = param.default;
} else {
const count = resolveNestedCount(param, schema, parameters);
filled[param.name] = Array.from({ length: count }, (_, i) =>
buildNestedItem(param, i),
);
}
}
}
return { steps, schemas, parameters };
}
/** @private Resolves the count for a nested-parameter array (defaults length, counter ref, or fallback 1). */
function resolveNestedCount(param, schema, parameters) {
if (param.defaults?.length) {
return param.defaults.length;
}
if (param.counter.includes(".")) {
const [stepId, paramName] = param.counter.split(".");
return parameters[stepId]?.[paramName] || 1;
}
return schema.find((p) => p.name === param.counter)?.max || 1;
}
/** @private Builds one nested-array item: merges perItem overrides over template defaults. */
function buildNestedItem(param, i) {
const perItem = param.defaults?.[i];
const item = perItem ? { ...perItem } : {};
for (const sub of param.template) {
const fields = sub.type === "checkboxes" ? sub.items : [sub];
for (const f of fields) {
item[f.name] = perItem?.[f.name] ?? f.default;
}
}
return item;
}
|