@systemfsoftware/stryker-js 10.1.1 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/{Run.schema-BsSOfQnD.d.mts → Run.schema-B-Pi3bCB.d.mts} +1 -1
- package/dist/{Run.schema-B_KpPeBA.mjs → Run.schema-Ba34IwAY.mjs} +688 -29
- package/dist/{compiler-Faeg70AC.mjs → compiler-BTpMWGqK.mjs} +1 -170
- package/dist/{compiler-Dc7TYMb_.mjs → compiler-CEwQzMxZ.mjs} +1 -170
- package/dist/config.d.mts +1 -1
- package/dist/dist-CjdAPjrJ.mjs +1430 -0
- package/dist/dist-Cpq7Esc3.mjs +17404 -0
- package/dist/dist-DsmXFb2_.mjs +17404 -0
- package/dist/events.d.mts +1 -1
- package/dist/events.mjs +1 -1
- package/dist/{index-CogNSD0V.d.mts → index-tt2EziOT.d.mts} +2 -0
- package/dist/index.d.mts +9 -26
- package/dist/index.mjs +2 -2
- package/dist/main.mjs +6800 -760
- package/dist/{mutation-test.cell-DS86DvC9.d.mts → mutation-test.cell-Dq23b2NP.d.mts} +3 -2
- package/dist/promises.d.mts +2 -2
- package/dist/promises.mjs +1 -1
- package/dist/sourcemap-codec-qFD3eFBj.mjs +186 -0
- package/dist/{src-BkTsNvl0.mjs → src-CcqEZJIY.mjs} +144 -93
- package/package.json +18 -9
|
@@ -7,6 +7,7 @@ import * as S from "effect/Schema";
|
|
|
7
7
|
import * as Predicate from "effect/Predicate";
|
|
8
8
|
import * as Arr from "effect/Array";
|
|
9
9
|
import { Effect, Schema, SchemaGetter, SchemaTransformation } from "effect";
|
|
10
|
+
import * as Bool from "effect/Boolean";
|
|
10
11
|
import * as Rpc from "effect/unstable/rpc/Rpc";
|
|
11
12
|
import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
|
|
12
13
|
import * as RpcMiddleware from "effect/unstable/rpc/RpcMiddleware";
|
|
@@ -2659,7 +2660,8 @@ const IgnorerSchema = S.Unknown;
|
|
|
2659
2660
|
S.Struct({
|
|
2660
2661
|
excludedMutations: S.Array(S.String),
|
|
2661
2662
|
ignorers: S.Array(IgnorerSchema),
|
|
2662
|
-
noHeader: S.optional(S.Boolean)
|
|
2663
|
+
noHeader: S.optional(S.Boolean),
|
|
2664
|
+
optInMutations: S.optional(S.Array(S.String))
|
|
2663
2665
|
});
|
|
2664
2666
|
var InstrumentResult = class extends S.TaggedClass()("InstrumentResult", {
|
|
2665
2667
|
files: S.Array(FileSchema),
|
|
@@ -2968,6 +2970,22 @@ function unaryExpression(operator, argument, loc) {
|
|
|
2968
2970
|
prefix: true
|
|
2969
2971
|
}, loc);
|
|
2970
2972
|
}
|
|
2973
|
+
function binaryExpression(operator, left, right, loc) {
|
|
2974
|
+
return mark({
|
|
2975
|
+
type: "BinaryExpression",
|
|
2976
|
+
operator,
|
|
2977
|
+
left,
|
|
2978
|
+
right
|
|
2979
|
+
}, loc);
|
|
2980
|
+
}
|
|
2981
|
+
function logicalExpression(operator, left, right, loc) {
|
|
2982
|
+
return mark({
|
|
2983
|
+
type: "LogicalExpression",
|
|
2984
|
+
operator,
|
|
2985
|
+
left,
|
|
2986
|
+
right
|
|
2987
|
+
}, loc);
|
|
2988
|
+
}
|
|
2971
2989
|
function updateExpression(operator, argument, prefix, loc) {
|
|
2972
2990
|
return mark({
|
|
2973
2991
|
type: "UpdateExpression",
|
|
@@ -3606,7 +3624,7 @@ const loadWalkerModule = (specifier, fileName, cause) => Effect$1.gen(function*
|
|
|
3606
3624
|
return walk;
|
|
3607
3625
|
});
|
|
3608
3626
|
const parseSvelte = (text, fileName, context) => Effect$1.gen(function* () {
|
|
3609
|
-
const { parse: svelteParse, preprocess, VERSION } = yield* Effect$1.promise(() => import("./compiler-
|
|
3627
|
+
const { parse: svelteParse, preprocess, VERSION } = yield* Effect$1.promise(() => import("./compiler-BTpMWGqK.mjs"));
|
|
3610
3628
|
if (!isAtLeast(VERSION, MINIMUM_SVELTE_VERSION)) return yield* SvelteVersionNotSupported.make({
|
|
3611
3629
|
version: VERSION,
|
|
3612
3630
|
fileName,
|
|
@@ -5585,14 +5603,14 @@ function isTSType(node) {
|
|
|
5585
5603
|
function isNodeOfKind(node, kind) {
|
|
5586
5604
|
return node.type === kind;
|
|
5587
5605
|
}
|
|
5588
|
-
const FUNCTION_KINDS = {
|
|
5606
|
+
const FUNCTION_KINDS$1 = {
|
|
5589
5607
|
FunctionDeclaration: true,
|
|
5590
5608
|
FunctionExpression: true,
|
|
5591
5609
|
TSDeclareFunction: true,
|
|
5592
5610
|
TSEmptyBodyFunctionExpression: true
|
|
5593
5611
|
};
|
|
5594
5612
|
function isFunctionNode(node) {
|
|
5595
|
-
return FUNCTION_KINDS[node.type] === true;
|
|
5613
|
+
return FUNCTION_KINDS$1[node.type] === true;
|
|
5596
5614
|
}
|
|
5597
5615
|
function isAssignmentPattern(node) {
|
|
5598
5616
|
return node.type === "AssignmentPattern";
|
|
@@ -6088,6 +6106,583 @@ function errorToString(error) {
|
|
|
6088
6106
|
}
|
|
6089
6107
|
Object.freeze({ NoSuchFileOrDirectory: "ENOENT" });
|
|
6090
6108
|
/**
|
|
6109
|
+
* EffectCall — the resolution front half the opt-in concurrency mutators share.
|
|
6110
|
+
*
|
|
6111
|
+
* Given a visited node it answers: is this a covered Effect call (R1); through
|
|
6112
|
+
* which module and export did its callee resolve; which call form does its
|
|
6113
|
+
* argument count select (KTD10); does a data-last form sit where the replacement
|
|
6114
|
+
* function is contextually typed (R4); and how can each `effect` module the
|
|
6115
|
+
* replacement needs be reached from the file's own imports (KTD3). It decides
|
|
6116
|
+
* nothing about a replacement: a mutator asks for module access through the
|
|
6117
|
+
* description's `moduleAccess`, and gets none when the file has no unshadowed
|
|
6118
|
+
* binding for that module (R2).
|
|
6119
|
+
*
|
|
6120
|
+
* Pure. One expression per decision, no I/O, no throwing. The import table is
|
|
6121
|
+
* built once per Program and memoised in a WeakMap, because every visited node
|
|
6122
|
+
* asks for it and a file's imports never change mid-parse (KTD4).
|
|
6123
|
+
*/
|
|
6124
|
+
const MODULE_NAMES = [
|
|
6125
|
+
"Effect",
|
|
6126
|
+
"Ref",
|
|
6127
|
+
"Semaphore",
|
|
6128
|
+
"SynchronizedRef"
|
|
6129
|
+
];
|
|
6130
|
+
const EFFECT_SOURCE = "effect";
|
|
6131
|
+
const FUNCTION_SOURCE = "effect/Function";
|
|
6132
|
+
const DATA_FIRST = "data-first";
|
|
6133
|
+
const DATA_LAST_PIPE_ARG = "data-last-pipe-arg";
|
|
6134
|
+
const DATA_LAST_PIPE_METHOD = "data-last-pipe-method";
|
|
6135
|
+
const DATA_LAST_IMMEDIATE = "data-last-immediate";
|
|
6136
|
+
const PIPED_REFERENCE = "piped-reference";
|
|
6137
|
+
const NO_ARGUMENTS = Object.freeze([]);
|
|
6138
|
+
const ARITIES = Object.freeze({
|
|
6139
|
+
"Ref.modify": {
|
|
6140
|
+
dataFirst: [2],
|
|
6141
|
+
dataLast: 1
|
|
6142
|
+
},
|
|
6143
|
+
"Ref.modifySome": {
|
|
6144
|
+
dataFirst: [2],
|
|
6145
|
+
dataLast: 1
|
|
6146
|
+
},
|
|
6147
|
+
"Ref.update": {
|
|
6148
|
+
dataFirst: [2],
|
|
6149
|
+
dataLast: 1
|
|
6150
|
+
},
|
|
6151
|
+
"Ref.updateSome": {
|
|
6152
|
+
dataFirst: [2],
|
|
6153
|
+
dataLast: 1
|
|
6154
|
+
},
|
|
6155
|
+
"Ref.updateAndGet": {
|
|
6156
|
+
dataFirst: [2],
|
|
6157
|
+
dataLast: 1
|
|
6158
|
+
},
|
|
6159
|
+
"Ref.getAndUpdate": {
|
|
6160
|
+
dataFirst: [2],
|
|
6161
|
+
dataLast: 1
|
|
6162
|
+
},
|
|
6163
|
+
"SynchronizedRef.modify": {
|
|
6164
|
+
dataFirst: [2],
|
|
6165
|
+
dataLast: 1
|
|
6166
|
+
},
|
|
6167
|
+
"SynchronizedRef.modifySome": {
|
|
6168
|
+
dataFirst: [2],
|
|
6169
|
+
dataLast: 1
|
|
6170
|
+
},
|
|
6171
|
+
"SynchronizedRef.update": {
|
|
6172
|
+
dataFirst: [2],
|
|
6173
|
+
dataLast: 1
|
|
6174
|
+
},
|
|
6175
|
+
"SynchronizedRef.updateSome": {
|
|
6176
|
+
dataFirst: [2],
|
|
6177
|
+
dataLast: 1
|
|
6178
|
+
},
|
|
6179
|
+
"SynchronizedRef.updateAndGet": {
|
|
6180
|
+
dataFirst: [2],
|
|
6181
|
+
dataLast: 1
|
|
6182
|
+
},
|
|
6183
|
+
"SynchronizedRef.getAndUpdate": {
|
|
6184
|
+
dataFirst: [2],
|
|
6185
|
+
dataLast: 1
|
|
6186
|
+
},
|
|
6187
|
+
"Semaphore.withPermits": {
|
|
6188
|
+
dataFirst: [3],
|
|
6189
|
+
dataLast: 2
|
|
6190
|
+
},
|
|
6191
|
+
"Semaphore.withPermit": {
|
|
6192
|
+
dataFirst: [2],
|
|
6193
|
+
dataLast: 1
|
|
6194
|
+
},
|
|
6195
|
+
"Effect.ensuring": {
|
|
6196
|
+
dataFirst: [2],
|
|
6197
|
+
dataLast: 1
|
|
6198
|
+
},
|
|
6199
|
+
"Effect.onExit": {
|
|
6200
|
+
dataFirst: [2],
|
|
6201
|
+
dataLast: 1
|
|
6202
|
+
},
|
|
6203
|
+
"Effect.onError": {
|
|
6204
|
+
dataFirst: [2],
|
|
6205
|
+
dataLast: 1
|
|
6206
|
+
},
|
|
6207
|
+
"Effect.onInterrupt": {
|
|
6208
|
+
dataFirst: [2],
|
|
6209
|
+
dataLast: 1
|
|
6210
|
+
},
|
|
6211
|
+
"Effect.uninterruptible": { dataFirst: [1] },
|
|
6212
|
+
"Effect.uninterruptibleMask": { dataFirst: [1] },
|
|
6213
|
+
"Effect.acquireRelease": { dataFirst: [2, 3] },
|
|
6214
|
+
"Effect.acquireUseRelease": { dataFirst: [3] }
|
|
6215
|
+
});
|
|
6216
|
+
const EMPTY_IMPORT_TABLE = Object.freeze({
|
|
6217
|
+
moduleBindings: /* @__PURE__ */ new Map(),
|
|
6218
|
+
namespaces: /* @__PURE__ */ new Map(),
|
|
6219
|
+
bareFunctions: /* @__PURE__ */ new Map(),
|
|
6220
|
+
pipeBindings: /* @__PURE__ */ new Set()
|
|
6221
|
+
});
|
|
6222
|
+
const importTables = /* @__PURE__ */ new WeakMap();
|
|
6223
|
+
const importTableFor = (program) => Option.getOrElse(Option.fromNullishOr(importTables.get(program)), () => rememberImportTable(program));
|
|
6224
|
+
function rememberImportTable(program) {
|
|
6225
|
+
const table = buildImportTable(program);
|
|
6226
|
+
importTables.set(program, table);
|
|
6227
|
+
return table;
|
|
6228
|
+
}
|
|
6229
|
+
const buildImportTable = (program) => Arr.reduce(Arr.flatMap(Arr.filter(program.body, isImportDeclaration$1), importContributions), EMPTY_IMPORT_TABLE, applyContribution);
|
|
6230
|
+
const withEntry = (entries, key, value) => new Map([...entries, [key, value]]);
|
|
6231
|
+
const withMember = (members, value) => /* @__PURE__ */ new Set([...members, value]);
|
|
6232
|
+
const applyContribution = (table, contribution) => Match.value(contribution).pipe(Match.when((candidate) => candidate.kind === "module", (moduleBinding) => ({
|
|
6233
|
+
...table,
|
|
6234
|
+
moduleBindings: withEntry(table.moduleBindings, moduleBinding.local, moduleBinding.module)
|
|
6235
|
+
})), Match.when((candidate) => candidate.kind === "namespace", (namespaceBinding) => ({
|
|
6236
|
+
...table,
|
|
6237
|
+
namespaces: withEntry(table.namespaces, namespaceBinding.local, namespaceBinding.binding)
|
|
6238
|
+
})), Match.when((candidate) => candidate.kind === "bareFunction", (bareFunction) => ({
|
|
6239
|
+
...table,
|
|
6240
|
+
bareFunctions: withEntry(table.bareFunctions, bareFunction.local, {
|
|
6241
|
+
module: bareFunction.module,
|
|
6242
|
+
exportName: bareFunction.exportName
|
|
6243
|
+
})
|
|
6244
|
+
})), Match.orElse((pipeBinding) => ({
|
|
6245
|
+
...table,
|
|
6246
|
+
pipeBindings: withMember(table.pipeBindings, pipeBinding.local)
|
|
6247
|
+
})));
|
|
6248
|
+
const importContributions = (declaration) => Option.toArray(onlyWhen(declaration.importKind !== "type", declaration)).flatMap((imported) => Arr.flatMap(imported.specifiers, (specifier) => Option.toArray(specifierContribution(imported.source.value, specifier))));
|
|
6249
|
+
const specifierContribution = (source, specifier) => Match.value(specifier).pipe(Match.when(isNamedImportSpecifier, (named) => namedSpecifierContribution(source, named)), Match.when(isNamespaceImportSpecifier, (namespace) => namespaceSpecifierContribution(source, namespace)), Match.orElse(() => Option.none()));
|
|
6250
|
+
const namedSpecifierContribution = (source, specifier) => onlyWhen(specifier.importKind !== "type", specifier).pipe(Option.flatMap((imported) => namedContribution(source, moduleExportName(imported.imported), imported.local.name)));
|
|
6251
|
+
const namedContribution = (source, importedName, localName) => Match.value(source).pipe(Match.when((candidate) => candidate === EFFECT_SOURCE, () => effectRootContribution(importedName, localName)), Match.when((candidate) => candidate === FUNCTION_SOURCE, () => pipeContribution(importedName, localName)), Match.orElse(() => Option.map(moduleNameFromSource(source), (module) => bareFunctionContribution(localName, module, importedName))));
|
|
6252
|
+
const effectRootContribution = (importedName, localName) => Option.orElse(Option.map(moduleNameFromName(importedName), (module) => moduleContribution(localName, module)), () => pipeContribution(importedName, localName));
|
|
6253
|
+
const pipeContribution = (importedName, localName) => onlyWhen(importedName === "pipe", pipeContributionOf(localName));
|
|
6254
|
+
const namespaceSpecifierContribution = (source, specifier) => Option.map(namespaceBindingFor(source), (binding) => ({
|
|
6255
|
+
kind: "namespace",
|
|
6256
|
+
local: specifier.local.name,
|
|
6257
|
+
binding
|
|
6258
|
+
}));
|
|
6259
|
+
const moduleContribution = (local, module) => ({
|
|
6260
|
+
kind: "module",
|
|
6261
|
+
local,
|
|
6262
|
+
module
|
|
6263
|
+
});
|
|
6264
|
+
const bareFunctionContribution = (local, module, exportName) => ({
|
|
6265
|
+
kind: "bareFunction",
|
|
6266
|
+
local,
|
|
6267
|
+
module,
|
|
6268
|
+
exportName
|
|
6269
|
+
});
|
|
6270
|
+
const pipeContributionOf = (local) => ({
|
|
6271
|
+
kind: "pipe",
|
|
6272
|
+
local
|
|
6273
|
+
});
|
|
6274
|
+
const namespaceBindingFor = (source) => Match.value(source).pipe(Match.when((candidate) => candidate === EFFECT_SOURCE, () => Option.some({ kind: "root" })), Match.when((candidate) => candidate === FUNCTION_SOURCE, () => Option.some({ kind: "functionModule" })), Match.orElse(() => Option.map(moduleNameFromSource(source), (module) => ({
|
|
6275
|
+
kind: "module",
|
|
6276
|
+
module
|
|
6277
|
+
}))));
|
|
6278
|
+
const moduleNameFromName = (name) => Arr.findFirst(MODULE_NAMES, (module) => module === name);
|
|
6279
|
+
const moduleNameFromSource = (source) => Arr.findFirst(MODULE_NAMES, (module) => source === `${EFFECT_SOURCE}/${module}`);
|
|
6280
|
+
const resolveEffectCall = (node, context) => Option.flatMap(programOf(context), (program) => resolveIn(node, context, importTableFor(program)));
|
|
6281
|
+
const programOf = (context) => Arr.findLast(context.ancestors, isProgram);
|
|
6282
|
+
const resolveIn = (node, context, table) => Match.value(node).pipe(Match.when(isCallExpression$1, (call) => resolveCall(call, context, table)), Match.when(isMemberExpression, (member) => resolveReference(member, context, table)), Match.when(isIdentifier$1, (reference) => resolveReference(reference, context, table)), Match.orElse(() => Option.none()));
|
|
6283
|
+
const resolveCall = (call, context, table) => Option.flatMap(resolveCallee(call.callee, context, table), (callee) => Option.flatMap(spreadFreeArguments$1(call.arguments), (args) => Option.flatMap(callForm(callee, args, call, context, table), (form) => Option.some({
|
|
6284
|
+
module: callee.module,
|
|
6285
|
+
exportName: callee.exportName,
|
|
6286
|
+
form,
|
|
6287
|
+
args,
|
|
6288
|
+
moduleAccess: moduleAccessFunction(callee, context, table)
|
|
6289
|
+
}))));
|
|
6290
|
+
const resolveReference = (reference, context, table) => Option.flatMap(resolveCallee(reference, context, table), (callee) => Option.flatMap(referenceForm(reference, context, table), (form) => Option.some({
|
|
6291
|
+
module: callee.module,
|
|
6292
|
+
exportName: callee.exportName,
|
|
6293
|
+
form,
|
|
6294
|
+
args: NO_ARGUMENTS,
|
|
6295
|
+
moduleAccess: moduleAccessFunction(callee, context, table)
|
|
6296
|
+
})));
|
|
6297
|
+
const referenceForm = (reference, context, table) => Option.flatMap(parentCall(context), (parent) => Option.map(pipePosition(parent, reference, context, table), () => PIPED_REFERENCE));
|
|
6298
|
+
const spreadFreeArguments$1 = (args) => Match.value(args.some(isSpreadElement)).pipe(Match.when(true, () => Option.none()), Match.orElse(() => Option.some(args.filter(isSpreadFree))));
|
|
6299
|
+
const resolveCallee = (callee, context, table) => Match.value(callee).pipe(Match.when(isIdentifier$1, (reference) => resolveBareCallee(reference, context, table)), Match.when(isMemberExpression, (member) => resolveMemberCallee(member, context, table)), Match.orElse(() => Option.none()));
|
|
6300
|
+
const resolveBareCallee = (reference, context, table) => Option.flatMap(Option.fromNullishOr(table.bareFunctions.get(reference.name)), (binding) => Option.map(unshadowedName(reference.name, context), () => ({
|
|
6301
|
+
module: binding.module,
|
|
6302
|
+
exportName: binding.exportName,
|
|
6303
|
+
owner: Option.none()
|
|
6304
|
+
})));
|
|
6305
|
+
const resolveMemberCallee = (member, context, table) => Option.flatMap(staticMemberName(member), (exportName) => Option.map(resolveModuleObject(member.object, context, table), (owner) => ({
|
|
6306
|
+
module: owner.module,
|
|
6307
|
+
exportName,
|
|
6308
|
+
owner: Option.some(owner)
|
|
6309
|
+
})));
|
|
6310
|
+
const resolveModuleObject = (expression, context, table) => Match.value(expression).pipe(Match.when(isIdentifier$1, (reference) => identifierModuleObject(reference, context, table)), Match.when(isMemberExpression, (member) => namespacedModuleObject(member, context, table)), Match.orElse(() => Option.none()));
|
|
6311
|
+
const identifierModuleObject = (reference, context, table) => Option.orElse(Option.flatMap(Option.fromNullishOr(table.moduleBindings.get(reference.name)), (module) => Option.map(unshadowedName(reference.name, context), () => ({
|
|
6312
|
+
module,
|
|
6313
|
+
access: reference
|
|
6314
|
+
}))), () => Option.flatMap(namespaceOf(reference, context, table), (binding) => Option.map(moduleOf(binding), (module) => ({
|
|
6315
|
+
module,
|
|
6316
|
+
access: reference
|
|
6317
|
+
}))));
|
|
6318
|
+
const namespacedModuleObject = (member, context, table) => Option.flatMap(staticMemberName(member), (moduleName) => Option.flatMap(namespaceOf(member.object, context, table), (binding) => Match.value(binding).pipe(Match.when(isRootNamespace, () => Option.map(moduleNameFromName(moduleName), (module) => ({
|
|
6319
|
+
module,
|
|
6320
|
+
access: member
|
|
6321
|
+
}))), Match.when(isModuleNamespace, (moduleNamespace) => Option.map(onlyWhen(moduleNamespace.module === moduleName, member), (access) => ({
|
|
6322
|
+
module: moduleNamespace.module,
|
|
6323
|
+
access
|
|
6324
|
+
}))), Match.orElse(() => Option.none()))));
|
|
6325
|
+
const isRootNamespace = (binding) => binding.kind === "root";
|
|
6326
|
+
const moduleOf = (binding) => Match.value(binding).pipe(Match.when(isModuleNamespace, (moduleNamespace) => Option.some(moduleNamespace.module)), Match.orElse(() => Option.none()));
|
|
6327
|
+
const isModuleNamespace = (binding) => binding.kind === "module";
|
|
6328
|
+
const namespaceOf = (expression, context, table) => Match.value(expression).pipe(Match.when(isIdentifier$1, (reference) => Option.flatMap(Option.fromNullishOr(table.namespaces.get(reference.name)), (binding) => Option.map(unshadowedName(reference.name, context), () => binding))), Match.orElse(() => Option.none()));
|
|
6329
|
+
const callForm = (callee, args, call, context, table) => Option.flatMap(arityOf(callee), (arity) => Match.value(args.length).pipe(Match.when((count) => arity.dataFirst.includes(count), () => Option.some(DATA_FIRST)), Match.when((count) => arity.dataLast === count, () => dataLastForm(call, context, table)), Match.orElse(() => Option.none())));
|
|
6330
|
+
const arityOf = (callee) => Option.fromNullishOr(ARITIES[`${callee.module}.${callee.exportName}`]);
|
|
6331
|
+
const dataLastForm = (call, context, table) => Option.flatMap(parentCall(context), (parent) => Match.value(parent.callee === call).pipe(Match.when(true, () => Option.some(DATA_LAST_IMMEDIATE)), Match.orElse(() => Option.flatMap(pipePosition(parent, call, context, table), formForPosition))));
|
|
6332
|
+
const pipePosition = (parent, argument, context, table) => Option.flatMap(argumentIndex(parent.arguments, argument), (index) => Option.orElse(onlyWhen(isPipeMethodCall(parent), {
|
|
6333
|
+
index,
|
|
6334
|
+
callee: "method"
|
|
6335
|
+
}), () => onlyWhen(isEffectPipeCall(parent, context, table), {
|
|
6336
|
+
index,
|
|
6337
|
+
callee: "effect"
|
|
6338
|
+
})));
|
|
6339
|
+
const formForPosition = (position) => Match.value(position.callee).pipe(Match.when((callee) => callee === "method", () => Option.some(DATA_LAST_PIPE_METHOD)), Match.orElse(() => onlyWhen(position.index >= 1, DATA_LAST_PIPE_ARG)));
|
|
6340
|
+
const argumentIndex = (args, node) => Option.flatMap(Option.fromNullishOr(args.findIndex((argument) => sameNode(argument, node))), (index) => onlyWhen(index >= 0, index));
|
|
6341
|
+
const parentCall = (context) => Option.flatMap(Option.fromNullishOr(context.parent), (parent) => Match.value(parent).pipe(Match.when(isCallExpression$1, (call) => Option.some(call)), Match.orElse(() => Option.none())));
|
|
6342
|
+
const isPipeMethodCall = (parent) => Match.value(parent.callee).pipe(Match.when(isMemberExpression, (member) => Option.exists(staticMemberName(member), (name) => name === "pipe")), Match.orElse(() => false));
|
|
6343
|
+
const isEffectPipeCall = (parent, context, table) => Match.value(parent.callee).pipe(Match.when(isIdentifier$1, (reference) => Bool.and(isVisible(reference.name, context), table.pipeBindings.has(reference.name))), Match.when(isMemberExpression, (member) => Option.exists(staticMemberName(member), (name) => Bool.and(name === "pipe", isPipeNamespace(member.object, context, table)))), Match.orElse(() => false));
|
|
6344
|
+
const isPipeNamespace = (expression, context, table) => Match.value(expression).pipe(Match.when(isIdentifier$1, (reference) => Option.match(namespaceOf(expression, context, table), {
|
|
6345
|
+
onNone: () => false,
|
|
6346
|
+
onSome: (binding) => Bool.and(isPipeNamespaceBinding(binding), isVisible(reference.name, context))
|
|
6347
|
+
})), Match.orElse(() => false));
|
|
6348
|
+
const isPipeNamespaceBinding = (binding) => Match.value(binding.kind).pipe(Match.when((kind) => kind === "root", () => true), Match.when((kind) => kind === "functionModule", () => true), Match.orElse(() => false));
|
|
6349
|
+
const moduleAccessFunction = (callee, context, table) => (module) => Arr.findFirst([
|
|
6350
|
+
ownerAccessFor(callee, module),
|
|
6351
|
+
namedModuleAccess(module, context, table),
|
|
6352
|
+
rootNamespaceAccess(module, context, table),
|
|
6353
|
+
moduleNamespaceAccess(module, context, table)
|
|
6354
|
+
], Option.isSome).pipe(Option.flatten);
|
|
6355
|
+
const ownerAccessFor = (callee, module) => Option.flatMap(callee.owner, (owner) => onlyWhen(owner.module === module, owner.access));
|
|
6356
|
+
const namedModuleAccess = (module, context, table) => Option.map(Option.fromNullishOr([...table.moduleBindings].find(([local, bound]) => Bool.and(bound === module, isVisible(local, context)))), ([local]) => identifier(local));
|
|
6357
|
+
const rootNamespaceAccess = (module, context, table) => Option.map(Option.fromNullishOr([...table.namespaces].find(([local, binding]) => Bool.and(binding.kind === "root", isVisible(local, context)))), ([local]) => memberExpression(identifier(local), identifier(module), false));
|
|
6358
|
+
const moduleNamespaceAccess = (module, context, table) => Option.map(Option.fromNullishOr([...table.namespaces].find(([local, binding]) => Bool.and(Option.exists(moduleOf(binding), (bound) => bound === module), isVisible(local, context)))), ([local]) => identifier(local));
|
|
6359
|
+
const isMovableArgument = (node) => nodesOutsideFunctions(node).every((candidate) => YIELD_OR_AWAIT_KINDS[nodeType(candidate) ?? ""] !== true);
|
|
6360
|
+
const YIELD_OR_AWAIT_KINDS = {
|
|
6361
|
+
AwaitExpression: true,
|
|
6362
|
+
YieldExpression: true
|
|
6363
|
+
};
|
|
6364
|
+
const isDroppableArgument = (node) => Match.value(node).pipe(Match.when(isIdentifier$1, () => true), Match.when(isLiteral, () => true), Match.when(isThisExpression, () => true), Match.when(isFunctionLike, () => true), Match.when(isMemberExpression, (member) => isCallFreeMemberChain(member)), Match.orElse(() => false));
|
|
6365
|
+
const isCallFreeMemberChain = (member) => Match.value(member.computed).pipe(Match.when(true, () => false), Match.orElse(() => Match.value(member.object).pipe(Match.when(isIdentifier$1, () => true), Match.when(isThisExpression, () => true), Match.when(isMemberExpression, (inner) => isCallFreeMemberChain(inner)), Match.orElse(() => false))));
|
|
6366
|
+
const identifiersIn = (node) => allNodesUnder(node).flatMap((candidate) => Option.toArray(identifierText(candidate)));
|
|
6367
|
+
const freshIdentifier = (base, taken) => freeIdentifier(base, taken, 0);
|
|
6368
|
+
const freeIdentifier = (base, taken, suffix) => Match.value(taken.has(suffixedName(base, suffix))).pipe(Match.when(false, () => suffixedName(base, suffix)), Match.orElse(() => freeIdentifier(base, taken, suffix + 1)));
|
|
6369
|
+
const suffixedName = (base, suffix) => Match.value(suffix).pipe(Match.when(0, () => base), Match.orElse((count) => `${base}${count}`));
|
|
6370
|
+
const isShadowed = (name, context) => context.ancestors.some((ancestor) => scopeDeclares(ancestor, name));
|
|
6371
|
+
const isVisible = (name, context) => isShadowed(name, context) === false;
|
|
6372
|
+
const unshadowedName = (name, context) => onlyWhen(isVisible(name, context), name);
|
|
6373
|
+
const scopeDeclares = (ancestor, name) => Match.value(ancestor).pipe(Match.when(isProgram, (program) => statementsDeclare(program.body, name)), Match.when(isBlockStatement, (block) => statementsDeclare(block.body, name)), Match.when(isStaticBlock, (block) => statementsDeclare(block.body, name)), Match.when(isTSModuleBlock, (block) => statementsDeclare(block.body, name)), Match.when(isSwitchStatement, (statement) => statement.cases.some((caseClause) => statementsDeclare(caseClause.consequent, name))), Match.when(isFunctionLike, (fn) => functionDeclares(fn, name)), Match.when(isCatchClause, (clause) => patternDeclaresOr(clause.param, name)), Match.when(isForStatement, (statement) => variableDeclarationDeclaresOr(statement.init, name)), Match.when(isForInStatement, (statement) => variableDeclarationDeclaresOr(statement.left, name)), Match.when(isForOfStatement, (statement) => variableDeclarationDeclaresOr(statement.left, name)), Match.when(isClassLike, (cls) => declaresIdentifier(cls.id, name)), Match.orElse(() => false));
|
|
6374
|
+
const functionDeclares = (fn, name) => holdsAny([
|
|
6375
|
+
fn.params.some((param) => patternDeclaresOr(param, name)),
|
|
6376
|
+
declaresIdentifier(fn.id, name),
|
|
6377
|
+
blockBodyDeclaresHoistedVar(fn.body, name)
|
|
6378
|
+
]);
|
|
6379
|
+
const blockBodyDeclaresHoistedVar = (body, name) => Option.match(Option.fromNullishOr(body), {
|
|
6380
|
+
onNone: () => false,
|
|
6381
|
+
onSome: (present) => Match.value(present).pipe(Match.when(isBlockStatement, (block) => hoistedVarsDeclare(block, name)), Match.orElse(() => false))
|
|
6382
|
+
});
|
|
6383
|
+
const hoistedVarsDeclare = (block, name) => nodesOutsideFunctions(block).some((candidate) => hoistedCandidateDeclares(candidate, name));
|
|
6384
|
+
const hoistedCandidateDeclares = (candidate, name) => Match.value(candidate).pipe(Match.when(isVariableDeclaration, (declaration) => Bool.and(declaration.kind === "var", statementBindingsDeclare(declaration, name))), Match.orElse(() => false));
|
|
6385
|
+
const statementsDeclare = (statements, name) => statements.some((statement) => statementDeclares(statement, name));
|
|
6386
|
+
const statementDeclares = (statement, name) => Match.value(statement).pipe(Match.when(isVariableDeclaration, (declaration) => statementBindingsDeclare(declaration, name)), Match.when(isFunctionDeclaration, (declaration) => declaresIdentifier(declaration.id, name)), Match.when(isClassLike, (declaration) => declaresIdentifier(declaration.id, name)), Match.when(isTSEnumDeclaration, (declaration) => declaration.id.name === name), Match.when(isTSModuleDeclaration, (declaration) => moduleDeclarationDeclares(declaration, name)), Match.when(isTSImportEqualsDeclaration, (declaration) => importEqualsDeclares(declaration, name)), Match.when(isExportNamedDeclaration, (declaration) => Option.exists(Option.fromNullishOr(declaration.declaration), (inner) => statementDeclares(inner, name))), Match.orElse(() => false));
|
|
6387
|
+
const statementBindingsDeclare = (declaration, name) => declaration.declarations.some((declarator) => patternDeclaresOr(declarator.id, name));
|
|
6388
|
+
const variableDeclarationDeclaresOr = (node, name) => Option.match(Option.fromNullishOr(node), {
|
|
6389
|
+
onNone: () => false,
|
|
6390
|
+
onSome: (present) => Match.value(present).pipe(Match.when(isVariableDeclaration, (declaration) => statementBindingsDeclare(declaration, name)), Match.orElse(() => false))
|
|
6391
|
+
});
|
|
6392
|
+
const moduleDeclarationDeclares = (declaration, name) => Bool.and(declaration.body !== null, Option.exists(identifierText(declaration.id), (text) => text === name));
|
|
6393
|
+
const importEqualsDeclares = (declaration, name) => Bool.and(declaration.importKind !== "type", declaration.id.name === name);
|
|
6394
|
+
const declaresIdentifier = (id, name) => Option.exists(identifierText(id), (text) => text === name);
|
|
6395
|
+
const patternDeclaresOr = (pattern, name) => Option.match(Option.fromNullishOr(pattern), {
|
|
6396
|
+
onNone: () => false,
|
|
6397
|
+
onSome: (present) => Match.value(present).pipe(Match.when(isBindingIdentifierPattern, (binding) => binding.name === name), Match.when(isObjectBindingPattern, (object) => object.properties.some((property) => propertyDeclares(property, name))), Match.when(isArrayBindingPattern, (array) => array.elements.some((element) => patternDeclaresOr(element, name))), Match.when(isAssignmentBindingPattern, (assignment) => patternDeclaresOr(assignment.left, name)), Match.when(isBindingRestElement, (rest) => patternDeclaresOr(rest.argument, name)), Match.orElse(() => false))
|
|
6398
|
+
});
|
|
6399
|
+
const propertyDeclares = (property, name) => Match.value(property).pipe(Match.when(isBindingProperty, (binding) => patternDeclaresOr(binding.value, name)), Match.when(isBindingRestElement, (rest) => patternDeclaresOr(rest.argument, name)), Match.orElse(() => false));
|
|
6400
|
+
const isBindingIdentifierPattern = (candidate) => nodeType(candidate) === "Identifier";
|
|
6401
|
+
const isObjectBindingPattern = (candidate) => nodeType(candidate) === "ObjectPattern";
|
|
6402
|
+
const isArrayBindingPattern = (candidate) => nodeType(candidate) === "ArrayPattern";
|
|
6403
|
+
const isAssignmentBindingPattern = (candidate) => nodeType(candidate) === "AssignmentPattern";
|
|
6404
|
+
const isBindingRestElement = (candidate) => nodeType(candidate) === "RestElement";
|
|
6405
|
+
const isBindingProperty = (candidate) => nodeType(candidate) === "Property";
|
|
6406
|
+
const identifierText = (node) => Option.match(Option.fromNullishOr(node), {
|
|
6407
|
+
onNone: () => Option.none(),
|
|
6408
|
+
onSome: (present) => Match.value(present).pipe(Match.when(isNamedIdentifier, (name) => Option.some(name.name)), Match.when(isStringLiteral$1, (literal) => literalValueText(literal.value)), Match.orElse(() => Option.none()))
|
|
6409
|
+
});
|
|
6410
|
+
const literalValueText = (value) => Match.value(value).pipe(Match.when(Predicate.isString, (text) => Option.some(text)), Match.orElse(() => Option.none()));
|
|
6411
|
+
const moduleExportName = (name) => Option.getOrElse(identifierText(name), () => "");
|
|
6412
|
+
const staticMemberName = (member) => Match.value(member.computed).pipe(Match.when(false, () => identifierText(member.property)), Match.orElse(() => Option.none()));
|
|
6413
|
+
const nodesOutsideFunctions = (root) => {
|
|
6414
|
+
const collected = [];
|
|
6415
|
+
traverse(root, { enter(path) {
|
|
6416
|
+
collected.push(path.node);
|
|
6417
|
+
pruneAtFunction(path);
|
|
6418
|
+
} });
|
|
6419
|
+
return collected;
|
|
6420
|
+
};
|
|
6421
|
+
const allNodesUnder = (root) => {
|
|
6422
|
+
const collected = [];
|
|
6423
|
+
traverse(root, { enter(path) {
|
|
6424
|
+
collected.push(path.node);
|
|
6425
|
+
} });
|
|
6426
|
+
return collected;
|
|
6427
|
+
};
|
|
6428
|
+
const pruneAtFunction = (path) => Option.match(onlyWhen(isFunctionLike(path.node), path), {
|
|
6429
|
+
onNone: () => void 0,
|
|
6430
|
+
onSome: (atFunction) => atFunction.skip()
|
|
6431
|
+
});
|
|
6432
|
+
const moduleCall = (module, property, args) => callExpression(memberExpression(module, identifier(property), false), args);
|
|
6433
|
+
const onlyWhen = (holds, value) => Match.value(holds).pipe(Match.when(true, () => Option.some(value)), Match.orElse(() => Option.none()));
|
|
6434
|
+
const holdsAny = (conditions) => conditions.some((condition) => condition);
|
|
6435
|
+
const sameNode = (first, second) => first === second;
|
|
6436
|
+
const FUNCTION_KINDS = {
|
|
6437
|
+
ArrowFunctionExpression: true,
|
|
6438
|
+
FunctionDeclaration: true,
|
|
6439
|
+
FunctionExpression: true
|
|
6440
|
+
};
|
|
6441
|
+
const CLASS_KINDS = {
|
|
6442
|
+
ClassDeclaration: true,
|
|
6443
|
+
ClassExpression: true
|
|
6444
|
+
};
|
|
6445
|
+
const isFunctionLike = (candidate) => FUNCTION_KINDS[nodeType(candidate) ?? ""] === true;
|
|
6446
|
+
const isClassLike = (candidate) => CLASS_KINDS[nodeType(candidate) ?? ""] === true;
|
|
6447
|
+
const isProgram = (candidate) => nodeType(candidate) === "Program";
|
|
6448
|
+
const isBlockStatement = (candidate) => nodeType(candidate) === "BlockStatement";
|
|
6449
|
+
const isStaticBlock = (candidate) => nodeType(candidate) === "StaticBlock";
|
|
6450
|
+
const isTSModuleBlock = (candidate) => nodeType(candidate) === "TSModuleBlock";
|
|
6451
|
+
const isSwitchStatement = (candidate) => nodeType(candidate) === "SwitchStatement";
|
|
6452
|
+
const isCatchClause = (candidate) => nodeType(candidate) === "CatchClause";
|
|
6453
|
+
const isForStatement = (candidate) => nodeType(candidate) === "ForStatement";
|
|
6454
|
+
const isForInStatement = (candidate) => nodeType(candidate) === "ForInStatement";
|
|
6455
|
+
const isForOfStatement = (candidate) => nodeType(candidate) === "ForOfStatement";
|
|
6456
|
+
const isVariableDeclaration = (candidate) => nodeType(candidate) === "VariableDeclaration";
|
|
6457
|
+
const isFunctionDeclaration = (candidate) => nodeType(candidate) === "FunctionDeclaration";
|
|
6458
|
+
const isTSEnumDeclaration = (candidate) => nodeType(candidate) === "TSEnumDeclaration";
|
|
6459
|
+
const isTSModuleDeclaration = (candidate) => nodeType(candidate) === "TSModuleDeclaration";
|
|
6460
|
+
const isTSImportEqualsDeclaration = (candidate) => nodeType(candidate) === "TSImportEqualsDeclaration";
|
|
6461
|
+
const isExportNamedDeclaration = (candidate) => nodeType(candidate) === "ExportNamedDeclaration";
|
|
6462
|
+
const isImportDeclaration$1 = (candidate) => nodeType(candidate) === "ImportDeclaration";
|
|
6463
|
+
const isNamedImportSpecifier = (candidate) => nodeType(candidate) === "ImportSpecifier";
|
|
6464
|
+
const isNamespaceImportSpecifier = (candidate) => nodeType(candidate) === "ImportNamespaceSpecifier";
|
|
6465
|
+
const isCallExpression$1 = (candidate) => nodeType(candidate) === "CallExpression";
|
|
6466
|
+
const isMemberExpression = (candidate) => nodeType(candidate) === "MemberExpression";
|
|
6467
|
+
const isIdentifier$1 = (candidate) => nodeType(candidate) === "Identifier";
|
|
6468
|
+
const isNamedIdentifier = (candidate) => nodeType(candidate) === "Identifier";
|
|
6469
|
+
const isThisExpression = (candidate) => nodeType(candidate) === "ThisExpression";
|
|
6470
|
+
const isLiteral = (candidate) => nodeType(candidate) === "Literal";
|
|
6471
|
+
const isStringLiteral$1 = (candidate) => nodeType(candidate) === "Literal";
|
|
6472
|
+
const isSpreadElement = (argument) => nodeType(argument) === "SpreadElement";
|
|
6473
|
+
const isSpreadFree = (argument) => nodeType(argument) !== "SpreadElement";
|
|
6474
|
+
const NO_MUTANTS$3 = [];
|
|
6475
|
+
const ATOMIC_UPDATE_SPLIT_MODULES = ["Ref", "SynchronizedRef"];
|
|
6476
|
+
const ATOMIC_UPDATE_SPLIT_OPERATIONS = [
|
|
6477
|
+
"modify",
|
|
6478
|
+
"modifySome",
|
|
6479
|
+
"update",
|
|
6480
|
+
"updateSome",
|
|
6481
|
+
"updateAndGet",
|
|
6482
|
+
"getAndUpdate"
|
|
6483
|
+
];
|
|
6484
|
+
const atomicUpdateSplitMutator = (node, context) => Option.match(resolveEffectCall(node, context), {
|
|
6485
|
+
onNone: () => NO_MUTANTS$3,
|
|
6486
|
+
onSome: (call) => Option.toArray(atomicUpdateSplitReplacement(call))
|
|
6487
|
+
});
|
|
6488
|
+
const atomicUpdateSplitReplacement = (call) => Option.flatMap(splitOperation(call), (operation) => Option.some(replacementExpression$1(operation)));
|
|
6489
|
+
const splitOperation = (call) => Match.value(call).pipe(Match.when(isAtomicUpdateSplitOperation, (covered) => splitOperationOf(covered)), Match.orElse(() => Option.none()));
|
|
6490
|
+
const isAtomicUpdateSplitOperation = (call) => Bool.and(included(ATOMIC_UPDATE_SPLIT_MODULES, call.module), included(ATOMIC_UPDATE_SPLIT_OPERATIONS, call.exportName));
|
|
6491
|
+
const splitOperationOf = (call) => Option.flatMap(moduleBindings(call), (bindings) => Option.flatMap(splitArguments$1(call), (args) => Option.some({
|
|
6492
|
+
effectModule: bindings.effectModule,
|
|
6493
|
+
operationModule: bindings.operationModule,
|
|
6494
|
+
exportName: call.exportName,
|
|
6495
|
+
ref: args.ref,
|
|
6496
|
+
f: args.f,
|
|
6497
|
+
binders: freshBinders$1(takenNames$2(call, bindings, args.f))
|
|
6498
|
+
})));
|
|
6499
|
+
const splitArguments$1 = (call) => Match.value(call.form).pipe(Match.when((form) => form === "data-first", () => dataFirstArguments$1(call)), Match.when((form) => form === "piped-reference", () => Option.none()), Match.orElse(() => dataLastArguments(call)));
|
|
6500
|
+
const dataFirstArguments$1 = (call) => Option.flatMap(Arr.get(call.args, 0), (ref) => Option.flatMap(Arr.get(call.args, 1), (f) => onlyWhen(Bool.and(isMovableArgument(ref), isMovableArgument(f)), {
|
|
6501
|
+
ref: Option.some(cloneNode(ref)),
|
|
6502
|
+
f: cloneNode(f)
|
|
6503
|
+
})));
|
|
6504
|
+
const dataLastArguments = (call) => Option.flatMap(Arr.get(call.args, 0), (f) => onlyWhen(isMovableArgument(f), {
|
|
6505
|
+
ref: Option.none(),
|
|
6506
|
+
f: cloneNode(f)
|
|
6507
|
+
}));
|
|
6508
|
+
const moduleBindings = (call) => Option.flatMap(call.moduleAccess("Effect"), (effectModule) => Option.map(call.moduleAccess(call.module), (operationModule) => ({
|
|
6509
|
+
effectModule,
|
|
6510
|
+
operationModule
|
|
6511
|
+
})));
|
|
6512
|
+
const takenNames$2 = (call, bindings, f) => /* @__PURE__ */ new Set([
|
|
6513
|
+
...call.args.flatMap((argument) => identifiersIn(argument)),
|
|
6514
|
+
...identifiersIn(f),
|
|
6515
|
+
...identifiersIn(bindings.effectModule),
|
|
6516
|
+
...identifiersIn(bindings.operationModule)
|
|
6517
|
+
]);
|
|
6518
|
+
const freshBinders$1 = (taken) => ({
|
|
6519
|
+
self: freshIdentifier("self", taken),
|
|
6520
|
+
s: freshIdentifier("s", taken),
|
|
6521
|
+
snap: freshIdentifier("snap", taken),
|
|
6522
|
+
b: freshIdentifier("b", taken),
|
|
6523
|
+
a: freshIdentifier("a", taken)
|
|
6524
|
+
});
|
|
6525
|
+
const replacementExpression$1 = (operation) => Option.match(operation.ref, {
|
|
6526
|
+
onNone: () => arrowFunctionExpression([identifier(operation.binders.self)], splitBody(operation)),
|
|
6527
|
+
onSome: (ref) => moduleCall(operation.effectModule, "flatMap", [moduleCall(operation.effectModule, "succeed", [ref]), arrowFunctionExpression([identifier(operation.binders.self)], splitBody(operation))])
|
|
6528
|
+
});
|
|
6529
|
+
const splitBody = (operation) => moduleCall(operation.effectModule, "flatMap", [moduleCall(operation.operationModule, "get", [identifier(operation.binders.self)]), arrowFunctionExpression([identifier(operation.binders.s)], moduleCall(operation.effectModule, "flatMap", [moduleCall(operation.operationModule, "make", [identifier(operation.binders.s)]), arrowFunctionExpression([identifier(operation.binders.snap)], moduleCall(operation.effectModule, "flatMap", [moduleCall(operation.operationModule, operation.exportName, [identifier(operation.binders.snap), operation.f]), arrowFunctionExpression([identifier(operation.binders.b)], moduleCall(operation.effectModule, "flatMap", [memberExpression(operation.effectModule, identifier("yieldNow"), false), arrowFunctionExpression([], moduleCall(operation.effectModule, "flatMap", [moduleCall(operation.operationModule, "get", [identifier(operation.binders.snap)]), arrowFunctionExpression([identifier(operation.binders.a)], moduleCall(operation.effectModule, "as", [moduleCall(operation.operationModule, "set", [identifier(operation.binders.self), identifier(operation.binders.a)]), identifier(operation.binders.b)]))]))]))]))]))]);
|
|
6530
|
+
const included = (values, value) => values.includes(value);
|
|
6531
|
+
const NO_MUTANTS$2 = [];
|
|
6532
|
+
const COVERED_MODULE = "Effect";
|
|
6533
|
+
const TAG = "_tag";
|
|
6534
|
+
const SUCCESS_TAG = "Success";
|
|
6535
|
+
const INTERRUPT_TAG = "Interrupt";
|
|
6536
|
+
const finalizerEscapeMutator = (node, context) => Option.match(resolveEffectCall(node, context), {
|
|
6537
|
+
onNone: () => NO_MUTANTS$2,
|
|
6538
|
+
onSome: (call) => Option.toArray(replacementOf(call))
|
|
6539
|
+
});
|
|
6540
|
+
const replacementOf = (call) => Option.flatMap(onlyWhen(call.module === COVERED_MODULE, call), (covered) => Option.flatMap(covered.moduleAccess(COVERED_MODULE), (effect) => Option.flatMap(coveredForm(covered), (form) => Option.flatMap(splitArguments(covered, form), (split) => Option.flatMap(shapeOf(covered.exportName, split.rest), (shape) => Option.some(replacementExpression(call, effect, form, split, shape)))))));
|
|
6541
|
+
const replacementExpression = (call, effect, form, split, shape) => {
|
|
6542
|
+
const binders = freshBinders(takenNames$1(call, effect));
|
|
6543
|
+
const plan = {
|
|
6544
|
+
effect,
|
|
6545
|
+
self: selfExpression(split, binders),
|
|
6546
|
+
shape,
|
|
6547
|
+
binders
|
|
6548
|
+
};
|
|
6549
|
+
return placedBody(form, bodyExpression(plan), binders);
|
|
6550
|
+
};
|
|
6551
|
+
const coveredForm = (call) => Match.value(call.form).pipe(Match.when("data-first", () => Option.some("data-first")), Match.when("data-last-pipe-arg", () => Option.some("data-last")), Match.when("data-last-pipe-method", () => Option.some("data-last")), Match.when("data-last-immediate", () => Option.some("data-last")), Match.orElse(() => Option.none()));
|
|
6552
|
+
const splitArguments = (call, form) => Match.value(form).pipe(Match.when("data-first", () => dataFirstArguments(call)), Match.orElse(() => Option.some({
|
|
6553
|
+
self: Option.none(),
|
|
6554
|
+
rest: [...call.args]
|
|
6555
|
+
})));
|
|
6556
|
+
const dataFirstArguments = (call) => Option.map(Arr.get(call.args, 0), (self) => ({
|
|
6557
|
+
self: Option.some(cloneNode(self)),
|
|
6558
|
+
rest: call.args.slice(1)
|
|
6559
|
+
}));
|
|
6560
|
+
const selfExpression = (split, binders) => Option.getOrElse(split.self, () => identifier(binders.self));
|
|
6561
|
+
const shapeOf = (exportName, rest) => Match.value(exportName).pipe(Match.when("ensuring", () => finalizerShape(rest)), Match.when("onExit", () => exitShape(rest)), Match.when("onError", () => handlerShape(rest)), Match.when("onInterrupt", () => droppedHandlerShape(rest)), Match.when("acquireRelease", () => releaseShape(rest)), Match.when("acquireUseRelease", () => useReleaseShape(rest)), Match.orElse(() => Option.none()));
|
|
6562
|
+
const finalizerShape = (rest) => Option.flatMap(Arr.get(rest, 0), (fin) => onlyWhen(isMovableArgument(fin), {
|
|
6563
|
+
kind: "ensuring",
|
|
6564
|
+
fin
|
|
6565
|
+
}));
|
|
6566
|
+
const exitShape = (rest) => Option.map(Arr.get(rest, 0), (f) => ({
|
|
6567
|
+
kind: "onExit",
|
|
6568
|
+
f
|
|
6569
|
+
}));
|
|
6570
|
+
const handlerShape = (rest) => Option.map(Arr.get(rest, 0), (h) => ({
|
|
6571
|
+
kind: "onError",
|
|
6572
|
+
h
|
|
6573
|
+
}));
|
|
6574
|
+
const droppedHandlerShape = (rest) => Option.flatMap(Arr.get(rest, 0), (h) => onlyWhen(isDroppableArgument(h), {
|
|
6575
|
+
kind: "onInterrupt",
|
|
6576
|
+
h
|
|
6577
|
+
}));
|
|
6578
|
+
const releaseShape = (rest) => Option.flatMap(Arr.get(rest, 0), (rel) => Option.flatMap(droppableOptionAt(rest, 1), (optionsDroppable) => onlyWhen(Bool.and(isMovableArgument(rel), optionsDroppable), {
|
|
6579
|
+
kind: "acquireRelease",
|
|
6580
|
+
rel
|
|
6581
|
+
})));
|
|
6582
|
+
const useReleaseShape = (rest) => Option.flatMap(Arr.get(rest, 1), (rel) => Option.flatMap(Arr.get(rest, 0), (use) => Option.flatMap(releaseArityOf(rel), (releaseArity) => onlyWhen(isMovableArgument(rel), {
|
|
6583
|
+
kind: "acquireUseRelease",
|
|
6584
|
+
use,
|
|
6585
|
+
rel,
|
|
6586
|
+
releaseArity
|
|
6587
|
+
}))));
|
|
6588
|
+
const droppableOptionAt = (rest, index) => Option.match(Arr.get(rest, index), {
|
|
6589
|
+
onNone: () => Option.some(true),
|
|
6590
|
+
onSome: (argument) => onlyWhen(isDroppableArgument(argument), true)
|
|
6591
|
+
});
|
|
6592
|
+
const bodyExpression = (plan) => Match.value(plan.shape).pipe(Match.when({ kind: "ensuring" }, (shape) => moduleCall(plan.effect, "onExitIf", [
|
|
6593
|
+
plan.self,
|
|
6594
|
+
notInterruptedPredicate(plan.binders),
|
|
6595
|
+
arrowFunctionExpression([], shape.fin)
|
|
6596
|
+
])), Match.when({ kind: "onExit" }, (shape) => moduleCall(plan.effect, "onExitIf", [
|
|
6597
|
+
plan.self,
|
|
6598
|
+
notInterruptedPredicate(plan.binders),
|
|
6599
|
+
shape.f
|
|
6600
|
+
])), Match.when({ kind: "onError" }, (shape) => moduleCall(plan.effect, "onErrorIf", [
|
|
6601
|
+
plan.self,
|
|
6602
|
+
noInterruptPredicate(plan.binders),
|
|
6603
|
+
shape.h
|
|
6604
|
+
])), Match.when({ kind: "onInterrupt" }, () => plan.self), Match.when({ kind: "acquireRelease" }, (shape) => releaseBody(plan, shape)), Match.when({ kind: "acquireUseRelease" }, (shape) => useReleaseBody(plan, shape)), Match.exhaustive);
|
|
6605
|
+
const releaseBody = (plan, shape) => moduleCall(plan.effect, "flatMap", [moduleCall(plan.effect, "interruptible", [plan.self]), arrowFunctionExpression([identifier(plan.binders.a)], moduleCall(plan.effect, "acquireRelease", [moduleCall(plan.effect, "succeed", [identifier(plan.binders.a)]), shape.rel]))]);
|
|
6606
|
+
const useReleaseBody = (plan, shape) => moduleCall(plan.effect, "acquireUseRelease", [
|
|
6607
|
+
plan.self,
|
|
6608
|
+
shape.use,
|
|
6609
|
+
arrowFunctionExpression([identifier(plan.binders.a), identifier(plan.binders.exit)], conditionalExpression(notInterruptedTest(plan.binders), appliedRelease(shape.rel, plan.binders, shape.releaseArity), memberExpression(plan.effect, identifier("void"), false)))
|
|
6610
|
+
]);
|
|
6611
|
+
const appliedRelease = (rel, binders, releaseArity) => callExpression(rel, Arr.take([identifier(binders.a), identifier(binders.exit)], releaseArity));
|
|
6612
|
+
const releaseArityOf = (rel) => Match.value(rel).pipe(Match.when(isInlineFunction, plainParameterArity), Match.orElse(() => Option.none()));
|
|
6613
|
+
const isInlineFunction = (candidate) => nodeType(candidate) === "ArrowFunctionExpression" || nodeType(candidate) === "FunctionExpression";
|
|
6614
|
+
const plainParameterArity = (fn) => onlyWhen(Bool.and(fn.params.every(isPlainParameter), fn.params.length <= 2), fn.params.length);
|
|
6615
|
+
const isPlainParameter = (param) => nodeType(param) === "Identifier";
|
|
6616
|
+
const placedBody = (form, body, binders) => Match.value(form).pipe(Match.when("data-first", () => body), Match.orElse(() => arrowFunctionExpression([identifier(binders.self)], body)));
|
|
6617
|
+
const notInterruptedPredicate = (binders) => arrowFunctionExpression([identifier(binders.exit)], notInterruptedTest(binders));
|
|
6618
|
+
const notInterruptedTest = (binders) => logicalExpression("||", tagCheck(binders.exit, SUCCESS_TAG), unaryExpression("!", interruptionSome(failureReasons(binders.exit), binders.reason)));
|
|
6619
|
+
const noInterruptPredicate = (binders) => arrowFunctionExpression([identifier(binders.cause)], unaryExpression("!", interruptionSome(causeReasons(binders.cause), binders.reason)));
|
|
6620
|
+
const tagCheck = (name, tag) => binaryExpression("===", memberExpression(identifier(name), identifier(TAG), false), stringLiteral(tag));
|
|
6621
|
+
const failureReasons = (exitName) => memberExpression(memberExpression(identifier(exitName), identifier("cause"), false), identifier("reasons"), false);
|
|
6622
|
+
const causeReasons = (causeName) => memberExpression(identifier(causeName), identifier("reasons"), false);
|
|
6623
|
+
const interruptionSome = (reasons, reasonName) => callExpression(memberExpression(reasons, identifier("some"), false), [arrowFunctionExpression([identifier(reasonName)], tagCheck(reasonName, INTERRUPT_TAG))]);
|
|
6624
|
+
const takenNames$1 = (call, effect) => /* @__PURE__ */ new Set([...call.args.flatMap((argument) => identifiersIn(argument)), ...identifiersIn(effect)]);
|
|
6625
|
+
const freshBinders = (taken) => ({
|
|
6626
|
+
self: freshIdentifier("self", taken),
|
|
6627
|
+
exit: freshIdentifier("exit", taken),
|
|
6628
|
+
cause: freshIdentifier("cause", taken),
|
|
6629
|
+
reason: freshIdentifier("reason", taken),
|
|
6630
|
+
a: freshIdentifier("a", taken)
|
|
6631
|
+
});
|
|
6632
|
+
/**
|
|
6633
|
+
* SynchronizationRemoval — the R7 mutants: a removed lock and a removed mask.
|
|
6634
|
+
*
|
|
6635
|
+
* Four call shapes, each producing the wrapped effect alone:
|
|
6636
|
+
*
|
|
6637
|
+
* - `Semaphore.withPermits(sem, n, e)` and `Semaphore.withPermit(sem, e)` become
|
|
6638
|
+
* the guarded effect. The guard arguments are dropped, so they must be
|
|
6639
|
+
* droppable (KTD5); the effect itself is cloned so the mutant's tree shares
|
|
6640
|
+
* nothing with the original's.
|
|
6641
|
+
* - Their data-last forms become `(self) => self`, which the resolver only
|
|
6642
|
+
* reports where that function is contextually typed (R4, KTD9) — a piped
|
|
6643
|
+
* argument, a piped method argument, or the callee of an immediate call.
|
|
6644
|
+
* - `Effect.uninterruptible(e)` becomes `e`, and a bare `Effect.uninterruptible`
|
|
6645
|
+
* used as a pipe argument becomes `(self) => self` (KTD9).
|
|
6646
|
+
* - `Effect.uninterruptibleMask(f)` becomes `E.suspend(() => f(E.interruptible))`
|
|
6647
|
+
* (KTD7): `f` is called at run time, as the original calls it, and the restore
|
|
6648
|
+
* it receives is the identity wherever the surrounding region is interruptible.
|
|
6649
|
+
* This needs the Effect module object in scope (R2, KTD3).
|
|
6650
|
+
*
|
|
6651
|
+
* Resolution lives in `EffectCall.ts`; this module never inspects imports. It is
|
|
6652
|
+
* a pure function from a resolved call to the one mutant it implies, and yields
|
|
6653
|
+
* no mutant whenever the replacement would evaluate an argument twice or lean on
|
|
6654
|
+
* a moved argument that can yield.
|
|
6655
|
+
*/
|
|
6656
|
+
const NO_MUTANTS$1 = [];
|
|
6657
|
+
const synchronizationRemovalMutator = (node, context) => Option.match(resolveEffectCall(node, context), {
|
|
6658
|
+
onNone: () => NO_MUTANTS$1,
|
|
6659
|
+
onSome: (call) => Option.toArray(synchronizationRemovalReplacement(call))
|
|
6660
|
+
});
|
|
6661
|
+
const synchronizationRemovalReplacement = (call) => Match.value(call).pipe(Match.when(isWithPermits, withPermitsReplacement), Match.when(isWithPermit, withPermitReplacement), Match.when(isUninterruptible, uninterruptibleReplacement), Match.when(isUninterruptibleMask, uninterruptibleMaskReplacement), Match.orElse(() => Option.none()));
|
|
6662
|
+
const isWithPermits = (call) => Bool.and(call.module === "Semaphore", call.exportName === "withPermits");
|
|
6663
|
+
const isWithPermit = (call) => Bool.and(call.module === "Semaphore", call.exportName === "withPermit");
|
|
6664
|
+
const isUninterruptible = (call) => Bool.and(call.module === "Effect", call.exportName === "uninterruptible");
|
|
6665
|
+
const isUninterruptibleMask = (call) => Bool.and(call.module === "Effect", call.exportName === "uninterruptibleMask");
|
|
6666
|
+
const isDataFirst = (form) => form === "data-first";
|
|
6667
|
+
const isPipedReference = (form) => form === "piped-reference";
|
|
6668
|
+
const withPermitsReplacement = (call) => Match.value(call.form).pipe(Match.when(isDataFirst, () => whenDroppable(call, [0, 1], (guarded) => argumentReplacement(guarded, 2))), Match.orElse(() => whenDroppable(call, [0, 1], identityFunctionOf)));
|
|
6669
|
+
const withPermitReplacement = (call) => Match.value(call.form).pipe(Match.when(isDataFirst, () => whenDroppable(call, [0], (guarded) => argumentReplacement(guarded, 1))), Match.orElse(() => whenDroppable(call, [0], identityFunctionOf)));
|
|
6670
|
+
const uninterruptibleReplacement = (call) => Match.value(call.form).pipe(Match.when(isPipedReference, () => Option.some(identityFunction(call))), Match.orElse(() => argumentReplacement(call, 0)));
|
|
6671
|
+
const uninterruptibleMaskReplacement = (call) => whenMovable(call, [0], (masked) => Option.flatMap(masked.moduleAccess("Effect"), (effectModule) => Option.map(Arr.get(masked.args, 0), (f) => maskedReplacement(effectModule, f))));
|
|
6672
|
+
const maskedReplacement = (effectModule, f) => moduleCall(effectModule, "suspend", [arrowFunctionExpression([], callExpression(cloneNode(f), [memberExpression(effectModule, identifier("interruptible"), false)]))]);
|
|
6673
|
+
const argumentReplacement = (call, index) => Option.map(Arr.get(call.args, index), (argument) => cloneNode(argument));
|
|
6674
|
+
const identityFunctionOf = (call) => Option.some(identityFunction(call));
|
|
6675
|
+
const identityFunction = (call) => {
|
|
6676
|
+
const name = freshIdentifier("self", takenNames(call));
|
|
6677
|
+
return arrowFunctionExpression([identifier(name)], identifier(name));
|
|
6678
|
+
};
|
|
6679
|
+
const takenNames = (call) => new Set(call.args.flatMap((argument) => identifiersIn(argument)));
|
|
6680
|
+
const whenDroppable = (call, indices, build) => Option.flatMap(onlyWhen(argumentsDroppable(call, indices), call), build);
|
|
6681
|
+
const whenMovable = (call, indices, build) => Option.flatMap(onlyWhen(argumentsMovable(call, indices), call), build);
|
|
6682
|
+
const argumentsDroppable = (call, indices) => indices.every((index) => argumentSatisfies(call, index, isDroppableArgument));
|
|
6683
|
+
const argumentsMovable = (call, indices) => indices.every((index) => argumentSatisfies(call, index, isMovableArgument));
|
|
6684
|
+
const argumentSatisfies = (call, index, predicate) => Option.exists(Arr.get(call.args, index), predicate);
|
|
6685
|
+
/**
|
|
6091
6686
|
* Mutator — every mutation operator and its registry.
|
|
6092
6687
|
*/
|
|
6093
6688
|
/**
|
|
@@ -6920,8 +7515,11 @@ function isUpdateExpression(node) {
|
|
|
6920
7515
|
*
|
|
6921
7516
|
* Naming each mutator here costs one line when a mutator is added and makes
|
|
6922
7517
|
* that line a compile-checked import instead of a runtime effect.
|
|
7518
|
+
*
|
|
7519
|
+
* `optInMutators` below follows the same hand-written rule, for the same
|
|
7520
|
+
* reason: a mutator exists for a run only when a human named it here.
|
|
6923
7521
|
*/
|
|
6924
|
-
const
|
|
7522
|
+
const defaultMutators = Object.freeze({
|
|
6925
7523
|
ArithmeticOperator: arithmeticOperatorMutator,
|
|
6926
7524
|
ArrayDeclaration: arrayDeclarationMutator,
|
|
6927
7525
|
ArrowFunction: arrowFunctionMutator,
|
|
@@ -6939,6 +7537,28 @@ const allMutators = Object.freeze({
|
|
|
6939
7537
|
UnaryOperator: unaryOperatorMutator,
|
|
6940
7538
|
UpdateOperator: updateOperatorMutator
|
|
6941
7539
|
});
|
|
7540
|
+
const optInMutators = Object.freeze({
|
|
7541
|
+
AtomicUpdateSplit: atomicUpdateSplitMutator,
|
|
7542
|
+
SynchronizationRemoval: synchronizationRemovalMutator,
|
|
7543
|
+
FinalizerEscape: finalizerEscapeMutator
|
|
7544
|
+
});
|
|
7545
|
+
/**
|
|
7546
|
+
* The entries a run applies, and the names its directives may reference.
|
|
7547
|
+
*
|
|
7548
|
+
* Naming is additive, never a whitelist: `optInMutations` adds entries on top
|
|
7549
|
+
* of the defaults and removes none. Selection walks the registry's declared
|
|
7550
|
+
* order, not the order the run listed its names in, so a mutant's identity
|
|
7551
|
+
* never depends on how a config happened to spell the list; a name listed
|
|
7552
|
+
* twice selects its entry once. An unknown name selects nothing here —
|
|
7553
|
+
* `instrument` refuses it before any file is parsed, because a typo that
|
|
7554
|
+
* silently enables nothing removes mutants and raises the score.
|
|
7555
|
+
*
|
|
7556
|
+
* Pure: a registry and a run's names in, entries and names out.
|
|
7557
|
+
*/
|
|
7558
|
+
const selectMutators = (registry, optInMutations) => ({
|
|
7559
|
+
active: [...Object.entries(registry.defaults), ...Object.entries(registry.optIn).filter(([name]) => optInMutations.includes(name))],
|
|
7560
|
+
known: [...Object.keys(registry.defaults), ...Object.keys(registry.optIn)]
|
|
7561
|
+
});
|
|
6942
7562
|
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Transformer.schema/PlacementFailed")("PlacementFailed", {
|
|
6943
7563
|
fileName: S.String,
|
|
6944
7564
|
placerName: S.String,
|
|
@@ -6952,6 +7572,10 @@ S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Transformer.schema/Trans
|
|
|
6952
7572
|
const STRYKER_NAMESPACE_HELPER = "stryNS_9fa48";
|
|
6953
7573
|
const COVER_MUTANT_HELPER = "stryCov_9fa48";
|
|
6954
7574
|
const IS_MUTANT_ACTIVE_HELPER = "stryMutAct_9fa48";
|
|
7575
|
+
const DEFAULT_MUTATOR_REGISTRY = {
|
|
7576
|
+
defaults: defaultMutators,
|
|
7577
|
+
optIn: optInMutators
|
|
7578
|
+
};
|
|
6955
7579
|
function createMutantCollector() {
|
|
6956
7580
|
return [];
|
|
6957
7581
|
}
|
|
@@ -6987,11 +7611,11 @@ function directiveApplies(directive, lowerMutatorName, line) {
|
|
|
6987
7611
|
const NO_COMMENTS = [];
|
|
6988
7612
|
const PARSE_FAILURE = "Stryker directive without directive type or mutators";
|
|
6989
7613
|
const MISSING_LOCATION = "Comment without location";
|
|
6990
|
-
function processStrykerDirectives(rule, node,
|
|
7614
|
+
function processStrykerDirectives(rule, node, knownMutatorNames, originFileName, nodeLine) {
|
|
6991
7615
|
const directives = attachedComments(node).map(parseStrykerDirective).flatMap(Option.toArray);
|
|
6992
|
-
const warnings = directives.flatMap((directive) => mutatorWarnings(directive,
|
|
7616
|
+
const warnings = directives.flatMap((directive) => mutatorWarnings(directive, knownMutatorNames, originFileName));
|
|
6993
7617
|
return {
|
|
6994
|
-
rule: directives.reduce(applyStrykerDirective, rule),
|
|
7618
|
+
rule: directives.map((directive) => nextLineOn(directive, nodeLine)).reduce(applyStrykerDirective, rule),
|
|
6995
7619
|
warnings
|
|
6996
7620
|
};
|
|
6997
7621
|
}
|
|
@@ -7020,36 +7644,39 @@ function strykerDirective(match, loc) {
|
|
|
7020
7644
|
function matchGroup(match, group) {
|
|
7021
7645
|
return Option.getOrThrowWith(Option.fromNullishOr(match[group]), () => /* @__PURE__ */ new Error(PARSE_FAILURE));
|
|
7022
7646
|
}
|
|
7023
|
-
|
|
7024
|
-
|
|
7647
|
+
const nextLineOn = (directive, nodeLine) => ({
|
|
7648
|
+
directive,
|
|
7649
|
+
nodeLine
|
|
7650
|
+
});
|
|
7651
|
+
function applyStrykerDirective(rule, directed) {
|
|
7652
|
+
return Match.value(directed.directive.type).pipe(Match.when("disable", () => ignoreRuleFor(rule, directed)), Match.when("restore", () => restoreRuleFor(rule, directed)), Match.orElse(() => rule));
|
|
7025
7653
|
}
|
|
7026
|
-
function ignoreRuleFor(rule,
|
|
7654
|
+
function ignoreRuleFor(rule, directed) {
|
|
7027
7655
|
return {
|
|
7028
7656
|
kind: "Ignore",
|
|
7029
|
-
mutatorNames: directive.mutatorNames.map((mutatorName) => mutatorName.toLowerCase()),
|
|
7030
|
-
line: directiveLine(
|
|
7031
|
-
ignoreReason: directive.reason,
|
|
7657
|
+
mutatorNames: directed.directive.mutatorNames.map((mutatorName) => mutatorName.toLowerCase()),
|
|
7658
|
+
line: directiveLine(directed),
|
|
7659
|
+
ignoreReason: directed.directive.reason,
|
|
7032
7660
|
previous: rule
|
|
7033
7661
|
};
|
|
7034
7662
|
}
|
|
7035
|
-
function restoreRuleFor(rule,
|
|
7663
|
+
function restoreRuleFor(rule, directed) {
|
|
7036
7664
|
return {
|
|
7037
7665
|
kind: "Restore",
|
|
7038
|
-
mutatorNames: directive.mutatorNames.map((mutatorName) => mutatorName.toLowerCase()),
|
|
7039
|
-
line: directiveLine(
|
|
7666
|
+
mutatorNames: directed.directive.mutatorNames.map((mutatorName) => mutatorName.toLowerCase()),
|
|
7667
|
+
line: directiveLine(directed),
|
|
7040
7668
|
previous: rule
|
|
7041
7669
|
};
|
|
7042
7670
|
}
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
return Match.value(directive.scope).pipe(Match.when("next-line", () => commentLocation(directive.loc).start.line), Match.orElse(() => void 0));
|
|
7671
|
+
function directiveLine(directed) {
|
|
7672
|
+
return Match.value(directed.directive.scope).pipe(Match.when("next-line", () => directed.nodeLine), Match.orElse(() => void 0));
|
|
7046
7673
|
}
|
|
7047
7674
|
function commentLocation(loc) {
|
|
7048
7675
|
return Option.getOrThrowWith(Option.fromNullishOr(loc), () => /* @__PURE__ */ new Error(MISSING_LOCATION));
|
|
7049
7676
|
}
|
|
7050
|
-
/** Warnings for the directive's mutator names that
|
|
7051
|
-
function mutatorWarnings(directive,
|
|
7052
|
-
return directive.mutatorNames.filter((mutatorName) => mutatorName !== WILDCARD).filter((mutatorName) => !
|
|
7677
|
+
/** Warnings for the directive's mutator names that no registered mutator answers to, selected or not. */
|
|
7678
|
+
function mutatorWarnings(directive, knownMutatorNames, originFileName) {
|
|
7679
|
+
return directive.mutatorNames.filter((mutatorName) => mutatorName !== WILDCARD).filter((mutatorName) => !knownMutatorNames.includes(mutatorName.toLowerCase())).map((mutatorName) => mutatorWarning(directive, mutatorName, originFileName));
|
|
7053
7680
|
}
|
|
7054
7681
|
function mutatorWarning(directive, mutatorName, originFileName) {
|
|
7055
7682
|
const loc = commentLocation(directive.loc);
|
|
@@ -7535,19 +8162,21 @@ const emptyAppliedMutants = () => /* @__PURE__ */ new Map();
|
|
|
7535
8162
|
function isMutateRangeList(value) {
|
|
7536
8163
|
return Array.isArray(value);
|
|
7537
8164
|
}
|
|
7538
|
-
const transformScript = ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription, basePath },
|
|
8165
|
+
const transformScript = ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription, basePath }, registry, mutantPlacers) => {
|
|
7539
8166
|
const placementMap = /* @__PURE__ */ new Map();
|
|
7540
8167
|
return Effect$1.gen(function* () {
|
|
7541
8168
|
const lineTable = buildLineTable(rawContent);
|
|
7542
8169
|
attachComments(root, comments, lineTable);
|
|
7543
8170
|
let directiveRule = rootRule;
|
|
7544
|
-
const
|
|
8171
|
+
const mutatorRegistry = Option.getOrElse(Option.fromNullishOr(registry), () => DEFAULT_MUTATOR_REGISTRY);
|
|
8172
|
+
const selection = selectMutators(mutatorRegistry, options.optInMutations);
|
|
8173
|
+
const mutatorEntries = selection.active;
|
|
7545
8174
|
const placers = Option.getOrElse(Option.fromNullishOr(mutantPlacers), () => allMutantPlacers);
|
|
7546
|
-
const
|
|
8175
|
+
const knownMutatorNames = selection.known.map((name) => name.toLowerCase());
|
|
7547
8176
|
const warnings = [];
|
|
7548
8177
|
traverse(root, {
|
|
7549
8178
|
enter(path) {
|
|
7550
|
-
const result = processStrykerDirectives(directiveRule, path.node,
|
|
8179
|
+
const result = processStrykerDirectives(directiveRule, path.node, knownMutatorNames, originFileName, nodeStartLine(path.node));
|
|
7551
8180
|
directiveRule = result.rule;
|
|
7552
8181
|
warnings.push(...result.warnings);
|
|
7553
8182
|
visitNode(path);
|
|
@@ -7557,6 +8186,12 @@ const transformScript = ({ root, originFileName, rawContent, offset, comments },
|
|
|
7557
8186
|
if (hasAppliedMutants(placement)) applyPlacement(path, placement);
|
|
7558
8187
|
}
|
|
7559
8188
|
});
|
|
8189
|
+
function nodeStartLine(node) {
|
|
8190
|
+
return Option.match(Option.fromNullishOr(spanOf(node)), {
|
|
8191
|
+
onNone: () => 0,
|
|
8192
|
+
onSome: (span) => positionFromLineTable(span.start, lineTable).line
|
|
8193
|
+
});
|
|
8194
|
+
}
|
|
7560
8195
|
yield* placeHeaderIfNeeded(mutantCollector, originFileName, options, root);
|
|
7561
8196
|
return warnings;
|
|
7562
8197
|
function visitNode(path) {
|
|
@@ -7828,9 +8463,26 @@ function toOneBasedLineNumber(range) {
|
|
|
7828
8463
|
function isIgnorer(value) {
|
|
7829
8464
|
return Predicate.isObject(value) && typeof value["shouldIgnore"] === "function";
|
|
7830
8465
|
}
|
|
8466
|
+
const EMPTY_MUTATION_NAMES = [];
|
|
8467
|
+
const KNOWN_OPT_IN_MUTATIONS = Object.keys(optInMutators);
|
|
8468
|
+
const requestedOptInMutations = (options) => Option.getOrElse(Option.fromNullishOr(options.optInMutations), () => EMPTY_MUTATION_NAMES);
|
|
8469
|
+
const unknownOptInMutations = (requested) => requested.filter((name) => !KNOWN_OPT_IN_MUTATIONS.includes(name));
|
|
8470
|
+
const listNames = (names) => Option.match(Option.fromNullishOr(names.at(0)), {
|
|
8471
|
+
onNone: () => "none",
|
|
8472
|
+
onSome: () => names.map((name) => `'${name}'`).join(", ")
|
|
8473
|
+
});
|
|
8474
|
+
const unknownOptInMutationsError = (requested) => Option.map(Option.fromNullishOr(unknownOptInMutations(requested).at(0)), () => InstrumentError.make({
|
|
8475
|
+
message: `Unknown opt-in mutations: ${listNames(unknownOptInMutations(requested))}. Known opt-in mutations: ${listNames(KNOWN_OPT_IN_MUTATIONS)}.`,
|
|
8476
|
+
cause: void 0
|
|
8477
|
+
}));
|
|
8478
|
+
const refuseUnknownOptInMutations = (requested) => Option.match(unknownOptInMutationsError(requested), {
|
|
8479
|
+
onNone: () => Effect$1.void,
|
|
8480
|
+
onSome: (error) => Effect$1.fail(error)
|
|
8481
|
+
});
|
|
7831
8482
|
function toTransformerOptions(options) {
|
|
7832
8483
|
const base = {
|
|
7833
8484
|
excludedMutations: [...options.excludedMutations],
|
|
8485
|
+
optInMutations: [...requestedOptInMutations(options)],
|
|
7834
8486
|
ignorers: options.ignorers.filter(isIgnorer)
|
|
7835
8487
|
};
|
|
7836
8488
|
if (options.noHeader !== void 0) return {
|
|
@@ -7852,6 +8504,7 @@ function printedFile(file, ast) {
|
|
|
7852
8504
|
}];
|
|
7853
8505
|
}
|
|
7854
8506
|
const instrument = (files, options, basePath) => Effect$1.gen(function* () {
|
|
8507
|
+
yield* refuseUnknownOptInMutations(requestedOptInMutations(options));
|
|
7855
8508
|
const schemaFiles = files.map((file) => ({
|
|
7856
8509
|
name: file.name,
|
|
7857
8510
|
content: file.content,
|
|
@@ -8438,7 +9091,10 @@ const OrderedMutationScoreThresholds = S.declare(isMutationScoreThresholds, {
|
|
|
8438
9091
|
})
|
|
8439
9092
|
});
|
|
8440
9093
|
const MutationScoreThresholdsSchema = MutationScoreThresholdsValuesSchema.pipe(S.decodeTo(OrderedMutationScoreThresholds, SchemaTransformation.passthrough()));
|
|
8441
|
-
const MutatorDescriptor = S.Struct({
|
|
9094
|
+
const MutatorDescriptor = S.Struct({
|
|
9095
|
+
excludedMutations: defaulted(S.Array(S.String), []),
|
|
9096
|
+
optInMutations: defaulted(S.Array(S.String), [])
|
|
9097
|
+
});
|
|
8442
9098
|
const WarningOptions = openStruct({
|
|
8443
9099
|
unknownOptions: defaulted(S.Boolean, true),
|
|
8444
9100
|
preprocessorErrors: defaulted(S.Boolean, true),
|
|
@@ -8490,7 +9146,10 @@ const StrykerOptionsSchema = S.StructWithRest(S.Struct({
|
|
|
8490
9146
|
maxConcurrentTestRunners: defaulted(S.Finite, 9007199254740991),
|
|
8491
9147
|
maxTestRunnerReuse: defaulted(S.Finite, 0),
|
|
8492
9148
|
mutate: defaulted(S.Array(S.String), ["{src,lib}/**/!(*.+(s|S)pec|*.+(t|T)est).+(cjs|mjs|js|ts|mts|cts|jsx|tsx|html|vue|svelte)", "!{src,lib}/**/__tests__/**/*.+(cjs|mjs|js|ts|mts|cts|jsx|tsx|html|vue|svelte)"]),
|
|
8493
|
-
mutator: defaulted(MutatorDescriptor, {
|
|
9149
|
+
mutator: defaulted(MutatorDescriptor, {
|
|
9150
|
+
excludedMutations: [],
|
|
9151
|
+
optInMutations: []
|
|
9152
|
+
}),
|
|
8494
9153
|
packageManager: S.optional(PackageManager),
|
|
8495
9154
|
plugins: defaulted(S.Array(PluginFileUrl), []),
|
|
8496
9155
|
appendPlugins: defaulted(S.Array(PluginFileUrl), []),
|