@colrealpro/react-luau-doctor 0.20.1 → 0.20.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.
@@ -329,7 +329,7 @@
329
329
  "suggestion"
330
330
  ],
331
331
  "default": "warning",
332
- "description": "Do not read binding snapshots during render except to initialize a ref"
332
+ "description": "Do not read binding snapshots during render except in hook initialization arguments"
333
333
  },
334
334
  "react-luau/usememo-must-return": {
335
335
  "type": "string",
@@ -1168,7 +1168,13 @@ function isLazyRefInitialization(context, call) {
1168
1168
  }
1169
1169
  return false;
1170
1170
  }
1171
- function isRefInitializer(context, call) {
1171
+ var hookInitializerArguments = new Map([
1172
+ ["React.useRef", 0],
1173
+ ["React.useState", 0],
1174
+ ["React.useBinding", 0],
1175
+ ["React.useReducer", 1]
1176
+ ]);
1177
+ function isHookInitializer(context, call) {
1172
1178
  let node = call;
1173
1179
  while (node.parent) {
1174
1180
  const parent = node.parent;
@@ -1176,8 +1182,11 @@ function isRefInitializer(context, call) {
1176
1182
  return false;
1177
1183
  if (parent.type === "arguments") {
1178
1184
  const hook = parent.parent;
1179
- if (hook?.type === "function_call" && reactApiPath(context, hook) === "React.useRef" && context.callArguments(hook)[0]?.id === node.id)
1180
- return true;
1185
+ if (hook?.type === "function_call") {
1186
+ const argumentIndex = hookInitializerArguments.get(reactApiPath(context, hook) ?? "");
1187
+ if (argumentIndex !== undefined && context.callArguments(hook)[argumentIndex]?.id === node.id)
1188
+ return true;
1189
+ }
1181
1190
  }
1182
1191
  node = parent;
1183
1192
  }
@@ -1211,18 +1220,18 @@ var noBindingGetValueInRender = {
1211
1220
  id: "react-luau/no-binding-getvalue-in-render",
1212
1221
  category: "Correctness",
1213
1222
  severity: "warning",
1214
- description: "Do not read binding snapshots during render except to initialize a ref",
1223
+ description: "Do not read binding snapshots during render except in hook initialization arguments",
1215
1224
  guidance: {
1216
1225
  explanation: "getValue returns a snapshot without subscribing \u2014 later binding updates do not rerender the component or update props built from that snapshot",
1217
1226
  help: "Pass the binding directly to the prop or use binding:map(function(value) return ... end)",
1218
- caveat: "A snapshot used to initialize React.useRef is allowed because the initial value is intentionally preserved"
1227
+ caveat: "Snapshots in the first argument to React.useRef, React.useState, or React.useBinding, or the second argument to React.useReducer, are allowed because those arguments are used only for initialization"
1219
1228
  },
1220
1229
  run(context) {
1221
1230
  return context.findCalls().flatMap((call) => {
1222
1231
  const owner = context.nearestFunction(call);
1223
1232
  const name = call.childForFieldName("name");
1224
1233
  const receiver = name?.namedChildren[0];
1225
- if (!owner || !owner.isComponent && !owner.isHook || name?.type !== "method_index_expression" || name.namedChildren.at(-1)?.text !== "getValue" || !receiver || !isBinding(context, receiver) || isRefInitializer(context, call))
1234
+ if (!owner || !owner.isComponent && !owner.isHook || name?.type !== "method_index_expression" || name.namedChildren.at(-1)?.text !== "getValue" || !receiver || !isBinding(context, receiver) || isHookInitializer(context, call))
1226
1235
  return [];
1227
1236
  return [
1228
1237
  {
@@ -9329,6 +9338,7 @@ async function analyzeReactFile(input, tree, selectedRules = rules) {
9329
9338
  project: input.project
9330
9339
  };
9331
9340
  const context = createRuleContext(file);
9341
+ const syntaxFindings = parsedTree.rootNode.hasError ? parseErrors.run(context) : [];
9332
9342
  const categorySet = input.categories && input.categories.length > 0 ? new Set(input.categories) : null;
9333
9343
  const isSuppressed = input.respectInlineDisables ? createInlineSuppressionChecker(input.source) : () => false;
9334
9344
  const diagnostics = [];
@@ -9340,7 +9350,7 @@ async function analyzeReactFile(input, tree, selectedRules = rules) {
9340
9350
  const severity = effectiveSeverity(rule.severity, rule.id, input.config);
9341
9351
  if (!severity)
9342
9352
  continue;
9343
- const findings = rule.run(context);
9353
+ const findings = rule.id === parseErrors.id ? syntaxFindings : rule.run(context);
9344
9354
  for (const finding of findings) {
9345
9355
  const configuredSeverity = input.config.rules?.[rule.id];
9346
9356
  const diagnostic = toDiagnostic(file, rule.id, rule.category, severity, {
@@ -9361,7 +9371,8 @@ async function analyzeReactFile(input, tree, selectedRules = rules) {
9361
9371
  relativePath: input.relativePath,
9362
9372
  isReactFile: model.isReactFile,
9363
9373
  scanned: true,
9364
- diagnostics: filteredDiagnostics
9374
+ diagnostics: filteredDiagnostics,
9375
+ unverified: syntaxFindings.length > 0
9365
9376
  };
9366
9377
  } finally {
9367
9378
  if (!tree)
@@ -10348,5 +10359,5 @@ parentPort.on("message", async (request) => {
10348
10359
  }
10349
10360
  });
10350
10361
 
10351
- //# debugId=AB0DC00E72A2325A64756E2164756E21
10362
+ //# debugId=3E81A30ECFF40BE164756E2164756E21
10352
10363
  //# sourceMappingURL=scan-worker.js.map