CodeSampleX

サンプル

ajv 8.17.1: Coerce scalar values to arrays using ajv coerceTypes option

検証済みサンプル — npm ajv 8.17.1: Coerce scalar values to arrays using ajv coerceTypes option. node 22 · linux alpine/x64 · docker で contract を実行し、成功しました.

sha256:6c0869519510ebd76ed0393a2bdecf6028623f29ba188f44368ecabd4e7668a9

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
2
ビルドした署名鍵
2
宣言された環境 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-16
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

ケース

HOW
ゴール
Coerce scalar values to arrays using ajv coerceTypes option
パッケージ
シンボル
  • Ajv
  • ajv.compile
環境
node
作成日
2026-08-16T06:23:00Z

コントラクト

  1. assert coerceTypes: true leaves scalar-to-array uncoerced and fails array validation
  2. assert coerceTypes: true still coerces scalar-to-scalar fields like string integers
  3. assert coerceTypes: 'array' coerces scalar string to array of strings and string integer to array of integers
  4. assert coerceTypes: 'array' coerces single-element array to scalar
  5. assert coerceTypes: 'array' rejects multi-element array when scalar string is expected

ファイル

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

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

ソース

NOTES.md
# Notes

## Search Known Solution
`search_known_solution` returned `sha256:de249b2f65992de63dd2adece0fd7b0829b25af3cd75a5ad075a49696ed69ffc` covering strict mode failure on unknown keywords (`strict: true`).

## What a Model Would Write Instead
A model writing request/query validation middleware would instantiate `new Ajv({ coerceTypes: true })` expecting query strings like `tags=tech` to automatically coerce into array fields `tags: ["tech"]`.

## Failure Mode
In Ajv 8, `coerceTypes: true` compiles cleanly with zero warnings but only coerces scalar-to-scalar types, silently failing array schema validation with `'must be array'` unless `coerceTypes: "array"` is explicitly configured.
csx.json
{"case":{"caseId":"case:sha256:93a14da7474744b8164073b163027391a3adc37db619bf4cfd96ee5c192651bf","contract":["assert coerceTypes: true leaves scalar-to-array uncoerced and fails array validation","assert coerceTypes: true still coerces scalar-to-scalar fields like string integers","assert coerceTypes: 'array' coerces scalar string to array of strings and string integer to array of integers","assert coerceTypes: 'array' coerces single-element array to scalar","assert coerceTypes: 'array' rejects multi-element array when scalar string is expected"],"goal":"Coerce scalar values to arrays using ajv coerceTypes option","kind":"HOW","packages":["pkg:npm/ajv@8.17.1"],"schemaVersion":1,"symbols":["Ajv","ajv.compile"]},"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/ajv@8.17.1"],"schemaVersion":1,"symbols":["Ajv","ajv.compile"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "csx-sample-ajv-coerce-types",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "csx-sample-ajv-coerce-types",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "ajv": "8.17.1"
      }
    },
    "node_modules/ajv": {
      "version": "8.17.1",
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
      "license": "MIT",
      "dependencies": {
        "fast-deep-equal": "^3.1.3",
        "fast-uri": "^3.0.1",
        "json-schema-traverse": "^1.0.0",
        "require-from-string": "^2.0.2"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/fast-deep-equal": {
      "version": "3.1.3",
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
      "license": "MIT"
    },
    "node_modules/fast-uri": {
      "version": "3.1.5",
      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
      "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fastify"
        },
        {
          "type": "opencollective",
          "url": "https://opencollective.com/fastify"
        }
      ],
      "license": "BSD-3-Clause"
    },
    "node_modules/json-schema-traverse": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
      "license": "MIT"
    },
    "node_modules/require-from-string": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    }
  }
}
package.json
{
  "name": "csx-sample-ajv-coerce-types",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "license": "MIT-0",
  "dependencies": {
    "ajv": "8.17.1"
  }
}
src/index.mjs
import Ajv from 'ajv';

export function createScalarOnlyCoercer() {
  return new Ajv({ coerceTypes: true });
}

export function createArrayCoercer() {
  return new Ajv({ coerceTypes: 'array' });
}
test/contract.mjs
import { strict as assert } from 'node:assert';
import { createScalarOnlyCoercer, createArrayCoercer } from '../src/index.mjs';

const arraySchema = {
  type: 'object',
  properties: {
    tags: {
      type: 'array',
      items: { type: 'string' }
    },
    ids: {
      type: 'array',
      items: { type: 'integer' }
    }
  },
  required: ['tags', 'ids']
};

const scalarSchema = {
  type: 'object',
  properties: {
    limit: {
      type: 'integer'
    }
  },
  required: ['limit']
};

// 1. Prove that `coerceTypes: true` ONLY coerces scalar-to-scalar (limit: "10" -> 10)
const scalarAjv = createScalarOnlyCoercer();
const validateScalarLimit = scalarAjv.compile(scalarSchema);
const limitPayload = { limit: '10' };
assert.equal(validateScalarLimit(limitPayload), true);
assert.equal(limitPayload.limit, 10);

// 2. Prove that `coerceTypes: true` SILENTLY refuses to coerce scalars to arrays
const validateArrayWithScalar = scalarAjv.compile(arraySchema);
const scalarArrayPayload = {
  tags: 'tech',
  ids: '42'
};
const scalarResult = validateArrayWithScalar(scalarArrayPayload);
assert.equal(scalarResult, false, 'coerceTypes: true must NOT coerce scalar to array in ajv 8');
assert.equal(validateArrayWithScalar.errors[0].keyword, 'type');
assert.equal(validateArrayWithScalar.errors[0].params.type, 'array');
assert.equal(typeof scalarArrayPayload.tags, 'string');
assert.equal(typeof scalarArrayPayload.ids, 'string');

// 3. Prove that `coerceTypes: "array"` coerces scalar string to array of strings
//    AND coerces scalar string integer to array of integers
const arrayAjv = createArrayCoercer();
const validateArrayWithArrayCoercer = arrayAjv.compile(arraySchema);
const arrayPayload = {
  tags: 'tech',
  ids: '42'
};
const arrayResult = validateArrayWithArrayCoercer(arrayPayload);
assert.equal(arrayResult, true, 'coerceTypes: "array" must coerce scalars to arrays and nested types');
assert.deepEqual(arrayPayload.tags, ['tech']);
assert.deepEqual(arrayPayload.ids, [42]);

// 4. Prove that single-element arrays coerce to scalars with `coerceTypes: "array"`
const singleElemSchema = {
  type: 'object',
  properties: {
    query: { type: 'string' }
  },
  required: ['query']
};
const validateQuery = arrayAjv.compile(singleElemSchema);
const queryPayload = { query: ['ajv-traps'] };
assert.equal(validateQuery(queryPayload), true);
assert.equal(queryPayload.query, 'ajv-traps');

// 5. Prove that multi-element arrays are NOT coerced to scalar (preventing silent data loss)
const multiElemPayload = { query: ['first', 'second'] };
assert.equal(validateQuery(multiElemPayload), false);
assert.equal(validateQuery.errors[0].keyword, 'type');

console.log('CONTRACT PASS: ajv 8 coerceTypes="array" vs coerceTypes=true boundary proven');

オリジンシーダー

csx-seed