Skip to content

Commit

Permalink
feat: add optional clone method to FormatPlugin interface
Browse files Browse the repository at this point in the history
This method is used to clone the object returned by `read` before
passing it to `update`.

This is useful when the object returned by `read` is not trivially
cloneable. One use case is when trying to preserve comments in a JSONC
file using `json-comments`, which uses symbol properties on the object
to store comments. The default `clone` method would not preserve these
symbol properties, so a custom `clone` method is needed.

Fixes pnpm#10
  • Loading branch information
b0o committed Feb 1, 2024
1 parent 152beda commit 4c531f2
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 1 deletion.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ const ignoreFormat = createFormat({
const unique = (array) => Array.from(new Set() < T[number] > array).sort()
await fs.writeFile(resolvedPath, unique(expected).join('\n'), 'utf8')
},
// Optional: define a 'clone' function to control how the result of 'read' is cloned before being passed to 'update'
// Defaults to `structuredClone`[1] if available, otherwise `v8.deserialize(v8.serialize(obj))`.
clone(actual) {
return myCustomClone(actual)
},
})

export default async (_workspaceDir) => {
Expand Down
6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ export async function performUpdates<
_writeProjectManifest: writeProjectManifest,
}
const actual = (await fileExists(resolvedPath)) ? await formatPlugin.read(formatHandlerOptions) : null
const expected = await formatPlugin.update(clone(actual), updateFile as any, formatHandlerOptions)
const expected = await formatPlugin.update(
formatPlugin.clone ? formatPlugin.clone(actual, formatHandlerOptions) : clone(actual),
updateFile as any,
formatHandlerOptions,
)
const equal =
(actual == null && expected == null) ||
(actual != null && expected != null && (await formatPlugin.equal(expected, actual, formatHandlerOptions)))
Expand Down
7 changes: 7 additions & 0 deletions src/updater/formatPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ export interface FormatPlugin<Content> {

/** Called only if write is required (`--test` isn't specified, `expected != null` and `expected` is not equal to `actual`) */
write(expected: Content, options: FormatPluginFnOptions): PromiseOrValue<void>

/**
* Used to clone the object returned by `read` before passing it to `update`.
* Defaults to `structuredClone`[1] if available, otherwise `v8.deserialize(v8.serialize(obj))`.
* [1]: https://developer.mozilla.org/en-US/docs/web/api/structuredclone
*/
clone?<Content>(value: Content, options: FormatPluginFnOptions): Content
}

export interface FormatPluginFnOptions {
Expand Down

0 comments on commit 4c531f2

Please sign in to comment.