397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
2.6 KiB
JavaScript
54 lines
2.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* mutate-operators (Level B) — чистый генератор валидных операторных мутантов JS-исходника.
|
|
* Текстовая замена операторов (без AST-зависимости): каждый оператор флипается на свою пару
|
|
* по каждому вхождению, по одному мутанту за вхождение. Цель — НЕ исчерпать пространство, а
|
|
* получить горсть валидных мутантов, чтобы тест критерия имел шанс кого-то «убить». Невалидные/
|
|
* эквивалентные мутанты (задели строку/коммент) отсеивает baseline+run в mutate-runner (выживший/
|
|
* load-error). Детерминирован (стабильный порядок), dedup, cap (ограничение времени гейта, SE-LB-13).
|
|
* AST-точность — опциональное усиление (судья М4 / отдельный план).
|
|
*
|
|
* Операторы выбраны без capture-групп → замена n-го вхождения тривиальна и корректна.
|
|
* Пары не перекрываются: /===/ не матчит '!==' (две равны), /!==/ не матчит '===' (три равны),
|
|
* />=/ не матчит '=>' (стрелка = '=' затем '>'; '>=' = '>' затем '=').
|
|
*/
|
|
|
|
// [искать (global regex), заменить (литерал, без $-групп)].
|
|
const OPS = [
|
|
[/===/g, '!=='],
|
|
[/!==/g, '==='],
|
|
[/&&/g, '||'],
|
|
[/\|\|/g, '&&'],
|
|
[/\btrue\b/g, 'false'],
|
|
[/\bfalse\b/g, 'true'],
|
|
[/>=/g, '>'],
|
|
[/<=/g, '<'],
|
|
];
|
|
|
|
export const MUTATION_OPERATORS = { cap: 40 };
|
|
|
|
/** Заменить ТОЛЬКО n-е вхождение global-regex на литерал; остальные оставить. */
|
|
function replaceNth(source, re, replacement, nth) {
|
|
let i = -1;
|
|
return source.replace(re, (m) => {
|
|
i += 1;
|
|
return i === nth ? replacement : m;
|
|
});
|
|
}
|
|
|
|
export function generateMutants(source = '') {
|
|
const out = [];
|
|
const seen = new Set([source]);
|
|
for (const [re, rep] of OPS) {
|
|
const count = (source.match(re) || []).length;
|
|
for (let n = 0; n < count; n += 1) {
|
|
const mutated = replaceNth(source, new RegExp(re.source, re.flags), rep, n);
|
|
if (mutated === source || seen.has(mutated)) continue;
|
|
seen.add(mutated);
|
|
out.push({ label: `${re.source}->${rep}#${n}`, mutated });
|
|
if (out.length >= MUTATION_OPERATORS.cap) return out;
|
|
}
|
|
}
|
|
return out;
|
|
}
|