oxlint-plugin-arch 0.13.0 → 0.13.2

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +7 -7
  3. package/dist/index.js +2154 -504
  4. package/dist/preset/groups/top.d.ts +2 -0
  5. package/dist/preset/preset-sets.d.ts +2 -0
  6. package/dist/preset/preset.constants.d.ts +4 -1
  7. package/dist/preset/preset.js +299 -57
  8. package/dist/preset/preset.utils.d.ts +2 -0
  9. package/dist/rules/code/code-inside.d.ts +1 -0
  10. package/dist/rules/effect/effect-layer-keys.d.ts +1 -0
  11. package/dist/rules/effect/effect-service-params.d.ts +1 -0
  12. package/dist/rules/effect/effect-yield-name.d.ts +1 -0
  13. package/dist/rules/effect/effect-yields-first.d.ts +1 -0
  14. package/dist/rules/files/files-siblings.d.ts +1 -0
  15. package/dist/rules/files/files-top-level.d.ts +1 -0
  16. package/dist/rules/layout/layout-type-arguments.d.ts +1 -0
  17. package/dist/rules/naming/naming-imports.d.ts +1 -0
  18. package/dist/rules/naming/naming-keys.d.ts +1 -0
  19. package/dist/rules/naming/naming-labels.d.ts +1 -0
  20. package/dist/rules/naming/naming-pairs.d.ts +1 -0
  21. package/dist/types/boundaries.types.d.ts +33 -1
  22. package/dist/types/code.types.d.ts +12 -0
  23. package/dist/types/comments.types.d.ts +1 -0
  24. package/dist/types/dillon-anti-slop.types.d.ts +6 -0
  25. package/dist/types/effect.types.d.ts +21 -0
  26. package/dist/types/files.types.d.ts +33 -3
  27. package/dist/types/layout.types.d.ts +16 -0
  28. package/dist/types/naming.types.d.ts +74 -2
  29. package/dist/types/preset.types.d.ts +26 -0
  30. package/dist/types/react.types.d.ts +13 -0
  31. package/dist/types/types.types.d.ts +4 -0
  32. package/dist/utils/ast.utils.d.ts +1 -2
  33. package/dist/utils/boundaries.utils.d.ts +72 -4
  34. package/dist/utils/naming.utils.d.ts +4 -1
  35. package/dist/utils/options.utils.d.ts +2 -0
  36. package/dist/vendor/dillon-anti-slop/index.js +40 -15
  37. package/package.json +1 -1
  38. package/src/vendor/dillon-anti-slop/UPSTREAM.md +3 -0
@@ -152,6 +152,12 @@ 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
+ }
158
+ function optionsWildcards(names) {
159
+ return [names ?? []].flat().map((name) => new RegExp(`^${name.split("*").map(optionsEscape).join(".*")}$`));
160
+ }
155
161
 
156
162
  // src/utils/ast.utils.ts
157
163
  var astSkippedKeys = new Set(["parent", "type", "start", "end", "range", "loc", "tokens", "comments"]);
@@ -339,9 +345,6 @@ function astIsInlineFunction(node) {
339
345
  function astIsCall(node) {
340
346
  return node.type === "CallExpression" || node.type === "NewExpression";
341
347
  }
342
- function astIsPipe(node) {
343
- return node.callee.type === "MemberExpression" && astMemberName(node.callee) === "pipe";
344
- }
345
348
  function astChildren(node) {
346
349
  return Object.entries(node).filter(([key]) => !astSkippedKeys.has(key)).map(([, child]) => child);
347
350
  }
@@ -351,17 +354,20 @@ function astSome(value, test, enter = () => true) {
351
354
  }
352
355
  return astIsNode(value) && (test(value) || enter(value) && astChildren(value).some((child) => astSome(child, test, enter)));
353
356
  }
354
- function astCallDepth(value) {
357
+ function astCallDepth(value, callbacks = false) {
355
358
  if (Array.isArray(value)) {
356
- return Math.max(0, ...value.map(astCallDepth));
359
+ return Math.max(0, ...value.map((item) => astCallDepth(item, callbacks)));
357
360
  }
358
- if (!astIsNode(value) || astIsInlineFunction(value)) {
361
+ if (!astIsNode(value)) {
359
362
  return 0;
360
363
  }
364
+ if (astIsInlineFunction(value)) {
365
+ return callbacks ? astCallDepth(value.body, callbacks) : 0;
366
+ }
361
367
  if (astIsCall(value)) {
362
- return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments), astCallDepth(value.callee));
368
+ return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments, callbacks), astCallDepth(value.callee, callbacks));
363
369
  }
364
- return astCallDepth(astChildren(value));
370
+ return astCallDepth(astChildren(value), callbacks);
365
371
  }
366
372
 
367
373
  // src/vendor/dillon-anti-slop/shared/type-reference-name.ts
@@ -1247,7 +1253,6 @@ var noRuntimeTypeofRule = defineRule8({
1247
1253
 
1248
1254
  // src/vendor/dillon-anti-slop/rules/no-shape-in-symbol-names.ts
1249
1255
  import { defineRule as defineRule9 } from "@oxlint/plugins";
1250
- var FORBIDDEN_SYMBOL_NAME = "shape";
1251
1256
  function namesForeignApi(node) {
1252
1257
  const parent = node.parent;
1253
1258
  if (!parent) {
@@ -1279,22 +1284,29 @@ var noForbiddenTermInSymbolNamesRule = defineRule9({
1279
1284
  docs: {
1280
1285
  description: 'Disallow the case-insensitive substring "shape" in JavaScript, TypeScript, private, and JSX symbol names.'
1281
1286
  },
1287
+ schema: [{ type: "object", additionalProperties: false, properties: { terms: { type: "array", items: { type: "string", minLength: 1 }, minItems: 1 } } }],
1282
1288
  messages: {
1283
- forbiddenSymbolName: 'Rename symbol "{{name}}" for its domain role; "shape" describes structure rather than ownership.'
1289
+ forbiddenSymbolName: 'Rename symbol "{{name}}" for its domain role; "{{term}}" describes structure rather than ownership.'
1284
1290
  }
1285
1291
  },
1286
1292
  createOnce(context) {
1293
+ let terms = [];
1287
1294
  const reportForbiddenSymbolName = (node) => {
1288
- if (!node.name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME) || namesForeignApi(node)) {
1295
+ const lower = node.name.toLowerCase();
1296
+ const term = terms.find((candidate) => lower.includes(candidate));
1297
+ if (term === undefined || namesForeignApi(node)) {
1289
1298
  return;
1290
1299
  }
1291
1300
  context.report({
1292
1301
  node,
1293
1302
  messageId: "forbiddenSymbolName",
1294
- data: { name: node.name }
1303
+ data: { name: node.name, term }
1295
1304
  });
1296
1305
  };
1297
1306
  return {
1307
+ before() {
1308
+ terms = (optionsFirst(context, {}).terms ?? ["shape"]).map((term) => term.toLowerCase());
1309
+ },
1298
1310
  Identifier: reportForbiddenSymbolName,
1299
1311
  PrivateIdentifier: reportForbiddenSymbolName,
1300
1312
  JSXIdentifier: reportForbiddenSymbolName
@@ -1750,18 +1762,22 @@ var requireSafetyCommentForTypeAssertionRule = defineRule15({
1750
1762
  docs: {
1751
1763
  description: "Require a nearby SAFETY comment for every TypeScript type assertion except const assertions."
1752
1764
  },
1765
+ schema: [{ type: "object", additionalProperties: false, properties: { comment: { type: "string", minLength: 1 } } }],
1753
1766
  messages: {
1754
- missingSafetyComment: "This type assertion has no `SAFETY:` justification. State the checked invariant immediately before the assertion or its containing statement."
1767
+ missingSafetyComment: "This type assertion has no `{{comment}}` justification. State the checked invariant immediately before the assertion or its containing statement."
1755
1768
  }
1756
1769
  },
1757
1770
  createOnce(context) {
1771
+ let comment = "SAFETY:";
1772
+ let marker = /(?<![\p{L}\p{N}_])SAFETY\s*:/u;
1758
1773
  const checkAssertion = (node) => {
1759
1774
  if (expressionsIsConstAssertion(node)) {
1760
1775
  return;
1761
1776
  }
1762
1777
  let current = node;
1778
+ const justified = (candidate) => candidate.end <= node.start && marker.test(candidate.value);
1763
1779
  for (;; ) {
1764
- if (context.sourceCode.getCommentsBefore(current).some((comment) => comment.end <= node.start && /\bSAFETY\s*:/u.test(comment.value))) {
1780
+ if (context.sourceCode.getCommentsBefore(current).some(justified)) {
1765
1781
  return;
1766
1782
  }
1767
1783
  const parent = current.parent;
@@ -1770,9 +1786,18 @@ var requireSafetyCommentForTypeAssertionRule = defineRule15({
1770
1786
  }
1771
1787
  current = parent;
1772
1788
  }
1773
- context.report({ node, messageId: "missingSafetyComment" });
1789
+ context.report({
1790
+ node,
1791
+ messageId: "missingSafetyComment",
1792
+ data: { comment }
1793
+ });
1774
1794
  };
1775
1795
  return {
1796
+ before() {
1797
+ comment = optionsFirst(context, {}).comment ?? "SAFETY:";
1798
+ const word = optionsEscape(comment.replace(/:\s*$/, ""));
1799
+ marker = new RegExp(`(?<![\\p{L}\\p{N}_])${word}\\s*:`, "u");
1800
+ },
1776
1801
  TSAsExpression: checkAssertion,
1777
1802
  TSTypeAssertion: checkAssertion
1778
1803
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-arch",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Configurable architecture rules for Oxlint JavaScript plugins.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -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.