oxlint-plugin-react-doctor 0.9.2-dev.1f6e181 → 0.9.2-dev.2992a03

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +122 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -56090,6 +56090,9 @@ const isInitialOnlyPropName = (propName) => {
56090
56090
  return /^initial[A-Z]/.test(propName) || /^default[A-Z]/.test(propName) || /^seed[A-Z]/.test(propName) || /^starting[A-Z]/.test(propName) || /^baseline[A-Z]/.test(propName) || /^preset[A-Z]/.test(propName);
56091
56091
  };
56092
56092
  //#endregion
56093
+ //#region src/plugin/utils/nextjs-page-data-export-names.ts
56094
+ const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
56095
+ //#endregion
56093
56096
  //#region src/plugin/rules/state-and-effects/no-derived-use-state.ts
56094
56097
  const isInitialOnlySeedName = (propName) => isInitialOnlyPropName(propName) || propName === "initial" || propName === "autoFocus" || propName === "autoPlay" || propName === "startOpen" || /^initially[A-Z]/.test(propName) || /Initial([A-Z]|$)/.test(propName);
56095
56098
  const SNAPSHOT_STATE_NAME_PATTERN = /^(initial|previous|prev|preserved|saved|original|cached|snapshot|prior|debounced|deferred)([A-Z_]|$)/;
@@ -56246,7 +56249,6 @@ const isDraftCommittedToParent = (componentFunction, stateValueName, isPropName)
56246
56249
  });
56247
56250
  return isCommitted;
56248
56251
  };
56249
- const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
56250
56252
  const isNextjsDataFetchingPage = (node) => {
56251
56253
  const program = findProgramRoot(node);
56252
56254
  if (!program) return false;
@@ -67191,6 +67193,124 @@ const isInsideSnapshotHelper = (node) => {
67191
67193
  }
67192
67194
  return false;
67193
67195
  };
67196
+ const findEnclosingNextjsPageDataFunction = (node) => {
67197
+ let outermostFunction = null;
67198
+ let cursor = node.parent;
67199
+ while (cursor) {
67200
+ if (isFunctionLike$1(cursor)) outermostFunction = cursor;
67201
+ if (isNodeOfType(cursor, "Program")) {
67202
+ if (!outermostFunction) return null;
67203
+ for (const exportName of NEXTJS_PAGE_DATA_EXPORT_NAMES) {
67204
+ const exportedValue = findExportedValue(cursor, exportName);
67205
+ if (exportedValue && isAstDescendant(outermostFunction, exportedValue)) return outermostFunction;
67206
+ }
67207
+ return null;
67208
+ }
67209
+ cursor = cursor.parent ?? null;
67210
+ }
67211
+ return null;
67212
+ };
67213
+ const findConditionalReturnExpressionRoot = (node) => {
67214
+ let expressionRoot = findTransparentExpressionRoot(node);
67215
+ while (expressionRoot.parent && isNodeOfType(expressionRoot.parent, "ConditionalExpression") && (expressionRoot.parent.consequent === expressionRoot || expressionRoot.parent.alternate === expressionRoot)) expressionRoot = findTransparentExpressionRoot(expressionRoot.parent);
67216
+ return expressionRoot;
67217
+ };
67218
+ const isReturnedPageDataResultBinding = (returnExpression, pageDataFunction, context) => {
67219
+ const declarator = returnExpression.parent;
67220
+ if (!isNodeOfType(declarator, "VariableDeclarator") || declarator.init !== returnExpression || !isNodeOfType(declarator.id, "Identifier") || findEnclosingFunction$1(declarator) !== pageDataFunction) return false;
67221
+ const bindingSymbol = context.scopes.symbolFor(declarator.id);
67222
+ if (!bindingSymbol || bindingSymbol.references.length !== 1) return false;
67223
+ const referenceRoot = findTransparentExpressionRoot(bindingSymbol.references[0].identifier);
67224
+ const returnStatement = referenceRoot.parent;
67225
+ return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === referenceRoot && findEnclosingFunction$1(returnStatement) === pageDataFunction;
67226
+ };
67227
+ const isSameShorthandPropertyValue = (node, property) => property.shorthand && (node === property.key || node === property.value);
67228
+ const isValueForwardedThroughLiteralStructure = (node, structure) => {
67229
+ const strippedNode = stripParenExpression(node);
67230
+ const strippedStructure = stripParenExpression(structure);
67231
+ if (strippedNode === strippedStructure) return true;
67232
+ if (isNodeOfType(strippedStructure, "ConditionalExpression")) return isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.consequent) || isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.alternate);
67233
+ if (isNodeOfType(strippedStructure, "ArrayExpression")) return strippedStructure.elements.some((element) => element && !isNodeOfType(element, "SpreadElement") && isValueForwardedThroughLiteralStructure(strippedNode, element));
67234
+ if (!isNodeOfType(strippedStructure, "ObjectExpression")) return false;
67235
+ return strippedStructure.properties.some((property) => {
67236
+ if (isNodeOfType(property, "SpreadElement")) return isValueForwardedThroughLiteralStructure(strippedNode, property.argument);
67237
+ if (!isNodeOfType(property, "Property")) return false;
67238
+ if (isValueForwardedThroughLiteralStructure(strippedNode, property.value)) return true;
67239
+ return isSameShorthandPropertyValue(strippedNode, property);
67240
+ });
67241
+ };
67242
+ const isValueForwardedToPropertyValue = (node, property) => {
67243
+ const directValue = findConditionalReturnExpressionRoot(node);
67244
+ if (isValueForwardedThroughLiteralStructure(directValue, property.value)) return true;
67245
+ return isSameShorthandPropertyValue(directValue, property);
67246
+ };
67247
+ const isInsideReturnedNextjsProps = (node, pageDataFunction, context) => {
67248
+ let cursor = node.parent;
67249
+ while (cursor && cursor !== pageDataFunction) {
67250
+ if (isNodeOfType(cursor, "Property") && getStaticPropertyKeyName(cursor, { allowComputedString: true }) === "props" && isValueForwardedToPropertyValue(node, cursor)) {
67251
+ const propertyContainer = cursor.parent;
67252
+ if (!propertyContainer) return false;
67253
+ const returnExpression = findConditionalReturnExpressionRoot(propertyContainer);
67254
+ const returnStatement = returnExpression.parent;
67255
+ if (isNodeOfType(returnStatement, "ReturnStatement") && findEnclosingFunction$1(returnStatement) === pageDataFunction) return true;
67256
+ if (isNodeOfType(pageDataFunction, "ArrowFunctionExpression") && !isNodeOfType(pageDataFunction.body, "BlockStatement") && stripParenExpression(pageDataFunction.body) === stripParenExpression(returnExpression)) return true;
67257
+ if (isReturnedPageDataResultBinding(returnExpression, pageDataFunction, context)) return true;
67258
+ }
67259
+ cursor = cursor.parent ?? null;
67260
+ }
67261
+ return false;
67262
+ };
67263
+ const isExpressionReturnedByFunction = (node, functionNode) => {
67264
+ const returnExpression = findConditionalReturnExpressionRoot(node);
67265
+ if (isNodeOfType(functionNode, "ArrowFunctionExpression") && !isNodeOfType(functionNode.body, "BlockStatement")) return stripParenExpression(functionNode.body) === stripParenExpression(returnExpression);
67266
+ const returnStatement = returnExpression.parent;
67267
+ return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === returnExpression && findEnclosingFunction$1(returnStatement) === functionNode;
67268
+ };
67269
+ const isValueForwardedToBindingInitializer = (node, bindingInitializer) => {
67270
+ if (isValueForwardedThroughLiteralStructure(findConditionalReturnExpressionRoot(node), bindingInitializer)) return true;
67271
+ const initializer = stripParenExpression(bindingInitializer);
67272
+ if (!isNodeOfType(initializer, "CallExpression")) return false;
67273
+ const callee = stripParenExpression(initializer.callee);
67274
+ return isFunctionLike$1(callee) && isExpressionReturnedByFunction(node, callee);
67275
+ };
67276
+ const findPageDataResultBinding = (node) => {
67277
+ let cursor = node.parent;
67278
+ while (cursor) {
67279
+ if (isNodeOfType(cursor, "VariableDeclarator")) {
67280
+ if (cursor.init && isNodeOfType(cursor.id, "Identifier") && isValueForwardedToBindingInitializer(node, cursor.init)) return cursor.id;
67281
+ return null;
67282
+ }
67283
+ cursor = cursor.parent ?? null;
67284
+ }
67285
+ return null;
67286
+ };
67287
+ const isUsedToSerializeNextjsPageProps = (node, context) => {
67288
+ if (!isInProjectDirectory(context, "pages") || isInProjectDirectory(context, "pages/api")) return false;
67289
+ const pageDataFunction = findEnclosingNextjsPageDataFunction(node);
67290
+ if (!pageDataFunction) return false;
67291
+ if (isInsideReturnedNextjsProps(node, pageDataFunction, context)) return true;
67292
+ const bindingIdentifier = findPageDataResultBinding(node);
67293
+ const bindingSymbol = bindingIdentifier ? context.scopes.symbolFor(bindingIdentifier) : null;
67294
+ if (!bindingSymbol) return false;
67295
+ const aliasSymbols = collectConstAliasSymbols(bindingSymbol, context.scopes);
67296
+ const aliasSymbolIds = new Set(aliasSymbols.map((aliasSymbol) => aliasSymbol.id));
67297
+ let hasPagePropsReference = false;
67298
+ for (const aliasSymbol of aliasSymbols) for (const reference of aliasSymbol.references) {
67299
+ if (findEnclosingFunction$1(reference.identifier) !== pageDataFunction) return false;
67300
+ if (isInsideReturnedNextjsProps(reference.identifier, pageDataFunction, context)) {
67301
+ hasPagePropsReference = true;
67302
+ continue;
67303
+ }
67304
+ const referenceRoot = findTransparentExpressionRoot(reference.identifier);
67305
+ const declarator = referenceRoot.parent;
67306
+ if (isNodeOfType(declarator, "VariableDeclarator") && declarator.init === referenceRoot && isNodeOfType(declarator.id, "Identifier")) {
67307
+ const aliasSymbolForReference = context.scopes.symbolFor(declarator.id);
67308
+ if (aliasSymbolForReference && aliasSymbolIds.has(aliasSymbolForReference.id)) continue;
67309
+ }
67310
+ return false;
67311
+ }
67312
+ return hasPagePropsReference;
67313
+ };
67194
67314
  const noJsonParseStringifyClone = defineRule({
67195
67315
  id: "no-json-parse-stringify-clone",
67196
67316
  title: "JSON parse/stringify deep clone",
@@ -67208,6 +67328,7 @@ const noJsonParseStringifyClone = defineRule({
67208
67328
  if (isInsideSnapshotHelper(node)) return;
67209
67329
  if (isAssignedToNormalizationBinding(node)) return;
67210
67330
  if (isCatchParameterRoundTrip(firstArgument)) return;
67331
+ if (isUsedToSerializeNextjsPageProps(node, context)) return;
67211
67332
  context.report({
67212
67333
  node,
67213
67334
  message: MESSAGE$35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.9.2-dev.1f6e181",
3
+ "version": "0.9.2-dev.2992a03",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",