oxlint-plugin-arch 0.12.3 → 0.12.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/dist/index.js CHANGED
@@ -225,6 +225,39 @@ function astSelectorRule(selector, message) {
225
225
  }
226
226
  });
227
227
  }
228
+ function astIsOneLine(node) {
229
+ return node.loc.start.line === node.loc.end.line;
230
+ }
231
+ function astIsInlineFunction(node) {
232
+ return node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
233
+ }
234
+ function astIsCall(node) {
235
+ return node.type === "CallExpression" || node.type === "NewExpression";
236
+ }
237
+ function astIsPipe(node) {
238
+ return node.callee.type === "MemberExpression" && astMemberName(node.callee) === "pipe";
239
+ }
240
+ function astChildren(node) {
241
+ return Object.entries(node).filter(([key]) => !astSkippedKeys.has(key)).map(([, child]) => child);
242
+ }
243
+ function astSome(value, test, enter = () => true) {
244
+ if (Array.isArray(value)) {
245
+ return value.some((child) => astSome(child, test, enter));
246
+ }
247
+ return astIsNode(value) && (test(value) || enter(value) && astChildren(value).some((child) => astSome(child, test, enter)));
248
+ }
249
+ function astCallDepth(value) {
250
+ if (Array.isArray(value)) {
251
+ return Math.max(0, ...value.map(astCallDepth));
252
+ }
253
+ if (!astIsNode(value) || astIsInlineFunction(value)) {
254
+ return 0;
255
+ }
256
+ if (astIsCall(value)) {
257
+ return Math.max(value.arguments.length === 0 ? 0 : 1 + astCallDepth(value.arguments), astCallDepth(value.callee));
258
+ }
259
+ return astCallDepth(astChildren(value));
260
+ }
228
261
 
229
262
  // src/rules/backend/backend-orpc-output.ts
230
263
  function backendFindChainCall(expression, method) {
@@ -1786,9 +1819,59 @@ var boundariesTokenOwner = defineRule10({
1786
1819
  }
1787
1820
  });
1788
1821
 
1789
- // src/rules/code/code-constructor.ts
1822
+ // src/rules/code/code-branch-once.ts
1790
1823
  import { defineRule as defineRule11 } from "@oxlint/plugins";
1791
- var codeConstructor = defineRule11({
1824
+ function codeBranchOnceSubjects(node, source) {
1825
+ if (node.type === "LogicalExpression") {
1826
+ return [...codeBranchOnceSubjects(node.left, source), ...codeBranchOnceSubjects(node.right, source)];
1827
+ }
1828
+ if (node.type === "UnaryExpression" && node.operator === "!") {
1829
+ return codeBranchOnceSubjects(node.argument, source);
1830
+ }
1831
+ if (node.type !== "BinaryExpression" || node.operator !== "===" && node.operator !== "!==") {
1832
+ return [];
1833
+ }
1834
+ const sides = [node.left, node.right];
1835
+ const member = sides.find((side) => side.type === "MemberExpression");
1836
+ const literal = sides.some((side) => side.type === "Literal" && typeof side.value === "string");
1837
+ return member && literal ? [source.getText(member)] : [];
1838
+ }
1839
+ var codeBranchOnce = defineRule11({
1840
+ meta: {
1841
+ type: "suggestion",
1842
+ messages: {
1843
+ once: "{{subject}} is compared to a string in {{count}} ternaries in this file. Branch on it once and return a record."
1844
+ }
1845
+ },
1846
+ createOnce(context) {
1847
+ let groups = new Map;
1848
+ return {
1849
+ before() {
1850
+ groups = new Map;
1851
+ },
1852
+ ConditionalExpression(node) {
1853
+ for (const subject of new Set(codeBranchOnceSubjects(node.test, context.sourceCode))) {
1854
+ groups.set(subject, [...groups.get(subject) ?? [], node]);
1855
+ }
1856
+ },
1857
+ "Program:exit"() {
1858
+ for (const [subject, ternaries] of groups) {
1859
+ for (const node of ternaries.length > 1 ? ternaries : []) {
1860
+ context.report({
1861
+ node,
1862
+ messageId: "once",
1863
+ data: { subject, count: String(ternaries.length) }
1864
+ });
1865
+ }
1866
+ }
1867
+ }
1868
+ };
1869
+ }
1870
+ });
1871
+
1872
+ // src/rules/code/code-constructor.ts
1873
+ import { defineRule as defineRule12 } from "@oxlint/plugins";
1874
+ var codeConstructor = defineRule12({
1792
1875
  meta: {
1793
1876
  type: "problem",
1794
1877
  schema: [
@@ -1871,9 +1954,285 @@ var codeConstructor = defineRule11({
1871
1954
  // src/rules/code/code-double-negation.ts
1872
1955
  var codeDoubleNegation = astSelectorRule('UnaryExpression[operator="!"] > UnaryExpression[operator="!"]', "Use Boolean(value) or an explicit comparison.");
1873
1956
 
1957
+ // src/rules/code/code-function-nesting.ts
1958
+ import { defineRule as defineRule13 } from "@oxlint/plugins";
1959
+ var codeFunctionNesting = defineRule13({
1960
+ meta: {
1961
+ type: "suggestion",
1962
+ schema: [
1963
+ {
1964
+ type: "object",
1965
+ additionalProperties: false,
1966
+ properties: { max: { type: "integer", minimum: 1, default: 4 } }
1967
+ }
1968
+ ],
1969
+ messages: {
1970
+ deep: "Functions nest {{depth}} deep (max {{max}}). Name the inner step."
1971
+ }
1972
+ },
1973
+ createOnce(context) {
1974
+ let max = 4;
1975
+ const check = (node) => {
1976
+ let depth = 0;
1977
+ for (let current = node;current; current = current.parent) {
1978
+ depth += current.type === "FunctionDeclaration" || astIsInlineFunction(current) ? 1 : 0;
1979
+ }
1980
+ if (depth === max + 1) {
1981
+ context.report({
1982
+ node,
1983
+ messageId: "deep",
1984
+ data: { depth: String(depth), max: String(max) }
1985
+ });
1986
+ }
1987
+ };
1988
+ return {
1989
+ before() {
1990
+ max = optionsFirst(context, {}).max ?? 4;
1991
+ },
1992
+ ArrowFunctionExpression: check,
1993
+ FunctionExpression: check,
1994
+ FunctionDeclaration: check
1995
+ };
1996
+ }
1997
+ });
1998
+
1999
+ // src/rules/code/code-inline.ts
2000
+ import { defineRule as defineRule14 } from "@oxlint/plugins";
2001
+
2002
+ // src/utils/source.utils.ts
2003
+ var sourceDirective = /^\s*(?:\/\s*<(?:reference\b|amd-[\w-]+\b)|@ts-(?:check|ignore|expect-error|nocheck)\b|(?:#|@)__(?:PURE|NO_SIDE_EFFECTS)__\b|@jsx(?:ImportSource|Runtime|Frag)?\b|@vite-ignore\b|(?:[#@]\s*)?sourceMappingURL=|(?:es|ox)lint-(?:disable|enable)|prettier-ignore|biome-ignore|[cv]8 ignore|istanbul ignore|webpack[A-Z])/;
2004
+ var sourceLegalBlock = "\x00legal-block\x00";
2005
+ var sourceIndentSchema = {
2006
+ anyOf: [
2007
+ { type: "integer", minimum: 0 },
2008
+ { type: "string", enum: ["tab"] }
2009
+ ]
2010
+ };
2011
+ function sourceCommentText(comment) {
2012
+ const value = (comment.type === "Block" ? comment.value.replace(/^\s*\* ?/gm, "") : comment.value).trimStart();
2013
+ return comment.type === "Block" && comment.value.startsWith("!") ? sourceLegalBlock + value : value;
2014
+ }
2015
+ function sourceIsDirective(text) {
2016
+ return text.startsWith(sourceLegalBlock) || sourceDirective.test(text);
2017
+ }
2018
+ function sourceLineIndent(text, offset) {
2019
+ const lineStart = text.lastIndexOf(`
2020
+ `, offset - 1) + 1;
2021
+ return /^[\t ]*/.exec(text.slice(lineStart, offset))?.[0] ?? "";
2022
+ }
2023
+ function sourceIndentUnit(indent = 2) {
2024
+ return indent === "tab" ? "\t" : " ".repeat(indent);
2025
+ }
2026
+ function sourceNewline(text) {
2027
+ return text.includes(`\r
2028
+ `) ? `\r
2029
+ ` : `
2030
+ `;
2031
+ }
2032
+ function sourceLineStart(text, offset) {
2033
+ return text.lastIndexOf(`
2034
+ `, offset - 1) + 1;
2035
+ }
2036
+ function sourceLineEnd(text, offset) {
2037
+ const end = text.indexOf(`
2038
+ `, offset);
2039
+ return end === -1 ? text.length : end;
2040
+ }
2041
+ function sourceItemGaps(open, items, close) {
2042
+ const edges = [open, ...items.flatMap((item) => item.range), close];
2043
+ return Array.from({ length: items.length + 1 }, (_, index) => [edges[index * 2] ?? open, edges[index * 2 + 1] ?? close]);
2044
+ }
2045
+ function sourceRespace(fixer, text, gaps, spacing) {
2046
+ const matches = gaps.map((gap) => /^\s*(,?)\s*$/.exec(text.slice(...gap)));
2047
+ if (matches.some((match) => match === null)) {
2048
+ return null;
2049
+ }
2050
+ return gaps.map((gap, index) => fixer.replaceTextRange(gap, `${matches[index]?.[1] ?? ""}${spacing(index, index === gaps.length - 1)}`));
2051
+ }
2052
+
2053
+ // src/rules/code/code-inline.ts
2054
+ function codeInlineIsData(node) {
2055
+ return node.type === "ObjectExpression" || node.type === "ArrayExpression" || (node.type === "TSSatisfiesExpression" || node.type === "TSAsExpression") && codeInlineIsData(node.expression);
2056
+ }
2057
+ function codeInlineOuterCall(node) {
2058
+ const parent = node.parent;
2059
+ if (!parent || astIsInlineFunction(parent) || parent.type.endsWith("Statement")) {
2060
+ return;
2061
+ }
2062
+ return astIsCall(parent) && parent.arguments.some((argument) => argument === node) ? parent : codeInlineOuterCall(parent);
2063
+ }
2064
+ function codeInlineEnclosingCalls(node) {
2065
+ const outer = codeInlineOuterCall(node);
2066
+ return outer && astIsOneLine(outer) ? 1 + codeInlineEnclosingCalls(outer) : 0;
2067
+ }
2068
+ var codeInlineWrapped = new Set(["ConditionalExpression", "LogicalExpression", "BinaryExpression", "ArrowFunctionExpression"]);
2069
+ var codeInline = defineRule14({
2070
+ meta: {
2071
+ type: "suggestion",
2072
+ schema: [
2073
+ {
2074
+ type: "object",
2075
+ additionalProperties: false,
2076
+ properties: {
2077
+ max: { type: "integer", minimum: 1, default: 160 },
2078
+ nesting: { type: "integer", minimum: 1, default: 2 },
2079
+ allow: optionsPatternSchema,
2080
+ keep: optionsPatternSchema,
2081
+ services: { type: "array", items: { type: "string" } }
2082
+ }
2083
+ }
2084
+ ],
2085
+ messages: {
2086
+ once: "{{name}} is used once: inline it.",
2087
+ trivial: "{{name}} only wraps one call or expression: inline it at each use."
2088
+ }
2089
+ },
2090
+ createOnce(context) {
2091
+ let options = {};
2092
+ let allowed = [];
2093
+ let kept = [];
2094
+ const reads = (node) => {
2095
+ const variable = context.sourceCode.getDeclaredVariables(node).at(0);
2096
+ return variable ? variable.references.filter((reference) => !reference.init) : [];
2097
+ };
2098
+ const top = (node, id, init) => {
2099
+ if (id.type !== "Identifier" || !astIsOneLine(node) || init && codeInlineIsData(init) || optionsPatternsTest(allowed, id.name)) {
2100
+ return;
2101
+ }
2102
+ const uses = reads(node);
2103
+ if (uses.some((reference) => reference.identifier.parent.type === "ExportSpecifier")) {
2104
+ return;
2105
+ }
2106
+ if (uses.length === 1) {
2107
+ context.report({
2108
+ node: id,
2109
+ messageId: "once",
2110
+ data: { name: id.name }
2111
+ });
2112
+ return;
2113
+ }
2114
+ const arrow = init?.type === "ArrowFunctionExpression" && init.body.type !== "BlockStatement" && !astSome(init.body, astIsInlineFunction);
2115
+ const call = init?.type === "CallExpression" && !astSome(init.arguments, astIsInlineFunction) && astCallDepth(init) <= 2;
2116
+ if (!optionsPatternsTest(kept, id.name) && (arrow || call)) {
2117
+ context.report({
2118
+ node: id,
2119
+ messageId: "trivial",
2120
+ data: { name: id.name }
2121
+ });
2122
+ }
2123
+ };
2124
+ const local = (declarator) => {
2125
+ const { id, init } = declarator;
2126
+ const yields = (node) => node.type === "YieldExpression";
2127
+ if (id.type !== "Identifier" || !init || !astIsOneLine(declarator) || codeInlineIsData(init) || astSome(init, yields, (node) => !astIsInlineFunction(node))) {
2128
+ return;
2129
+ }
2130
+ const uses = reads(declarator);
2131
+ const use = uses.at(0)?.identifier;
2132
+ if (!use || uses.length > 1 || optionsPatternsTest(allowed, id.name)) {
2133
+ return;
2134
+ }
2135
+ const text = context.sourceCode.text;
2136
+ const line = text.slice(sourceLineStart(text, use.range[0]), sourceLineEnd(text, use.range[0]));
2137
+ const owner = use.parent.type === "Property" ? use.parent.parent.parent : null;
2138
+ const service = owner && astIsCall(owner) && owner.callee.type === "MemberExpression" && (options.services ?? []).includes(astMemberName(owner.callee) ?? "");
2139
+ let deferred = false;
2140
+ for (let current = use.parent;current && current !== declarator.parent.parent; current = current.parent) {
2141
+ deferred ||= current.type === "FunctionDeclaration" || astIsInlineFunction(current);
2142
+ }
2143
+ const wrapped = codeInlineWrapped.has(init.type) && use.parent.type === "MemberExpression" && use.parent.object === use;
2144
+ if (service || wrapped || deferred || codeInlineEnclosingCalls(use) + astCallDepth(init) > (options.nesting ?? 2) || line.length - id.name.length + context.sourceCode.getText(init).length > (options.max ?? 160)) {
2145
+ return;
2146
+ }
2147
+ context.report({
2148
+ node: id,
2149
+ messageId: "once",
2150
+ data: { name: id.name }
2151
+ });
2152
+ };
2153
+ return {
2154
+ before() {
2155
+ options = optionsFirst(context, {});
2156
+ allowed = optionsPatterns(options.allow);
2157
+ kept = optionsPatterns(options.keep);
2158
+ },
2159
+ VariableDeclaration(node) {
2160
+ if (node.kind === "const" && node.parent.type === "BlockStatement") {
2161
+ node.declarations.forEach(local);
2162
+ }
2163
+ },
2164
+ Program(program) {
2165
+ for (const statement of program.body) {
2166
+ if (statement.type === "VariableDeclaration" && statement.kind === "const") {
2167
+ statement.declarations.forEach((declarator) => top(declarator, declarator.id, declarator.init));
2168
+ }
2169
+ if (statement.type === "FunctionDeclaration" && statement.id) {
2170
+ top(statement, statement.id, null);
2171
+ }
2172
+ }
2173
+ }
2174
+ };
2175
+ }
2176
+ });
2177
+
2178
+ // src/rules/code/code-justified-call.ts
2179
+ import { defineRule as defineRule15 } from "@oxlint/plugins";
2180
+ var codeJustifiedCall = defineRule15({
2181
+ meta: {
2182
+ type: "problem",
2183
+ schema: [
2184
+ {
2185
+ type: "object",
2186
+ additionalProperties: false,
2187
+ required: ["calls"],
2188
+ properties: {
2189
+ calls: { type: "array", items: { type: "string" }, minItems: 1 },
2190
+ comment: { type: "string", default: "SAFETY:" },
2191
+ message: { type: "string" }
2192
+ }
2193
+ }
2194
+ ],
2195
+ messages: {
2196
+ missing: "{{call}} needs a `// {{comment}} <why>` comment on the line above.{{message}}"
2197
+ }
2198
+ },
2199
+ createOnce(context) {
2200
+ let calls = new Set;
2201
+ let comment = "SAFETY:";
2202
+ let message = "";
2203
+ let comments = [];
2204
+ const justified = (line) => {
2205
+ const above = comments.find((candidate) => candidate.loc.end.line === line - 1);
2206
+ if (!above) {
2207
+ return false;
2208
+ }
2209
+ return above.value.trimStart().startsWith(`${comment} `) || above.type === "Line" && justified(above.loc.start.line);
2210
+ };
2211
+ return {
2212
+ before() {
2213
+ const options = optionsFirst(context, { calls: [] });
2214
+ calls = new Set(options.calls);
2215
+ comment = options.comment ?? "SAFETY:";
2216
+ message = options.message ? ` ${options.message}` : "";
2217
+ comments = context.sourceCode.getAllComments();
2218
+ },
2219
+ CallExpression(node) {
2220
+ const call = astDottedName(node.callee);
2221
+ if (call && calls.has(call) && !justified(node.loc.start.line)) {
2222
+ context.report({
2223
+ node,
2224
+ messageId: "missing",
2225
+ data: { call, comment, message }
2226
+ });
2227
+ }
2228
+ }
2229
+ };
2230
+ }
2231
+ });
2232
+
1874
2233
  // src/rules/code/code-literal-in.ts
1875
- import { defineRule as defineRule12 } from "@oxlint/plugins";
1876
- var codeLiteralIn = defineRule12({
2234
+ import { defineRule as defineRule16 } from "@oxlint/plugins";
2235
+ var codeLiteralIn = defineRule16({
1877
2236
  meta: {
1878
2237
  type: "suggestion",
1879
2238
  schema: [
@@ -1914,7 +2273,7 @@ var codeLiteralIn = defineRule12({
1914
2273
  });
1915
2274
 
1916
2275
  // src/rules/code/code-mutable-state.ts
1917
- import { defineRule as defineRule13 } from "@oxlint/plugins";
2276
+ import { defineRule as defineRule17 } from "@oxlint/plugins";
1918
2277
  var functionScopes = new Set([
1919
2278
  "FunctionDeclaration",
1920
2279
  "FunctionExpression",
@@ -1931,7 +2290,7 @@ function hasAncestor(node, test) {
1931
2290
  }
1932
2291
  return false;
1933
2292
  }
1934
- var codeMutableState = defineRule13({
2293
+ var codeMutableState = defineRule17({
1935
2294
  meta: {
1936
2295
  type: "problem",
1937
2296
  schema: [
@@ -1989,7 +2348,7 @@ var codeMutableState = defineRule13({
1989
2348
  });
1990
2349
 
1991
2350
  // src/rules/code/code-object-params.ts
1992
- import { defineRule as defineRule14 } from "@oxlint/plugins";
2351
+ import { defineRule as defineRule18 } from "@oxlint/plugins";
1993
2352
  function isObjectParam(node) {
1994
2353
  if (node.type === "ObjectPattern") {
1995
2354
  return true;
@@ -2003,7 +2362,7 @@ function isObjectParam(node) {
2003
2362
  const annotation = node.typeAnnotation?.typeAnnotation;
2004
2363
  return !annotation || annotation.type === "TSTypeReference" || annotation.type === "TSTypeLiteral" || annotation.type === "TSIntersectionType";
2005
2364
  }
2006
- var codeObjectParams = defineRule14({
2365
+ var codeObjectParams = defineRule18({
2007
2366
  meta: {
2008
2367
  type: "problem",
2009
2368
  schema: [
@@ -2052,8 +2411,8 @@ var codeObjectParams = defineRule14({
2052
2411
  });
2053
2412
 
2054
2413
  // src/rules/code/code-paired-call.ts
2055
- import { defineRule as defineRule15 } from "@oxlint/plugins";
2056
- var codePairedCall = defineRule15({
2414
+ import { defineRule as defineRule19 } from "@oxlint/plugins";
2415
+ var codePairedCall = defineRule19({
2057
2416
  meta: {
2058
2417
  type: "problem",
2059
2418
  schema: [
@@ -2137,7 +2496,7 @@ var codePairedCall = defineRule15({
2137
2496
  });
2138
2497
 
2139
2498
  // src/rules/code/code-promise-mutation.ts
2140
- import { defineRule as defineRule16 } from "@oxlint/plugins";
2499
+ import { defineRule as defineRule20 } from "@oxlint/plugins";
2141
2500
  function mutationBinding(node) {
2142
2501
  if (node.type === "Identifier") {
2143
2502
  return node;
@@ -2166,7 +2525,7 @@ function mutationBindings(node) {
2166
2525
  const binding = mutationBinding(node);
2167
2526
  return binding ? [binding] : [];
2168
2527
  }
2169
- var codePromiseMutation = defineRule16({
2528
+ var codePromiseMutation = defineRule20({
2170
2529
  meta: {
2171
2530
  type: "problem",
2172
2531
  schema: [
@@ -2258,8 +2617,96 @@ var codePromiseMutation = defineRule16({
2258
2617
  // src/rules/code/code-switch.ts
2259
2618
  var codeSwitch = astSelectorRule("SwitchStatement", "Avoid switch statements.");
2260
2619
 
2620
+ // src/rules/code/code-traced.ts
2621
+ import { defineRule as defineRule21 } from "@oxlint/plugins";
2622
+ var codeTraced = defineRule21({
2623
+ meta: {
2624
+ type: "problem",
2625
+ schema: [
2626
+ {
2627
+ type: "object",
2628
+ additionalProperties: false,
2629
+ properties: {
2630
+ untraced: { type: "array", items: { type: "string" }, default: ["Effect.fnUntraced"] },
2631
+ exports: optionsPatternSchema,
2632
+ services: { type: "array", items: { type: "string" }, default: ["of"] },
2633
+ skip: optionsPatternSchema,
2634
+ message: { type: "string" }
2635
+ }
2636
+ }
2637
+ ],
2638
+ messages: {
2639
+ surface: "{{message}}"
2640
+ }
2641
+ },
2642
+ createOnce(context) {
2643
+ let untraced = new Set;
2644
+ let services = new Set;
2645
+ let exported = true;
2646
+ let skipped = [];
2647
+ let message = "";
2648
+ const isUntraced = (node) => node?.type === "CallExpression" && untraced.has(astDottedName(node.callee) ?? "");
2649
+ const resolves = (value) => {
2650
+ if (value.type !== "Identifier") {
2651
+ return isUntraced(value);
2652
+ }
2653
+ let scope = context.sourceCode.getScope(value);
2654
+ while (scope && !scope.set.has(value.name)) {
2655
+ scope = scope.upper;
2656
+ }
2657
+ const declaration = scope?.set.get(value.name)?.defs.at(0)?.node;
2658
+ return declaration?.type === "VariableDeclarator" && isUntraced(declaration.init);
2659
+ };
2660
+ return {
2661
+ before() {
2662
+ const options = optionsFirst(context, {});
2663
+ const files = optionsPatterns(options.exports);
2664
+ untraced = new Set(options.untraced ?? ["Effect.fnUntraced"]);
2665
+ services = new Set(options.services ?? ["of"]);
2666
+ exported = files.length === 0 || optionsPatternsTest(files, context.filename.replaceAll("\\", "/"));
2667
+ skipped = optionsPatterns(options.skip);
2668
+ message = options.message ?? `An exported function or service method gets a span: replace ${[...untraced].join(", ")} with its traced form.`;
2669
+ },
2670
+ ExportNamedDeclaration(node) {
2671
+ if (!exported || node.declaration?.type !== "VariableDeclaration") {
2672
+ return;
2673
+ }
2674
+ for (const declarator of node.declaration.declarations) {
2675
+ if (isUntraced(declarator.init)) {
2676
+ context.report({
2677
+ node: declarator,
2678
+ messageId: "surface",
2679
+ data: { message }
2680
+ });
2681
+ }
2682
+ }
2683
+ },
2684
+ CallExpression(node) {
2685
+ const service = node.arguments.at(0);
2686
+ const callee = node.callee;
2687
+ if (callee.type !== "MemberExpression" || !services.has(astMemberName(callee) ?? "") || service?.type !== "ObjectExpression") {
2688
+ return;
2689
+ }
2690
+ const tag = callee.object.type === "MemberExpression" ? astMemberName(callee.object) : astDottedName(callee.object);
2691
+ if (optionsPatternsTest(skipped, tag ?? "")) {
2692
+ return;
2693
+ }
2694
+ for (const property of service.properties) {
2695
+ if (property.type === "Property" && resolves(property.value)) {
2696
+ context.report({
2697
+ node: property,
2698
+ messageId: "surface",
2699
+ data: { message }
2700
+ });
2701
+ }
2702
+ }
2703
+ }
2704
+ };
2705
+ }
2706
+ });
2707
+
2261
2708
  // src/rules/code/code-trivial-functions.ts
2262
- import { defineRule as defineRule17 } from "@oxlint/plugins";
2709
+ import { defineRule as defineRule22 } from "@oxlint/plugins";
2263
2710
  var codeTrivialFunctionsBanned = [
2264
2711
  "isRecord",
2265
2712
  "isPlainObject",
@@ -2389,7 +2836,7 @@ function guardStatement(node, state) {
2389
2836
  return guardFallback(declaration.init);
2390
2837
  });
2391
2838
  }
2392
- var codeTrivialFunctions = defineRule17({
2839
+ var codeTrivialFunctions = defineRule22({
2393
2840
  meta: {
2394
2841
  type: "problem",
2395
2842
  schema: [
@@ -2519,41 +2966,31 @@ var codeTrivialFunctions = defineRule17({
2519
2966
  }
2520
2967
  });
2521
2968
 
2522
- // src/rules/comments/comments-code.ts
2523
- import { defineRule as defineRule18 } from "@oxlint/plugins";
2524
-
2525
- // src/utils/source.utils.ts
2526
- var sourceDirective = /^\s*(?:\/\s*<(?:reference\b|amd-[\w-]+\b)|@ts-(?:check|ignore|expect-error|nocheck)\b|(?:#|@)__(?:PURE|NO_SIDE_EFFECTS)__\b|@jsx(?:ImportSource|Runtime|Frag)?\b|@vite-ignore\b|(?:[#@]\s*)?sourceMappingURL=|(?:es|ox)lint-(?:disable|enable)|prettier-ignore|biome-ignore|[cv]8 ignore|istanbul ignore|webpack[A-Z])/;
2527
- var sourceLegalBlock = "\x00legal-block\x00";
2528
- var sourceIndentSchema = {
2529
- anyOf: [
2530
- { type: "integer", minimum: 0 },
2531
- { type: "string", enum: ["tab"] }
2532
- ]
2533
- };
2534
- function sourceCommentText(comment) {
2535
- const value = (comment.type === "Block" ? comment.value.replace(/^\s*\* ?/gm, "") : comment.value).trimStart();
2536
- return comment.type === "Block" && comment.value.startsWith("!") ? sourceLegalBlock + value : value;
2537
- }
2538
- function sourceIsDirective(text) {
2539
- return text.startsWith(sourceLegalBlock) || sourceDirective.test(text);
2540
- }
2541
- function sourceLineIndent(text, offset) {
2542
- const lineStart = text.lastIndexOf(`
2543
- `, offset - 1) + 1;
2544
- return /^[\t ]*/.exec(text.slice(lineStart, offset))?.[0] ?? "";
2545
- }
2546
- function sourceIndentUnit(indent = 2) {
2547
- return indent === "tab" ? "\t" : " ".repeat(indent);
2548
- }
2549
- function sourceNewline(text) {
2550
- return text.includes(`\r
2551
- `) ? `\r
2552
- ` : `
2553
- `;
2554
- }
2969
+ // src/rules/code/code-yield-argument.ts
2970
+ import { defineRule as defineRule23 } from "@oxlint/plugins";
2971
+ var codeYieldArgument = defineRule23({
2972
+ meta: {
2973
+ type: "suggestion",
2974
+ messages: {
2975
+ named: "Yield into a named const first, then pass the name."
2976
+ }
2977
+ },
2978
+ createOnce(context) {
2979
+ return {
2980
+ YieldExpression(node) {
2981
+ const parent = node.parent;
2982
+ const argument = astIsCall(parent) && parent.arguments.some((item) => item === node);
2983
+ const receiver = parent.type === "MemberExpression" && parent.object === node;
2984
+ if (node.delegate && (argument || receiver)) {
2985
+ context.report({ node, messageId: "named" });
2986
+ }
2987
+ }
2988
+ };
2989
+ }
2990
+ });
2555
2991
 
2556
2992
  // src/rules/comments/comments-code.ts
2993
+ import { defineRule as defineRule24 } from "@oxlint/plugins";
2557
2994
  var commentsLineGap = /^[\t \r\n\u2028\u2029]*$/;
2558
2995
  var commentsLineTerminator = /\r\n|[\n\r\u2028\u2029]/;
2559
2996
  var commentsUnicodeTerminator = /[\u2028\u2029]/;
@@ -2604,7 +3041,7 @@ function commentsFollowsOpeningBrace(text, offset) {
2604
3041
  }
2605
3042
  return false;
2606
3043
  }
2607
- var commentsCode = defineRule18({
3044
+ var commentsCode = defineRule24({
2608
3045
  meta: {
2609
3046
  type: "suggestion",
2610
3047
  fixable: "code",
@@ -2768,9 +3205,9 @@ var commentsCode = defineRule18({
2768
3205
  });
2769
3206
 
2770
3207
  // src/rules/comments/comments-directives.ts
2771
- import { defineRule as defineRule19 } from "@oxlint/plugins";
3208
+ import { defineRule as defineRule25 } from "@oxlint/plugins";
2772
3209
  var directive = /^\s*(?:oxlint|eslint)-disable(?:-next-line|-line)?\b(.*)$/s;
2773
- var commentsDirectives = defineRule19({
3210
+ var commentsDirectives = defineRule25({
2774
3211
  meta: {
2775
3212
  type: "problem",
2776
3213
  schema: [],
@@ -2798,9 +3235,9 @@ var commentsDirectives = defineRule19({
2798
3235
  });
2799
3236
 
2800
3237
  // src/rules/copy/copy-dashes.ts
2801
- import { defineRule as defineRule20 } from "@oxlint/plugins";
3238
+ import { defineRule as defineRule26 } from "@oxlint/plugins";
2802
3239
  var copyDashesMessage = "Use a comma, colon, period or parentheses instead.";
2803
- var copyDashes = defineRule20({
3240
+ var copyDashes = defineRule26({
2804
3241
  meta: {
2805
3242
  type: "suggestion",
2806
3243
  schema: [
@@ -2856,7 +3293,7 @@ var copyDashes = defineRule20({
2856
3293
  });
2857
3294
 
2858
3295
  // src/rules/files/files-components-only.ts
2859
- import { defineRule as defineRule21 } from "@oxlint/plugins";
3296
+ import { defineRule as defineRule27 } from "@oxlint/plugins";
2860
3297
 
2861
3298
  // src/utils/react.utils.ts
2862
3299
  function reactReturnsOutput(program, node) {
@@ -2928,7 +3365,7 @@ function reactIsComponent(program, candidate) {
2928
3365
  function componentName(basename2) {
2929
3366
  return basename2.replace(/\.(tsx?|jsx?)$/, "").replaceAll(/(?:^[-.]*|[-.]+)(.?)/g, (_, char) => char.toUpperCase());
2930
3367
  }
2931
- var filesComponentsOnly = defineRule21({
3368
+ var filesComponentsOnly = defineRule27({
2932
3369
  meta: {
2933
3370
  type: "problem",
2934
3371
  schema: [
@@ -3013,7 +3450,7 @@ var filesComponentsOnly = defineRule21({
3013
3450
  });
3014
3451
 
3015
3452
  // src/rules/files/files-constants-only.ts
3016
- import { defineRule as defineRule22 } from "@oxlint/plugins";
3453
+ import { defineRule as defineRule28 } from "@oxlint/plugins";
3017
3454
  function unwrap(expression) {
3018
3455
  if (expression.type === "ParenthesizedExpression" || expression.type === "TSAsExpression" || expression.type === "TSSatisfiesExpression" || expression.type === "TSTypeAssertion" || expression.type === "TSNonNullExpression" || expression.type === "TSInstantiationExpression") {
3019
3456
  return unwrap(expression.expression);
@@ -3068,7 +3505,7 @@ function collectBindings(program) {
3068
3505
  }
3069
3506
  return bindings;
3070
3507
  }
3071
- var filesConstantsOnly = defineRule22({
3508
+ var filesConstantsOnly = defineRule28({
3072
3509
  meta: {
3073
3510
  type: "problem",
3074
3511
  schema: [
@@ -3167,7 +3604,7 @@ var filesConstantsOnly = defineRule22({
3167
3604
  });
3168
3605
 
3169
3606
  // src/rules/files/files-domain-constants.ts
3170
- import { defineRule as defineRule23 } from "@oxlint/plugins";
3607
+ import { defineRule as defineRule29 } from "@oxlint/plugins";
3171
3608
  import { basename as basename2, dirname as dirname2 } from "node:path";
3172
3609
  function isData(expression) {
3173
3610
  const value = astUnwrap(expression);
@@ -3185,7 +3622,7 @@ function isData(expression) {
3185
3622
  }
3186
3623
  return value.type === "NewExpression" && value.callee.type === "Identifier" && ["Map", "Set"].includes(value.callee.name) && value.arguments[0]?.type === "ArrayExpression" && value.arguments[0].elements.length > 0;
3187
3624
  }
3188
- var filesDomainConstants = defineRule23({
3625
+ var filesDomainConstants = defineRule29({
3189
3626
  meta: {
3190
3627
  type: "problem",
3191
3628
  schema: [
@@ -3231,11 +3668,11 @@ var filesDomainConstants = defineRule23({
3231
3668
  });
3232
3669
 
3233
3670
  // src/rules/files/files-exports.ts
3234
- import { defineRule as defineRule24 } from "@oxlint/plugins";
3671
+ import { defineRule as defineRule30 } from "@oxlint/plugins";
3235
3672
  function escapeRegExp(value) {
3236
3673
  return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
3237
3674
  }
3238
- var filesExports = defineRule24({
3675
+ var filesExports = defineRule30({
3239
3676
  meta: {
3240
3677
  type: "problem",
3241
3678
  schema: [
@@ -3316,11 +3753,11 @@ var filesExports = defineRule24({
3316
3753
  });
3317
3754
 
3318
3755
  // src/rules/files/files-externals.ts
3319
- import { defineRule as defineRule25 } from "@oxlint/plugins";
3756
+ import { defineRule as defineRule31 } from "@oxlint/plugins";
3320
3757
  import { existsSync as existsSync2, readFileSync } from "node:fs";
3321
3758
  import { builtinModules as builtinModules2 } from "node:module";
3322
3759
  import { dirname as dirname3, join as join2 } from "node:path";
3323
- var filesExternals = defineRule25({
3760
+ var filesExternals = defineRule31({
3324
3761
  meta: {
3325
3762
  type: "problem",
3326
3763
  schema: [
@@ -3411,7 +3848,7 @@ var filesExternals = defineRule25({
3411
3848
  });
3412
3849
 
3413
3850
  // src/rules/files/files-factory-keys.ts
3414
- import { defineRule as defineRule26 } from "@oxlint/plugins";
3851
+ import { defineRule as defineRule32 } from "@oxlint/plugins";
3415
3852
  function returnedObject(expression) {
3416
3853
  if (expression?.type === "TSAsExpression" || expression?.type === "TSSatisfiesExpression" || expression?.type === "TSTypeAssertion" || expression?.type === "TSNonNullExpression") {
3417
3854
  return returnedObject(expression.expression);
@@ -3422,7 +3859,7 @@ function compileKeys(pattern, keys, requireKeys) {
3422
3859
  const allowedList = keys.concat(requireKeys.filter((key) => !keys.includes(key)));
3423
3860
  return { patterns: optionsPatternsWithEmpty(pattern), allowed: new Set(allowedList), allowedList, required: requireKeys };
3424
3861
  }
3425
- var filesFactoryKeys = defineRule26({
3862
+ var filesFactoryKeys = defineRule32({
3426
3863
  meta: {
3427
3864
  type: "problem",
3428
3865
  schema: [
@@ -3540,8 +3977,8 @@ var filesFactoryKeys = defineRule26({
3540
3977
  });
3541
3978
 
3542
3979
  // src/rules/files/files-helpers.ts
3543
- import { defineRule as defineRule27 } from "@oxlint/plugins";
3544
- var filesHelpers = defineRule27({
3980
+ import { defineRule as defineRule33 } from "@oxlint/plugins";
3981
+ var filesHelpers = defineRule33({
3545
3982
  meta: {
3546
3983
  type: "problem",
3547
3984
  schema: [
@@ -3589,8 +4026,8 @@ var filesHelpers = defineRule27({
3589
4026
  });
3590
4027
 
3591
4028
  // src/rules/files/files-no-functions.ts
3592
- import { defineRule as defineRule28 } from "@oxlint/plugins";
3593
- var filesNoFunctions = defineRule28({
4029
+ import { defineRule as defineRule34 } from "@oxlint/plugins";
4030
+ var filesNoFunctions = defineRule34({
3594
4031
  meta: {
3595
4032
  type: "problem",
3596
4033
  schema: [
@@ -3644,8 +4081,8 @@ var filesNoFunctions = defineRule28({
3644
4081
  });
3645
4082
 
3646
4083
  // src/rules/files/files-restricted.ts
3647
- import { defineRule as defineRule29 } from "@oxlint/plugins";
3648
- var filesRestricted = defineRule29({
4084
+ import { defineRule as defineRule35 } from "@oxlint/plugins";
4085
+ var filesRestricted = defineRule35({
3649
4086
  meta: {
3650
4087
  type: "problem",
3651
4088
  schema: [
@@ -3677,7 +4114,7 @@ var filesRestricted = defineRule29({
3677
4114
  });
3678
4115
 
3679
4116
  // src/rules/files/files-route.ts
3680
- import { defineRule as defineRule30 } from "@oxlint/plugins";
4117
+ import { defineRule as defineRule36 } from "@oxlint/plugins";
3681
4118
  function inspectAdapter(context, item, bannedHooks, banIntrinsicJsx) {
3682
4119
  astVisit(item.node.body, [item.node], (node) => {
3683
4120
  if (banIntrinsicJsx && node.type === "JSXOpeningElement" && node.name.type === "JSXIdentifier" && /^[a-z]/.test(node.name.name)) {
@@ -3697,7 +4134,7 @@ function inspectAdapter(context, item, bannedHooks, banIntrinsicJsx) {
3697
4134
  }
3698
4135
  });
3699
4136
  }
3700
- var filesRoute = defineRule30({
4137
+ var filesRoute = defineRule36({
3701
4138
  meta: {
3702
4139
  type: "problem",
3703
4140
  schema: [
@@ -3767,7 +4204,7 @@ var filesRoute = defineRule30({
3767
4204
  });
3768
4205
 
3769
4206
  // src/rules/files/files-types-only.ts
3770
- import { defineRule as defineRule31 } from "@oxlint/plugins";
4207
+ import { defineRule as defineRule37 } from "@oxlint/plugins";
3771
4208
  function runtimeImportLocalNames(statement) {
3772
4209
  return statement.specifiers.flatMap((specifier) => specifier.type !== "ImportSpecifier" || specifier.importKind !== "type" ? [specifier.local.name] : []);
3773
4210
  }
@@ -3936,7 +4373,7 @@ function runtimeKind(node) {
3936
4373
  }
3937
4374
  return node.type === "FunctionDeclaration" ? "function" : "variable";
3938
4375
  }
3939
- var filesTypesOnly = defineRule31({
4376
+ var filesTypesOnly = defineRule37({
3940
4377
  meta: {
3941
4378
  type: "problem",
3942
4379
  schema: [
@@ -4043,9 +4480,66 @@ var filesTypesOnly = defineRule31({
4043
4480
  }
4044
4481
  });
4045
4482
 
4483
+ // src/rules/layout/layout-arrow-body.ts
4484
+ import { defineRule as defineRule38 } from "@oxlint/plugins";
4485
+ var layoutArrowBody = defineRule38({
4486
+ meta: {
4487
+ type: "layout",
4488
+ fixable: "whitespace",
4489
+ schema: [
4490
+ {
4491
+ type: "object",
4492
+ additionalProperties: false,
4493
+ properties: { max: { type: "integer", minimum: 1, default: 160 } }
4494
+ }
4495
+ ],
4496
+ messages: {
4497
+ sameLine: "Start the arrow body on the same line as =>. When the line is too long, break its arguments."
4498
+ }
4499
+ },
4500
+ createOnce(context) {
4501
+ let max = 160;
4502
+ return {
4503
+ before() {
4504
+ max = optionsFirst(context, {}).max ?? 160;
4505
+ },
4506
+ ArrowFunctionExpression(node) {
4507
+ const source = context.sourceCode;
4508
+ const body = node.body;
4509
+ const arrow = source.getTokenBefore(body, { filter: (token) => token.value === "=>" });
4510
+ const next = arrow ? source.getTokenAfter(arrow) : null;
4511
+ if (body.type === "BlockStatement" || !arrow || !next || next.loc.start.line === arrow.loc.end.line || source.commentsExistBetween(arrow, next)) {
4512
+ return;
4513
+ }
4514
+ let root = body;
4515
+ let calls = 0;
4516
+ while (root.type === "CallExpression" && root.callee.type === "MemberExpression") {
4517
+ calls += 1;
4518
+ root = root.callee.object;
4519
+ }
4520
+ const open = astIsCall(body) && astIsOneLine(body) ? source.getTokenAfter(body.typeArguments ?? body.callee) : null;
4521
+ const callEnd = open ? open.range[1] : sourceLineEnd(source.text, next.range[0]);
4522
+ const headEnd = calls >= 2 && astIsOneLine(body) ? root.range[1] : callEnd;
4523
+ if (arrow.loc.end.column + 1 + source.text.slice(next.range[0], headEnd).length > max) {
4524
+ return;
4525
+ }
4526
+ context.report({
4527
+ node: body,
4528
+ messageId: "sameLine",
4529
+ fix: (fixer) => fixer.replaceTextRange([arrow.range[1], next.range[0]], " ")
4530
+ });
4531
+ }
4532
+ };
4533
+ }
4534
+ });
4535
+
4046
4536
  // src/rules/layout/layout-call-arguments.ts
4047
- import { defineRule as defineRule32 } from "@oxlint/plugins";
4048
- var layoutCallArguments = defineRule32({
4537
+ import { defineRule as defineRule39 } from "@oxlint/plugins";
4538
+ function layoutCallArgumentsHuggable(node) {
4539
+ return astIsInlineFunction(node) || node.type === "ObjectExpression" || node.type === "ArrayExpression" || astIsCall(node) && node.arguments.length === 1 && (node.callee.type !== "MemberExpression" || astIsOneLine(node.callee)) && node.arguments.every(layoutCallArgumentsHuggable);
4540
+ }
4541
+ var layoutCallArgumentsMax = { type: "integer", minimum: 1 };
4542
+ var layoutCallArguments = defineRule39({
4049
4543
  meta: {
4050
4544
  type: "layout",
4051
4545
  fixable: "whitespace",
@@ -4063,18 +4557,42 @@ var layoutCallArguments = defineRule32({
4063
4557
  type: "integer",
4064
4558
  minimum: 1,
4065
4559
  default: 2
4560
+ },
4561
+ split: {
4562
+ type: "boolean",
4563
+ default: true
4564
+ },
4565
+ hug: {
4566
+ type: "object",
4567
+ additionalProperties: false,
4568
+ required: ["max"],
4569
+ properties: { max: layoutCallArgumentsMax }
4570
+ },
4571
+ join: {
4572
+ type: "object",
4573
+ additionalProperties: false,
4574
+ required: ["max"],
4575
+ properties: {
4576
+ max: layoutCallArgumentsMax,
4577
+ nesting: layoutCallArgumentsMax,
4578
+ keep: { type: "array", items: { type: "string" } }
4579
+ }
4066
4580
  }
4067
4581
  }
4068
4582
  }
4069
4583
  ],
4070
4584
  messages: {
4071
- multiline: "A call with {{min}}+ arguments puts each argument on its own line."
4585
+ multiline: "A call with {{min}}+ arguments puts each argument on its own line.",
4586
+ hug: "Put every argument on its own line. Only a last callback, object or array may hug the call, after simple arguments.",
4587
+ prefer: "Hug the last argument: it is a callback, object or array after simple arguments.",
4588
+ join: "This fits on one line, so keep it on one line."
4072
4589
  }
4073
4590
  },
4074
4591
  createOnce(context) {
4592
+ let options = {};
4075
4593
  let minArguments = 3;
4076
4594
  let indent = 2;
4077
- const check = (node) => {
4595
+ const split = (node) => {
4078
4596
  const args = node.arguments;
4079
4597
  const last = args.at(-1);
4080
4598
  const source = context.sourceCode;
@@ -4111,25 +4629,109 @@ var layoutCallArguments = defineRule32({
4111
4629
  })
4112
4630
  });
4113
4631
  };
4632
+ const hug = (node, max) => {
4633
+ const source = context.sourceCode;
4634
+ const text = source.text;
4635
+ const args = node.arguments;
4636
+ const first = args.at(0);
4637
+ const last = args.at(-1);
4638
+ const open = source.getTokenAfter(node.typeArguments ?? node.callee);
4639
+ const close = source.getLastToken(node);
4640
+ if (!first || !last || !open || !close || args.every(astIsOneLine) || source.getCommentsInside(node).length > 0) {
4641
+ return;
4642
+ }
4643
+ const leading = args.slice(0, -1);
4644
+ const canHug = !astIsPipe(node) && leading.every((arg) => astIsOneLine(arg) && astCallDepth(arg) <= 1) && layoutCallArgumentsHuggable(last);
4645
+ const gaps = sourceItemGaps(open.range[1], args, close.range[0]);
4646
+ if (first.loc.start.line > open.loc.end.line) {
4647
+ const head = [...leading.map((arg) => source.getText(arg)), text.slice(last.range[0], sourceLineEnd(text, last.range[0]))];
4648
+ const hugged = `${text.slice(sourceLineStart(text, open.range[0]), open.range[1])}${head.join(", ")}`;
4649
+ if (canHug && args.length <= 2 && hugged.length <= max) {
4650
+ context.report({
4651
+ node,
4652
+ messageId: "prefer",
4653
+ fix: (fixer) => sourceRespace(fixer, text, gaps, (index, end) => index === 0 || end ? "" : " ")
4654
+ });
4655
+ }
4656
+ return;
4657
+ }
4658
+ if (astIsOneLine(node) || canHug) {
4659
+ return;
4660
+ }
4661
+ const newline = sourceNewline(text);
4662
+ const base = sourceLineIndent(text, open.range[0]);
4663
+ const inner = `${base}${" ".repeat(indent)}`;
4664
+ context.report({
4665
+ node,
4666
+ messageId: "hug",
4667
+ fix: (fixer) => sourceRespace(fixer, text, gaps, (_, end) => `${newline}${end ? base : inner}`)
4668
+ });
4669
+ };
4670
+ const join3 = (node, items, open, close) => {
4671
+ const source = context.sourceCode;
4672
+ const text = source.text;
4673
+ const first = items.at(0);
4674
+ if (!first || !open || !close || items.length > 2 || first.loc.start.line === open.loc.end.line || !items.every(astIsOneLine) || source.commentsExistBetween(open, close)) {
4675
+ return;
4676
+ }
4677
+ const inside = items.map((item) => source.getText(item)).join(", ");
4678
+ const before = text.slice(sourceLineStart(text, open.range[0]), open.range[1]);
4679
+ const after = text.slice(close.range[0], sourceLineEnd(text, close.range[0]));
4680
+ if (`${before}${inside}${after}`.length > (options.join?.max ?? 0)) {
4681
+ return;
4682
+ }
4683
+ const gaps = sourceItemGaps(open.range[1], items, close.range[0]);
4684
+ context.report({
4685
+ node,
4686
+ messageId: "join",
4687
+ fix: (fixer) => sourceRespace(fixer, text, gaps, (index, end) => index === 0 || end ? "" : " ")
4688
+ });
4689
+ };
4690
+ const call = (node) => {
4691
+ const source = context.sourceCode;
4692
+ if (options.split !== false) {
4693
+ split(node);
4694
+ }
4695
+ if (options.hug) {
4696
+ hug(node, options.hug.max);
4697
+ }
4698
+ if (options.join && !(options.join.keep ?? []).includes(source.getText(node.callee)) && !(astIsPipe(node) && node.arguments.length > 1) && astCallDepth(node) <= (options.join.nesting ?? Number.POSITIVE_INFINITY)) {
4699
+ join3(node, node.arguments, source.getTokenAfter(node.typeArguments ?? node.callee), source.getLastToken(node));
4700
+ }
4701
+ };
4702
+ const parameters = (node) => {
4703
+ const source = context.sourceCode;
4704
+ const first = node.params.at(0);
4705
+ const last = node.params.at(-1);
4706
+ if (!options.join || !first || !last) {
4707
+ return;
4708
+ }
4709
+ join3(node, node.params, source.getTokenBefore(first, { filter: (token) => token.value === "(" }), source.getTokenAfter(last, { filter: (token) => token.value === ")" }));
4710
+ };
4114
4711
  return {
4115
4712
  before() {
4116
- const options = optionsFirst(context, {});
4713
+ options = optionsFirst(context, {});
4117
4714
  minArguments = options.min ?? 3;
4118
4715
  indent = options.indent ?? 2;
4119
4716
  },
4120
- CallExpression: check,
4121
- NewExpression: check
4717
+ CallExpression: call,
4718
+ NewExpression: call,
4719
+ FunctionExpression: parameters,
4720
+ FunctionDeclaration: parameters,
4721
+ ArrowFunctionExpression: parameters,
4722
+ TSFunctionType: parameters,
4723
+ TSMethodSignature: parameters
4122
4724
  };
4123
4725
  }
4124
4726
  });
4125
4727
 
4126
4728
  // src/rules/layout/layout-call-array.ts
4127
- import { defineRule as defineRule33 } from "@oxlint/plugins";
4729
+ import { defineRule as defineRule40 } from "@oxlint/plugins";
4128
4730
  var layoutCallArrayDefaultCallees = ["Promise.all", "Promise.allSettled"];
4129
4731
  function layoutCallArrayRoot(node) {
4130
4732
  return node.type === "MemberExpression" ? layoutCallArrayRoot(node.object) : node;
4131
4733
  }
4132
- var layoutCallArray = defineRule33({
4734
+ var layoutCallArray = defineRule40({
4133
4735
  meta: {
4134
4736
  type: "layout",
4135
4737
  fixable: "whitespace",
@@ -4244,9 +4846,56 @@ var layoutCallArray = defineRule33({
4244
4846
  }
4245
4847
  });
4246
4848
 
4849
+ // src/rules/layout/layout-call-depth.ts
4850
+ import { defineRule as defineRule41 } from "@oxlint/plugins";
4851
+ function layoutCallDepthOuter(node) {
4852
+ const parent = node.parent;
4853
+ if (!parent || parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression" || parent.type.endsWith("Statement")) {
4854
+ return;
4855
+ }
4856
+ return astIsCall(parent) && parent.arguments.some((argument) => argument === node) ? parent : layoutCallDepthOuter(parent);
4857
+ }
4858
+ var layoutCallDepth = defineRule41({
4859
+ meta: {
4860
+ type: "layout",
4861
+ schema: [
4862
+ {
4863
+ type: "object",
4864
+ additionalProperties: false,
4865
+ properties: { max: { type: "integer", minimum: 1, default: 2 } }
4866
+ }
4867
+ ],
4868
+ messages: {
4869
+ deep: "Calls nest {{depth}} deep on one line (max {{max}}). Break the outer call or name an inner value."
4870
+ }
4871
+ },
4872
+ createOnce(context) {
4873
+ let max = 2;
4874
+ const check = (node) => {
4875
+ const depth = astCallDepth(node);
4876
+ const outer = layoutCallDepthOuter(node);
4877
+ if (!astIsOneLine(node) || depth <= max || outer !== undefined && astIsOneLine(outer) && astCallDepth(outer) > max) {
4878
+ return;
4879
+ }
4880
+ context.report({
4881
+ node,
4882
+ messageId: "deep",
4883
+ data: { depth: String(depth), max: String(max) }
4884
+ });
4885
+ };
4886
+ return {
4887
+ before() {
4888
+ max = optionsFirst(context, {}).max ?? 2;
4889
+ },
4890
+ CallExpression: check,
4891
+ NewExpression: check
4892
+ };
4893
+ }
4894
+ });
4895
+
4247
4896
  // src/rules/layout/layout-chain.ts
4248
- import { defineRule as defineRule34 } from "@oxlint/plugins";
4249
- var layoutChain = defineRule34({
4897
+ import { defineRule as defineRule42 } from "@oxlint/plugins";
4898
+ var layoutChain = defineRule42({
4250
4899
  meta: {
4251
4900
  type: "layout",
4252
4901
  fixable: "whitespace",
@@ -4364,9 +5013,65 @@ var layoutChain = defineRule34({
4364
5013
  }
4365
5014
  });
4366
5015
 
5016
+ // src/rules/layout/layout-items.ts
5017
+ import { defineRule as defineRule43 } from "@oxlint/plugins";
5018
+ var layoutItems = defineRule43({
5019
+ meta: {
5020
+ type: "layout",
5021
+ fixable: "whitespace",
5022
+ schema: [
5023
+ {
5024
+ type: "object",
5025
+ additionalProperties: false,
5026
+ properties: { indent: { ...sourceIndentSchema, default: 2 } }
5027
+ }
5028
+ ],
5029
+ messages: {
5030
+ object: "A multi-line object puts each property on its own line.",
5031
+ array: "A multi-line array puts each element on its own line."
5032
+ }
5033
+ },
5034
+ createOnce(context) {
5035
+ let indentUnit = sourceIndentUnit();
5036
+ const check = (node) => {
5037
+ const source = context.sourceCode;
5038
+ const items = node.type === "ObjectExpression" ? node.properties : node.elements;
5039
+ const present = items.filter((item) => item !== null);
5040
+ const open = source.getFirstToken(node);
5041
+ const close = source.getLastToken(node);
5042
+ if (!open || !close || astIsOneLine(node) || present.length < 2) {
5043
+ return;
5044
+ }
5045
+ const packed = [open, ...present].some((item, index) => {
5046
+ const next = present.at(index);
5047
+ return next !== undefined && item.loc.end.line === next.loc.start.line;
5048
+ });
5049
+ if (!packed) {
5050
+ return;
5051
+ }
5052
+ const text = source.text;
5053
+ const newline = sourceNewline(text);
5054
+ const base = sourceLineIndent(text, node.range[0]);
5055
+ const gaps = sourceItemGaps(open.range[1], present, close.range[0]);
5056
+ context.report({
5057
+ node,
5058
+ messageId: node.type === "ObjectExpression" ? "object" : "array",
5059
+ fix: (fixer) => present.length === items.length ? sourceRespace(fixer, text, gaps, (_, end) => `${newline}${base}${end ? "" : indentUnit}`) : null
5060
+ });
5061
+ };
5062
+ return {
5063
+ before() {
5064
+ indentUnit = sourceIndentUnit(optionsFirst(context, {}).indent);
5065
+ },
5066
+ ObjectExpression: check,
5067
+ ArrayExpression: check
5068
+ };
5069
+ }
5070
+ });
5071
+
4367
5072
  // src/rules/layout/layout-jsx-attributes.ts
4368
- import { defineRule as defineRule35 } from "@oxlint/plugins";
4369
- var layoutJsxAttributes = defineRule35({
5073
+ import { defineRule as defineRule44 } from "@oxlint/plugins";
5074
+ var layoutJsxAttributes = defineRule44({
4370
5075
  meta: {
4371
5076
  type: "layout",
4372
5077
  fixable: "whitespace",
@@ -4430,8 +5135,8 @@ var layoutJsxAttributes = defineRule35({
4430
5135
  });
4431
5136
 
4432
5137
  // src/rules/layout/layout-key-value.ts
4433
- import { defineRule as defineRule36 } from "@oxlint/plugins";
4434
- var layoutKeyValue = defineRule36({
5138
+ import { defineRule as defineRule45 } from "@oxlint/plugins";
5139
+ var layoutKeyValue = defineRule45({
4435
5140
  meta: {
4436
5141
  type: "layout",
4437
5142
  fixable: "whitespace",
@@ -4467,11 +5172,11 @@ var layoutKeyValue = defineRule36({
4467
5172
  });
4468
5173
 
4469
5174
  // src/rules/layout/layout-object.ts
4470
- import { defineRule as defineRule37 } from "@oxlint/plugins";
5175
+ import { defineRule as defineRule46 } from "@oxlint/plugins";
4471
5176
  function layoutObjectIsWhitespace(text) {
4472
5177
  return /^[\t\n\r\f ]*$/.test(text);
4473
5178
  }
4474
- var layoutObject = defineRule37({
5179
+ var layoutObject = defineRule46({
4475
5180
  meta: {
4476
5181
  type: "layout",
4477
5182
  fixable: "whitespace",
@@ -4555,7 +5260,7 @@ var layoutObject = defineRule37({
4555
5260
  });
4556
5261
 
4557
5262
  // src/rules/layout/layout-padding.ts
4558
- import { defineRule as defineRule38 } from "@oxlint/plugins";
5263
+ import { defineRule as defineRule47 } from "@oxlint/plugins";
4559
5264
  var layoutPaddingControl = new Set([
4560
5265
  "IfStatement",
4561
5266
  "ForStatement",
@@ -4584,7 +5289,7 @@ function layoutPaddingKind(node) {
4584
5289
  function layoutPaddingIsMultilineVariable(node, kind) {
4585
5290
  return kind === "variable" && node.loc.start.line !== node.loc.end.line;
4586
5291
  }
4587
- var layoutPadding = defineRule38({
5292
+ var layoutPadding = defineRule47({
4588
5293
  meta: {
4589
5294
  type: "layout",
4590
5295
  fixable: "whitespace",
@@ -4672,13 +5377,48 @@ var layoutPadding = defineRule38({
4672
5377
  }
4673
5378
  });
4674
5379
 
5380
+ // src/rules/layout/layout-pipe.ts
5381
+ import { defineRule as defineRule48 } from "@oxlint/plugins";
5382
+ var layoutPipe = defineRule48({
5383
+ meta: {
5384
+ type: "layout",
5385
+ messages: {
5386
+ after: "No ).pipe( after a call that spans lines. Name the value and pipe the name, or pass the call to the step data-first.",
5387
+ step: "A pipe step may span lines only through a callback, object or array. Name this call first, then pass the name."
5388
+ }
5389
+ },
5390
+ createOnce(context) {
5391
+ return {
5392
+ CallExpression(node) {
5393
+ const callee = node.callee;
5394
+ if (callee.type === "MemberExpression" && astMemberName(callee) === "pipe" && astIsCall(callee.object) && !astIsOneLine(callee.object) && callee.property.loc.start.line === callee.object.loc.end.line) {
5395
+ context.report({ node: callee.property, messageId: "after" });
5396
+ }
5397
+ if (!astIsPipe(node)) {
5398
+ return;
5399
+ }
5400
+ for (const step of node.arguments) {
5401
+ for (const argument of astIsCall(step) ? step.arguments : []) {
5402
+ if (astIsCall(argument) && !astIsOneLine(argument)) {
5403
+ context.report({ node: argument, messageId: "step" });
5404
+ }
5405
+ }
5406
+ }
5407
+ }
5408
+ };
5409
+ }
5410
+ });
5411
+
4675
5412
  // src/rules/layout/layout-ternary.ts
4676
- import { defineRule as defineRule39 } from "@oxlint/plugins";
5413
+ import { defineRule as defineRule49 } from "@oxlint/plugins";
5414
+ function layoutTernaryLines(node) {
5415
+ return node.loc.end.line - node.loc.start.line + 1;
5416
+ }
4677
5417
  function layoutTernaryBreak(between, operator, newline) {
4678
5418
  const at = between.indexOf(operator);
4679
5419
  return `${between.slice(0, at).trimEnd()}${newline}${operator} ${between.slice(at + 1).trimStart()}`;
4680
5420
  }
4681
- var layoutTernary = defineRule39({
5421
+ var layoutTernary = defineRule49({
4682
5422
  meta: {
4683
5423
  type: "layout",
4684
5424
  fixable: "whitespace",
@@ -4696,11 +5436,23 @@ var layoutTernary = defineRule39({
4696
5436
  type: "integer",
4697
5437
  minimum: 1,
4698
5438
  default: 2
5439
+ },
5440
+ fit: {
5441
+ type: "boolean",
5442
+ default: true
5443
+ },
5444
+ branch: {
5445
+ type: "object",
5446
+ additionalProperties: false,
5447
+ required: ["max"],
5448
+ properties: { max: { type: "integer", minimum: 1 } }
4699
5449
  }
4700
5450
  }
4701
5451
  }
4702
5452
  ],
4703
5453
  messages: {
5454
+ long: "This ternary branch spans {{lines}} lines (max {{max}}). Name it.",
5455
+ yield: "A yield* ternary takes one-line operands. Name the multi-line branch.",
4704
5456
  join: "Keep this conditional on one line ({{length}} columns; limit {{max}}, except in template literals).",
4705
5457
  split: "This conditional does not fit on one line ({{length}} of {{max}} columns); break before `?` and `:`."
4706
5458
  }
@@ -4708,14 +5460,38 @@ var layoutTernary = defineRule39({
4708
5460
  createOnce(context) {
4709
5461
  let maxLength = 160;
4710
5462
  let indent = 2;
5463
+ let fit = true;
5464
+ let branchMax;
5465
+ const branch = (node, max) => {
5466
+ const long = [node.consequent, node.alternate].filter((operand) => layoutTernaryLines(operand) > max);
5467
+ for (const operand of long) {
5468
+ context.report({
5469
+ node: operand,
5470
+ messageId: "long",
5471
+ data: { lines: String(layoutTernaryLines(operand)), max: String(max) }
5472
+ });
5473
+ }
5474
+ const yielded = node.parent.type === "YieldExpression" && node.parent.delegate;
5475
+ if (yielded && long.length === 0 && [node.test, node.consequent, node.alternate].some((operand) => layoutTernaryLines(operand) > 1)) {
5476
+ context.report({ node, messageId: "yield" });
5477
+ }
5478
+ };
4711
5479
  return {
4712
5480
  before() {
4713
5481
  const options = optionsFirst(context, {});
4714
5482
  maxLength = options.max ?? 160;
4715
5483
  indent = options.indent ?? 2;
5484
+ fit = options.fit ?? true;
5485
+ branchMax = options.branch?.max;
4716
5486
  },
4717
5487
  ConditionalExpression(node) {
4718
5488
  const source = context.sourceCode;
5489
+ if (branchMax !== undefined) {
5490
+ branch(node, branchMax);
5491
+ }
5492
+ if (!fit) {
5493
+ return;
5494
+ }
4719
5495
  const operands = [node.test, node.consequent, node.alternate];
4720
5496
  if (node.parent.type === "ConditionalExpression" || operands.some((operand) => operand.type === "ConditionalExpression" || operand.loc.start.line !== operand.loc.end.line) || source.getCommentsInside(node).length > 0) {
4721
5497
  return;
@@ -4762,9 +5538,9 @@ var layoutTernary = defineRule39({
4762
5538
  });
4763
5539
 
4764
5540
  // src/rules/naming/naming-declarations.ts
4765
- import { defineRule as defineRule40 } from "@oxlint/plugins";
5541
+ import { defineRule as defineRule50 } from "@oxlint/plugins";
4766
5542
  var namingDeclarationsKinds = ["function", "const", "let", "var", "class", "type", "interface", "enum"];
4767
- var namingDeclarations = defineRule40({
5543
+ var namingDeclarations = defineRule50({
4768
5544
  meta: {
4769
5545
  type: "problem",
4770
5546
  schema: [
@@ -4843,7 +5619,7 @@ var namingDeclarations = defineRule40({
4843
5619
  });
4844
5620
 
4845
5621
  // src/rules/naming/naming-exports.ts
4846
- import { defineRule as defineRule41 } from "@oxlint/plugins";
5622
+ import { defineRule as defineRule51 } from "@oxlint/plugins";
4847
5623
  var namingExportsScopeProperties = {
4848
5624
  scope: { type: "string", enum: ["exports", "functions", "declarations"] },
4849
5625
  types: { type: "boolean" },
@@ -4869,7 +5645,7 @@ function matchTemplate(basename3, template, placeholder = "[a-z0-9-]+") {
4869
5645
  }
4870
5646
  return new RegExp(`^${pattern}$`).exec(basename3)?.groups ?? null;
4871
5647
  }
4872
- var namingExports = defineRule41({
5648
+ var namingExports = defineRule51({
4873
5649
  meta: {
4874
5650
  type: "problem",
4875
5651
  schema: {
@@ -5003,10 +5779,10 @@ var namingExports = defineRule41({
5003
5779
  });
5004
5780
 
5005
5781
  // src/rules/naming/naming-file.ts
5006
- import { defineRule as defineRule42 } from "@oxlint/plugins";
5782
+ import { defineRule as defineRule52 } from "@oxlint/plugins";
5007
5783
  import { readdirSync as readdirSync2 } from "node:fs";
5008
5784
  import { dirname as dirname4 } from "node:path";
5009
- var namingFile = defineRule42({
5785
+ var namingFile = defineRule52({
5010
5786
  meta: {
5011
5787
  type: "problem",
5012
5788
  schema: {
@@ -5076,9 +5852,9 @@ var namingFile = defineRule42({
5076
5852
  });
5077
5853
 
5078
5854
  // src/rules/naming/naming-folder.ts
5079
- import { defineRule as defineRule43 } from "@oxlint/plugins";
5855
+ import { defineRule as defineRule53 } from "@oxlint/plugins";
5080
5856
  import { posix as posix2 } from "node:path";
5081
- var namingFolder = defineRule43({
5857
+ var namingFolder = defineRule53({
5082
5858
  meta: {
5083
5859
  type: "problem",
5084
5860
  schema: [
@@ -5152,9 +5928,9 @@ var reactDynamicClasses = astSelectorRule(':matches(JSXAttribute[name.name="clas
5152
5928
  var reactEmptyEffect = astSelectorRule(':matches(CallExpression[callee.name=/^use(Layout)?Effect$/], CallExpression[callee.object.name="React"][callee.property.name=/^use(Layout)?Effect$/]) > :matches(ArrowFunctionExpression, FunctionExpression) > BlockStatement[body.length=0]', "Remove the empty effect.");
5153
5929
 
5154
5930
  // src/rules/react/react-memo.ts
5155
- import { defineRule as defineRule44 } from "@oxlint/plugins";
5931
+ import { defineRule as defineRule54 } from "@oxlint/plugins";
5156
5932
  var reactMemoNames = ["memo", "useMemo", "useCallback"];
5157
- var reactMemo = defineRule44({
5933
+ var reactMemo = defineRule54({
5158
5934
  meta: {
5159
5935
  type: "problem",
5160
5936
  schema: [],
@@ -5189,7 +5965,7 @@ var reactMemo = defineRule44({
5189
5965
  });
5190
5966
 
5191
5967
  // src/rules/react/react-props.ts
5192
- import { defineRule as defineRule45 } from "@oxlint/plugins";
5968
+ import { defineRule as defineRule55 } from "@oxlint/plugins";
5193
5969
  function reactPropsTarget(node) {
5194
5970
  if (node?.type === "FunctionDeclaration" || node?.type === "FunctionExpression" || node?.type === "ArrowFunctionExpression") {
5195
5971
  return { fn: node };
@@ -5216,7 +5992,7 @@ function reactIsPassThrough(type) {
5216
5992
  const argument = type.typeArguments?.params.length === 1 ? type.typeArguments.params[0] : undefined;
5217
5993
  return name.type === "Identifier" && name.name === "ComponentProps" && (argument?.type === "TSTypeQuery" || argument?.type === "TSLiteralType" && argument.literal.type === "Literal" && typeof argument.literal.value === "string");
5218
5994
  }
5219
- var reactProps = defineRule45({
5995
+ var reactProps = defineRule55({
5220
5996
  meta: {
5221
5997
  type: "problem",
5222
5998
  schema: [
@@ -5314,7 +6090,7 @@ var reactProps = defineRule45({
5314
6090
  });
5315
6091
 
5316
6092
  // src/rules/schemas/schemas-inline.ts
5317
- import { defineRule as defineRule46 } from "@oxlint/plugins";
6093
+ import { defineRule as defineRule56 } from "@oxlint/plugins";
5318
6094
 
5319
6095
  // src/utils/schemas.utils.ts
5320
6096
  var schemasElementOptionsSchema = {
@@ -5350,7 +6126,7 @@ function schemasIsAllowedElement(node, allowScalars, namespaces, structuralMetho
5350
6126
  }
5351
6127
 
5352
6128
  // src/rules/schemas/schemas-inline.ts
5353
- var schemasInline = defineRule46({
6129
+ var schemasInline = defineRule56({
5354
6130
  meta: {
5355
6131
  type: "problem",
5356
6132
  schema: [schemasElementOptionsSchema],
@@ -5399,11 +6175,11 @@ var schemasInline = defineRule46({
5399
6175
  });
5400
6176
 
5401
6177
  // src/rules/schemas/schemas-local.ts
5402
- import { defineRule as defineRule47 } from "@oxlint/plugins";
6178
+ import { defineRule as defineRule57 } from "@oxlint/plugins";
5403
6179
  var schemasLocalImportMessage = "Do not import runtime schema constructors from {{source}}; import a named schema instead.";
5404
6180
  var schemasLocalConstructionMessage = "Do not construct schemas locally; import a named schema instead.";
5405
6181
  var schemasLocalCalls = ["config", "prettifyError", "treeifyError", "flattenError", "formatError"];
5406
- var schemasLocal = defineRule47({
6182
+ var schemasLocal = defineRule57({
5407
6183
  meta: {
5408
6184
  type: "problem",
5409
6185
  schema: [
@@ -5528,8 +6304,8 @@ var schemasLocal = defineRule47({
5528
6304
  });
5529
6305
 
5530
6306
  // src/rules/schemas/schemas-rederive.ts
5531
- import { defineRule as defineRule48 } from "@oxlint/plugins";
5532
- var schemasRederive = defineRule48({
6307
+ import { defineRule as defineRule58 } from "@oxlint/plugins";
6308
+ var schemasRederive = defineRule58({
5533
6309
  meta: {
5534
6310
  type: "problem",
5535
6311
  schema: [
@@ -5575,7 +6351,7 @@ var schemasRederive = defineRule48({
5575
6351
  });
5576
6352
 
5577
6353
  // src/rules/schemas/schemas-single-use.ts
5578
- import { defineRule as defineRule49 } from "@oxlint/plugins";
6354
+ import { defineRule as defineRule59 } from "@oxlint/plugins";
5579
6355
  function isScalarSchema(node, namespaces, structuralMethods) {
5580
6356
  if (node.type !== "CallExpression" || node.callee.type !== "MemberExpression") {
5581
6357
  return false;
@@ -5589,7 +6365,7 @@ function isScalarSchema(node, namespaces, structuralMethods) {
5589
6365
  }
5590
6366
  return node.callee.object.type === "CallExpression" && isScalarSchema(node.callee.object, namespaces, structuralMethods);
5591
6367
  }
5592
- var schemasSingleUse = defineRule49({
6368
+ var schemasSingleUse = defineRule59({
5593
6369
  meta: {
5594
6370
  type: "suggestion",
5595
6371
  schema: [schemasElementOptionsSchema],
@@ -5665,7 +6441,7 @@ var schemasSingleUse = defineRule49({
5665
6441
  });
5666
6442
 
5667
6443
  // src/rules/tests/tests-assertions.ts
5668
- import { defineRule as defineRule50 } from "@oxlint/plugins";
6444
+ import { defineRule as defineRule60 } from "@oxlint/plugins";
5669
6445
  var testsAssertionsModifiers = new Set(["for", "each", "concurrent", "sequential", "only", "skip"]);
5670
6446
  var testsAssertionsFunctions = [
5671
6447
  "expect",
@@ -5855,7 +6631,7 @@ function isAssertedTest(registration, sourceCode, state) {
5855
6631
  }
5856
6632
  return rows.length > 0 && rows.every((row) => hasAssertion(callback, row.bindings, new Set, state));
5857
6633
  }
5858
- var testsAssertions = defineRule50({
6634
+ var testsAssertions = defineRule60({
5859
6635
  meta: {
5860
6636
  type: "problem",
5861
6637
  schema: [
@@ -5981,8 +6757,8 @@ var testsAssertions = defineRule50({
5981
6757
  });
5982
6758
 
5983
6759
  // src/rules/tests/tests-concurrent-db.ts
5984
- import { defineRule as defineRule51 } from "@oxlint/plugins";
5985
- var testsConcurrentDb = defineRule51({
6760
+ import { defineRule as defineRule61 } from "@oxlint/plugins";
6761
+ var testsConcurrentDb = defineRule61({
5986
6762
  meta: {
5987
6763
  type: "problem",
5988
6764
  schema: [{ type: "object", properties: { message: { type: "string" } }, additionalProperties: false }],
@@ -6019,7 +6795,7 @@ var testsConcurrentDb = defineRule51({
6019
6795
  });
6020
6796
 
6021
6797
  // src/rules/tests/tests-modifiers.ts
6022
- import { defineRule as defineRule52 } from "@oxlint/plugins";
6798
+ import { defineRule as defineRule62 } from "@oxlint/plugins";
6023
6799
  var testsModifiersNames = ["test", "it", "describe", "suite"];
6024
6800
  var testsModifiersPackages = new Set(["vitest", "bun:test", "@playwright/test", "@jest/globals"]);
6025
6801
  var testsModifiersBanned = new Set(["only", "skip", "todo"]);
@@ -6038,7 +6814,7 @@ function modifierName(node) {
6038
6814
  const property = astMemberName(node);
6039
6815
  return object && property ? `${object}.${property}` : undefined;
6040
6816
  }
6041
- var testsModifiers = defineRule52({
6817
+ var testsModifiers = defineRule62({
6042
6818
  meta: {
6043
6819
  type: "problem",
6044
6820
  schema: [
@@ -6089,9 +6865,9 @@ var testsModifiers = defineRule52({
6089
6865
  });
6090
6866
 
6091
6867
  // src/rules/tests/tests-titles.ts
6092
- import { defineRule as defineRule53 } from "@oxlint/plugins";
6868
+ import { defineRule as defineRule63 } from "@oxlint/plugins";
6093
6869
  var testsTitlesModifiers = new Set(["only", "skip", "concurrent", "sequential", "todo", "each", "for"]);
6094
- var testsTitles = defineRule53({
6870
+ var testsTitles = defineRule63({
6095
6871
  meta: {
6096
6872
  type: "suggestion",
6097
6873
  schema: [
@@ -6166,11 +6942,11 @@ var testsTitles = defineRule53({
6166
6942
  });
6167
6943
 
6168
6944
  // src/rules/types/types-declarations.ts
6169
- import { defineRule as defineRule54 } from "@oxlint/plugins";
6945
+ import { defineRule as defineRule64 } from "@oxlint/plugins";
6170
6946
  function isValuePattern(source) {
6171
6947
  return /^\^?=/.test(source);
6172
6948
  }
6173
- var typesDeclarations = defineRule54({
6949
+ var typesDeclarations = defineRule64({
6174
6950
  meta: {
6175
6951
  type: "problem",
6176
6952
  schema: [
@@ -6213,7 +6989,7 @@ var typesDeclarations = defineRule54({
6213
6989
  });
6214
6990
 
6215
6991
  // src/rules/types/types-imported-alias.ts
6216
- import { defineRule as defineRule55 } from "@oxlint/plugins";
6992
+ import { defineRule as defineRule65 } from "@oxlint/plugins";
6217
6993
  function importedAliasTarget(declaration, imports) {
6218
6994
  if (declaration?.type !== "TSTypeAliasDeclaration") {
6219
6995
  return;
@@ -6225,7 +7001,7 @@ function importedAliasTarget(declaration, imports) {
6225
7001
  const { name } = type.typeName;
6226
7002
  return imports.has(name) && !declaration.typeParameters?.params.some((parameter) => parameter.name.name === name) ? name : undefined;
6227
7003
  }
6228
- var typesImportedAlias = defineRule55({
7004
+ var typesImportedAlias = defineRule65({
6229
7005
  meta: {
6230
7006
  type: "problem",
6231
7007
  schema: [],
@@ -6287,7 +7063,7 @@ var typesImportedAlias = defineRule55({
6287
7063
  });
6288
7064
 
6289
7065
  // src/rules/types/types-inline.ts
6290
- import { defineRule as defineRule56 } from "@oxlint/plugins";
7066
+ import { defineRule as defineRule66 } from "@oxlint/plugins";
6291
7067
  function parameterAnnotation(parameter) {
6292
7068
  if (parameter.type === "TSParameterProperty") {
6293
7069
  return parameterAnnotation(parameter.parameter);
@@ -6297,7 +7073,7 @@ function parameterAnnotation(parameter) {
6297
7073
  }
6298
7074
  return parameter.typeAnnotation;
6299
7075
  }
6300
- var typesInline = defineRule56({
7076
+ var typesInline = defineRule66({
6301
7077
  meta: {
6302
7078
  type: "problem",
6303
7079
  schema: [
@@ -6373,8 +7149,8 @@ var typesInline = defineRule56({
6373
7149
  var typesLocalAlias = astSelectorRule("TSTypeAliasDeclaration", "Local component/hook contracts use interfaces named for their owner. Derived or reusable aliases belong in domain types; do not substitute an empty interface.");
6374
7150
 
6375
7151
  // src/rules/types/types-namespace-import.ts
6376
- import { defineRule as defineRule57 } from "@oxlint/plugins";
6377
- var typesNamespaceImport = defineRule57({
7152
+ import { defineRule as defineRule67 } from "@oxlint/plugins";
7153
+ var typesNamespaceImport = defineRule67({
6378
7154
  meta: {
6379
7155
  type: "suggestion",
6380
7156
  schema: [
@@ -6416,8 +7192,8 @@ var typesNamespaceImport = defineRule57({
6416
7192
  });
6417
7193
 
6418
7194
  // src/rules/types/types-service.ts
6419
- import { defineRule as defineRule58 } from "@oxlint/plugins";
6420
- var typesService = defineRule58({
7195
+ import { defineRule as defineRule68 } from "@oxlint/plugins";
7196
+ var typesService = defineRule68({
6421
7197
  meta: {
6422
7198
  type: "problem",
6423
7199
  schema: [],
@@ -6443,12 +7219,12 @@ var typesService = defineRule58({
6443
7219
  });
6444
7220
 
6445
7221
  // src/rules/types/types-unknown.ts
6446
- import { defineRule as defineRule59 } from "@oxlint/plugins";
7222
+ import { defineRule as defineRule69 } from "@oxlint/plugins";
6447
7223
  function isCatchName(node) {
6448
7224
  const key = "key" in node && !(("computed" in node) && node.computed) ? node.key : undefined;
6449
7225
  return key?.type === "Identifier" && key.name === "catch";
6450
7226
  }
6451
- var typesUnknown = defineRule59({
7227
+ var typesUnknown = defineRule69({
6452
7228
  meta: { type: "problem", schema: [], messages: { forbidden: "Use an owned domain type rather than unknown." } },
6453
7229
  createOnce(context) {
6454
7230
  return {
@@ -6485,15 +7261,21 @@ var src_default = eslintCompatPlugin({
6485
7261
  "boundaries-rpc-database": boundariesRpcDatabase,
6486
7262
  "boundaries-tanstack": boundariesTanstack,
6487
7263
  "boundaries-token-owner": boundariesTokenOwner,
7264
+ "code-branch-once": codeBranchOnce,
6488
7265
  "code-constructor": codeConstructor,
6489
7266
  "code-double-negation": codeDoubleNegation,
7267
+ "code-function-nesting": codeFunctionNesting,
7268
+ "code-inline": codeInline,
7269
+ "code-justified-call": codeJustifiedCall,
6490
7270
  "code-literal-in": codeLiteralIn,
6491
7271
  "code-mutable-state": codeMutableState,
6492
7272
  "code-object-params": codeObjectParams,
6493
7273
  "code-paired-call": codePairedCall,
6494
7274
  "code-promise-mutation": codePromiseMutation,
6495
7275
  "code-switch": codeSwitch,
7276
+ "code-traced": codeTraced,
6496
7277
  "code-trivial-functions": codeTrivialFunctions,
7278
+ "code-yield-argument": codeYieldArgument,
6497
7279
  "comments-code": commentsCode,
6498
7280
  "comments-directives": commentsDirectives,
6499
7281
  "copy-dashes": copyDashes,
@@ -6508,13 +7290,17 @@ var src_default = eslintCompatPlugin({
6508
7290
  "files-restricted": filesRestricted,
6509
7291
  "files-route": filesRoute,
6510
7292
  "files-types-only": filesTypesOnly,
7293
+ "layout-arrow-body": layoutArrowBody,
6511
7294
  "layout-call-arguments": layoutCallArguments,
6512
7295
  "layout-call-array": layoutCallArray,
7296
+ "layout-call-depth": layoutCallDepth,
6513
7297
  "layout-chain": layoutChain,
7298
+ "layout-items": layoutItems,
6514
7299
  "layout-jsx-attributes": layoutJsxAttributes,
6515
7300
  "layout-key-value": layoutKeyValue,
6516
7301
  "layout-object": layoutObject,
6517
7302
  "layout-padding": layoutPadding,
7303
+ "layout-pipe": layoutPipe,
6518
7304
  "layout-ternary": layoutTernary,
6519
7305
  "naming-declarations": namingDeclarations,
6520
7306
  "naming-exports": namingExports,