Files
openclaw/scripts/oxlint-boundary-guards.mjs
ff95d0c269 improve(ci): replace boundary guards with focused Oxlint rules (#95368)
* perf(ci): move boundary guards to oxlint

Co-authored-by: Sash Zats <sash@zats.io>

* fix(ci): avoid dead editor URL export

Co-authored-by: Sash Zats <sash@zats.io>

* fix(ci): declare path-loaded boundary guard roots

Co-authored-by: Sash Zats <sash@zats.io>

* fix(ci): model Oxlint plugin export in Knip

Co-authored-by: Sash Zats <sash@zats.io>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 11:37:35 +01:00

67 lines
2.4 KiB
JavaScript

const EXPRESSION_WRAPPER_RE =
/^(?:ChainExpression|ParenthesizedExpression|TSAsExpression|TSNonNullExpression|TSTypeAssertion)$/;
const TEST_FILE_SUFFIXES = [".test.ts", ".test-utils.ts", ".test-harness.ts", ".e2e-harness.ts"];
function unwrapExpression(node) {
let current = node;
while (EXPRESSION_WRAPPER_RE.test(current.type)) {
current = current.expression;
}
return current;
}
function restrictedCallRule({ allowedFiles = [], message, objects, property, roots }) {
return {
create(context) {
const filename = context.physicalFilename.replaceAll("\\", "/");
const cwd = context.cwd.replaceAll("\\", "/");
const repoPath = filename.startsWith(`${cwd}/`) ? filename.slice(cwd.length + 1) : filename;
if (
!filename.endsWith(".ts") ||
!roots.some((root) => repoPath === root || repoPath.startsWith(`${root}/`)) ||
TEST_FILE_SUFFIXES.some((suffix) => filename.endsWith(suffix)) ||
allowedFiles.includes(repoPath)
) {
return {};
}
return {
CallExpression(node) {
const callee = unwrapExpression(node.callee);
if (
callee.type !== "MemberExpression" ||
callee.computed ||
callee.property.type !== "Identifier" ||
callee.property.name !== property
) {
return;
}
const receiver = unwrapExpression(callee.object);
if (objects && (receiver.type !== "Identifier" || !objects.includes(receiver.name))) {
return;
}
context.report({ message, node: node.callee });
},
};
},
};
}
export default {
meta: { name: "openclaw-boundaries" },
rules: {
"no-raw-window-open-call": restrictedCallRule({
allowedFiles: ["ui/src/lib/editor-links.ts", "ui/src/lib/open-external-url.ts"],
roots: ["ui/src", "test/fixtures/oxlint-boundary-guards"],
property: "open",
objects: ["window", "globalThis"],
message: "Use openExternalUrlSafe(...) from ui/src/lib/open-external-url.ts instead.",
}),
"no-register-http-handler-call": restrictedCallRule({
roots: ["src", "extensions", "test/fixtures/oxlint-boundary-guards"],
property: "registerHttpHandler",
message:
"Use registerHttpRoute({ path, auth, match, handler }) and registerPluginHttpRoute for dynamic webhook paths.",
}),
},
};