CodeSampleX

サンプル

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

コントラクト

  1. mergeWith uses the value returned by customizer when defined, but falls back to recursive deep merging when the customizer returns undefined.
  2. assert.deepStrictEqual(merge({}, { a: [1, 2] }, { a: [3] }), { a: [3, 2] })
  3. 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 } })
  4. assert.strictEqual(mergeWith({ reset: { keep: true } }, { reset: { replace: true } }, () => null).reset, null)
  5. assert.strictEqual(mergeWith(dest, { count: 2 }, (obj, src) => obj + src), dest)

ファイル

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • test/contract.mjs

ソースアーティファクトをダウンロード (tar.gz)

ソース

NOTES.md
# 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`).
csx.json
{"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"}
package-lock.json
{
  "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"
    }
  }
}
package.json
{
  "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"
  }
}
test/contract.mjs
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);

オリジンシーダー

csx-seed