import { stringify } from "./expressions"; import type { ExprValue } from "./expressions"; import type { JobSpec } from "./spec"; const MAX_MATRIX_COMBINATIONS = 64; export function expandMatrix(spec: JobSpec): Array> { const matrix = spec.strategy?.matrix; if (!matrix) return [{}]; const { include, exclude, ...axes } = matrix; let combos: Array> = [{}]; for (const [axis, values] of Object.entries(axes)) { if (!Array.isArray(values)) continue; combos = combos.flatMap((combo) => values.map((value) => ({ ...combo, [axis]: value }))); } if (Object.keys(axes).length === 0) combos = []; const matches = (combo: Record, row: Record) => Object.entries(row).every(([key, value]) => combo[key] === value); combos = combos.filter((combo) => !(exclude ?? []).some((row) => matches(combo, row))); for (const row of include ?? []) { const target = combos.find((combo) => Object.keys(axes).every((axis) => !(axis in row) || combo[axis] === row[axis]), ); if (target && Object.keys(row).some((key) => key in axes)) Object.assign(target, row); else combos.push({ ...row }); } if (combos.length > MAX_MATRIX_COMBINATIONS) throw new Error(`matrix expands to more than ${MAX_MATRIX_COMBINATIONS} jobs`); return combos.length > 0 ? combos : [{}]; } export function matrixLabel(values: Record): string { return Object.values(values).map(stringify).join(", "); }