Skip to content

Refactor of globals and State#2

Open
lsnow99 wants to merge 7 commits intojstrieb:masterfrom
lsnow99:logan/const-globals
Open

Refactor of globals and State#2
lsnow99 wants to merge 7 commits intojstrieb:masterfrom
lsnow99:logan/const-globals

Conversation

@lsnow99
Copy link
Collaborator

@lsnow99 lsnow99 commented Jan 30, 2026

Remake of #1

@lsnow99 lsnow99 changed the title Logan/const globals Refactor of globals and State Jan 30, 2026
Copy link
Owner

@jstrieb jstrieb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to update the CI pipeline to run on pull requests. (Haven't had any, so didn't need to think about that until now.) I'm sure you ran tests locally, but I'm not going to merge until CI runs on this, even if it's otherwise done.

src/App.svelte Outdated
load(urlData) ?? new State([new Sheet("Sheet 1", 10, 10)]),
);
let globals;
globals = load(urlData) ?? new State([new Sheet("Sheet 1", 10, 10)]);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the constructor to not take Sheet instances, or else handle them specially. See comment below.

let result = new State(
data.sheets.map((sheet) => {
constructor(sheets, formulaCode) {
this.load({ sheets, formulaCode });
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this happens to work, but isn't quite correct. We can either change the constructor, or change what we pass to it. (I lean towards the latter.)

Right now, the constructor is called on Sheet instances. In a Sheet instance, the cell values are rederivable stores. In State.load, those rederivable stores are being passed as the values for each cell. Instead, the values are supposed to be raw values, not stores. Probably as soon as the formula is evaluated the raw values are thrown out in all of the test cases (except self-reference), which is why this wasn't caught by the tests. This is the problematic line:

https://github.com/lsnow99/code-grid/blob/5cda4e26ae3b0149ba7322496087d0807b03b647/src/classes.svelte.js#L75

I think the best fix is to never pass fully initialized Sheet instances to the constructor like we're currently doing elsewhere. But I am open to other ideas.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact: TypeScript would probably have caught this. Gonna have to set that up at some point...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch, thank you.

Fun fact: TypeScript would probably have caught this. Gonna have to set that up at some point...

Yeah probably. Also consider jsdoc if you don't want to deal with the transpiling, but then again svelte has a compilation step anyway

Comment on lines +694 to +714
test("State.load preserves elements", async () => {
const state = createSheet([["1", "2", "3"]]);
await expectSheet(state.currentSheet, [[1, 2, 3]]);
state.elements.formulaBar = document.createElement("textarea");
state.elements.formulaBar.setAttribute("data-testid", "shouldPreserve");

const savedState = createSheet([["4", "5", "6"]]);
await expectSheet(savedState.currentSheet, [[4, 5, 6]]);

const testFormulaCode = "functions.testFormulaCode = () => {}";
state.load({
sheets: savedState.sheets,
formulaCode: testFormulaCode,
});

await expectSheet(state.currentSheet, [[4, 5, 6]]);
expect(state.formulaCode).toBe(testFormulaCode);
expect(state.elements.formulaBar.getAttribute("data-testid")).toBe(
"shouldPreserve",
);
});
Copy link
Owner

@jstrieb jstrieb Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my view, this is really two different tests: one tests that the bug you originally reported is fixed (i.e., the formula bar is not broken by loading a sheet), while the other tests that state.load works correctly for updating a sheet's data.

What might make sense instead is to add a much more comprehensive State.load test in addition and leave this one unchanged? (You could also break this one into two, but that seems extreme.) I'm thinking of one that has elements in cells and custom formulas and async formulas and stuff like that so we can verify that none of the tricky features are broken by the State.load implementation.

@lsnow99
Copy link
Collaborator Author

lsnow99 commented Jan 30, 2026

I'm going to update the CI pipeline to run on pull requests. (Haven't had any, so didn't need to think about that until now.) I'm sure you ran tests locally, but I'm not going to merge until CI runs on this, even if it's otherwise done.

Sounds good, I'll also fix the sheet state initialization issue you caught. I ran tests since they run on git commit

@lsnow99 lsnow99 mentioned this pull request Feb 1, 2026
],
formulaCode: globals.formulaCode,
});
save(createSaveData(globals.sheets, globals.formulaCode));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this actually works? Last I tried to move this logic elsewhere, the $effect didn't deeply detect the reactive dependencies, and the save behavior changed: saving didn't happen often enough. I don't have behavior tests for saving, did you confirm in the UI that everything behaves correctly when you do this?

Even if it does work, I'm not sure it fits in this PR. As far as I understand, changing globals to const didn't actually break anything here, and therefore doesn't necessitate this change. Since I don't have tests, I'm hesitant to add this in with everything else.

We can talk more in-person.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're probably right about the deeply nested reactivity breaking

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants