Skip to content

Commit 2aabd27

Browse files
authored
fix: keep state mutations on one file (#31)
1 parent 9151414 commit 2aabd27

7 files changed

Lines changed: 182 additions & 138 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Useful scripts:
1919

2020
| Script | What it does |
2121
| --- | --- |
22-
| `bun run test` | Run the unit test suite serially |
23-
| `bun run test:coverage` | Run the serial test suite with a coverage report |
22+
| `bun run test` | Run the unit test suite |
23+
| `bun run test:coverage` | Run the test suite with a coverage report |
2424
| `bun run lint` | ESLint over the repo |
2525
| `bun run typecheck` | TypeScript `--noEmit` check |
2626
| `bun run build` | Bundle `src/server.ts` into `dist/` |

‎dist/server.js‎

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,7 @@ function parseStateText(raw, file) {
242242
function decodeState(value) {
243243
return Schema.decodeUnknown(StateSchema)(value).pipe(Effect.map(mutableState), Effect.map(normalizeState), Effect.mapError((cause) => new StateDecodeError({ cause })));
244244
}
245-
function readStateEffect() {
246-
const file = statePath();
245+
function readStateEffect(file = statePath()) {
247246
return Effect.tryPromise({
248247
try: () => readFile(file, "utf8"),
249248
catch: (cause) => new StateReadError({ cause })
@@ -252,10 +251,9 @@ function readStateEffect() {
252251
catch: (cause) => new StateDecodeError({ cause })
253252
})), Effect.flatMap(decodeState), Effect.catchAll((error) => error._tag === "StateReadError" && isMissingStateFile(error.cause) ? Effect.succeed(emptyState()) : Effect.fail(error)));
254253
}
255-
function writeStateEffect(state) {
254+
function writeStateEffect(state, file = statePath()) {
256255
return Effect.tryPromise({
257256
try: async () => {
258-
const file = statePath();
259257
await mkdir(dirname2(file), { recursive: true, mode: 448 });
260258
await atomicWriteFile(file, JSON.stringify(state, null, 2) + `
261259
`);
@@ -277,15 +275,18 @@ function enqueueMutation(operation) {
277275
return current;
278276
}
279277
async function mutate(fn) {
280-
return enqueueMutation(() => Effect.runPromise(Effect.gen(function* () {
281-
const state = yield* readStateEffect();
282-
const result = yield* Effect.tryPromise({
283-
try: () => Promise.resolve(fn(state)),
284-
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause))
285-
});
286-
yield* writeStateEffect(state);
287-
return result;
288-
})));
278+
return enqueueMutation(() => {
279+
const file = statePath();
280+
return Effect.runPromise(Effect.gen(function* () {
281+
const state = yield* readStateEffect(file);
282+
const result = yield* Effect.tryPromise({
283+
try: () => Promise.resolve(fn(state)),
284+
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause))
285+
});
286+
yield* writeStateEffect(state, file);
287+
return result;
288+
}));
289+
});
289290
}
290291
function validateObjective(objective) {
291292
const value = objective.trim();

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
"ci:version": "bun scripts/resolve-ci-version.ts",
4949
"lint": "eslint .",
5050
"pack:dry-run": "npm pack --dry-run",
51-
"test": "bun test --concurrent --max-concurrency 1",
52-
"test:coverage": "bun test --concurrent --max-concurrency 1 --coverage",
51+
"test": "bun test",
52+
"test:coverage": "bun test --coverage",
5353
"typecheck": "tsc --noEmit",
5454
"prepublishOnly": "bun run test && bun run build"
5555
},

‎src/state.ts‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,7 @@ function decodeState(value: unknown) {
320320
)
321321
}
322322

323-
function readStateEffect() {
324-
const file = statePath()
323+
function readStateEffect(file = statePath()) {
325324
return Effect.tryPromise({
326325
try: () => readFile(file, "utf8"),
327326
catch: (cause) => new StateReadError({ cause }),
@@ -339,10 +338,9 @@ function readStateEffect() {
339338
)
340339
}
341340

342-
function writeStateEffect(state: State) {
341+
function writeStateEffect(state: State, file = statePath()) {
343342
return Effect.tryPromise({
344343
try: async () => {
345-
const file = statePath()
346344
await mkdir(dirname(file), { recursive: true, mode: 0o700 })
347345
// atomicWriteFile writes to a same-directory temp file, fsyncs it, then
348346
// renames it into place: the final path is only ever replaced by a
@@ -387,19 +385,20 @@ function enqueueMutation<T>(operation: () => Promise<T>) {
387385
}
388386

389387
async function mutate<T>(fn: (state: State) => T | Promise<T>) {
390-
return enqueueMutation(() =>
391-
Effect.runPromise(
388+
return enqueueMutation(() => {
389+
const file = statePath()
390+
return Effect.runPromise(
392391
Effect.gen(function* () {
393-
const state = yield* readStateEffect()
392+
const state = yield* readStateEffect(file)
394393
const result = yield* Effect.tryPromise({
395394
try: () => Promise.resolve(fn(state)),
396395
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
397396
})
398-
yield* writeStateEffect(state)
397+
yield* writeStateEffect(state, file)
399398
return result
400399
}),
401-
),
402-
)
400+
)
401+
})
403402
}
404403

405404
export function validateObjective(objective: string) {

0 commit comments

Comments
 (0)