oxlint-plugin-react-doctor 0.5.6-dev.8908f98 → 0.5.6-dev.b08ca1c

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 +125 -4
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -3104,6 +3104,76 @@ const AUTH_FUNCTION_NAMES = new Set([
3104
3104
  "getAuth",
3105
3105
  "validateSession"
3106
3106
  ]);
3107
+ const AUTH_STRONG_TOKEN_PATTERN = /^auth(?:n|z|ed|enticate[ds]?|enticating|entication|orize[ds]?|orizing|orization|orizer)?$/;
3108
+ const AUTH_STANDALONE_NOUN_TOKENS = new Set([
3109
+ "signedin",
3110
+ "loggedin",
3111
+ "signin"
3112
+ ]);
3113
+ const AUTH_ASSERTIVE_VERB_TOKENS = new Set([
3114
+ "require",
3115
+ "ensure",
3116
+ "assert",
3117
+ "verify",
3118
+ "validate",
3119
+ "check",
3120
+ "protect",
3121
+ "enforce",
3122
+ "guard",
3123
+ "gate",
3124
+ "restrict",
3125
+ "is",
3126
+ "has",
3127
+ "can",
3128
+ "must"
3129
+ ]);
3130
+ const AUTH_GETTER_VERB_TOKENS = new Set([
3131
+ "get",
3132
+ "fetch",
3133
+ "load",
3134
+ "read",
3135
+ "resolve",
3136
+ "retrieve",
3137
+ "use"
3138
+ ]);
3139
+ const AUTH_QUALIFIER_TOKENS = new Set([
3140
+ "current",
3141
+ "my",
3142
+ "own"
3143
+ ]);
3144
+ const AUTH_STRONG_NOUN_TOKENS = new Set([
3145
+ "session",
3146
+ "sessions",
3147
+ "login",
3148
+ "admin",
3149
+ "admins",
3150
+ "superadmin",
3151
+ "superuser",
3152
+ "role",
3153
+ "roles",
3154
+ "permission",
3155
+ "permissions",
3156
+ "jwt",
3157
+ "identity",
3158
+ "principal",
3159
+ "credential",
3160
+ "credentials"
3161
+ ]);
3162
+ const AUTH_WEAK_NOUN_TOKENS = new Set([
3163
+ "user",
3164
+ "users",
3165
+ "account",
3166
+ "accounts",
3167
+ "token",
3168
+ "tokens",
3169
+ "access",
3170
+ "me",
3171
+ "viewer",
3172
+ "caller",
3173
+ "subject",
3174
+ "scope",
3175
+ "scopes"
3176
+ ]);
3107
3177
  const GENERIC_AUTH_METHOD_NAMES = new Set(["getUser"]);
3108
3178
  const AUTH_OBJECT_PATTERN = /(?:^|[._])(?:auth|authn|authz|clerk|session|jwt|firebase|supabase|nextauth|kinde|workos|stytch|descope|cognito|propelauth|lucia)/i;
3109
3179
  const SECRET_PATTERNS = [
@@ -22944,11 +23014,17 @@ const classifySecretFileExposure = (filename, options = {}) => {
22944
23014
  return "unknown";
22945
23015
  };
22946
23016
  //#endregion
22947
- //#region src/plugin/utils/get-identifier-trailing-word.ts
22948
- const getIdentifierTrailingWord = (identifierName) => {
22949
- return identifierName.match(/[A-Z]+(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+|\d+/g)?.at(-1)?.toLowerCase() ?? identifierName.toLowerCase();
23017
+ //#region src/plugin/utils/tokenize-identifier-words.ts
23018
+ const IDENTIFIER_WORD_PATTERN = /[A-Z]+(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+|\d+/g;
23019
+ const tokenizeIdentifierWords = (identifierName) => {
23020
+ const words = identifierName.match(IDENTIFIER_WORD_PATTERN);
23021
+ if (!words) return [];
23022
+ return words.map((word) => word.toLowerCase());
22950
23023
  };
22951
23024
  //#endregion
23025
+ //#region src/plugin/utils/get-identifier-trailing-word.ts
23026
+ const getIdentifierTrailingWord = (identifierName) => tokenizeIdentifierWords(identifierName).at(-1) ?? identifierName.toLowerCase();
23027
+ //#endregion
22952
23028
  //#region src/plugin/constants/tanstack.ts
22953
23029
  const TANSTACK_ROUTE_FILE_PATTERN = /\/routes\//;
22954
23030
  const TANSTACK_ROOT_ROUTE_FILE_PATTERN = /__root\.(tsx?|jsx?)$/;
@@ -34895,6 +34971,47 @@ const serverAfterNonblocking = defineRule({
34895
34971
  }
34896
34972
  });
34897
34973
  //#endregion
34974
+ //#region src/plugin/utils/is-auth-guard-name.ts
34975
+ const SIGNED_IN_HEAD_TOKENS = new Set([
34976
+ "signed",
34977
+ "logged",
34978
+ "sign"
34979
+ ]);
34980
+ const mergeSignedInTokens = (tokens) => {
34981
+ const mergedTokens = [];
34982
+ for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex += 1) {
34983
+ const currentToken = tokens[tokenIndex];
34984
+ if (SIGNED_IN_HEAD_TOKENS.has(currentToken) && tokens[tokenIndex + 1] === "in") {
34985
+ mergedTokens.push(`${currentToken}in`);
34986
+ tokenIndex += 1;
34987
+ continue;
34988
+ }
34989
+ mergedTokens.push(currentToken);
34990
+ }
34991
+ return mergedTokens;
34992
+ };
34993
+ const isAuthGuardName = (calleeName) => {
34994
+ const tokens = mergeSignedInTokens(tokenizeIdentifierWords(calleeName));
34995
+ if (tokens.length === 0) return false;
34996
+ let hasAssertiveVerb = false;
34997
+ let hasGetterVerb = false;
34998
+ let hasQualifier = false;
34999
+ let hasStrongNoun = false;
35000
+ let hasWeakNoun = false;
35001
+ for (const token of tokens) {
35002
+ if (AUTH_STRONG_TOKEN_PATTERN.test(token) || AUTH_STANDALONE_NOUN_TOKENS.has(token)) return true;
35003
+ if (AUTH_ASSERTIVE_VERB_TOKENS.has(token)) hasAssertiveVerb = true;
35004
+ if (AUTH_GETTER_VERB_TOKENS.has(token)) hasGetterVerb = true;
35005
+ if (AUTH_QUALIFIER_TOKENS.has(token)) hasQualifier = true;
35006
+ if (AUTH_STRONG_NOUN_TOKENS.has(token)) hasStrongNoun = true;
35007
+ if (AUTH_WEAK_NOUN_TOKENS.has(token)) hasWeakNoun = true;
35008
+ }
35009
+ if (hasAssertiveVerb && (hasStrongNoun || hasWeakNoun)) return true;
35010
+ if (hasGetterVerb && hasStrongNoun) return true;
35011
+ if (hasQualifier && hasWeakNoun) return true;
35012
+ return false;
35013
+ };
35014
+ //#endregion
34898
35015
  //#region src/plugin/rules/server/server-auth-actions.ts
34899
35016
  const isAsyncFunctionLikeNode = (node) => {
34900
35017
  if (!node) return false;
@@ -34937,9 +35054,13 @@ const isMemberCallAuthRelated = (receiverNode, methodName, genericMethodNames) =
34937
35054
  const getAuthCallName = (callExpression, allowedFunctionNames, genericMethodNames) => {
34938
35055
  const calleeNode = unwrapTypeWrappedCallee(callExpression.callee);
34939
35056
  if (!calleeNode) return null;
34940
- if (isNodeOfType(calleeNode, "Identifier")) return allowedFunctionNames.has(calleeNode.name) ? calleeNode.name : null;
35057
+ if (isNodeOfType(calleeNode, "Identifier")) {
35058
+ const calleeName = calleeNode.name;
35059
+ return allowedFunctionNames.has(calleeName) || isAuthGuardName(calleeName) ? calleeName : null;
35060
+ }
34941
35061
  if (isNodeOfType(calleeNode, "MemberExpression") && isNodeOfType(calleeNode.property, "Identifier")) {
34942
35062
  const methodName = calleeNode.property.name;
35063
+ if (isAuthGuardName(methodName)) return methodName;
34943
35064
  if (!allowedFunctionNames.has(methodName)) return null;
34944
35065
  if (!isMemberCallAuthRelated(calleeNode.object, methodName, genericMethodNames)) return null;
34945
35066
  return methodName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.5.6-dev.8908f98",
3
+ "version": "0.5.6-dev.b08ca1c",
4
4
  "description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -44,7 +44,7 @@
44
44
  "@typescript-eslint/types": "^8.59.3",
45
45
  "eslint-scope": "^9.1.2",
46
46
  "eslint-visitor-keys": "^5.0.1",
47
- "oxc-parser": "^0.132.0"
47
+ "oxc-parser": "^0.135.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^25.6.0"