Skip to content

fix(include): apply patches on refresh - #57

Open
tdwhere123 wants to merge 4 commits into
cordiverse:mainfrom
tdwhere123:fix/include-refresh-patches
Open

fix(include): apply patches on refresh#57
tdwhere123 wants to merge 4 commits into
cordiverse:mainfrom
tdwhere123:fix/include-refresh-patches

Conversation

@tdwhere123

@tdwhere123 tdwhere123 commented Aug 14, 2026

Copy link
Copy Markdown

Problem

Include[Service.init] applies patches before root.update(). refresh() feeds this.data straight into the tree.

read() always replaces this.data with the file contents. HMR config reloads call include.refresh(), so a disabled / config override / insert patch is dropped whenever the file changes and has not been baked back to disk (readonly files never are).

A writable refresh that recreates an insert (new anonymous id) goes through EntryGroup.removefiber.dispose()tree.write() and dumps root.data (overlays) over the user's file. The next real edit then double-applies insert.

Path Current main This change
[Service.init] applyPatches then await root.update insert stamps a stable id; skip if id/name already present
refresh() after a file change tree matches the file; patches gone patches reapplied; await root.update; no write()
same-path internal/update root.update(this.data) unchanged (deferred)

Change

Reuse the init sequence in refresh(): await this.root.update(this.applyPatches([...this.data!])).

applyPatches insert copies each entry after ensureId on the patch item, and skips if that id is already in the tree or the target list already has that name.

refresh() treats the file as source of truth: overlapping calls are queued, in-flight writeFile timers are dropped, and write() is ignored until root.update returns.

The same-path internal/update handler still calls this.root.update(this.data!). Nested insert still mutates shared entry objects; that path stays deferred until a clone-then-patch exists.

writeFile / stop / the debounce queue implementation are otherwise untouched (#47).

Regression coverage

packages/include/tests/patch.spec.ts:

  • disable inner via patch, rewrite the file, refresh(), entry stays disabled
  • insert ./extra-plugin, write() bake, rewrite the file, refresh, one extra row
  • insert ./extra-plugin, comment-only rewrite, refresh: file bytes stay the comment (no bake), extra id unchanged

Validation

  • yarn lint
  • yarn test include/patch — 13 tests passed

refresh() reloaded the file and updated the tree without applyPatches, so HMR config reloads dropped disabled/config overrides. Reuse the init path and await the tree update.
Drop the constructor internal/update hunk: applyPatches mutates nested entries, so a same-path update could insert twice. refresh() is the HMR path; await loader quiescence in the regression instead of sleeps.
refresh() re-runs applyPatches on a baked file. Pushing the patch object
let ensureId stamp an id back onto Include config, so the next apply
appended a second same-id row. Copy the entry and skip if that id or
name is already in the target list.
Insert overlays now stamp a stable id on the patch item so a re-read
updates the same entry instead of remove+create. refresh() is the disk
snapshot path: drop in-flight writes, ignore tree.write() until it
returns, and queue overlapping calls.
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.

1 participant