fix: prevent crash when frames lack 3DMOL_STYLE blocks

This commit is contained in:
Daniel Caspi
2026-02-27 00:02:39 -06:00
parent 2d0796f810
commit 98c3b746e9
3 changed files with 31 additions and 13 deletions

View File

@@ -1998,7 +1998,7 @@ export class GLModel {
}
model.molObj = null;
if (model.modelDatas && framenum < model.modelDatas.length) {
model.modelData = model.modelDatas[framenum];
model.modelData = model.modelDatas[framenum] || {};
if (model.unitCellObjects && viewer) {
viewer.removeUnitCell(model);
viewer.addUnitCell(model);
@@ -2127,7 +2127,7 @@ export class GLModel {
var mData = parsedAtoms.modelData;
if (mData) {
if (Array.isArray(mData)) {
this.modelData = mData[0];
this.modelData = mData[0] || {};
this.modelDatas = mData;
} else {
this.modelData = mData;

View File

@@ -29,7 +29,8 @@ const apply3DmolStyle = function (
return;
}
const frameAtoms = atoms[atoms.length - 1];
const frameIdx = atoms.length - 1;
const frameAtoms = atoms[frameIdx];
if (styleObj.bonds && typeof styleObj.bonds === "object") {
const bonds = styleObj.bonds;
@@ -70,9 +71,6 @@ const apply3DmolStyle = function (
}
if (Object.keys(styleObj).length > 0) {
if (!atoms.modelData) atoms.modelData = [];
const frameIdx = atoms.length - 1;
if (!atoms.modelData[frameIdx]) atoms.modelData[frameIdx] = {};
atoms.modelData[frameIdx].style = styleObj;
}
};
@@ -140,6 +138,8 @@ const addBond = function (curFrame: any[], from: number, to: number, order: numb
const parseV2000 = function (lines: any, options: ParserOptionsSpec) {
const atoms: any & Record<string, any> = [[]];
const modelData = atoms.modelData = [] as any[];
modelData.push({}); // entry for frame 0
const noH = typeof options.keepH !== "undefined" ? !options.keepH : false;
let lineIndex = 0;
@@ -192,7 +192,10 @@ const parseV2000 = function (lines: any, options: ParserOptionsSpec) {
lineIndex = parseSDProperties(lines, lineIndex + offset, atoms, serialToIndex, start);
if (!options.multimodel) break;
if (!options.onemol) atoms.push([]);
if (!options.onemol) {
atoms.push([]);
modelData.push({}); // 1:1 with frames — prevents undefined on frame switch
}
}
return atoms;
};
@@ -205,6 +208,8 @@ const parseV2000 = function (lines: any, options: ParserOptionsSpec) {
const parseV3000 = function (lines: any, options: ParserOptionsSpec) {
const atoms: any[][] & Record<string, any> = [[]];
const modelData = atoms.modelData = [] as any[];
modelData.push({}); // entry for frame 0
const noH = typeof options.keepH !== "undefined" ? !options.keepH : false;
let lineIndex = 0;
@@ -280,7 +285,10 @@ const parseV3000 = function (lines: any, options: ParserOptionsSpec) {
lineIndex = parseSDProperties(lines, lineIndex + offset, atoms, serialToIndex, start);
if (!options.multimodel) break;
if (!options.onemol) atoms.push([]);
if (!options.onemol) {
atoms.push([]);
modelData.push({}); // 1:1 with frames
}
}
return atoms;

View File

@@ -14,31 +14,41 @@ describe('Function SDF | parseV2000 |', ()=>{
test("Atoms is empty when input data is not greater than 3 lines",()=>{
let test_data1 = "line1\nline2\nline3";
let test_atoms1 = $3Dmol.Parsers.SDF(test_data1, {});
expect(test_atoms1).toEqual([[]]);
expect(test_atoms1.length).toBe(1);
expect(test_atoms1[0]).toEqual([]);
expect(test_atoms1.modelData).toEqual([{}]);
});
test("Atoms is empty when length of line 4 of input data is less than 38",()=>{
let test_data2 = "line1\nline2\nline3\nlessthan38";
let test_atoms2 = $3Dmol.Parsers.SDF(test_data2, {});
expect(test_atoms2).toEqual([[]]);
expect(test_atoms2.length).toBe(1);
expect(test_atoms2[0]).toEqual([]);
expect(test_atoms2.modelData).toEqual([{}]);
});
test("Atoms is empty when atomCount is not a number", ()=>{
let test_data3 = "line1\nline2\nline3\natomCount";
let test_atoms3 = $3Dmol.Parsers.SDF(test_data3, {});
expect(test_atoms3).toEqual([[]]);
expect(test_atoms3.length).toBe(1);
expect(test_atoms3[0]).toEqual([]);
expect(test_atoms3.modelData).toEqual([{}]);
});
test("Atoms is empty when atomCount is not greater than 0", ()=>{
let test_data4 = "line1\nline2\nline3\n -1";
let test_atoms4 = $3Dmol.Parsers.SDF(test_data4, {});
expect(test_atoms4).toEqual([[]]);
expect(test_atoms4.length).toBe(1);
expect(test_atoms4[0]).toEqual([]);
expect(test_atoms4.modelData).toEqual([{}]);
});
test("Atoms is empty when the number of lines of input is less than 4 + atomCount + bondCount", ()=>{
let test_data5 = "line1\nline2\nline3\n 1 0 ";// atomCount=0, bondCount=1
let test_atoms5 = $3Dmol.Parsers.SDF(test_data5, {});
expect(test_atoms5).toEqual([[]]);
expect(test_atoms5.length).toBe(1);
expect(test_atoms5[0]).toEqual([]);
expect(test_atoms5.modelData).toEqual([{}]);
});
test("Length of atoms is 1", ()=>{