@webpresso/agent-config 0.4.2 → 0.4.4
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/README.md +33 -0
- package/dist/esm/oxlint/basenames.d.ts +29 -0
- package/dist/esm/oxlint/basenames.js +42 -0
- package/dist/esm/oxlint/code-safety.d.ts +18 -0
- package/dist/esm/oxlint/code-safety.js +89 -0
- package/dist/esm/oxlint/foundation-purity.d.ts +21 -0
- package/dist/esm/oxlint/foundation-purity.js +52 -0
- package/dist/esm/oxlint/graphql-conventions.d.ts +23 -0
- package/dist/esm/oxlint/graphql-conventions.js +202 -0
- package/dist/esm/oxlint/import-hygiene.d.ts +38 -0
- package/dist/esm/oxlint/import-hygiene.js +220 -0
- package/dist/esm/oxlint/index.d.ts +23 -0
- package/dist/esm/oxlint/index.js +29 -0
- package/dist/esm/oxlint/monorepo-paths.d.ts +22 -0
- package/dist/esm/oxlint/monorepo-paths.js +135 -0
- package/dist/esm/oxlint/path-roles.d.ts +24 -0
- package/dist/esm/oxlint/path-roles.js +53 -0
- package/dist/esm/oxlint/query-patterns.d.ts +24 -0
- package/dist/esm/oxlint/query-patterns.js +122 -0
- package/dist/esm/oxlint/testing-quality.d.ts +35 -0
- package/dist/esm/oxlint/testing-quality.js +186 -0
- package/dist/esm/oxlint/tier-boundaries.d.ts +35 -0
- package/dist/esm/oxlint/tier-boundaries.js +133 -0
- package/dist/esm/stryker/index.d.ts +14 -5
- package/dist/esm/stryker/index.js +12 -3
- package/package.json +80 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
declare const plugin: {
|
|
2
|
+
meta: {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
rules: {
|
|
6
|
+
"no-weak-assertions": {
|
|
7
|
+
create(context: any): {
|
|
8
|
+
CallExpression(node: any): void;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
"no-bare-spy-assertions": {
|
|
12
|
+
create(context: any): {
|
|
13
|
+
CallExpression(node: any): void;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
"no-internal-mocks": {
|
|
17
|
+
create(context: any): {
|
|
18
|
+
CallExpression(node: any): void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
"no-real-timers-in-tests": {
|
|
22
|
+
create(context: any): {
|
|
23
|
+
NewExpression(node: any): void;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
"no-cold-dynamic-import": {
|
|
27
|
+
create(context: any): {
|
|
28
|
+
CallExpression(node: any): void;
|
|
29
|
+
"CallExpression:exit"(node: any): void;
|
|
30
|
+
ImportExpression(node: any): void;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export default plugin;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Webpresso testing quality rules — replaces GritQL patterns:
|
|
3
|
+
// - no-weak-assertions (no-tobefalsy, no-tobedefined)
|
|
4
|
+
// - no-bare-spy-assertions
|
|
5
|
+
// - no-internal-mocks
|
|
6
|
+
// - no-real-timers-in-tests
|
|
7
|
+
const noWeakAssertions = {
|
|
8
|
+
create(context) {
|
|
9
|
+
return {
|
|
10
|
+
CallExpression(node) {
|
|
11
|
+
if (node.callee.type !== "MemberExpression" || node.callee.property.type !== "Identifier") {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const method = node.callee.property.name;
|
|
15
|
+
const weak = ["toBeTruthy", "toBeFalsy", "toBeDefined", "toBeUndefined", "toBeTypeOf"];
|
|
16
|
+
if (!weak.includes(method))
|
|
17
|
+
return;
|
|
18
|
+
if (node.arguments.length > 0 && method !== "toBeTypeOf")
|
|
19
|
+
return;
|
|
20
|
+
const messages = {
|
|
21
|
+
toBeTruthy: "Weak assertion: toBeTruthy() matches too many values. Use toBe(true) for strict equality.",
|
|
22
|
+
toBeFalsy: "Weak assertion: toBeFalsy() matches too many values. Use toBe(false) for strict equality.",
|
|
23
|
+
toBeDefined: "Weak assertion: toBeDefined() allows equivalent mutants. Use toBe(expectedValue) or toEqual(expectedValue).",
|
|
24
|
+
toBeUndefined: "Weak assertion: toBeUndefined() allows equivalent mutants. Use toBe(undefined) explicitly.",
|
|
25
|
+
toBeTypeOf: "Weak assertion: toBeTypeOf() only checks the type, not the value. Use toBe(expectedValue) or toEqual(expectedValue).",
|
|
26
|
+
};
|
|
27
|
+
context.report({ node: node.callee.property, message: messages[method] });
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const noBareSpy = {
|
|
33
|
+
create(context) {
|
|
34
|
+
return {
|
|
35
|
+
CallExpression(node) {
|
|
36
|
+
if (node.callee.type !== "MemberExpression" ||
|
|
37
|
+
node.callee.property.type !== "Identifier" ||
|
|
38
|
+
node.callee.property.name !== "toHaveBeenCalled" ||
|
|
39
|
+
node.arguments.length > 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Allow .not.toHaveBeenCalled()
|
|
43
|
+
const obj = node.callee.object;
|
|
44
|
+
if (obj.type === "MemberExpression" &&
|
|
45
|
+
obj.property.type === "Identifier" &&
|
|
46
|
+
obj.property.name === "not") {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
context.report({
|
|
50
|
+
node: node.callee.property,
|
|
51
|
+
message: "Weak spy assertion: toHaveBeenCalled() without arguments. Use toHaveBeenCalledWith(expected), toHaveBeenNthCalledWith(n, expected), or toHaveBeenCalledTimes(count).",
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const noInternalMocks = {
|
|
58
|
+
create(context) {
|
|
59
|
+
return {
|
|
60
|
+
CallExpression(node) {
|
|
61
|
+
if (node.callee.type !== "MemberExpression" ||
|
|
62
|
+
node.callee.object.type !== "Identifier" ||
|
|
63
|
+
node.callee.object.name !== "vi" ||
|
|
64
|
+
node.callee.property.type !== "Identifier" ||
|
|
65
|
+
node.callee.property.name !== "mock") {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const arg = node.arguments[0];
|
|
69
|
+
if (!arg || arg.type !== "Literal" || typeof arg.value !== "string")
|
|
70
|
+
return;
|
|
71
|
+
if (arg.value.includes("@webpresso")) {
|
|
72
|
+
// Allow mocking I/O boundary modules (filesystem loaders/writers)
|
|
73
|
+
// These are legitimate mock targets even in unit tests
|
|
74
|
+
const ioBoundaryPrefixes = [
|
|
75
|
+
"@webpresso/schema/loaders/", // YAML filesystem loaders & writers
|
|
76
|
+
"@webpresso/scripts/", // Repo-wide scripts & dev orchestration I/O boundaries
|
|
77
|
+
];
|
|
78
|
+
if (ioBoundaryPrefixes.some((prefix) => arg.value.startsWith(prefix)))
|
|
79
|
+
return;
|
|
80
|
+
context.report({
|
|
81
|
+
node: arg,
|
|
82
|
+
message: "Mocking internal @webpresso/* package. Use real dependencies (PGlite for DB, real services for logic). Convert to .integration.test.ts if needed.",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
const noRealTimers = {
|
|
90
|
+
create(context) {
|
|
91
|
+
return {
|
|
92
|
+
NewExpression(node) {
|
|
93
|
+
if (node.callee.type !== "Identifier" || node.callee.name !== "Promise") {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const arg = node.arguments[0];
|
|
97
|
+
if (!arg || (arg.type !== "ArrowFunctionExpression" && arg.type !== "FunctionExpression")) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const body = arg.body.type === "CallExpression"
|
|
101
|
+
? arg.body
|
|
102
|
+
: arg.body.type === "BlockStatement" &&
|
|
103
|
+
arg.body.body.length === 1 &&
|
|
104
|
+
arg.body.body[0].type === "ExpressionStatement"
|
|
105
|
+
? arg.body.body[0].expression
|
|
106
|
+
: null;
|
|
107
|
+
if (body &&
|
|
108
|
+
body.type === "CallExpression" &&
|
|
109
|
+
body.callee.type === "Identifier" &&
|
|
110
|
+
body.callee.name === "setTimeout") {
|
|
111
|
+
context.report({
|
|
112
|
+
node,
|
|
113
|
+
message: "setTimeout inside Promise constructor will hang with fake timers. Use await Promise.resolve() for microtask delays, or vi.advanceTimersByTimeAsync() for time-based delays.",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
function isTestCall(node) {
|
|
121
|
+
const { callee } = node;
|
|
122
|
+
if (callee.type === "Identifier")
|
|
123
|
+
return callee.name === "it" || callee.name === "test";
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
function isBeforeAllCall(node) {
|
|
127
|
+
const { callee } = node;
|
|
128
|
+
return callee.type === "Identifier" && callee.name === "beforeAll";
|
|
129
|
+
}
|
|
130
|
+
const noColdDynamicImport = {
|
|
131
|
+
create(context) {
|
|
132
|
+
// Track depth inside it()/test() callback bodies via the linter's own traversal.
|
|
133
|
+
// Using ':exit' to decrement so we never need to walk the subtree manually
|
|
134
|
+
// (manual walks hit circular parent back-references in oxlint's proxy AST).
|
|
135
|
+
let testDepth = 0;
|
|
136
|
+
let beforeAllDepth = 0;
|
|
137
|
+
const prewarmedModules = new Set();
|
|
138
|
+
return {
|
|
139
|
+
CallExpression(node) {
|
|
140
|
+
if (isTestCall(node))
|
|
141
|
+
testDepth++;
|
|
142
|
+
if (isBeforeAllCall(node))
|
|
143
|
+
beforeAllDepth++;
|
|
144
|
+
},
|
|
145
|
+
"CallExpression:exit"(node) {
|
|
146
|
+
if (isTestCall(node))
|
|
147
|
+
testDepth--;
|
|
148
|
+
if (isBeforeAllCall(node))
|
|
149
|
+
beforeAllDepth--;
|
|
150
|
+
},
|
|
151
|
+
ImportExpression(node) {
|
|
152
|
+
const src = node.source;
|
|
153
|
+
if (src.type !== "Literal" || typeof src.value !== "string")
|
|
154
|
+
return;
|
|
155
|
+
if (!src.value.startsWith("@webpresso/") && !src.value.startsWith("#"))
|
|
156
|
+
return;
|
|
157
|
+
// Track modules pre-warmed in beforeAll
|
|
158
|
+
if (beforeAllDepth > 0) {
|
|
159
|
+
prewarmedModules.add(src.value);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (testDepth === 0)
|
|
163
|
+
return;
|
|
164
|
+
// Skip if module was pre-warmed via beforeAll
|
|
165
|
+
if (prewarmedModules.has(src.value))
|
|
166
|
+
return;
|
|
167
|
+
context.report({
|
|
168
|
+
node: src,
|
|
169
|
+
message: `Dynamic @webpresso/* import inside test body causes cold-start timeouts under parallel execution. ` +
|
|
170
|
+
`Add \`beforeAll(() => import('${src.value}'))\` at the top of the file to pre-warm the module cache.`,
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
const plugin = {
|
|
177
|
+
meta: { name: "webpresso-testing" },
|
|
178
|
+
rules: {
|
|
179
|
+
"no-weak-assertions": noWeakAssertions,
|
|
180
|
+
"no-bare-spy-assertions": noBareSpy,
|
|
181
|
+
"no-internal-mocks": noInternalMocks,
|
|
182
|
+
"no-real-timers-in-tests": noRealTimers,
|
|
183
|
+
"no-cold-dynamic-import": noColdDynamicImport,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
export default plugin;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare function resolveFileTierContext(filename: any): {
|
|
2
|
+
kind: string;
|
|
3
|
+
packageName: any;
|
|
4
|
+
tier: number;
|
|
5
|
+
} | {
|
|
6
|
+
kind: string;
|
|
7
|
+
} | null;
|
|
8
|
+
export declare function resolveImportTierContext(source: any): {
|
|
9
|
+
kind: string;
|
|
10
|
+
packageName: any;
|
|
11
|
+
tier: number;
|
|
12
|
+
} | {
|
|
13
|
+
kind: string;
|
|
14
|
+
} | null;
|
|
15
|
+
declare const plugin: {
|
|
16
|
+
meta: {
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
rules: {
|
|
20
|
+
"no-higher-tier-imports": {
|
|
21
|
+
create(context: any): {
|
|
22
|
+
ImportDeclaration?: undefined;
|
|
23
|
+
ExportNamedDeclaration?: undefined;
|
|
24
|
+
ExportAllDeclaration?: undefined;
|
|
25
|
+
ImportExpression?: undefined;
|
|
26
|
+
} | {
|
|
27
|
+
ImportDeclaration(node: any): void;
|
|
28
|
+
ExportNamedDeclaration(node: any): void;
|
|
29
|
+
ExportAllDeclaration(node: any): void;
|
|
30
|
+
ImportExpression(node: any): void;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export default plugin;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
const FALLBACK_PACKAGE_TIERS = {
|
|
5
|
+
utils: 0,
|
|
6
|
+
types: 0,
|
|
7
|
+
database: 1,
|
|
8
|
+
ui: 1,
|
|
9
|
+
"app-core": 2,
|
|
10
|
+
"cli-wp": 3,
|
|
11
|
+
};
|
|
12
|
+
async function loadPackageTiers() {
|
|
13
|
+
const packageBoundaryModuleUrl = pathToFileURL(resolve(process.cwd(), "package-boundaries.js"));
|
|
14
|
+
try {
|
|
15
|
+
const packageBoundaryModule = await import(packageBoundaryModuleUrl.href);
|
|
16
|
+
return packageBoundaryModule.PACKAGE_TIERS ?? FALLBACK_PACKAGE_TIERS;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return FALLBACK_PACKAGE_TIERS;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const PACKAGE_TIERS = await loadPackageTiers();
|
|
23
|
+
function normalizeFilename(filename) {
|
|
24
|
+
return typeof filename === "string" ? filename.replaceAll("\\", "/") : "";
|
|
25
|
+
}
|
|
26
|
+
function getFilename(context) {
|
|
27
|
+
if (typeof context.getFilename === "function") {
|
|
28
|
+
return normalizeFilename(context.getFilename());
|
|
29
|
+
}
|
|
30
|
+
return normalizeFilename(context.filename);
|
|
31
|
+
}
|
|
32
|
+
function getPathSegments(filename) {
|
|
33
|
+
return normalizeFilename(filename).split("/").filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
function getWorkspacePackageContext(packageName) {
|
|
36
|
+
const tier = PACKAGE_TIERS[packageName];
|
|
37
|
+
if (typeof tier !== "number") {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
kind: "package",
|
|
42
|
+
packageName,
|
|
43
|
+
tier,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function resolveFileTierContext(filename) {
|
|
47
|
+
const segments = getPathSegments(filename);
|
|
48
|
+
if (segments.includes("infra")) {
|
|
49
|
+
return { kind: "infra" };
|
|
50
|
+
}
|
|
51
|
+
if (segments.includes("packages-public")) {
|
|
52
|
+
return { kind: "packages-public" };
|
|
53
|
+
}
|
|
54
|
+
const packagesIndex = segments.indexOf("packages");
|
|
55
|
+
if (packagesIndex !== -1 && packagesIndex + 2 < segments.length) {
|
|
56
|
+
return getWorkspacePackageContext(segments[packagesIndex + 2]);
|
|
57
|
+
}
|
|
58
|
+
const appsIndex = segments.indexOf("apps");
|
|
59
|
+
if (appsIndex !== -1) {
|
|
60
|
+
const directAppContext = getWorkspacePackageContext(segments[appsIndex + 1]);
|
|
61
|
+
if (directAppContext) {
|
|
62
|
+
return directAppContext;
|
|
63
|
+
}
|
|
64
|
+
if (appsIndex + 2 < segments.length) {
|
|
65
|
+
return getWorkspacePackageContext(segments[appsIndex + 2]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
export function resolveImportTierContext(source) {
|
|
71
|
+
if (typeof source !== "string") {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (source.startsWith("packages-public/")) {
|
|
75
|
+
return { kind: "packages-public" };
|
|
76
|
+
}
|
|
77
|
+
if (!source.startsWith("@webpresso/")) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const packageName = source.slice("@webpresso/".length).split("/")[0];
|
|
81
|
+
return getWorkspacePackageContext(packageName);
|
|
82
|
+
}
|
|
83
|
+
function reportTierViolation(context, node, fromContext, toContext) {
|
|
84
|
+
context.report({
|
|
85
|
+
node,
|
|
86
|
+
message: `Tier boundary violation: "${fromContext.packageName}" (tier ${fromContext.tier}) must not import higher-tier package "${toContext.packageName}" (tier ${toContext.tier}).`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function checkStaticModuleSource(node, callback) {
|
|
90
|
+
if (!node.source)
|
|
91
|
+
return;
|
|
92
|
+
callback(node.source.value, node.source);
|
|
93
|
+
}
|
|
94
|
+
const noHigherTierImports = {
|
|
95
|
+
create(context) {
|
|
96
|
+
const fromContext = resolveFileTierContext(getFilename(context));
|
|
97
|
+
if (!fromContext || fromContext.kind !== "package") {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
function checkImport(source, node) {
|
|
101
|
+
const toContext = resolveImportTierContext(source);
|
|
102
|
+
if (!toContext || toContext.kind !== "package") {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (toContext.tier > fromContext.tier) {
|
|
106
|
+
reportTierViolation(context, node, fromContext, toContext);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
ImportDeclaration(node) {
|
|
111
|
+
checkImport(node.source.value, node.source);
|
|
112
|
+
},
|
|
113
|
+
ExportNamedDeclaration(node) {
|
|
114
|
+
checkStaticModuleSource(node, checkImport);
|
|
115
|
+
},
|
|
116
|
+
ExportAllDeclaration(node) {
|
|
117
|
+
checkStaticModuleSource(node, checkImport);
|
|
118
|
+
},
|
|
119
|
+
ImportExpression(node) {
|
|
120
|
+
if (node.source.type !== "Literal")
|
|
121
|
+
return;
|
|
122
|
+
checkImport(node.source.value, node.source);
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
const plugin = {
|
|
128
|
+
meta: { name: "webpresso-tier-boundaries" },
|
|
129
|
+
rules: {
|
|
130
|
+
"no-higher-tier-imports": noHigherTierImports,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
export default plugin;
|
|
@@ -44,9 +44,20 @@ export declare const baseConfig: {
|
|
|
44
44
|
incrementalFile: string;
|
|
45
45
|
};
|
|
46
46
|
/**
|
|
47
|
-
* Extends baseConfig
|
|
47
|
+
* Extends baseConfig for TypeScript packages.
|
|
48
48
|
* Use this in any TypeScript package instead of baseConfig directly.
|
|
49
49
|
*
|
|
50
|
+
* Does NOT wire `@stryker-mutator/typescript-checker`: that plugin depends on
|
|
51
|
+
* classic TypeScript compiler-API symbols (`ts.sys`,
|
|
52
|
+
* `ts.createSolutionBuilderWithWatch`, `ts.createSolutionBuilderWithWatchHost`,
|
|
53
|
+
* `ts.createEmitAndSemanticDiagnosticsBuilderProgram`,
|
|
54
|
+
* `ts.parseConfigFileTextToJson`, `ts.formatDiagnostics`) that are all
|
|
55
|
+
* `undefined` on TypeScript 7.0.2, so wiring it breaks mutation runs on TS7
|
|
56
|
+
* with a hard failure rather than classifying compile errors. Consumers who
|
|
57
|
+
* still want mutant type-checking on TS7 must add a consumer-side pnpm
|
|
58
|
+
* override aliasing the plugin's `typescript` import to
|
|
59
|
+
* `@typescript/typescript6` themselves.
|
|
60
|
+
*
|
|
50
61
|
* @example
|
|
51
62
|
* import { typescriptBaseConfig } from '@webpresso/agent-config/stryker'
|
|
52
63
|
*
|
|
@@ -57,6 +68,7 @@ export declare const baseConfig: {
|
|
|
57
68
|
export declare const typescriptBaseConfig: {
|
|
58
69
|
packageManager: string;
|
|
59
70
|
testRunner: string;
|
|
71
|
+
plugins: string[];
|
|
60
72
|
ignorePatterns: string[];
|
|
61
73
|
mutate: string[];
|
|
62
74
|
concurrency: number;
|
|
@@ -83,8 +95,6 @@ export declare const typescriptBaseConfig: {
|
|
|
83
95
|
};
|
|
84
96
|
incremental: boolean;
|
|
85
97
|
incrementalFile: string;
|
|
86
|
-
plugins: string[];
|
|
87
|
-
checkers: string[];
|
|
88
98
|
tsconfigFile: string;
|
|
89
99
|
};
|
|
90
100
|
/**
|
|
@@ -101,6 +111,7 @@ export declare const typescriptBaseConfig: {
|
|
|
101
111
|
export declare const typescriptWorkersBaseConfig: {
|
|
102
112
|
packageManager: string;
|
|
103
113
|
testRunner: string;
|
|
114
|
+
plugins: string[];
|
|
104
115
|
ignorePatterns: string[];
|
|
105
116
|
mutate: string[];
|
|
106
117
|
concurrency: number;
|
|
@@ -124,8 +135,6 @@ export declare const typescriptWorkersBaseConfig: {
|
|
|
124
135
|
};
|
|
125
136
|
incremental: boolean;
|
|
126
137
|
incrementalFile: string;
|
|
127
|
-
plugins: string[];
|
|
128
|
-
checkers: string[];
|
|
129
138
|
tsconfigFile: string;
|
|
130
139
|
vitest: {
|
|
131
140
|
configFile: string;
|
|
@@ -93,9 +93,20 @@ export const baseConfig = {
|
|
|
93
93
|
incrementalFile: "reports/stryker-incremental.json",
|
|
94
94
|
};
|
|
95
95
|
/**
|
|
96
|
-
* Extends baseConfig
|
|
96
|
+
* Extends baseConfig for TypeScript packages.
|
|
97
97
|
* Use this in any TypeScript package instead of baseConfig directly.
|
|
98
98
|
*
|
|
99
|
+
* Does NOT wire `@stryker-mutator/typescript-checker`: that plugin depends on
|
|
100
|
+
* classic TypeScript compiler-API symbols (`ts.sys`,
|
|
101
|
+
* `ts.createSolutionBuilderWithWatch`, `ts.createSolutionBuilderWithWatchHost`,
|
|
102
|
+
* `ts.createEmitAndSemanticDiagnosticsBuilderProgram`,
|
|
103
|
+
* `ts.parseConfigFileTextToJson`, `ts.formatDiagnostics`) that are all
|
|
104
|
+
* `undefined` on TypeScript 7.0.2, so wiring it breaks mutation runs on TS7
|
|
105
|
+
* with a hard failure rather than classifying compile errors. Consumers who
|
|
106
|
+
* still want mutant type-checking on TS7 must add a consumer-side pnpm
|
|
107
|
+
* override aliasing the plugin's `typescript` import to
|
|
108
|
+
* `@typescript/typescript6` themselves.
|
|
109
|
+
*
|
|
99
110
|
* @example
|
|
100
111
|
* import { typescriptBaseConfig } from '@webpresso/agent-config/stryker'
|
|
101
112
|
*
|
|
@@ -105,8 +116,6 @@ export const baseConfig = {
|
|
|
105
116
|
*/
|
|
106
117
|
export const typescriptBaseConfig = {
|
|
107
118
|
...baseConfig,
|
|
108
|
-
plugins: [...baseConfig.plugins, "@stryker-mutator/typescript-checker"],
|
|
109
|
-
checkers: ["typescript"],
|
|
110
119
|
tsconfigFile: "tsconfig.json",
|
|
111
120
|
};
|
|
112
121
|
/**
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpresso/agent-config",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "Shared vitest, tsconfig, stryker,
|
|
5
|
+
"description": "Shared vitest, tsconfig, stryker, workers-test, and oxlint policy plugins for webpresso consumers. Binary-free — pure test/config tooling.",
|
|
6
6
|
"homepage": "https://github.com/webpresso/agent-kit#readme",
|
|
7
7
|
"bugs": {
|
|
8
8
|
"url": "https://github.com/webpresso/agent-kit/issues"
|
|
@@ -45,6 +45,72 @@
|
|
|
45
45
|
"default": "./dist/esm/e2e/index.js"
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
|
+
"./oxlint": {
|
|
49
|
+
"types": "./dist/esm/oxlint/index.d.ts",
|
|
50
|
+
"import": "./dist/esm/oxlint/index.js",
|
|
51
|
+
"require": "./dist/esm/oxlint/index.js",
|
|
52
|
+
"default": "./dist/esm/oxlint/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./oxlint/basenames": {
|
|
55
|
+
"types": "./dist/esm/oxlint/basenames.d.ts",
|
|
56
|
+
"import": "./dist/esm/oxlint/basenames.js",
|
|
57
|
+
"require": "./dist/esm/oxlint/basenames.js",
|
|
58
|
+
"default": "./dist/esm/oxlint/basenames.js"
|
|
59
|
+
},
|
|
60
|
+
"./oxlint/code-safety": {
|
|
61
|
+
"types": "./dist/esm/oxlint/code-safety.d.ts",
|
|
62
|
+
"import": "./dist/esm/oxlint/code-safety.js",
|
|
63
|
+
"require": "./dist/esm/oxlint/code-safety.js",
|
|
64
|
+
"default": "./dist/esm/oxlint/code-safety.js"
|
|
65
|
+
},
|
|
66
|
+
"./oxlint/foundation-purity": {
|
|
67
|
+
"types": "./dist/esm/oxlint/foundation-purity.d.ts",
|
|
68
|
+
"import": "./dist/esm/oxlint/foundation-purity.js",
|
|
69
|
+
"require": "./dist/esm/oxlint/foundation-purity.js",
|
|
70
|
+
"default": "./dist/esm/oxlint/foundation-purity.js"
|
|
71
|
+
},
|
|
72
|
+
"./oxlint/graphql-conventions": {
|
|
73
|
+
"types": "./dist/esm/oxlint/graphql-conventions.d.ts",
|
|
74
|
+
"import": "./dist/esm/oxlint/graphql-conventions.js",
|
|
75
|
+
"require": "./dist/esm/oxlint/graphql-conventions.js",
|
|
76
|
+
"default": "./dist/esm/oxlint/graphql-conventions.js"
|
|
77
|
+
},
|
|
78
|
+
"./oxlint/import-hygiene": {
|
|
79
|
+
"types": "./dist/esm/oxlint/import-hygiene.d.ts",
|
|
80
|
+
"import": "./dist/esm/oxlint/import-hygiene.js",
|
|
81
|
+
"require": "./dist/esm/oxlint/import-hygiene.js",
|
|
82
|
+
"default": "./dist/esm/oxlint/import-hygiene.js"
|
|
83
|
+
},
|
|
84
|
+
"./oxlint/monorepo-paths": {
|
|
85
|
+
"types": "./dist/esm/oxlint/monorepo-paths.d.ts",
|
|
86
|
+
"import": "./dist/esm/oxlint/monorepo-paths.js",
|
|
87
|
+
"require": "./dist/esm/oxlint/monorepo-paths.js",
|
|
88
|
+
"default": "./dist/esm/oxlint/monorepo-paths.js"
|
|
89
|
+
},
|
|
90
|
+
"./oxlint/path-roles": {
|
|
91
|
+
"types": "./dist/esm/oxlint/path-roles.d.ts",
|
|
92
|
+
"import": "./dist/esm/oxlint/path-roles.js",
|
|
93
|
+
"require": "./dist/esm/oxlint/path-roles.js",
|
|
94
|
+
"default": "./dist/esm/oxlint/path-roles.js"
|
|
95
|
+
},
|
|
96
|
+
"./oxlint/query-patterns": {
|
|
97
|
+
"types": "./dist/esm/oxlint/query-patterns.d.ts",
|
|
98
|
+
"import": "./dist/esm/oxlint/query-patterns.js",
|
|
99
|
+
"require": "./dist/esm/oxlint/query-patterns.js",
|
|
100
|
+
"default": "./dist/esm/oxlint/query-patterns.js"
|
|
101
|
+
},
|
|
102
|
+
"./oxlint/testing-quality": {
|
|
103
|
+
"types": "./dist/esm/oxlint/testing-quality.d.ts",
|
|
104
|
+
"import": "./dist/esm/oxlint/testing-quality.js",
|
|
105
|
+
"require": "./dist/esm/oxlint/testing-quality.js",
|
|
106
|
+
"default": "./dist/esm/oxlint/testing-quality.js"
|
|
107
|
+
},
|
|
108
|
+
"./oxlint/tier-boundaries": {
|
|
109
|
+
"types": "./dist/esm/oxlint/tier-boundaries.d.ts",
|
|
110
|
+
"import": "./dist/esm/oxlint/tier-boundaries.js",
|
|
111
|
+
"require": "./dist/esm/oxlint/tier-boundaries.js",
|
|
112
|
+
"default": "./dist/esm/oxlint/tier-boundaries.js"
|
|
113
|
+
},
|
|
48
114
|
"./playwright/quality-scaffold": {
|
|
49
115
|
"import": {
|
|
50
116
|
"types": "./dist/esm/playwright/quality-scaffold.d.ts",
|
|
@@ -177,7 +243,7 @@
|
|
|
177
243
|
"registry": "https://registry.npmjs.org/"
|
|
178
244
|
},
|
|
179
245
|
"scripts": {
|
|
180
|
-
"build": "tshy && bun scripts/normalize-tsconfig-json-exports.ts",
|
|
246
|
+
"build": "tshy && bun scripts/normalize-tsconfig-json-exports.ts && bun scripts/normalize-oxlint-exports.ts",
|
|
181
247
|
"prepublishOnly": "vp run build",
|
|
182
248
|
"typecheck": "tsc --noEmit",
|
|
183
249
|
"lint:pkg": "publint && attw --pack . --profile esm-only"
|
|
@@ -234,6 +300,17 @@
|
|
|
234
300
|
"./deploy": "./src/deploy/index.ts",
|
|
235
301
|
"./dev": "./src/dev/index.ts",
|
|
236
302
|
"./e2e": "./src/e2e/index.ts",
|
|
303
|
+
"./oxlint": "./src/oxlint/index.ts",
|
|
304
|
+
"./oxlint/basenames": "./src/oxlint/basenames.ts",
|
|
305
|
+
"./oxlint/code-safety": "./src/oxlint/code-safety.ts",
|
|
306
|
+
"./oxlint/foundation-purity": "./src/oxlint/foundation-purity.ts",
|
|
307
|
+
"./oxlint/graphql-conventions": "./src/oxlint/graphql-conventions.ts",
|
|
308
|
+
"./oxlint/import-hygiene": "./src/oxlint/import-hygiene.ts",
|
|
309
|
+
"./oxlint/monorepo-paths": "./src/oxlint/monorepo-paths.ts",
|
|
310
|
+
"./oxlint/path-roles": "./src/oxlint/path-roles.ts",
|
|
311
|
+
"./oxlint/query-patterns": "./src/oxlint/query-patterns.ts",
|
|
312
|
+
"./oxlint/testing-quality": "./src/oxlint/testing-quality.ts",
|
|
313
|
+
"./oxlint/tier-boundaries": "./src/oxlint/tier-boundaries.ts",
|
|
237
314
|
"./playwright/quality-scaffold": "./src/playwright/quality-scaffold.ts",
|
|
238
315
|
"./process": "./src/process/index.ts",
|
|
239
316
|
"./repo-root": "./src/repo-root/index.ts",
|