From 44e802810aad9e456b54a61ca6e6ae19721bce25 Mon Sep 17 00:00:00 2001 From: Hannah Tsukamoto Date: Fri, 29 May 2026 10:42:59 -0400 Subject: [PATCH 1/3] Fix always-empty columns being dropped from variableMeasured Columns whose values are null/empty across the entire dataset were never registered in variableMeasured, causing Psych-DS validation failures. Pre-register every column header with value:"unknown" before the null-skip guard so always-empty columns still appear in the output. When a real value is later encountered, generateMetadata upgrades value:"unknown" to the actual type. Co-Authored-By: Claude Sonnet 4.6 --- packages/metadata/src/index.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/metadata/src/index.ts b/packages/metadata/src/index.ts index a81a30e..c5a9792 100644 --- a/packages/metadata/src/index.ts +++ b/packages/metadata/src/index.ts @@ -425,7 +425,19 @@ export default class JsPsychMetadata { var value = observation[variable]; var type = typeof value; - if (value === null || value === undefined || value === '' || value === "null"){ + // Ensure every column header appears in variableMeasured even if all its values are null/empty. + // Columns that never get a real value keep value:"unknown" and no levels, which satisfies the + // Psych-DS requirement that every CSV column header has a corresponding variableMeasured entry. + if (!this.containsVariable(variable) && !this.ignored_variables.has(variable)) { + this.setVariable({ + "@type": "PropertyValue", + name: variable, + description: { default: "unknown" }, + value: "unknown", + }); + } + + if (value === null || value === undefined || value === '' || value === "null"){ continue; // Error checking } @@ -484,7 +496,6 @@ export default class JsPsychMetadata { var type = typeof value; if (!this.containsVariable(variable)) { - // probs should have update description called here const new_var = { "@type": "PropertyValue", name: variable, @@ -492,6 +503,11 @@ export default class JsPsychMetadata { value: type, }; this.setVariable(new_var); + } else { + // Column was pre-registered with value:"unknown" in generateObservation; upgrade to the real type + // now that we have a concrete value. + const existing = this.getVariable(variable) as VariableFields; + if (existing.value === "unknown") this.updateVariable(variable, "value", type); } // hit the update variable decription fields From bd7858a8184873d0dcb1f877d75c50728c9e163b Mon Sep 17 00:00:00 2001 From: Hannah Tsukamoto Date: Fri, 29 May 2026 12:06:43 -0400 Subject: [PATCH 2/3] Add tests for always-empty column fix in variableMeasured Covers three cases: column with all empty cells, column with all "null" string values, and column that is empty in some rows but has a real value in others (verifies the type upgrades from "unknown" to the actual type). Co-Authored-By: Claude Sonnet 4.6 --- .../metadata/tests/metadata-module.test.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/packages/metadata/tests/metadata-module.test.ts b/packages/metadata/tests/metadata-module.test.ts index c5f8080..cbcdb6d 100644 --- a/packages/metadata/tests/metadata-module.test.ts +++ b/packages/metadata/tests/metadata-module.test.ts @@ -1,5 +1,71 @@ import JsPsychMetadata from "../src/index"; +describe("always-empty columns in variableMeasured", () => { + let jsPsychMetadata: JsPsychMetadata; + + beforeEach(() => { + jsPsychMetadata = new JsPsychMetadata(); + }); + + test("column with all empty values appears in variableMeasured with value:unknown", async () => { + const csv = [ + "trial_type,rt,eye_tracking_status", + "jsPsych-html-keyboard-response,450,", + "jsPsych-html-keyboard-response,512,", + "jsPsych-html-keyboard-response,389,", + ].join("\n"); + + await jsPsychMetadata.generate(csv, {}, "csv"); + + const variableMeasured = jsPsychMetadata.getMetadata()["variableMeasured"] as any[]; + const names = variableMeasured.map((v) => v.name); + + expect(names).toContain("eye_tracking_status"); + + const emptyCol = variableMeasured.find((v) => v.name === "eye_tracking_status"); + expect(emptyCol.value).toBe("unknown"); + expect(emptyCol.levels).toBeUndefined(); + expect(emptyCol.minValue).toBeUndefined(); + expect(emptyCol.maxValue).toBeUndefined(); + }); + + test("column with only null string values appears in variableMeasured with value:unknown", async () => { + const csv = [ + "trial_type,rt,score", + "jsPsych-html-keyboard-response,450,null", + "jsPsych-html-keyboard-response,512,null", + ].join("\n"); + + await jsPsychMetadata.generate(csv, {}, "csv"); + + const variableMeasured = jsPsychMetadata.getMetadata()["variableMeasured"] as any[]; + const emptyCol = variableMeasured.find((v) => v.name === "score"); + + expect(emptyCol).toBeDefined(); + expect(emptyCol.value).toBe("unknown"); + expect(emptyCol.levels).toBeUndefined(); + }); + + test("column with some empty and some real values gets the correct type, not unknown", async () => { + const csv = [ + "trial_type,rt,score", + "jsPsych-html-keyboard-response,450,", + "jsPsych-html-keyboard-response,512,8", + "jsPsych-html-keyboard-response,389,", + ].join("\n"); + + await jsPsychMetadata.generate(csv, {}, "csv"); + + const variableMeasured = jsPsychMetadata.getMetadata()["variableMeasured"] as any[]; + const partialCol = variableMeasured.find((v) => v.name === "score"); + + expect(partialCol).toBeDefined(); + expect(partialCol.value).toBe("number"); + expect(partialCol.value).not.toBe("unknown"); + }); + +}); + // missing displaying data modules tests describe("JsPsychMetadata", () => { let jsPsychMetadata: JsPsychMetadata; From e80e57cae676bb50a3e4866a75c1aef9450b2407 Mon Sep 17 00:00:00 2001 From: Hannah Tsukamoto Date: Fri, 29 May 2026 13:34:39 -0400 Subject: [PATCH 3/3] Add changeset for always-empty columns fix (patch bump) Co-Authored-By: Claude Sonnet 4.6 --- .changeset/fix-always-empty-columns.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-always-empty-columns.md diff --git a/.changeset/fix-always-empty-columns.md b/.changeset/fix-always-empty-columns.md new file mode 100644 index 0000000..942fa45 --- /dev/null +++ b/.changeset/fix-always-empty-columns.md @@ -0,0 +1,5 @@ +--- +"@jspsych/metadata": patch +--- + +Fix always-empty columns being silently dropped from variableMeasured. Columns whose values are null or empty across all rows in a dataset now appear in variableMeasured with a minimal `"value": "unknown"` entry, satisfying the Psych-DS requirement that every CSV column header has a corresponding entry.