Skip to content

Commit ca14774

Browse files
committed
feat: add optional clone method to FormatPlugin interface
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 the `comment-json` package, 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
1 parent 152beda commit ca14774

File tree

3 files changed

+17
-1
lines changed

3 files changed

+17
-1
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ const ignoreFormat = createFormat({
7171
const unique = (array) => Array.from(new Set() < T[number] > array).sort()
7272
await fs.writeFile(resolvedPath, unique(expected).join('\n'), 'utf8')
7373
},
74+
// Optional: define a 'clone' function to control how the result of 'read' is cloned before being passed to 'update'
75+
// Defaults to `structuredClone`[1] if available, otherwise `v8.deserialize(v8.serialize(obj))`.
76+
clone(actual) {
77+
return myCustomClone(actual)
78+
},
7479
})
7580

7681
export default async (_workspaceDir) => {

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ export async function performUpdates<
8888
_writeProjectManifest: writeProjectManifest,
8989
}
9090
const actual = (await fileExists(resolvedPath)) ? await formatPlugin.read(formatHandlerOptions) : null
91-
const expected = await formatPlugin.update(clone(actual), updateFile as any, formatHandlerOptions)
91+
const expected = await formatPlugin.update(
92+
formatPlugin.clone ? formatPlugin.clone(actual, formatHandlerOptions) : clone(actual),
93+
updateFile as any,
94+
formatHandlerOptions,
95+
)
9296
const equal =
9397
(actual == null && expected == null) ||
9498
(actual != null && expected != null && (await formatPlugin.equal(expected, actual, formatHandlerOptions)))

src/updater/formatPlugin.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ export interface FormatPlugin<Content> {
2424

2525
/** Called only if write is required (`--test` isn't specified, `expected != null` and `expected` is not equal to `actual`) */
2626
write(expected: Content, options: FormatPluginFnOptions): PromiseOrValue<void>
27+
28+
/**
29+
* Used to clone the object returned by `read` before passing it to `update`.
30+
* Defaults to `structuredClone`[1] if available, otherwise `v8.deserialize(v8.serialize(obj))`.
31+
* [1]: https://developer.mozilla.org/en-US/docs/web/api/structuredclone
32+
*/
33+
clone?<Content>(value: Content, options: FormatPluginFnOptions): Content
2734
}
2835

2936
export interface FormatPluginFnOptions {

0 commit comments

Comments
 (0)