このページは、式言語の組み込み関数に関する完全なリファレンスです。この集合は閉じており、名前は正確に16個だけです。また、すべてが純粋関数です。時計、ランダム性、I/O はありません。これにより、コンパイラは式が非決定性を隠していないことを静的に証明できます。 すべての組み込み関数は、YAML と SDK で同じ方法で呼び出します。YAML の ${{ fn(args) }} は、SDK のバインディングクロージャ (c) => fn(args) の中にある同一の呼び出しへと下げられます。組み込み関数専用の SDK メソッド面はありません。これらは式構文であり、SDK ビルダーではありません。そのため、以下では <CodeGroup> のペアは不要です。各関数につき1つの例を示し、その式形式が両方の場所で使われます。
16個すべては packages/core/src/expr/eval.ts に実装され、packages/core/src/expr/ast.ts の閉じた BuiltinName union として列挙されています。このページは、間違えやすいエッジケースも含め、そのコードが正確に何をするかを文書化しています。

概要

関数シグネチャ戻り値
lenlen(v: string | array)number
lowerlower(v: any)string
upperupper(v: any)string
trimtrim(v: any)string
jsonjson(v: any)string
defaultdefault(v: any, fallback: any)any
mapmap(arr: array, proj: expr)array
filterfilter(arr: array, pred: expr)array
containscontains(hay: string | array, needle: any)boolean
splitsplit(s: string, sep: string)array<string>
joinjoin(arr: array, sep: string)string
replacereplace(s: string, find: string, repl: string)string
sliceslice(v: string | array, start: number, end?: number)string | array
nthnth(v: string | array, i: number)any | null
to_numberto_number(v: any)number
uniqueunique(arr: array)array
mapfilter特殊形式です。第2引数は値として事前に評価されません。要素ごとに1回評価される式であり、その要素は item 参照に、その位置は index に束縛されます。これは foreach 手順が公開する item/index バインディングと同じです。他のすべての組み込み関数は、まずすべての引数を通常の値として評価します。

len

len(v: string | array) -> number
文字列または配列の長さを返します。文字列では、長さは UTF-16 コードユニットではなく Unicode コードポイントで数えられます。実装は [...v].length です。文字列の spread はコードポイントを反復するため、絵文字やその他のサロゲートペアを使う文字は2ではなく1として数えられます。
${{ len(steps.lookup.output.results) }}
${{ len("café") }}
エッジケース
  • 文字列でも配列でもない引数は ExprEvalError を投げます: len() expects a string or array
  • len("")0len([])0 です。
  • Basic Multilingual Plane の外にある文字(例: "😀")は 1 と数えられます。これは下記の split("", "") と一致します。どちらも同じ [...v] のコードポイント基準を使います。

lower

lower(v: any) -> string
v を文字列に強制変換し(下記の文字列強制変換を参照)、.toLowerCase() を呼び出します。
${{ lower(steps.lookup.output.title) }}
エッジケース
  • 文字列以外の入力は先に強制変換されます: lower(42)"42"lower(true)"true"lower(null)"null"。オブジェクトや配列は、小文字化の前に JSON 文字列化されます。
  • JavaScript のロケール非依存な .toLowerCase() を使います。ロケールパラメーターはありません。

upper

upper(v: any) -> string
v を文字列に強制変換し、.toUpperCase() を呼び出します。強制変換の規則は lower と同じです。
${{ upper(input.countryCode) }}

trim

trim(v: any) -> string
v を文字列に強制変換し、.trim() を呼び出して、先頭と末尾の空白を取り除きます(JavaScript の String.prototype.trim の空白定義に従います)。
${{ trim(input.query) }}
エッジケース
  • trim(42)"42"(数値は先に強制変換されるため、裸の数値から取り除く空白はありません)。
  • 取り除かれるのは先頭と末尾の空白だけです。内部の空白はそのまま残ります。

json

json(v: any) -> string
JSON.stringify により v を JSON 文字列にシリアライズします。オブジェクトや配列を含む任意の値で動作します。これは、共有の文字列強制変換ヘルパーを基盤にしていない、唯一の文字列生成系の組み込み関数です。
${{ json(steps.shape.output) }}
エッジケース
  • json("a")"\"a\""(文字列は JSON クォートされます。文字列を裸のまま残す lower/upper/trim/join の強制変換とは異なります)。
  • json(null)"null"
  • json() に渡された secret. 参照は、コンパイル時に secret_leak として拒否されます。どの組み込み関数もシークレットに触れることはできません。式内のシークレットを参照してください。

default

default(v: any, fallback: any) -> any
vnull または undefined でない限り v を返します。その場合は fallback を返します。ほとんどの組み込み関数と異なり、これは文字列への強制変換を行いません。v または fallback がどの型であっても、そのまま通します。
${{ default(steps.lookup.output.currency, "USD") }}
エッジケース
  • fallback を発火させるのは null/undefined だけです。falsy だが存在する値(0""false)はそのまま返され、置き換えられません。default|| ではありません。
  • どちらの引数も通常の値であり、即時に評価されます(map/filter の第2引数のように遅延評価されません)。

map

map(arr: array, proj: expr) -> array
arr の各要素に proj を適用し、射影された値の新しい配列を返します。proj は特殊形式の引数です。事前には評価されません。各要素について、その要素を item に、そのインデックスを index に束縛した状態で評価されます。
${{ map(steps.lookup.output.results, item.price) }}
${{ map(steps.lookup.output.results, item.price * index) }}
エッジケース
  • 第1引数は配列でなければなりません。それ以外は ExprEvalError を投げます: map() expects an array
  • 射影の中の item/index は、外側の item/index バインディング(例: foreach 手順の中にネストされた map)をシャドーイングします。各呼び出しは自身の反復用にそれらを再束縛します。
  • map/filter/foreach のコンテキストitem または index を参照すると例外が投げられます("item" is only bound inside foreach/map/filter)。

filter

filter(arr: array, pred: expr) -> array
pred が truthy になる arr の要素を残し、それ以外を落とします。第2引数は map と同じ特殊形式です。pred は要素ごとに、item/index が束縛された状態で評価されます。
${{ filter(steps.lookup.output.results, item.price < 100) }}
エッジケース
  • 第1引数は配列でなければなりません。そうでない場合は ExprEvalError を投げます: filter() expects an array
  • truthiness は式言語の truthy 規則に従います。0""falsenull は falsy です。それ以外は、空配列やオブジェクトも含めて truthy です。

contains

contains(hay: string | array, needle: any) -> boolean
  • hay文字列の場合、これは部分文字列テストです: hay.includes(String(needle))(needle は文字列に強制変換されます)。
  • hay配列の場合、これは各要素に対して深い等価性(deepEqual)を使う membership テストです。そのため、contains は needle 自体がオブジェクトや配列である場合にも一致できます。スカラーだけに限りません。
${{ contains(lower(steps.lookup.output.title), "sale") }}
${{ contains(steps.lookup.output.tags, "urgent") }}
エッジケース
  • hay が文字列または配列以外の場合は ExprEvalError を投げます: contains() expects a string or array
  • 配列 membership は deepEqual を使います。これは == が使うものと同じ構造的等価性関数です。そのため、2つのオブジェクトが別参照であっても、contains([{a:1}], {a:1})true です。
  • 文字列 membership は共有の文字列強制変換規則で needle を強制変換します。そのため、contains("id-42", 42)true です(42"42" に強制変換されます)。

split

split(s: string, sep: string) -> array<string>
リテラルの区切り文字 seps を分割します。
sep空文字列の場合、split は JavaScript ネイティブの "".split("")(UTF-16 コードユニットで分割する)にはフォールバックしません。明示的に Unicode コードポイント、つまり [...s] に分割します。これは len() が使う基準と同じです。これは JS のデフォルト挙動からの意図的な逸脱であり、ソースコメントでも直接示されています: “Empty separator splits into Unicode code points (mirrors len()‘s […v]).”
${{ split(input.csv, ",") }}
${{ split("café", "") }}
エッジケース
  • split("café", "")["c", "a", "f", "é"]、つまり4要素(コードポイント)です。len("café") = 4 と一致します。
  • s の中に空でない区切り文字が見つからない場合は [s] を返します(標準の String.prototype.split の挙動)。
  • split("", ",")[""](空文字列を空でない区切り文字で分割すると、JS セマンティクスに従い、単一の空文字列要素になります)。

join

join(arr: array, sep: string) -> string
arr のすべての要素を文字列に強制変換し、sep で結合します。
${{ join(map(steps.lookup.output.results, item.name), ", ") }}
エッジケース
  • 第1引数は配列でなければなりません。そうでない場合は ExprEvalError を投げます: join() expects an array
  • 要素は結合前に共有の文字列強制変換規則で強制変換されます。join([1, true, null], "-")"1-true-null"
  • join([], ",")""

replace

replace(s: string, find: string, repl: string) -> string
s 内にある find のリテラル出現をすべて repl に置き換えます。これはリテラルな部分文字列の全置換です。find が正規表現として扱われることはないため、find 内の正規表現メタ文字(.*([ など)は文字どおりそれ自身に一致します。実装は s.split(find).join(repl) であり、それこそが全出現を対象にし、正規表現を使わない理由です。
${{ replace(input.slug, "_", "-") }}
${{ replace(steps.lookup.output.price, "$", "") }}
エッジケース
  • find === ""何もしませんreplace(s, "", repl)repl に関係なく s を変更せず返します。(コードは空の find で短絡し、s.split("").join(repl) に落ちません。そうでなければすべての文字の間に repl が挟まります。)
  • リテラルなので、replace("a.b.c", ".", "-")"a-b-c" です。. はリテラルのドットだけに一致し、正規表現の場合のように「任意の文字」には一致しません。
  • 重なって見える置換は split/join により左から右へ解決されます。そのため、置換済みテキストが再スキャンされることはありません。

slice

slice(v: string | array, start: number, end?: number) -> string | array
vstart から end の直前までのサブスライスを返します。end が省略された場合は v の末尾までです。セマンティクスは JavaScript の Array.prototype.slice / コードポイント安全な文字列 slice を反映します。末尾から数える負のインデックスもサポートします。 文字列の場合、v はまず Unicode コードポイント([...v])に分割され、スライスされ、再結合されます。そのため、スライスは UTF-16 ユニット安全ではなく、コードポイント安全です。
${{ slice(steps.lookup.output.results, 0, 3) }}
${{ slice(input.query, -4) }}
エッジケース
  • end は任意であり、値ではなく引数の存在によって検出されます。第3引数を省略すると末尾までスライスします。渡した場合は(0 であっても)明示的な終端として尊重されます。
  • 負の start/end は標準の Array.slice のクランプ規則に従います(例: slice(arr, -2) は最後の2要素を返します)。
  • 文字列でも配列でもない vExprEvalError を投げます: slice() expects a string or array
  • 範囲外のスライスは例外を投げません。ネイティブの slice の挙動に合わせて、空文字列または空配列を返します。

nth

nth(v: string | array, i: number) -> any | null
インデックス i の要素(文字列の場合はコードポイント)を返します。範囲外の場合は null を返します。負のインデックスをサポートし、その扱いは Python 風です。負の i は slice によって末尾からインデックスするのではなく、v の長さを加えることで折り返されます(i < 0 ? length + i : i)。そのため、nth(v, -1) は最後の要素、nth(v, -2) は後ろから2番目の要素、という形になります。
${{ nth(steps.lookup.output.results, 0) }}
${{ nth(steps.lookup.output.results, -1) }}
エッジケース
  • 範囲外のインデックスは、長さを加えた後もまだ負である折り返し後の負インデックス(例: nth([1,2,3], -10))を含め、例外ではなく null を返します。
  • 文字列の場合、返される要素は単一のコードポイントです(len/slice/split のコードポイント基準と一致します)。UTF-16 コードユニットではありません。
  • 文字列でも配列でもない vExprEvalError を投げます: nth() expects a string or array

to_number

to_number(v: any) -> number
v を数値に強制変換します。
  • v がすでに number の場合は、変更せず返します(再パースしません)。
  • それ以外の場合、v は文字列に強制変換され、.trim() され、すべてのカンマが取り除かれます.replace(/,/g, ""))。これは桁区切りへの便宜です。その後、Number(...) でパースされます。
他のすべての組み込み関数と異なり、to_number はパースできない入力に対して、null のような番兵値を返すのではなく例外を投げます。クリーン後の文字列が空である場合、または Number(...) が有限値を生成しない場合(NaN/Infinity/-Infinity)、ExprEvalError を投げます: to_number() could not parse "<original string>"
${{ to_number(steps.lookup.output.priceText) }}
${{ to_number("1,234.56") }}
エッジケース
  • to_number("1,234.56")1234.56。カンマは文字列内のどこにあっても取り除かれます。桁区切りグループだけではないため、to_number("1,2,3")123 にもなります(位置の検証はありません)。
  • to_number("") は例外を投げます(trim とカンマ除去の後に空)。
  • to_number("abc") は例外を投げます。
  • to_number(" 42 ")42(周囲の空白は先に trim されます)。
  • 通貨記号、単位、ロケール固有の小数区切りは処理されません。先頭の "$" や、ヨーロッパ式の "1.234,56" のような数値はパースに失敗して例外を投げます。そのような文字は先に replace で取り除いてください。

unique

unique(arr: array) -> array
重複要素を取り除いた新しい配列を返し、最初に出現した順序を保持します。重複排除には、==containsmap/filter の比較と同じ構造的な deepEqual 関数を使います。参照等価でも JSON 文字列キーでもありません。そのため、別参照にある構造的に同一の2つのオブジェクトは重複として扱われます。
${{ unique(steps.lookup.output.tags) }}
${{ unique(map(steps.lookup.output.results, item.category)) }}
エッジケース
  • 引数は配列でなければなりません。そうでない場合は ExprEvalError を投げます: unique() expects an array
  • unique([{a:1}, {a:1}])[{a:1}]。deep-equal なオブジェクトは、別々の参照であっても1つに畳み込まれます。
  • 実装は O(n²) です(要素ごとに seen.some(...))。典型的な手順出力サイズでは問題ありませんが、Tool ではなく式の中で非常に大きな配列を重複排除する場合は知っておく価値があります。
  • unique([])[]

共有セマンティクス

上記の複数の組み込み関数に共通する挙動がいくつかあります。関数ごとに繰り返すのではなく、ここで一度だけまとめます。
文字列を消費するほとんどの組み込み関数は、文字列以外の引数を同じ強制変換規則に通します。
  • string → それ自身。変更なし。
  • number / booleanString(v)(例: 42"42"true"true")。
  • null → リテラル文字列 "null"
  • object / array → JSON.stringify(v)
json() が唯一の例外です。常に JSON シリアライズするため、文字列引数は裸の文字列ではなく JSON クォートされて戻ります。
  • null → falsy。
  • boolean → それ自身。
  • number0 のときだけ falsy。
  • string → 空文字列("")のときだけ falsy。
  • array または object → []{} であっても常に truthy
2つの値は、次の場合に deep-equal です。=== で等しい場合。または、両方が non-null の配列で、長さが等しく、対応する要素がそれぞれ deep-equal である場合。または、両方が non-null で配列ではないオブジェクトであり、同じキー集合を持ち、対応する値がそれぞれ deep-equal である場合。JS の typeof が異なる値は決して等しくありません(ただし null/null の場合は === によって処理されます)。
4つの組み込み関数は、文字列を UTF-16 コードユニットではなく Unicode コードポイントの配列として扱います(spread の [...v] によります)。これにより、マルチバイト文字(アクセント付き文字、ほとんどの CJK、多くの絵文字)が、lensplit("", "")slicenth のすべてで一貫して1つの「文字」として数えられます。そのため、ある関数の結果を別の関数に正しく合成できます(例: len で境界付けされたループが返したインデックスで nth する場合)。

関連

式言語

参照、演算子、リテラル、および式がどのようにコンパイルされチェックされるか。

制御フロー

whenbranchforeachmap/filter の代替ではない、手順レベルの構造です。

シークレット

どの組み込み関数も secret. 参照に触れられない理由と、secret_leak 診断がそれをどのように強制するか。