@systemfsoftware/stryker-js-instrumenter 3.0.0 → 4.0.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 +21 -0
- package/dist/index.d.mts +2 -3
- package/dist/index.mjs +58 -142
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @systemfsoftware/stryker-js-instrumenter
|
|
2
2
|
|
|
3
|
+
## 4.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- instrument() keeps its public signature; the decision moved to a plain kernel, and the instrument workflow now distinguishes in-place from ephemeral output
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @systemfsoftware/effect-cell-types@6.0.0
|
|
13
|
+
- @systemfsoftware/stryker-js@1.0.0
|
|
14
|
+
|
|
15
|
+
## 3.0.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Refreshed builds on the platform-services dependency graph; the packages no longer reach for host builtins directly. No CLI flags or option names change.
|
|
20
|
+
|
|
21
|
+
- Updated dependencies:
|
|
22
|
+
- @systemfsoftware/stryker-js@0.2.0
|
|
23
|
+
|
|
3
24
|
## 3.0.0
|
|
4
25
|
|
|
5
26
|
### Major Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { Wire, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
2
1
|
import { FileDescription, Mutant } from "@systemfsoftware/stryker-js/Mutant";
|
|
3
2
|
import * as Effect from "effect/Effect";
|
|
4
|
-
import "effect
|
|
3
|
+
import { Wire } from "@systemfsoftware/effect-cell-types";
|
|
5
4
|
import * as S from "effect/Schema";
|
|
6
5
|
import { IgnorerService } from "@systemfsoftware/stryker-js/Ignorer";
|
|
7
6
|
import "effect/Option";
|
|
8
|
-
//#region src/Instrument.
|
|
7
|
+
//#region src/Instrument.schema.d.ts
|
|
9
8
|
declare const InstrumentError_base: S.Class<InstrumentError, S.TaggedStruct<"InstrumentError", {
|
|
10
9
|
readonly message: S.String;
|
|
11
10
|
readonly cause: S.Defect;
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Cell, Wire, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
2
1
|
import { INSTRUMENTER_CONSTANTS, Mutant } from "@systemfsoftware/stryker-js/Mutant";
|
|
3
2
|
import * as Effect from "effect/Effect";
|
|
4
|
-
import { pipe } from "effect/Function";
|
|
5
3
|
import * as Predicate from "effect/Predicate";
|
|
6
|
-
import
|
|
4
|
+
import { Wire } from "@systemfsoftware/effect-cell-types";
|
|
7
5
|
import * as S from "effect/Schema";
|
|
8
6
|
import { parseSync } from "oxc-parser";
|
|
9
7
|
import path from "path";
|
|
@@ -12,17 +10,7 @@ import { propertyPath, strykerReportBugUrl } from "@systemfsoftware/stryker-js/S
|
|
|
12
10
|
import * as Option from "effect/Option";
|
|
13
11
|
import path$1 from "node:path";
|
|
14
12
|
import { RegExpParser, visitRegExpAST } from "@eslint-community/regexpp";
|
|
15
|
-
//#region src/Instrument.
|
|
16
|
-
/**
|
|
17
|
-
* Instrument.workflow — pure decision for the instrument capability.
|
|
18
|
-
*
|
|
19
|
-
* The heavy lifting (AST traversal, mutant collection, code generation)
|
|
20
|
-
* happens in `Instrument.ts`'s read phase, which is allowed to be stateful.
|
|
21
|
-
* This decision receives the already-collected mutants as data and wraps them
|
|
22
|
-
* into the decision type. All helpers and schemas live in this file so the
|
|
23
|
-
* decision body only reaches parameters, const locals, same-file declarations,
|
|
24
|
-
* and the sealed pure effect surface.
|
|
25
|
-
*/
|
|
13
|
+
//#region src/Instrument.schema.ts
|
|
26
14
|
var InstrumentError = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/InstrumentError")("InstrumentError", {
|
|
27
15
|
message: S.String,
|
|
28
16
|
cause: S.Defect()
|
|
@@ -72,11 +60,6 @@ var InstrumentResult = class extends S.TaggedClass()("InstrumentResult", {
|
|
|
72
60
|
files: S.Array(FileSchema),
|
|
73
61
|
mutants: S.Array(Mutant)
|
|
74
62
|
}) {};
|
|
75
|
-
const instrumentWorkflow = Workflow.make(InstrumentDecoded, (decoded) => Result.succeed(InstrumentDecision.make({
|
|
76
|
-
files: decoded.files,
|
|
77
|
-
mutants: decoded.mutants,
|
|
78
|
-
asts: decoded.asts
|
|
79
|
-
})));
|
|
80
63
|
S.Literals([
|
|
81
64
|
"html",
|
|
82
65
|
"js",
|
|
@@ -3988,19 +3971,9 @@ const PredicateRecord = { key: (node) => Predicate.hasProperty(node, "key") ? no
|
|
|
3988
3971
|
function isTypeNode(path) {
|
|
3989
3972
|
return flowTypeAnnotationNodeTypes.includes(path.node.type) || tsTypeAnnotationNodeTypes.includes(path.node.type) || isDeclareVariableStatement(path.node) || isDeclareModule(path.node);
|
|
3990
3973
|
}
|
|
3991
|
-
/**
|
|
3992
|
-
* Determines whether or not it is a declare variable statement node.
|
|
3993
|
-
* @example
|
|
3994
|
-
* declare const foo: 'foo';
|
|
3995
|
-
*/
|
|
3996
3974
|
function isDeclareVariableStatement(node) {
|
|
3997
3975
|
return nodeType(node) === "VariableDeclaration" && "declare" in node && node.declare === true;
|
|
3998
3976
|
}
|
|
3999
|
-
/**
|
|
4000
|
-
* Determines whether or not a node is a string literal that is the name of a module.
|
|
4001
|
-
* @example
|
|
4002
|
-
* declare module "express" {};
|
|
4003
|
-
*/
|
|
4004
3977
|
function isDeclareModule(node) {
|
|
4005
3978
|
return nodeType(node) === "TSModuleDeclaration" && "declare" in node && node.declare === true;
|
|
4006
3979
|
}
|
|
@@ -4032,30 +4005,15 @@ const flowTypeAnnotationNodeTypes = Object.freeze([
|
|
|
4032
4005
|
function isImportDeclaration(path) {
|
|
4033
4006
|
return nodeType(path.node) === "TSImportEqualsDeclaration" || path.node.type === "ImportDeclaration";
|
|
4034
4007
|
}
|
|
4035
|
-
/**
|
|
4036
|
-
* returns syntax for `global.activeMutant === $mutantId`
|
|
4037
|
-
* @param mutantId The id of the mutant to switch
|
|
4038
|
-
*/
|
|
4039
4008
|
function mutantTestExpression(mutantId) {
|
|
4040
4009
|
return callExpression(identifier(IS_MUTANT_ACTIVE_HELPER), [stringLiteral(mutantId)]);
|
|
4041
4010
|
}
|
|
4042
|
-
/**
|
|
4043
|
-
* Returns a sequence of mutation coverage counters with an optional last expression.
|
|
4044
|
-
*
|
|
4045
|
-
* @example (global.__coverMutant__(0, 1), 40 + 2)
|
|
4046
|
-
* @param mutants The mutants for which covering syntax needs to be generated
|
|
4047
|
-
* @param targetExpression The original expression
|
|
4048
|
-
*/
|
|
4049
4011
|
function mutationCoverageSequenceExpression(mutants, targetExpression) {
|
|
4050
4012
|
const mutantIds = [...mutants].map((mutant) => stringLiteral(mutant.id));
|
|
4051
4013
|
const sequence = [callExpression(identifier(COVER_MUTANT_HELPER), mutantIds)];
|
|
4052
4014
|
if (targetExpression) sequence.push(targetExpression);
|
|
4053
4015
|
return sequenceExpression(sequence);
|
|
4054
4016
|
}
|
|
4055
|
-
/**
|
|
4056
|
-
* Verifies the placer's claim: `canPlace` established the node kind, so a
|
|
4057
|
-
* mismatch here means the placer was handed a mutant it never accepted.
|
|
4058
|
-
*/
|
|
4059
4017
|
function nodeOfKind(mutant, node, isKind, kind) {
|
|
4060
4018
|
if (!isKind(node)) throw new Error(`Cannot place mutant ${mutant.id}: expected ${kind}, got ${node.type}`);
|
|
4061
4019
|
return node;
|
|
@@ -4068,14 +4026,6 @@ function throwPlacementError(error, nodePath, placer, mutants, fileName, lineTab
|
|
|
4068
4026
|
const errorMessage = `${location} ${message}. Either remove this file from the list of files to be mutated, or exclude the mutator (using ${propertyPath()("mutator", "excludedMutations")}). Please report this issue at ${strykerReportBugUrl(message)}. Original error: ${error.stack}`;
|
|
4069
4027
|
throw new Error(errorMessage);
|
|
4070
4028
|
}
|
|
4071
|
-
/**
|
|
4072
|
-
* Will set the identifier of anonymous function expressions if is located in a variable declaration.
|
|
4073
|
-
* Will treat input as readonly. Returns undefined if not needed.
|
|
4074
|
-
* @example
|
|
4075
|
-
* const a = function() { }
|
|
4076
|
-
* becomes
|
|
4077
|
-
* const a = function a() {}
|
|
4078
|
-
*/
|
|
4079
4029
|
function classOrFunctionExpressionNamedIfNeeded(path) {
|
|
4080
4030
|
const kind = nodeType(path.node);
|
|
4081
4031
|
if ((kind === "FunctionExpression" || kind === "ClassExpression") && !("id" in path.node) === false && path.node["id"] !== null) {}
|
|
@@ -4088,14 +4038,6 @@ function classOrFunctionExpressionNamedIfNeeded(path) {
|
|
|
4088
4038
|
if (parentPath !== null && parentPath.node.type === "Property" && parentPath.node.key.type === "Identifier" && path.getStatementParent()?.node.type === "VariableDeclaration") return path.node;
|
|
4089
4039
|
}
|
|
4090
4040
|
}
|
|
4091
|
-
/**
|
|
4092
|
-
* Will set the identifier of anonymous arrow function expressions if is located in a variable declaration.
|
|
4093
|
-
* Will treat input as readonly. Returns undefined if not needed.
|
|
4094
|
-
* @example
|
|
4095
|
-
* const a = () => { }
|
|
4096
|
-
* becomes
|
|
4097
|
-
* const a = (() => { const a = () => {}; return a; })()
|
|
4098
|
-
*/
|
|
4099
4041
|
function arrowFunctionExpressionNamedIfNeeded(path) {
|
|
4100
4042
|
const parentPath = path.parentPath;
|
|
4101
4043
|
if (path.node.type === "ArrowFunctionExpression" && parentPath !== null && parentPath.node.type === "VariableDeclarator" && parentPath.node.id.type === "Identifier") {
|
|
@@ -4123,52 +4065,30 @@ function isValidExpression(path) {
|
|
|
4123
4065
|
if (parent === null) return true;
|
|
4124
4066
|
const parentNode = parent.node;
|
|
4125
4067
|
return !isObjectPropertyKey() && !isPartOfChain() && !(parentNode.type === "TaggedTemplateExpression") && !isPartOfDeleteExpression() && !isPartOfAssignmentExpression();
|
|
4126
|
-
/**
|
|
4127
|
-
* Determines if the expression is property of an object.
|
|
4128
|
-
* @example
|
|
4129
|
-
* const a = {
|
|
4130
|
-
* 'foo': 'bar' // 'foo' here is an object property
|
|
4131
|
-
* };
|
|
4132
|
-
*/
|
|
4133
4068
|
function isObjectPropertyKey() {
|
|
4134
4069
|
return parentNode.type === "Property" && parentNode.key === path.node;
|
|
4135
4070
|
}
|
|
4136
|
-
/**
|
|
4137
|
-
* Determines if the expression is part of a call/member chain.
|
|
4138
|
-
* @example
|
|
4139
|
-
* // bar is part of chain, foo is NOT part of the chain:
|
|
4140
|
-
* foo.bar.baz();
|
|
4141
|
-
* foo.bar?.baz()
|
|
4142
|
-
* foo.bar;
|
|
4143
|
-
* foo.bar!;
|
|
4144
|
-
* foo.bar();
|
|
4145
|
-
* foo?.bar();
|
|
4146
|
-
* baz[foo.bar()]
|
|
4147
|
-
* bar?.baz[0]
|
|
4148
|
-
*/
|
|
4149
4071
|
function isPartOfChain() {
|
|
4150
4072
|
return isMemberOrCallOrNonNullExpression(path) && (isMemberExpressionNode(parent) && !(parentNode.type === "MemberExpression" && parentNode.computed && parentNode.property === path.node) || nodeType(parentNode) === "TSNonNullExpression" || isCallExpressionNode(parent) && parentNode.type === "CallExpression" && parentNode.callee === path.node);
|
|
4151
4073
|
}
|
|
4152
|
-
/**
|
|
4153
|
-
* Determines if the expression is part of a delete expression.
|
|
4154
|
-
* @returns true if the expression is part of a delete expression
|
|
4155
|
-
* @example
|
|
4156
|
-
* delete foo.bar;
|
|
4157
|
-
*/
|
|
4158
4074
|
function isPartOfDeleteExpression() {
|
|
4159
4075
|
return parentNode.type === "UnaryExpression" && parentNode.operator === "delete";
|
|
4160
4076
|
}
|
|
4161
|
-
/**
|
|
4162
|
-
* Determines if the expression is part of an assignment expression.
|
|
4163
|
-
* @returns true if the expression is part of an assignment expression
|
|
4164
|
-
* @example
|
|
4165
|
-
* foo.bar = 42;
|
|
4166
|
-
* initialNodes.filter((n) => n.id === 'tiptilt')[0].className = tiptiltState;
|
|
4167
|
-
*/
|
|
4168
4077
|
function isPartOfAssignmentExpression() {
|
|
4169
4078
|
return parentNode.type === "AssignmentExpression" && parentNode.left === path.node;
|
|
4170
4079
|
}
|
|
4171
4080
|
}
|
|
4081
|
+
function unwrapParenthesizedExpression(node) {
|
|
4082
|
+
let current = node;
|
|
4083
|
+
while (nodeType(current) === "ParenthesizedExpression") {
|
|
4084
|
+
const wrapper = current;
|
|
4085
|
+
if (typeof wrapper !== "object" || wrapper === null || !("expression" in wrapper)) break;
|
|
4086
|
+
const inner = wrapper.expression;
|
|
4087
|
+
if (inner === void 0 || inner === null) break;
|
|
4088
|
+
current = inner;
|
|
4089
|
+
}
|
|
4090
|
+
return current;
|
|
4091
|
+
}
|
|
4172
4092
|
const allMutantPlacers = Object.freeze([
|
|
4173
4093
|
{
|
|
4174
4094
|
name: "expressionMutantPlacer",
|
|
@@ -4178,7 +4098,7 @@ const allMutantPlacers = Object.freeze([
|
|
|
4178
4098
|
place(path, appliedMutants) {
|
|
4179
4099
|
let expression = nameIfAnonymous(path);
|
|
4180
4100
|
expression = mutationCoverageSequenceExpression(appliedMutants.keys(), expression);
|
|
4181
|
-
for (const [mutant, appliedMutant] of appliedMutants) expression = conditionalExpression(mutantTestExpression(mutant.id), nodeOfKind(mutant, appliedMutant, isExpressionKind, "an expression"), expression);
|
|
4101
|
+
for (const [mutant, appliedMutant] of appliedMutants) expression = conditionalExpression(mutantTestExpression(mutant.id), nodeOfKind(mutant, unwrapParenthesizedExpression(appliedMutant), isExpressionKind, "an expression"), expression);
|
|
4182
4102
|
path.replaceWith(expression);
|
|
4183
4103
|
}
|
|
4184
4104
|
},
|
|
@@ -4284,11 +4204,6 @@ function isMemberExpressionWithIdentifier(node, objectNames, propertyName) {
|
|
|
4284
4204
|
}
|
|
4285
4205
|
const strykerPlugins = [];
|
|
4286
4206
|
const frameworkPluginsFileUrl = import.meta.url;
|
|
4287
|
-
/**
|
|
4288
|
-
* The instrumentation header: parsed once with oxc, frozen, shared. The
|
|
4289
|
-
* `globalThis` implementation is based on core-js's — see
|
|
4290
|
-
* https://github.com/stryker-mutator/stryker-js/issues/4035
|
|
4291
|
-
*/
|
|
4292
4207
|
const parsedInstrumentationHeader = parseSync("instrumenter-header.js", `// @ts-nocheck
|
|
4293
4208
|
var ${STRYKER_NAMESPACE_HELPER} = function(){
|
|
4294
4209
|
var g = typeof globalThis === 'object' && globalThis && globalThis.Math === Math && globalThis || new Function("return this")();
|
|
@@ -4561,9 +4476,6 @@ function toError(value) {
|
|
|
4561
4476
|
}
|
|
4562
4477
|
//#endregion
|
|
4563
4478
|
//#region src/Instrument.ts
|
|
4564
|
-
/**
|
|
4565
|
-
* Instrument — the instrument capability: Cell description, file/mutant types and the instrument entry point.
|
|
4566
|
-
*/
|
|
4567
4479
|
const commentDirectiveRegEx = /^(\s*)@(ts-[a-z-]+).*$/;
|
|
4568
4480
|
const tsDirectiveLikeRegEx = /@(ts-[a-z-]+)/;
|
|
4569
4481
|
const startingCommentRegex = /(^\s*\/\*.*?\*\/)/gs;
|
|
@@ -4707,7 +4619,7 @@ function toTransformerOptions(options) {
|
|
|
4707
4619
|
function isAst(value) {
|
|
4708
4620
|
return typeof value === "object" && value !== null && "format" in value && "root" in value;
|
|
4709
4621
|
}
|
|
4710
|
-
const
|
|
4622
|
+
const readCollected = (command) => Effect.gen(function* () {
|
|
4711
4623
|
const files = command.files;
|
|
4712
4624
|
const options = command.options;
|
|
4713
4625
|
const parse = createParser();
|
|
@@ -4751,54 +4663,58 @@ const instrumentDescription = pipe(Cell.read((command) => Effect.gen(function* (
|
|
|
4751
4663
|
})
|
|
4752
4664
|
})
|
|
4753
4665
|
};
|
|
4754
|
-
})
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
const
|
|
4766
|
-
const
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
const ast = maybeAst;
|
|
4773
|
-
const file = maybeFile;
|
|
4774
|
-
const mutatedContent = print(ast);
|
|
4775
|
-
outFiles.push({
|
|
4776
|
-
name: file.name,
|
|
4777
|
-
mutate: file.mutate,
|
|
4778
|
-
content: mutatedContent
|
|
4779
|
-
});
|
|
4780
|
-
}
|
|
4781
|
-
return InstrumentResult.make({
|
|
4782
|
-
files: outFiles,
|
|
4783
|
-
mutants: decision.mutants
|
|
4666
|
+
});
|
|
4667
|
+
const printDecision = (decision) => Effect.try({
|
|
4668
|
+
try: () => {
|
|
4669
|
+
const files = decision.files;
|
|
4670
|
+
const asts = decision.asts;
|
|
4671
|
+
const outFiles = [];
|
|
4672
|
+
for (let i = 0; i < asts.length; i++) {
|
|
4673
|
+
const maybeAst = asts[i];
|
|
4674
|
+
const maybeFile = files[i];
|
|
4675
|
+
if (maybeAst === void 0 || maybeFile === void 0) continue;
|
|
4676
|
+
if (!isAst(maybeAst)) continue;
|
|
4677
|
+
const ast = maybeAst;
|
|
4678
|
+
const file = maybeFile;
|
|
4679
|
+
const mutatedContent = print(ast);
|
|
4680
|
+
outFiles.push({
|
|
4681
|
+
name: file.name,
|
|
4682
|
+
mutate: file.mutate,
|
|
4683
|
+
content: mutatedContent
|
|
4784
4684
|
});
|
|
4785
|
-
}
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
})
|
|
4685
|
+
}
|
|
4686
|
+
return InstrumentResult.make({
|
|
4687
|
+
files: outFiles,
|
|
4688
|
+
mutants: decision.mutants
|
|
4689
|
+
});
|
|
4690
|
+
},
|
|
4691
|
+
catch: (cause) => new InstrumentError({
|
|
4692
|
+
message: "Failed to print",
|
|
4693
|
+
cause
|
|
4790
4694
|
})
|
|
4791
|
-
})
|
|
4792
|
-
const
|
|
4695
|
+
});
|
|
4696
|
+
const decideInstrument = (decoded) => InstrumentDecision.make({
|
|
4697
|
+
files: decoded.files,
|
|
4698
|
+
mutants: decoded.mutants,
|
|
4699
|
+
asts: decoded.asts
|
|
4700
|
+
});
|
|
4701
|
+
const instrument = (files, options) => Effect.gen(function* () {
|
|
4793
4702
|
const schemaFiles = files.map((file) => ({
|
|
4794
4703
|
name: file.name,
|
|
4795
4704
|
content: file.content,
|
|
4796
4705
|
mutate: file.mutate
|
|
4797
4706
|
}));
|
|
4798
|
-
|
|
4707
|
+
const collected = yield* readCollected(InstrumentCommand.make({
|
|
4799
4708
|
files: schemaFiles,
|
|
4800
4709
|
options
|
|
4801
4710
|
}));
|
|
4802
|
-
|
|
4711
|
+
const decision = decideInstrument(InstrumentDecoded.make({
|
|
4712
|
+
files: collected.files,
|
|
4713
|
+
options: collected.options,
|
|
4714
|
+
asts: collected.asts,
|
|
4715
|
+
mutants: collected.mutants
|
|
4716
|
+
}));
|
|
4717
|
+
return yield* printDecision(decision);
|
|
4718
|
+
});
|
|
4803
4719
|
//#endregion
|
|
4804
4720
|
export { angularIgnorer, disableTypeChecks, frameworkPluginsFileUrl, instrument, strykerPlugins };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@systemfsoftware/stryker-js-instrumenter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/systemfsoftware/systemfsoftware.git",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"angular-html-parser": "~10.4.0",
|
|
25
25
|
"effect": "^4.0.0-rc.112",
|
|
26
26
|
"oxc-parser": "^0.140.0",
|
|
27
|
-
"@systemfsoftware/effect-cell-types": "^
|
|
28
|
-
"@systemfsoftware/stryker-js": "^0.
|
|
27
|
+
"@systemfsoftware/effect-cell-types": "^6.0.0",
|
|
28
|
+
"@systemfsoftware/stryker-js": "^1.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@systemfsoftware/arethetypeswrong-cli": "^1.1.1",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"tsdown": "^0.22.14",
|
|
38
38
|
"typescript": "^7",
|
|
39
39
|
"vitest": "^4",
|
|
40
|
-
"@systemfsoftware/all": "^1.
|
|
41
|
-
"@systemfsoftware/effect-gherkin-spec": "^4.0.0",
|
|
40
|
+
"@systemfsoftware/all": "^1.1.2",
|
|
42
41
|
"@systemfsoftware/oxlint-config": "^0.1.0",
|
|
43
|
-
"@systemfsoftware/
|
|
44
|
-
"@systemfsoftware/tsconfig": "^1.3.3"
|
|
42
|
+
"@systemfsoftware/effect-gherkin-spec": "^4.0.0",
|
|
43
|
+
"@systemfsoftware/tsconfig": "^1.3.3",
|
|
44
|
+
"@systemfsoftware/vitest-config": "^0.1.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=20.0.0"
|