@foldkit/oxlint-plugin 0.10.0-canary.cc8d62ecc9cf → 0.10.0-canary.dc82c7255dbf

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
@@ -4,7 +4,7 @@ var __export = (target, all5) => {
4
4
  __defProp(target, name, { get: all5[name], enumerable: true });
5
5
  };
6
6
 
7
- // ../../node_modules/.pnpm/effect-oxlint@0.3.2_effect@4.0.0-rc.112/node_modules/effect-oxlint/dist/chunk.js
7
+ // ../../node_modules/.pnpm/effect-oxlint@0.3.3_effect@4.0.0-rc.112/node_modules/effect-oxlint/dist/chunk.js
8
8
  var __defProp2 = Object.defineProperty;
9
9
  var __exportAll = (all5, no_symbols) => {
10
10
  let target = {};
@@ -7399,7 +7399,7 @@ var flatMapEager2 = flatMapEager;
7399
7399
  var catchEager2 = catchEager;
7400
7400
  var fnUntracedEager2 = fnUntracedEager;
7401
7401
 
7402
- // ../../node_modules/.pnpm/effect-oxlint@0.3.2_effect@4.0.0-rc.112/node_modules/effect-oxlint/dist/RuleContext.js
7402
+ // ../../node_modules/.pnpm/effect-oxlint@0.3.3_effect@4.0.0-rc.112/node_modules/effect-oxlint/dist/RuleContext.js
7403
7403
  var RuleContextBase = Service()("effect-oxlint/RuleContext");
7404
7404
  var RuleContext = class extends RuleContextBase {
7405
7405
  };
@@ -10014,7 +10014,7 @@ var updateSomeAndGet = /* @__PURE__ */ dual(2, (self, pf) => sync2(() => {
10014
10014
  }));
10015
10015
  var getUnsafe3 = (self) => self.ref.current;
10016
10016
 
10017
- // ../../node_modules/.pnpm/effect-oxlint@0.3.2_effect@4.0.0-rc.112/node_modules/effect-oxlint/dist/index.js
10017
+ // ../../node_modules/.pnpm/effect-oxlint@0.3.3_effect@4.0.0-rc.112/node_modules/effect-oxlint/dist/index.js
10018
10018
  var AST_exports = /* @__PURE__ */ __exportAll({
10019
10019
  calleeIdentifier: () => calleeIdentifier,
10020
10020
  calleeName: () => calleeName,
@@ -11086,92 +11086,134 @@ var lazyViewStableReferences = Rule_exports.define({
11086
11086
 
11087
11087
  // src/rules/mount-factory-must-use-element.ts
11088
11088
  var MOUNT_DEFINITION_METHODS = ["define", "defineStream"];
11089
- var NO_ELEMENT_PARAMETER_MESSAGE = "This Mount factory never receives the element: it declares no usable element parameter. A Mount exists for element-caused, element-targeted work. If the element is irrelevant, use a Command, Subscription, or ManagedResource instead.";
11090
- var ignoredElementParameterMessage = (parameterName) => `The element parameter \`${parameterName}\` is named as ignored. A Mount factory must read or write its live element; if the element does not matter here, the side effect has a different cause and belongs in a Command, Subscription, or ManagedResource.`;
11091
- var unusedElementParameterMessage = (parameterName) => `The element parameter \`${parameterName}\` is never referenced in this Mount factory. A Mount factory must use its live element; work that does not need the element belongs in a Command, Subscription, or ManagedResource.`;
11092
- var isFactoryFunction = (node) => node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
11093
- var isMountDefinitionChain = (call) => {
11094
- if (call.callee.type === "MemberExpression") {
11095
- return AST_exports.isMember(call.callee, "Mount", MOUNT_DEFINITION_METHODS);
11096
- }
11097
- if (call.callee.type === "CallExpression") {
11098
- return isMountDefinitionChain(call.callee);
11099
- }
11100
- return false;
11101
- };
11102
- var returnedFactoryFunction = (statement) => {
11103
- if (statement.type !== "ReturnStatement" || statement.argument === null) {
11104
- return Option_exports.none();
11105
- }
11106
- return isFactoryFunction(statement.argument) ? Option_exports.some(statement.argument) : Option_exports.none();
11107
- };
11108
- var descendToElementFactory = (builder) => {
11109
- const body = builder.body;
11110
- if (body === null) return builder;
11111
- if (isFactoryFunction(body)) return body;
11112
- if (body.type === "BlockStatement") {
11113
- return pipe(
11114
- body.body,
11115
- Array_exports.findFirst(returnedFactoryFunction),
11116
- Option_exports.getOrElse(() => builder)
11117
- );
11118
- }
11119
- return builder;
11120
- };
11089
+ var ELEMENT_FIELD = "element";
11090
+ var NO_ELEMENT_BINDING_MESSAGE = `This Mount's \`execute\` never receives the element: it does not destructure \`element\` from its input. A Mount exists for element-caused, element-targeted work. If the element is irrelevant, use a Command, Subscription, or ManagedResource instead.`;
11091
+ var ignoredElementBindingMessage = (bindingName) => `The element binding \`${bindingName}\` is named as ignored. A Mount's \`execute\` must read or write its live element; if the element does not matter here, the side effect has a different cause and belongs in a Command, Subscription, or ManagedResource.`;
11092
+ var unusedElementBindingMessage = (bindingName) => `The element binding \`${bindingName}\` is never referenced in this Mount's \`execute\`. A Mount's \`execute\` must use its live element; work that does not need the element belongs in a Command, Subscription, or ManagedResource.`;
11093
+ var unreadElementFieldMessage = (bindingName) => `This Mount's \`execute\` reads other fields off \`${bindingName}\` but never its \`element\`. Destructure \`element\` from the input so the check can see the read, or if the element is irrelevant, use a Command, Subscription, or ManagedResource instead.`;
11094
+ var unusedInputMessage = (bindingName) => `This Mount's \`execute\` never references \`${bindingName}\`, so it never reaches the live element. Destructure \`element\` from the input so the check can see the read, or if the element is irrelevant, use a Command, Subscription, or ManagedResource instead.`;
11095
+ var isExecuteFunction = (node) => node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
11121
11096
  var isRecord = (value) => typeof value === "object" && value !== null;
11122
- var shadowsParameterName = (functionNode, parameterName) => {
11097
+ var shadowsBindingName = (functionNode, bindingName) => {
11123
11098
  const parameters = functionNode.params;
11124
11099
  if (!isRecord(parameters)) return false;
11125
11100
  return Object.values(parameters).some(
11126
- (parameter) => isRecord(parameter) && parameter.type === "Identifier" && parameter.name === parameterName
11101
+ (parameter) => isRecord(parameter) && parameter.type === "Identifier" && parameter.name === bindingName
11127
11102
  );
11128
11103
  };
11129
- var referencesName = (value, parameterName) => {
11104
+ var referencesName = (value, bindingName) => {
11130
11105
  if (!isRecord(value)) return false;
11131
- if (value.type === "Identifier" && value.name === parameterName) return true;
11132
- if ((value.type === "ArrowFunctionExpression" || value.type === "FunctionExpression") && shadowsParameterName(value, parameterName)) {
11106
+ if (value.type === "Identifier" && value.name === bindingName) return true;
11107
+ if ((value.type === "ArrowFunctionExpression" || value.type === "FunctionExpression") && shadowsBindingName(value, bindingName)) {
11133
11108
  return false;
11134
11109
  }
11110
+ if (value.type === "MemberExpression" && value.computed !== true) {
11111
+ return referencesName(value.object, bindingName);
11112
+ }
11135
11113
  if (value.type === "Property") {
11136
- const computedKeyReferences = value.computed === true && referencesName(value.key, parameterName);
11137
- return computedKeyReferences || referencesName(value.value, parameterName);
11114
+ const computedKeyReferences = value.computed === true && referencesName(value.key, bindingName);
11115
+ return computedKeyReferences || referencesName(value.value, bindingName);
11138
11116
  }
11139
11117
  return Object.entries(value).some(
11140
- ([key, child]) => key !== "parent" && referencesName(child, parameterName)
11118
+ ([key, child]) => key !== "parent" && referencesName(child, bindingName)
11141
11119
  );
11142
11120
  };
11143
- var elementFactoryDiagnostic = (factory) => {
11144
- const [firstParameter] = factory.params;
11145
- if (firstParameter === void 0 || firstParameter.type !== "Identifier") {
11146
- return Option_exports.some(NO_ELEMENT_PARAMETER_MESSAGE);
11121
+ var inputUses = (value, inputName) => {
11122
+ if (!isRecord(value)) return [];
11123
+ if (value.type === "MemberExpression" && isRecord(value.object) && value.object.type === "Identifier" && value.object.name === inputName) {
11124
+ if (value.computed === true) return ["MaybeElement"];
11125
+ return isRecord(value.property) && value.property.type === "Identifier" && value.property.name === ELEMENT_FIELD ? ["Element"] : ["OtherField"];
11126
+ }
11127
+ if (value.type === "MemberExpression" && value.computed !== true) {
11128
+ return inputUses(value.object, inputName);
11129
+ }
11130
+ if ((value.type === "ArrowFunctionExpression" || value.type === "FunctionExpression") && shadowsBindingName(value, inputName)) {
11131
+ return [];
11132
+ }
11133
+ if (value.type === "Property") {
11134
+ const keyUses = value.computed === true ? inputUses(value.key, inputName) : [];
11135
+ return [...keyUses, ...inputUses(value.value, inputName)];
11147
11136
  }
11148
- if (firstParameter.name.startsWith("_")) {
11149
- return Option_exports.some(ignoredElementParameterMessage(firstParameter.name));
11137
+ if (value.type === "Identifier" && value.name === inputName) {
11138
+ return ["MaybeElement"];
11150
11139
  }
11151
- return referencesName(factory.body, firstParameter.name) ? Option_exports.none() : Option_exports.some(unusedElementParameterMessage(firstParameter.name));
11140
+ return Object.entries(value).flatMap(
11141
+ ([key, child]) => key === "parent" ? [] : inputUses(child, inputName)
11142
+ );
11152
11143
  };
11144
+ var elementProperty = (pattern) => pipe(
11145
+ pattern.properties,
11146
+ Array_exports.findFirst(
11147
+ (property) => property.type === "Property" && (property.key.type === "Literal" ? property.key.value === ELEMENT_FIELD : !property.computed && property.key.type === "Identifier" && property.key.name === ELEMENT_FIELD)
11148
+ )
11149
+ );
11150
+ var restBindingName = (pattern) => pipe(
11151
+ pattern.properties,
11152
+ Array_exports.findFirst(
11153
+ (property) => property.type === "RestElement" && property.argument.type === "Identifier" ? Option_exports.some(property.argument.name) : Option_exports.none()
11154
+ )
11155
+ );
11156
+ var withoutDefault = (value) => value.type === "AssignmentPattern" ? value.left : value;
11157
+ var bindingDiagnostic = (execute, bindingName) => {
11158
+ if (bindingName.startsWith("_")) {
11159
+ return Option_exports.some(ignoredElementBindingMessage(bindingName));
11160
+ }
11161
+ return referencesName(execute.body, bindingName) ? Option_exports.none() : Option_exports.some(unusedElementBindingMessage(bindingName));
11162
+ };
11163
+ var unpackedDiagnostic = (execute, bindingName) => {
11164
+ const uses = inputUses(execute.body, bindingName);
11165
+ if (Array_exports.isReadonlyArrayEmpty(uses)) {
11166
+ return Option_exports.some(unusedInputMessage(bindingName));
11167
+ }
11168
+ return uses.every((use) => use === "OtherField") ? Option_exports.some(unreadElementFieldMessage(bindingName)) : Option_exports.none();
11169
+ };
11170
+ var executeDiagnostic = (execute) => {
11171
+ const [firstParameter] = execute.params;
11172
+ if (firstParameter === void 0) {
11173
+ return Option_exports.some(NO_ELEMENT_BINDING_MESSAGE);
11174
+ }
11175
+ if (firstParameter.type === "Identifier") {
11176
+ return unpackedDiagnostic(execute, firstParameter.name);
11177
+ }
11178
+ if (firstParameter.type !== "ObjectPattern") {
11179
+ return Option_exports.some(NO_ELEMENT_BINDING_MESSAGE);
11180
+ }
11181
+ return Option_exports.match(elementProperty(firstParameter), {
11182
+ onNone: () => Option_exports.match(restBindingName(firstParameter), {
11183
+ onNone: () => Option_exports.some(NO_ELEMENT_BINDING_MESSAGE),
11184
+ onSome: (restName) => unpackedDiagnostic(execute, restName)
11185
+ }),
11186
+ onSome: (property) => {
11187
+ const pattern = withoutDefault(property.value);
11188
+ return pattern.type === "Identifier" ? bindingDiagnostic(execute, pattern.name) : Option_exports.none();
11189
+ }
11190
+ });
11191
+ };
11192
+ var executeFunction = (node) => pipe(
11193
+ Array_exports.get(node.arguments, 1),
11194
+ Option_exports.filter(isObjectExpression),
11195
+ Option_exports.flatMap((config) => AST_exports.objectGetValue(config, "execute")),
11196
+ Option_exports.filter(isExecuteFunction)
11197
+ );
11153
11198
  var mountFactoryMustUseElement = Rule_exports.define({
11154
11199
  name: "mount-factory-must-use-element",
11155
11200
  meta: Rule_exports.meta({
11156
11201
  type: "suggestion",
11157
- description: "Require Mount factories to use their live element."
11202
+ description: "Require a Mount's execute to use its live element."
11158
11203
  }),
11159
11204
  create: function* () {
11160
11205
  const ctx = yield* RuleContext;
11161
11206
  return {
11162
11207
  CallExpression: (node) => {
11163
- if (!isCallExpression(node)) return Effect_exports.void;
11164
- if (node.callee.type !== "CallExpression" || !isMountDefinitionChain(node.callee)) {
11165
- return Effect_exports.void;
11166
- }
11167
- const [factoryArgument] = node.arguments;
11168
- if (factoryArgument === void 0 || !isFactoryFunction(factoryArgument)) {
11208
+ if (!isCallExpression(node) || !AST_exports.isCallOf(node, "Mount", MOUNT_DEFINITION_METHODS)) {
11169
11209
  return Effect_exports.void;
11170
11210
  }
11171
- const elementFactory = descendToElementFactory(factoryArgument);
11172
- return Option_exports.match(elementFactoryDiagnostic(elementFactory), {
11211
+ return Option_exports.match(executeFunction(node), {
11173
11212
  onNone: () => Effect_exports.void,
11174
- onSome: (message) => ctx.report(Diagnostic_exports.make({ node: elementFactory, message }))
11213
+ onSome: (execute) => Option_exports.match(executeDiagnostic(execute), {
11214
+ onNone: () => Effect_exports.void,
11215
+ onSome: (message) => ctx.report(Diagnostic_exports.make({ node: execute, message }))
11216
+ })
11175
11217
  });
11176
11218
  }
11177
11219
  };
@@ -11456,7 +11498,7 @@ var noDisablingDevGuardrails = Rule_exports.define({
11456
11498
  });
11457
11499
 
11458
11500
  // src/rules/no-duplicate-onmount-per-element.ts
11459
- var DUPLICATE_ON_MOUNT_MESSAGE = "Only one OnMount attribute can attach to an element. Foldkit installs a single insert hook and tracks a single Mount fiber per element, so a later OnMount replaces the earlier one and its factory never runs. Combine the behaviors into one Mount definition.";
11501
+ var DUPLICATE_ON_MOUNT_MESSAGE = "Only one OnMount attribute can attach to an element. Foldkit installs a single insert hook and tracks a single Mount fiber per element, so a later OnMount replaces the earlier one and its `execute` never runs. Combine the behaviors into one Mount definition.";
11460
11502
  var isOnMountCallee = (callee) => {
11461
11503
  if (callee.type === "Identifier") {
11462
11504
  return callee.name === "OnMount";
@@ -1,3 +1,3 @@
1
- /** Flags applied Mount.define and Mount.defineStream factories that never use their element parameter. A Mount exists for element-caused, element-targeted work; a factory that ignores the element belongs in a Command, Subscription, or ManagedResource. */
1
+ /** Flags Mount.define and Mount.defineStream definitions whose `execute` never uses its element. A Mount exists for element-caused, element-targeted work; work that ignores the element belongs in a Command, Subscription, or ManagedResource. */
2
2
  export declare const mountFactoryMustUseElement: import("effect-oxlint").CreateRule;
3
3
  //# sourceMappingURL=mount-factory-must-use-element.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mount-factory-must-use-element.d.ts","sourceRoot":"","sources":["../../src/rules/mount-factory-must-use-element.ts"],"names":[],"mappings":"AA4GA,+PAA+P;AAC/P,eAAO,MAAM,0BAA0B,oCAiCrC,CAAA"}
1
+ {"version":3,"file":"mount-factory-must-use-element.d.ts","sourceRoot":"","sources":["../../src/rules/mount-factory-must-use-element.ts"],"names":[],"mappings":"AA0NA,oPAAoP;AACpP,eAAO,MAAM,0BAA0B,oCA4BrC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldkit/oxlint-plugin",
3
- "version": "0.10.0-canary.cc8d62ecc9cf",
3
+ "version": "0.10.0-canary.dc82c7255dbf",
4
4
  "description": "Oxlint rules for Foldkit applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,15 +15,15 @@
15
15
  "./all.json": "./all.json"
16
16
  },
17
17
  "dependencies": {
18
- "effect-oxlint": "^0.3.2"
18
+ "effect-oxlint": "^0.3.3"
19
19
  },
20
20
  "devDependencies": {
21
- "@types/node": "^25.9.3",
21
+ "@types/node": "^25.9.5",
22
22
  "effect": "4.0.0-rc.112",
23
- "esbuild": "^0.28.1",
23
+ "esbuild": "^0.28.2",
24
24
  "rimraf": "^6.1.3",
25
25
  "typescript": "^6.0.3",
26
- "vitest": "^4.1.9"
26
+ "vitest": "^4.1.11"
27
27
  },
28
28
  "files": [
29
29
  "dist",