{ } jq-lite

Compatibility notes

On this pageDecision statusesInventoryWhat this inventory does not cover
このページの目次判断状態A. 2.xで維持する互換性上の動作B. 算術と型変換C. 比較D. null、欠損値、パスE. 反復とパイプラインF. 代入と更新G. 未対応のjq機能H. 明示的な拡張と移行補助この一覧の対象外

JQ::Liteは実用的なjq形式の言語を実装しますが、jqのすべての実行時の意味論をそのまま再現するものではありません。この文書は、両者が受け付けるフィルターでも結果や失敗の振る舞いが異なる既知のケースを記録します。2.xの動作の一覧であり、未対応の構文への対応を宣言するものではありません。

jq列の基準はjq 1.7です。JQ::Liteの結果はt/jq_semantic_differences.tで保護され、回帰テストにjq実行ファイルは不要です。

判断状態

  • 維持:jqと異なってもJQ::Liteの意味を保つ。
  • v3で変更:2.xでは保ち、個別レビューを経てv3でjq互換へ寄せる。
  • 未決定:v3での決定はまだない。決定まで2.xの動作をテストで保護する。

この分類はロードマップ上の判断であり、2.xの動作変更ではありません。検討対象は架空のIssue番号ではなく、議題名で示します。

A. 2.xで維持する互換性上の動作

既存利用者が依存し得るため、構文解析やフィルター整理のついでに変更してはいけません。

項目 例 jq 1.7 JQ::Lite 2.x v3の判断 検討対象
配列のcontains [1,2,3] | contains([1,3]) true:再帰的な部分集合包含 false:引数全体と等しい1要素を探す v3で変更 包含の意味論
入れ子のオブジェクト {"a":{"b":1,"c":2}} | contains({"a":{"b":1}}) true false:入れ子の値は等値が必要 v3で変更 包含の意味論
代替値演算子 false // 9 9 false:null・欠損・空出力のみ代替 v3で変更 nullと代替値
不揃いな行の転置 [[1,2],[3]] | transpose [[1,3],[2,null]] [[1,3]]:最短行で切り詰める 維持 なし

contains_subset(value)は再帰的で順序を問わない包含のための代替ですが、jqのcontainsと同一ではありません。多重集合として重複回数を数え、スカラーを文字列表現で比較します。

[1] | contains_subset([1,1])はfalseですが、jqのcontains([1,1])はtrueです。["1"] | contains_subset([1])はtrueですが、jqのcontains([1])はfalseです。

B. 算術と型変換

JQ::Liteは値を失わないパイプライン処理やPerlのスカラー変換を重視する場合があり、jqの型エラーや演算子の振る舞いと異なります。

項目 例 jq 1.7 JQ::Lite 2.x v3の判断 検討対象
数値への変換 "1e3" * 1 "1e3":文字列の反復 1000 未決定 算術・型変換
真偽値の算術 true + 1 型エラー 2 v3で変更 算術・型変換
配列への丸め [1.2,"2.8","x"] | floor 型エラー [1,2,"x"] 維持 なし
値を保持するJSON解析 ["1","true","bad"] | fromjson 型エラー:文字列でない入力 [1,true,"bad"]:要素ごとに解析し不正な文字列は維持 維持 なし
正規表現のスカラー変換 42 | match("2") 型エラー "42"に対する一致オブジェクト 未決定 型変換

JQ::Liteで成功しても、jqが同じ入力型を受け付けるとは限りません。jqの演算子の振る舞いをPerlの数値変換と同じだと仮定しないでください。

C. 比較

項目 例 jq 1.7 JQ::Lite 2.x v3の判断 検討対象
異なる型の等値 "10" == 10 false true:数値に見える文字列を数値比較 v3で変更 比較の意味論
JSON型間の順序 false < 0 true true 維持 一致を保つ回帰テスト
配列の順序 [1,2] < [1,3] true:辞書式の順序 false v3で変更 比較の意味論
欠損値の比較 .missing == null true true 維持 一致を保つ回帰テスト

一致する行も意図的に含めています。型変換の修正により、既にjqと一致する近接ケースが変わるのを防ぎます。

D. null、欠損値、パス

項目 例 jq 1.7 JQ::Lite 2.x v3の判断 検討対象
欠損したフィールド {}に.missing nullを1つ返す 結果なし v3で変更 null・欠損・パス
欠損フィールド経由 {}に.missing.value nullを1つ返す 結果なし v3で変更 null・欠損・パス
配列の不正なフィールドパス {"a":[]}に.a.value 型エラー 結果なし 未決定 パスのエラー方針
オブジェクトの数値添字 {}に.[5] 型エラー nullを1つ返す v3で変更 パスのエラー方針

直接のパス出力では、欠損の探索結果(空の結果列)と明示的なJSON nullを区別します。一方、.missing == nullの比較では現状同様に扱います。

E. 反復とパイプライン

項目 例 jq 1.7 JQ::Lite 2.x v3の判断 検討対象
配列のパス射影 [{"x":1},{"x":2}] | .x 型エラー 1, 2 維持 なし
混合型の反復後の射影 {"a":[{"x":1}],"n":3} | .[] | .x 配列で型エラー 1:配列を射影しスカラーの欠損は落とす 未決定 反復・パイプライン
反復の接尾構文 keys[] keys | .[]と同じ keys | .[]と同じ 維持 一致を保つ回帰テスト
コンマと反復 0, [4,5][] 0, 4, 5 0, 4, 5 維持 一致を保つ回帰テスト

F. 代入と更新

項目 例 jq 1.7 JQ::Lite 2.x v3の判断 検討対象
通常の代入 {"a":1} | .a = 2 {"a":2} {"a":2} 維持 一致を保つ回帰テスト
更新代入の結果 {"a":1} | .a |= . + 1 {"a":2} 2:ルートではなく更新値を返す v3で変更 代入・更新
欠損した更新先 {"a":1} | .missing |= . + 1 "missing":1を含むオブジェクト 結果なし v3で変更 代入・更新
複数結果の代入 {"a":0} | .a = (1,2) 更新したオブジェクトを2つ返す 結果なし 未決定 代入と結果列

G. 未対応のjq機能

機能がないことと意味論の衝突は別ですが、移植性に影響するため記録します。

機能 例 JQ::Lite 2.x v3の判断 検討対象
ユーザー定義関数 def inc: . + 1; inc 未実装。現状はnullと評価 未決定 未対応構文の方針
ラベルとbreak label $out | break $out 未実装 未決定 制御フロー
モジュール・import import "x" as x; ... 未実装 維持 軽量な範囲の対象外
ストリーミング解析 --stream CLIオプション未実装 維持 現在のCLI範囲外

H. 明示的な拡張と移行補助

jqと衝突する意味ではなく、JQ::Liteの意図や既存パイプラインに有用な動作を表します。

拡張 目的 v3の判断 検討対象
contains_subset(value) 再帰的・順序非依存の多重集合包含。重複には重複した一致が必要で、スカラーは文字列比較 未決定 contains変更時に名前と意味を整合
to_number() 厳密なtonumberと異なる、値を保持する要素ごとの数値変換 維持 なし
flatten_all(), flatten_depth(n) 平坦化の明示的な形式 維持 なし
統計・便利な補助関数 avg、median、mode、percentile、variance、stddev、clampなど 維持 なし

この一覧の対象外

  • 未対応の組み込み関数・CLIオプションをすべて列挙したものではありません。
  • CLI診断は安定したCLI仕様に従い、jqの厳密なエラー文言は保証しません。
  • JSONオブジェクトのキー順序は移植可能な意味論の保証でないため比較しません。
  • jq 1.7以降の変更と、JQ::Lite自身の変更は別々に確認する必要があります。

差分を発見した場合は該当分類へ追加し、外部依存なしで現在の動作を保護する回帰テストを追加します。将来の変更は2.xへの影響を明示し、別の提案として扱います。

JQ::Lite implements a useful jq-like language, but it is not a drop-in implementation of every jq runtime semantic. This document records the currently known semantic differences: cases where a filter is accepted by both tools but its result or failure behaviour differs. It is a snapshot of the 2.x behaviour, not a claim that unsupported jq syntax is supported.

The examples in the jq column describe jq 1.7 behaviour. The JQ::Lite results are protected by t/jq_semantic_differences.t; the regression suite does not require a jq executable.

Decision statuses

Every inventoried item has one of the decision statuses requested for the v3 planning process:

  • preserve — keep the JQ::Lite meaning, even though jq differs;
  • change in v3 — retain it throughout 2.x, but make jq compatibility the target of a separately reviewed v3 change;
  • undecided — no v3 decision has been made. The 2.x behaviour remains regression-protected until that decision is made.

The status is a roadmap classification, not a runtime change in the 2.x series. “Follow-up” deliberately uses topic names rather than inventing issue numbers; it can be replaced by a concrete issue link when that work is filed.

Inventory

A. Preserved 2.x compatibility behaviour

These differences are observable existing behaviour on which 2.x callers may rely. Changing them requires an explicit compatibility decision rather than an incidental parser or filter refactor.

Area Example jq JQ::Lite 2.x v3 status Follow-up
Array contains [1,2,3] | contains([1,3]) true (recursive subset containment) false (looks for one element equal to the complete argument) change in v3 containment semantics
Nested object contains {"a":{"b":1,"c":2}} | contains({"a":{"b":1}}) true false (nested values must be equal) change in v3 containment semantics
Alternative operator false // 9 9 false (only null, missing, or empty output selects the fallback) change in v3 null and fallback semantics
Jagged transpose [[1,2],[3]] | transpose [[1,3],[2,null]] [[1,3]] (truncates to the shortest row) preserve none

For recursive, order-insensitive array containment, JQ::Lite provides the explicit contains_subset(value) alternative. It avoids changing the established meaning of contains(value) in the 2.x series, but it is not a drop-in implementation of jq's contains: it uses multiset counting, whereas jq can satisfy repeated needles with one matching value, and it compares scalars by their string forms, whereas jq keeps JSON scalar types distinct. For example, [1] | contains_subset([1,1]) is false although jq's contains([1,1]) is true; ["1"] | contains_subset([1]) is true although jq's contains([1]) is false.

B. Arithmetic and type coercion

JQ::Lite commonly favours lossless pipeline processing and Perl scalar coercion where jq reports a type error or applies a different overloaded operation.

Area Example jq JQ::Lite 2.x v3 status Follow-up
Numeric coercion "1e3" * 1 "1e3" (string repetition) 1000 undecided arithmetic/coercion
Boolean arithmetic true + 1 type error 2 change in v3 arithmetic/coercion
Vectorised rounding [1.2,"2.8","x"] | floor type error [1,2,"x"] preserve none
Lossless JSON parsing ["1","true","bad"] | fromjson type error (input is not a string) [1,true,"bad"] (element-wise, invalid text passes through) preserve none
Regex scalar coercion 42 | match("2") type error a match object for the string form "42" undecided type coercion

This category is especially important when moving filters between the tools: successful JQ::Lite output does not imply that jq will accept the same input types. Conversely, jq operator overloading must not be assumed to use Perl's numeric coercion in JQ::Lite.

C. Comparison

Area Example jq JQ::Lite 2.x v3 status Follow-up
Equality across types "10" == 10 false true (numeric-looking strings compare numerically) change in v3 comparison semantics
Ordering across JSON types false < 0 true true preserve none; regression parity guard
Array ordering [1,2] < [1,3] true (lexicographic ordering) false change in v3 comparison semantics
Missing-value comparison .missing == null true true preserve none; regression parity guard

Parity rows are included intentionally: they mark adjacent behaviour that was checked during the inventory and prevent a future coercion fix from changing a currently jq-compatible case by accident.

D. Null, missing values, and paths

Area Example jq JQ::Lite 2.x v3 status Follow-up
Missing object field {} with .missing one null result no results change in v3 null/missing/path semantics
Path through a missing field {} with .missing.value one null result no results change in v3 null/missing/path semantics
Invalid array field path {"a":[]} with .a.value type error no results undecided path error policy
Numeric index on an object {} with .[5] type error one null result change in v3 path error policy

JQ::Lite therefore distinguishes a missing traversal (an empty result stream) from an explicit JSON null in direct path output, even though comparisons such as .missing == null currently treat them alike.

E. Iterators and pipelines

Area Example jq JQ::Lite 2.x v3 status Follow-up
Array path projection [{"x":1},{"x":2}] | .x type error 1, 2 preserve none
Projection after mixed iteration {"a":[{"x":1}],"n":3} | .[] | .x type error on the array 1 (projects through the array and drops the scalar's missing value) undecided iterator/pipeline semantics
Iterator suffix keys[] same results as keys | .[] same results as keys | .[] preserve none; regression parity guard
Comma plus iterator 0, [4,5][] 0, 4, 5 0, 4, 5 preserve none; regression parity guard

F. Assignment and update

Area Example jq JQ::Lite 2.x v3 status Follow-up
Plain assignment {"a":1} | .a = 2 {"a":2} {"a":2} preserve none; regression parity guard
Update assignment result {"a":1} | .a |= . + 1 {"a":2} 2 (emits the updated value, not the root) change in v3 assignment/update semantics
Missing update target {"a":1} | .missing |= . + 1 object with "missing":1 no results change in v3 assignment/update semantics
Multi-result assignment {"a":0} | .a = (1,2) two updated objects no results undecided assignment/update stream semantics

G. Unsupported jq behaviour

Feature absence is distinct from a semantic conflict, but unsupported jq constructs affect portability and are therefore tracked here as required by the audit.

jq facility Example JQ::Lite 2.x v3 status Follow-up
User-defined functions def inc: . + 1; inc not implemented; currently evaluates to null undecided parser unsupported-syntax policy
Labels and break label $out | break $out not implemented undecided control-flow coverage
Modules/imports import "x" as x; ... not implemented preserve none; outside lightweight scope
jq streaming parser mode --stream CLI option not implemented preserve none; outside current CLI scope

H. Explicit JQ::Lite extensions and migration aids

These names do not represent a conflicting jq meaning; they make JQ::Lite's intent explicit or provide behaviours useful to existing pipelines.

Extension Purpose v3 status Follow-up
contains_subset(value) Recursive, order-insensitive multiset containment; unlike jq, duplicate needles require duplicate matches and scalar comparison coerces to strings undecided reconcile its semantics and name if contains changes in v3
to_number() Lossless/vectorised numeric conversion, distinct from strict tonumber() preserve none
flatten_all(), flatten_depth(n) Explicit flattening variants preserve none
Statistical and convenience helpers avg, median, mode, percentile, variance, stddev, clamp, and the other extensions listed in the function reference preserve none

What this inventory does not cover

  • The unsupported-behaviour table is representative rather than a complete list of every jq built-in or command-line option not implemented by JQ::Lite.
  • CLI diagnostics are governed by the stable CLI contract; exact jq error text is not a JQ::Lite compatibility promise.
  • Object key order is not compared because JSON object ordering is not a portable semantic guarantee.
  • jq may evolve after 1.7. When this inventory is updated, jq-version changes and JQ::Lite behaviour changes should be reviewed separately.

When a new difference is found, add it to the appropriate category and add a dependency-free regression assertion for the current JQ::Lite behaviour. A future behaviour change should be proposed separately, with the relevant 2.x compatibility impact called out explicitly.