oxlint-plugin-arch 0.12.6 → 0.13.1
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 +121 -0
- package/README.md +4 -4
- package/dist/index.js +1059 -306
- package/dist/preset/preset-effect.d.ts +3 -0
- package/dist/preset/preset-recipes.d.ts +10 -0
- package/dist/preset/preset.constants.d.ts +21 -2
- package/dist/preset/preset.d.ts +11 -1
- package/dist/preset/preset.js +715 -223
- package/dist/preset/preset.utils.d.ts +6 -0
- package/dist/rules/code/code-delegate.d.ts +1 -0
- package/dist/rules/layout/layout-type-arguments.d.ts +1 -0
- package/dist/rules/react/react-query-props.d.ts +1 -0
- package/dist/types/backend.types.d.ts +2 -3
- package/dist/types/boundaries.types.d.ts +26 -1
- package/dist/types/code.types.d.ts +7 -0
- package/dist/types/comments.types.d.ts +1 -0
- package/dist/types/dillon-anti-slop.types.d.ts +6 -0
- package/dist/types/effect.types.d.ts +1 -0
- package/dist/types/files.types.d.ts +3 -2
- package/dist/types/layout.types.d.ts +16 -0
- package/dist/types/naming.types.d.ts +4 -0
- package/dist/types/preset.types.d.ts +26 -24
- package/dist/types/react.types.d.ts +17 -0
- package/dist/types/types.types.d.ts +8 -0
- package/dist/utils/ast.utils.d.ts +1 -2
- package/dist/utils/boundaries.utils.d.ts +72 -4
- package/dist/utils/options.utils.d.ts +1 -0
- package/dist/vendor/dillon-anti-slop/index.js +38 -16
- package/package.json +15 -1
- package/src/vendor/dillon-anti-slop/UPSTREAM.md +3 -0
|
@@ -139,7 +139,7 @@ function optionsPatternsTest(patterns, value) {
|
|
|
139
139
|
function optionsGlob(pattern) {
|
|
140
140
|
const negated = [];
|
|
141
141
|
const source = pattern.replaceAll(/!\(([^()]*)\)/g, (_, options) => {
|
|
142
|
-
negated.push(options.split("|").map((option) => option.replaceAll(/[.+^$()|[\]
|
|
142
|
+
negated.push(options.split("|").map((option) => option.replaceAll(/[.+^$()|[\]\\?{}]/g, "\\$&").replaceAll("*", "[^/]*")).join("|"));
|
|
143
143
|
return `\x02${negated.length - 1}\x03`;
|
|
144
144
|
}).replaceAll(/[.+^$()|[\]\\]/g, "\\$&").replaceAll("?", "[^/]").replaceAll("**/", "\x00").replaceAll("**", "\x01").replaceAll("*", "[^/]*").replaceAll("\x00", "(?:.*/)?").replaceAll("\x01", ".*").replaceAll(/\{([^}]*)\}/g, (_, options) => `(?:${options.split(",").join("|")})`);
|
|
145
145
|
return new RegExp(`^${negated.reduce((text, names, index) => text.replace(`\x02${index}\x03`, `(?!(?:${names})(?:/|$))[^/]*`), source)}$`);
|
|
@@ -152,6 +152,9 @@ function optionsAssertMockingApis(patterns) {
|
|
|
152
152
|
throw new OptionsError("Test mocking APIs must be `*` or `<vi|jest|*>.<method|*>`.");
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
+
function optionsEscape(value) {
|
|
156
|
+
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
157
|
+
}
|
|
155
158
|
|
|
156
159
|
// src/utils/ast.utils.ts
|
|
157
160
|
var astSkippedKeys = new Set(["parent", "type", "start", "end", "range", "loc", "tokens", "comments"]);
|
|
@@ -339,9 +342,6 @@ function astIsInlineFunction(node) {
|
|
|
339
342
|
function astIsCall(node) {
|
|
340
343
|
return node.type === "CallExpression" || node.type === "NewExpression";
|
|
341
344
|
}
|
|
342
|
-
function astIsPipe(node) {
|
|
343
|
-
return node.callee.type === "MemberExpression" && astMemberName(node.callee) === "pipe";
|
|
344
|
-
}
|
|
345
345
|
function astChildren(node) {
|
|
346
346
|
return Object.entries(node).filter(([key]) => !astSkippedKeys.has(key)).map(([, child]) => child);
|
|
347
347
|
}
|
|
@@ -351,17 +351,20 @@ function astSome(value, test, enter = () => true) {
|
|
|
351
351
|
}
|
|
352
352
|
return astIsNode(value) && (test(value) || enter(value) && astChildren(value).some((child) => astSome(child, test, enter)));
|
|
353
353
|
}
|
|
354
|
-
function astCallDepth(value) {
|
|
354
|
+
function astCallDepth(value, callbacks = false) {
|
|
355
355
|
if (Array.isArray(value)) {
|
|
356
|
-
return Math.max(0, ...value.map(astCallDepth));
|
|
356
|
+
return Math.max(0, ...value.map((item) => astCallDepth(item, callbacks)));
|
|
357
357
|
}
|
|
358
|
-
if (!astIsNode(value)
|
|
358
|
+
if (!astIsNode(value)) {
|
|
359
359
|
return 0;
|
|
360
360
|
}
|
|
361
|
+
if (astIsInlineFunction(value)) {
|
|
362
|
+
return callbacks ? astCallDepth(value.body, callbacks) : 0;
|
|
363
|
+
}
|
|
361
364
|
if (astIsCall(value)) {
|
|
362
|
-
return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments), astCallDepth(value.callee));
|
|
365
|
+
return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments, callbacks), astCallDepth(value.callee, callbacks));
|
|
363
366
|
}
|
|
364
|
-
return astCallDepth(astChildren(value));
|
|
367
|
+
return astCallDepth(astChildren(value), callbacks);
|
|
365
368
|
}
|
|
366
369
|
|
|
367
370
|
// src/vendor/dillon-anti-slop/shared/type-reference-name.ts
|
|
@@ -1247,7 +1250,6 @@ var noRuntimeTypeofRule = defineRule8({
|
|
|
1247
1250
|
|
|
1248
1251
|
// src/vendor/dillon-anti-slop/rules/no-shape-in-symbol-names.ts
|
|
1249
1252
|
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1250
|
-
var FORBIDDEN_SYMBOL_NAME = "shape";
|
|
1251
1253
|
function namesForeignApi(node) {
|
|
1252
1254
|
const parent = node.parent;
|
|
1253
1255
|
if (!parent) {
|
|
@@ -1279,22 +1281,29 @@ var noForbiddenTermInSymbolNamesRule = defineRule9({
|
|
|
1279
1281
|
docs: {
|
|
1280
1282
|
description: 'Disallow the case-insensitive substring "shape" in JavaScript, TypeScript, private, and JSX symbol names.'
|
|
1281
1283
|
},
|
|
1284
|
+
schema: [{ type: "object", additionalProperties: false, properties: { terms: { type: "array", items: { type: "string", minLength: 1 }, minItems: 1 } } }],
|
|
1282
1285
|
messages: {
|
|
1283
|
-
forbiddenSymbolName: 'Rename symbol "{{name}}" for its domain role; "
|
|
1286
|
+
forbiddenSymbolName: 'Rename symbol "{{name}}" for its domain role; "{{term}}" describes structure rather than ownership.'
|
|
1284
1287
|
}
|
|
1285
1288
|
},
|
|
1286
1289
|
createOnce(context) {
|
|
1290
|
+
let terms = [];
|
|
1287
1291
|
const reportForbiddenSymbolName = (node) => {
|
|
1288
|
-
|
|
1292
|
+
const lower = node.name.toLowerCase();
|
|
1293
|
+
const term = terms.find((candidate) => lower.includes(candidate));
|
|
1294
|
+
if (term === undefined || namesForeignApi(node)) {
|
|
1289
1295
|
return;
|
|
1290
1296
|
}
|
|
1291
1297
|
context.report({
|
|
1292
1298
|
node,
|
|
1293
1299
|
messageId: "forbiddenSymbolName",
|
|
1294
|
-
data: { name: node.name }
|
|
1300
|
+
data: { name: node.name, term }
|
|
1295
1301
|
});
|
|
1296
1302
|
};
|
|
1297
1303
|
return {
|
|
1304
|
+
before() {
|
|
1305
|
+
terms = (optionsFirst(context, {}).terms ?? ["shape"]).map((term) => term.toLowerCase());
|
|
1306
|
+
},
|
|
1298
1307
|
Identifier: reportForbiddenSymbolName,
|
|
1299
1308
|
PrivateIdentifier: reportForbiddenSymbolName,
|
|
1300
1309
|
JSXIdentifier: reportForbiddenSymbolName
|
|
@@ -1750,18 +1759,22 @@ var requireSafetyCommentForTypeAssertionRule = defineRule15({
|
|
|
1750
1759
|
docs: {
|
|
1751
1760
|
description: "Require a nearby SAFETY comment for every TypeScript type assertion except const assertions."
|
|
1752
1761
|
},
|
|
1762
|
+
schema: [{ type: "object", additionalProperties: false, properties: { comment: { type: "string", minLength: 1 } } }],
|
|
1753
1763
|
messages: {
|
|
1754
|
-
missingSafetyComment: "This type assertion has no `
|
|
1764
|
+
missingSafetyComment: "This type assertion has no `{{comment}}` justification. State the checked invariant immediately before the assertion or its containing statement."
|
|
1755
1765
|
}
|
|
1756
1766
|
},
|
|
1757
1767
|
createOnce(context) {
|
|
1768
|
+
let comment = "SAFETY:";
|
|
1769
|
+
let marker = /(?<![\p{L}\p{N}_])SAFETY\s*:/u;
|
|
1758
1770
|
const checkAssertion = (node) => {
|
|
1759
1771
|
if (expressionsIsConstAssertion(node)) {
|
|
1760
1772
|
return;
|
|
1761
1773
|
}
|
|
1762
1774
|
let current = node;
|
|
1775
|
+
const justified = (candidate) => candidate.end <= node.start && marker.test(candidate.value);
|
|
1763
1776
|
for (;; ) {
|
|
1764
|
-
if (context.sourceCode.getCommentsBefore(current).some(
|
|
1777
|
+
if (context.sourceCode.getCommentsBefore(current).some(justified)) {
|
|
1765
1778
|
return;
|
|
1766
1779
|
}
|
|
1767
1780
|
const parent = current.parent;
|
|
@@ -1770,9 +1783,18 @@ var requireSafetyCommentForTypeAssertionRule = defineRule15({
|
|
|
1770
1783
|
}
|
|
1771
1784
|
current = parent;
|
|
1772
1785
|
}
|
|
1773
|
-
context.report({
|
|
1786
|
+
context.report({
|
|
1787
|
+
node,
|
|
1788
|
+
messageId: "missingSafetyComment",
|
|
1789
|
+
data: { comment }
|
|
1790
|
+
});
|
|
1774
1791
|
};
|
|
1775
1792
|
return {
|
|
1793
|
+
before() {
|
|
1794
|
+
comment = optionsFirst(context, {}).comment ?? "SAFETY:";
|
|
1795
|
+
const word = optionsEscape(comment.replace(/:\s*$/, ""));
|
|
1796
|
+
marker = new RegExp(`(?<![\\p{L}\\p{N}_])${word}\\s*:`, "u");
|
|
1797
|
+
},
|
|
1776
1798
|
TSAsExpression: checkAssertion,
|
|
1777
1799
|
TSTypeAssertion: checkAssertion
|
|
1778
1800
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxlint-plugin-arch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Configurable architecture rules for Oxlint JavaScript plugins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -57,8 +57,11 @@
|
|
|
57
57
|
"@effect/tsgo": ">=0.67.1",
|
|
58
58
|
"@opsydyn/oxlint-effect": ">=2.0.1",
|
|
59
59
|
"@shadcn/lint": ">=0.2.3",
|
|
60
|
+
"eslint-plugin-de-morgan": ">=2.3.0",
|
|
60
61
|
"eslint-plugin-react": ">=7.37.5",
|
|
61
62
|
"eslint-plugin-react-you-might-not-need-an-effect": ">=1.0.2",
|
|
63
|
+
"eslint-plugin-regexp": ">=3.3.3",
|
|
64
|
+
"eslint-plugin-sonarjs": ">=4.2.2",
|
|
62
65
|
"eslint-plugin-svg-jsx": ">=1.3.0",
|
|
63
66
|
"oxlint": ">=1.85.0",
|
|
64
67
|
"oxlint-tailwindcss": ">=1.16.0",
|
|
@@ -70,8 +73,10 @@
|
|
|
70
73
|
"@shadcn/lint": "0.2.3",
|
|
71
74
|
"@types/node": "26.6.5",
|
|
72
75
|
"bumpp": "12.3.0",
|
|
76
|
+
"eslint-plugin-de-morgan": "2.3.0",
|
|
73
77
|
"eslint-plugin-react": "7.37.5",
|
|
74
78
|
"eslint-plugin-react-you-might-not-need-an-effect": "1.0.2",
|
|
79
|
+
"eslint-plugin-regexp": "3.3.3",
|
|
75
80
|
"eslint-plugin-svg-jsx": "1.3.0",
|
|
76
81
|
"fallow": "3.36.0",
|
|
77
82
|
"oxlint": "1.89.0",
|
|
@@ -111,12 +116,21 @@
|
|
|
111
116
|
"@shadcn/lint": {
|
|
112
117
|
"optional": true
|
|
113
118
|
},
|
|
119
|
+
"eslint-plugin-de-morgan": {
|
|
120
|
+
"optional": true
|
|
121
|
+
},
|
|
114
122
|
"eslint-plugin-react": {
|
|
115
123
|
"optional": true
|
|
116
124
|
},
|
|
117
125
|
"eslint-plugin-react-you-might-not-need-an-effect": {
|
|
118
126
|
"optional": true
|
|
119
127
|
},
|
|
128
|
+
"eslint-plugin-regexp": {
|
|
129
|
+
"optional": true
|
|
130
|
+
},
|
|
131
|
+
"eslint-plugin-sonarjs": {
|
|
132
|
+
"optional": true
|
|
133
|
+
},
|
|
120
134
|
"eslint-plugin-svg-jsx": {
|
|
121
135
|
"optional": true
|
|
122
136
|
},
|
|
@@ -14,6 +14,9 @@ The TanStack preset selects the enabled rules; this directory implements them
|
|
|
14
14
|
and is not a separate preset. Upstream intentionally distributes source for
|
|
15
15
|
vendoring and does not publish an official npm package.
|
|
16
16
|
|
|
17
|
+
Local options: `terms` on `no-shape-in-symbol-names` and `comment` on
|
|
18
|
+
`require-safety-comment-for-type-assertion`; their defaults keep upstream behavior.
|
|
19
|
+
|
|
17
20
|
Local behavior fixes recognize `SAFETY:` comments on exported declarations and
|
|
18
21
|
export-default assertions, while retaining statement boundaries for other
|
|
19
22
|
assertions.
|