サンプル
lodash 4.17.21: lodash.mergeWith applies customizer return values to override default property assignment while falling back to recursive deep merge when returning undefined
検証済みサンプル — npm lodash 4.17.21: lodash.mergeWith applies customizer return values to override default property assignment while falling back to recursive deep…
sha256:fbf4e7bf582a93245baffdb5a1571715f43c2a6407dfc0a34c5c54d1d7100679
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。
MIT-0
実行証拠
宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。
- 証拠の基準
- 署名済みコントラクト合格
- 検証レシート
- 3
- ビルドした署名鍵
- 3
宣言された環境
node linux x64 node node npm
検証実行環境
| 環境 | コントラクト | ステージ | 実行日 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-17 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-09-08 |
ケース
HOW- ゴール
- lodash.mergeWith applies customizer return values to override default property assignment while falling back to recursive deep merge when returning undefined
- パッケージ
- シンボル
-
- lodash.mergeWith
- 環境
- node
- 作成日
- 2026-08-17T12:17:14Z
コントラクト
- mergeWith uses the value returned by customizer when defined, but falls back to recursive deep merging when the customizer returns undefined.
- assert.deepStrictEqual(merge({}, { a: [1, 2] }, { a: [3] }), { a: [3, 2] })
- assert.deepStrictEqual(mergeWith({}, { a: [1, 2], b: { x: 10 } }, { a: [3, 4], b: { y: 20 } }, customizer), { a: [1, 2, 3, 4], b: { x: 10, y: 20 } })
- assert.strictEqual(mergeWith({ reset: { keep: true } }, { reset: { replace: true } }, () => null).reset, null)
- assert.strictEqual(mergeWith(dest, { count: 2 }, (obj, src) => obj + src), dest)
ファイル
- NOTES.md
- csx.json
- package-lock.json
- package.json
- test/contract.mjs
ソース
# lodash: mergeWith Customizer Semantics
## Known Solution Search
A search of known solutions returned two existing samples:
- `sha256:3d6913c88e87048b4b55cebf64b6e0bd0e5c2fa4e748e8f754ff20cd2baf86bd`: CommonJS dependencies under Vite SSR requiring `ssr.noExternal` and `ssr.optimizeDeps`.
- `sha256:e991b2b17774ff91d87fbe5ebfa2b3997a9f8b8c1fae7cb5d671573c6ebe68a9`: Importing CommonJS modules in ESM environments.
Neither sample covers `lodash.mergeWith` customizer delegation semantics or recursive merge fallback behavior.
## Pinned Release
- `lodash`: `4.17.21`
## Observed Behaviour
In `lodash@4.17.21`:
- `mergeWith(object, ...sources, customizer)` invokes the `customizer` function for each property being merged with arguments `(objValue, srcValue, key, object, source, stack)`.
- When `customizer` returns a defined value (including `null`, `false`, or an array), that value is directly assigned to the target property, bypassing standard recursive merging for that subtree.
- When `customizer` returns `undefined`, `mergeWith` falls back to standard deep recursive merging. For example, nested object structures continue to be merged recursively.
- Standard `merge` merges array elements by index (e.g. `[1, 2]` merged with `[3]` results in `[3, 2]`), whereas a customizer returning `objValue.concat(srcValue)` for arrays allows full concatenation (`[1, 2, 3, 4]`) while preserving recursive merging for sibling or nested object properties.
- `mergeWith` mutates and returns the first argument (`object`).
{"case":{"caseId":"case:sha256:4c4c7040d4b0ecb8d535724fa3f3d2e8da51b485b4ee30ab61464188755d5cdd","contract":["mergeWith uses the value returned by customizer when defined, but falls back to recursive deep merging when the customizer returns undefined.","assert.deepStrictEqual(merge({}, { a: [1, 2] }, { a: [3] }), { a: [3, 2] })","assert.deepStrictEqual(mergeWith({}, { a: [1, 2], b: { x: 10 } }, { a: [3, 4], b: { y: 20 } }, customizer), { a: [1, 2, 3, 4], b: { x: 10, y: 20 } })","assert.strictEqual(mergeWith({ reset: { keep: true } }, { reset: { replace: true } }, () =\u003e null).reset, null)","assert.strictEqual(mergeWith(dest, { count: 2 }, (obj, src) =\u003e obj + src), dest)"],"goal":"lodash.mergeWith applies customizer return values to override default property assignment while falling back to recursive deep merge when returning undefined","kind":"HOW","packages":["pkg:npm/lodash@4.17.21"],"schemaVersion":1,"symbols":["lodash.mergeWith"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/lodash@4.17.21"],"schemaVersion":1,"symbols":["lodash.mergeWith"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-lodash-version-depth",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-lodash-version-depth",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"lodash": "4.17.21"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
}
}
}
{
"name": "npm-lodash-version-depth",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"lodash": "4.17.21"
}
}
import assert from 'node:assert/strict';
import lodash from 'lodash';
const { mergeWith, merge } = lodash;
// 1. Default merge behavior on arrays: overwrites elements by index
const defaultTarget = { a: [1, 2], b: { x: 10 } };
const defaultSource = { a: [3], b: { y: 20 } };
const defaultMerged = merge({}, defaultTarget, defaultSource);
assert.deepStrictEqual(defaultMerged, {
a: [3, 2],
b: { x: 10, y: 20 }
});
// 2. Customizer returning a value replaces/overrides default merging:
// Concatenating arrays when objValue is an array
function customizer(objValue, srcValue) {
if (Array.isArray(objValue)) {
return objValue.concat(srcValue);
}
// Returning undefined delegates to default recursive merging
return undefined;
}
const customTarget = { a: [1, 2], b: { x: 10, nested: { count: 1 } } };
const customSource = { a: [3, 4], b: { y: 20, nested: { tag: 'v1' } } };
const result = mergeWith({}, customTarget, customSource, customizer);
// Array is concatenated because customizer returned an array:
assert.deepStrictEqual(result.a, [1, 2, 3, 4]);
// Nested objects are still recursively merged because customizer returned undefined:
assert.deepStrictEqual(result.b, {
x: 10,
y: 20,
nested: {
count: 1,
tag: 'v1'
}
});
// 3. Customizer returning null or false assigns that value directly
const nullCustomizer = (objValue, srcValue, key) => {
if (key === 'reset') return null;
return undefined;
};
const nullMerged = mergeWith({ reset: { keep: true } }, { reset: { replace: true } }, nullCustomizer);
assert.strictEqual(nullMerged.reset, null);
// 4. mergeWith mutates the destination object and returns it
const dest = { count: 1 };
const returned = mergeWith(dest, { count: 2 }, (obj, src) => obj + src);
assert.strictEqual(returned, dest);
assert.strictEqual(dest.count, 3);