/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var resource_exports = {};
__export(resource_exports, {
  collectAstFlowResourceAliasesFromAst: () => collectAstFlowResourceAliasesFromAst,
  collectAstInvalidFlowResourceMethodCall: () => collectAstInvalidFlowResourceMethodCall,
  collectAstInvalidResourceActionCalls: () => collectAstInvalidResourceActionCalls,
  collectAstInvalidResourceTypeCall: () => collectAstInvalidResourceTypeCall,
  collectAstSharedCtxResourceCallsInFunctions: () => collectAstSharedCtxResourceCallsInFunctions,
  collectPossibleAstFlowResourceSourcesFromAst: () => collectPossibleAstFlowResourceSourcesFromAst,
  getAstFlowResourceFactoryCallFromAst: () => getAstFlowResourceFactoryCallFromAst,
  getDirectAstFlowResourceSourceFromAst: () => getDirectAstFlowResourceSourceFromAst,
  getMaybeAstFlowResourceSourceFromAst: () => getMaybeAstFlowResourceSourceFromAst,
  getRunJsDefaultDataSourceKey: () => getRunJsDefaultDataSourceKey,
  isAstCtxResourceMember: () => isAstCtxResourceMember
});
module.exports = __toCommonJS(resource_exports);
var _ = __toESM(require("lodash"));
var import_service_helpers = require("../../service-helpers");
var import_constants = require("../runtime/constants");
var import_surface = require("../runtime/surface");
var import_source = require("../ast/source");
var import_walk = require("../ast/walk");
var import_bindings = require("../ast/bindings");
var import_execution = require("../ast/execution");
var import_static_values = require("../ast/static-values");
var import_request_config = require("../ast/request-config");
var import_ctx_api = require("./ctx-api");
function collectAstInvalidResourceTypeCall(node, method, capability, source, stringBindings, identifierBindings) {
  var _a;
  const firstArg = (_a = node.arguments) == null ? void 0 : _a[0];
  if (!firstArg) {
    return [
      {
        capability,
        expression: "",
        index: node.start || 0,
        ruleId: "runjs-make-resource-type-unresolved"
      }
    ];
  }
  const resolved = (0, import_static_values.resolveAstResourceTypeExpression)(firstArg, source, stringBindings, identifierBindings);
  if (resolved.status === "unresolved") {
    return [
      {
        capability,
        expression: resolved.expression,
        index: node.start || 0,
        ruleId: "runjs-make-resource-type-unresolved"
      }
    ];
  }
  const allowedResourceTypes = method === "initResource" ? import_constants.INIT_RESOURCE_CLASS_NAMES : import_constants.FLOW_RESOURCE_CLASS_NAMES;
  if (!allowedResourceTypes.has(resolved.value)) {
    return [
      {
        capability,
        expression: source.slice(firstArg.start || 0, firstArg.end || firstArg.start || 0).trim(),
        index: node.start || 0,
        resourceType: resolved.value,
        ruleId: "runjs-make-resource-type-invalid"
      }
    ];
  }
  return [];
}
function collectAstFlowResourceAliasesFromAst(ast, source, ctxMethodAliases, stringBindings, identifierBindings) {
  const aliases = [];
  const writes = (0, import_execution.collectAstIdentifierWritesFromAst)(ast, source);
  const getActiveAliases = () => (0, import_static_values.trimAstAliasesAfterWrites)(aliases, writes, identifierBindings);
  const addAlias = (name, resource, node, ancestors, isVar = false) => {
    const scope = (0, import_bindings.getAstBindingScopeRange)(ancestors, source.length, isVar);
    aliases.push({
      capability: resource.capability,
      declarationStart: typeof (node == null ? void 0 : node.start) === "number" ? node.start : scope.start,
      executionScope: (0, import_bindings.getAstExecutionScopeRange)(ancestors, source.length),
      name,
      resourceType: resource.resourceType,
      start: typeof (node == null ? void 0 : node.start) === "number" ? node.start : scope.start,
      end: scope.end
    });
  };
  const collectCtxResourcePatternAliases = (pattern, ctxNode, ancestors, isVar = false) => {
    if (!(0, import_static_values.isUnshadowedCtxIdentifier)(ctxNode, identifierBindings)) {
      return;
    }
    (0, import_static_values.collectAstObjectPatternAliases)(pattern, (name, member, aliasNode) => {
      if (member === "resource") {
        addAlias(
          name,
          {
            capability: "ctx.resource",
            index: typeof (ctxNode == null ? void 0 : ctxNode.start) === "number" ? ctxNode.start : 0,
            resourceType: "unknown"
          },
          aliasNode || pattern,
          ancestors,
          isVar
        );
      }
    });
  };
  (0, import_walk.walkAstAncestor)(ast, {
    AssignmentExpression(node, ancestors) {
      var _a, _b;
      if ((0, import_static_values.isAstCtxApiAliasAssignmentOperator)(node.operator) && ((_a = node.left) == null ? void 0 : _a.type) === "Identifier") {
        const resource = getMaybeAstFlowResourceSourceFromAst(
          node.right,
          getActiveAliases(),
          source,
          identifierBindings,
          ctxMethodAliases,
          stringBindings
        );
        if (resource) {
          addAlias(node.left.name, resource, node, ancestors);
        }
        return;
      }
      if (node.operator === "=" && ((_b = node.left) == null ? void 0 : _b.type) === "ObjectPattern") {
        collectCtxResourcePatternAliases(node.left, node.right, ancestors);
      }
    },
    VariableDeclarator(node, ancestors) {
      var _a, _b;
      const declaration = (0, import_bindings.findAstAncestor)(ancestors, "VariableDeclaration");
      const isVar = (declaration == null ? void 0 : declaration.kind) === "var";
      if (((_a = node.id) == null ? void 0 : _a.type) === "Identifier") {
        const resource = getMaybeAstFlowResourceSourceFromAst(
          node.init,
          getActiveAliases(),
          source,
          identifierBindings,
          ctxMethodAliases,
          stringBindings
        );
        if (resource) {
          addAlias(node.id.name, resource, node, ancestors, isVar);
        }
        return;
      }
      if (((_b = node.id) == null ? void 0 : _b.type) === "ObjectPattern") {
        collectCtxResourcePatternAliases(node.id, node.init, ancestors, isVar);
      }
    }
  });
  return (0, import_static_values.trimAstAliasesAfterWrites)(aliases, writes, identifierBindings);
}
function collectAstInvalidFlowResourceMethodCall(node, aliases, source, identifierBindings, ctxMethodAliases, stringBindings) {
  var _a;
  const callee = (0, import_bindings.unwrapAstChainExpression)(node.callee);
  if (!callee || callee.type !== "MemberExpression") {
    return { invalidListCalls: [], invalidMethodCalls: [] };
  }
  const method = (0, import_static_values.getAstStaticPropertyName)(callee);
  if (!method) {
    return { invalidListCalls: [], invalidMethodCalls: [] };
  }
  const resource = getMaybeAstFlowResourceSourceFromAst(
    callee.object,
    aliases,
    source,
    identifierBindings,
    ctxMethodAliases,
    stringBindings
  );
  if (!resource) {
    return { invalidListCalls: [], invalidMethodCalls: [] };
  }
  const capability = (0, import_source.getAstSource)(callee, source);
  if (method === "list") {
    return {
      invalidListCalls: [
        {
          capability,
          index: typeof callee.start === "number" ? callee.start : node.start || 0
        }
      ],
      invalidMethodCalls: []
    };
  }
  if (getFlowResourceAllowedMethods(resource.resourceType).has(method)) {
    return { invalidListCalls: [], invalidMethodCalls: [] };
  }
  return {
    invalidListCalls: [],
    invalidMethodCalls: [
      {
        capability,
        index: typeof ((_a = callee.property) == null ? void 0 : _a.start) === "number" ? callee.property.start : typeof callee.start === "number" ? callee.start : node.start || 0,
        method,
        resourceType: resource.resourceType,
        suggestedMethod: getSuggestedFlowResourceMethod(method)
      }
    ]
  };
}
function collectAstInvalidResourceActionCalls(ast, source, aliases, identifierBindings, ctxMethodAliases, ctxApiAliases, ctxApiResourceAliases, stringBindings, staticFilterValueBindings, context) {
  const entries = [];
  const ctxResourceStates = /* @__PURE__ */ new Map();
  const aliasStates = /* @__PURE__ */ new Map();
  const events = [];
  const actionAliases = [];
  const writes = (0, import_execution.collectAstIdentifierWritesFromAst)(ast, source);
  const scopeKey = (scope) => `${scope.start}:${scope.end}`;
  const aliasKey = (alias) => `${alias.name}:${alias.declarationStart ?? alias.start}`;
  const defaultDataSourceKey = getRunJsDefaultDataSourceKey(context);
  const defaultCtxState = () => ({
    capability: "ctx.resource",
    collectionName: (0, import_surface.normalizeText)(context.currentCollectionName || context.hostCollectionName) || void 0,
    dataSourceKey: defaultDataSourceKey,
    resourceType: "unknown"
  });
  const mergeResourceState = (state, nextState) => {
    state.capability = nextState.capability;
    state.dataSourceKey = nextState.dataSourceKey;
    state.resourceType = nextState.resourceType;
    state.collectionName = nextState.collectionName;
    return state;
  };
  const getAliasState = (alias) => {
    const key = aliasKey(alias);
    const current = aliasStates.get(key);
    if (current) {
      return current;
    }
    const initial = alias.capability === "ctx.resource" ? {
      ...defaultCtxState(),
      resourceType: alias.resourceType === "unknown" ? defaultCtxState().resourceType : alias.resourceType
    } : {
      capability: alias.capability,
      dataSourceKey: defaultDataSourceKey,
      resourceType: alias.resourceType
    };
    aliasStates.set(key, initial);
    return initial;
  };
  const setAliasState = (alias, state) => {
    if (alias.resourceType !== "unknown") {
      state.resourceType = alias.resourceType;
    }
    aliasStates.set(aliasKey(alias), state);
    return state;
  };
  const setCtxState = (executionScope, state) => {
    const nextState = {
      ...state,
      capability: "ctx.resource"
    };
    ctxResourceStates.set(scopeKey(executionScope), {
      scope: executionScope,
      state: nextState
    });
    return nextState;
  };
  const getCtxState = (executionScope) => {
    var _a, _b;
    const exact = (_a = ctxResourceStates.get(scopeKey(executionScope))) == null ? void 0 : _a.state;
    if (exact) {
      return exact;
    }
    const inherited = (_b = Array.from(ctxResourceStates.values()).filter(({ scope }) => scope.start <= executionScope.start && scope.end >= executionScope.end).sort(
      (left, right) => left.scope.end - left.scope.start - (right.scope.end - right.scope.start) || right.scope.start - left.scope.start
    )[0]) == null ? void 0 : _b.state;
    if (inherited) {
      return inherited;
    }
    return setCtxState(executionScope, defaultCtxState());
  };
  const findDeclaredAlias = (aliasName, index) => aliases.filter((alias) => alias.name === aliasName && (alias.declarationStart ?? alias.start) <= index).sort((left, right) => (right.declarationStart ?? right.start) - (left.declarationStart ?? left.start))[0];
  const resolveStaticStringArg = (node) => {
    const resolved = (0, import_static_values.resolveAstResourceTypeExpression)(node, source, stringBindings, identifierBindings);
    return resolved.status === "resolved" ? resolved.value : void 0;
  };
  const applyStaticResourceStateMethod = (state, method, node) => {
    var _a, _b;
    if (method === "setDataSourceKey") {
      const dataSourceKey = resolveStaticStringArg((_a = node.arguments) == null ? void 0 : _a[0]);
      return {
        ...state,
        dataSourceKey: dataSourceKey || ""
      };
    }
    if (method === "setResourceName") {
      const collectionName = resolveStaticStringArg((_b = node.arguments) == null ? void 0 : _b[0]);
      return {
        ...state,
        collectionName
      };
    }
    return state;
  };
  const getAliasResourceTarget = (alias, executionScope) => ({
    capability: alias.capability,
    state: getAliasState(alias),
    updateState: (nextState) => {
      mergeResourceState(getAliasState(alias), nextState);
    }
  });
  const resolveResourceExpressionTarget = (node, executionScope) => {
    const unwrapped = (0, import_bindings.unwrapAstChainExpression)(node);
    if (!unwrapped) {
      return void 0;
    }
    if (isAstCtxResourceMember(unwrapped, identifierBindings)) {
      return {
        capability: "ctx.resource",
        state: getCtxState(executionScope),
        updateState: (nextState) => mergeResourceState(getCtxState(executionScope), nextState)
      };
    }
    if (unwrapped.type === "Identifier") {
      const alias = (0, import_static_values.resolveAstAliasBinding)(unwrapped.name, unwrapped.start || 0, aliases, identifierBindings);
      return alias ? getAliasResourceTarget(alias, executionScope) : void 0;
    }
    const factory = getAstFlowResourceFactoryCallFromAst(
      unwrapped,
      ctxMethodAliases,
      source,
      stringBindings,
      identifierBindings
    );
    if (factory) {
      return {
        capability: factory.capability,
        state: {
          capability: factory.capability,
          dataSourceKey: defaultDataSourceKey,
          resourceType: factory.resourceType
        },
        updateState: _.noop
      };
    }
    if (unwrapped.type === "CallExpression") {
      const callTarget = getResourceCallTarget(unwrapped, executionScope);
      if (!callTarget || !import_constants.RUNJS_RESOURCE_CHAINABLE_STATE_METHODS.has(callTarget.method)) {
        return void 0;
      }
      return {
        ...callTarget,
        state: applyStaticResourceStateMethod(callTarget.state, callTarget.method, unwrapped)
      };
    }
    return void 0;
  };
  const resolveExpressionState = (node, executionScope) => {
    var _a;
    return (_a = resolveResourceExpressionTarget(node, executionScope)) == null ? void 0 : _a.state;
  };
  const getResourceCallTarget = (node, executionScope) => {
    const callee = (0, import_bindings.unwrapAstChainExpression)(node.callee);
    if (!callee || callee.type !== "MemberExpression") {
      return void 0;
    }
    const method = (0, import_static_values.getAstStaticPropertyName)(callee);
    if (!method) {
      return void 0;
    }
    const objectTarget = resolveResourceExpressionTarget(callee.object, executionScope);
    if (objectTarget) {
      return {
        ...objectTarget,
        capability: (0, import_source.getAstSource)(callee, source),
        method
      };
    }
    return void 0;
  };
  const addInvalidAction = (input) => {
    const validation = validateRunJsCollectionResourceAction({
      actionName: input.actionName,
      collectionName: input.collectionName,
      dataSourceKey: input.dataSourceKey,
      context,
      resourceType: input.resourceType,
      strictCollectionEndpoint: input.strictCollectionEndpoint
    });
    if (!validation) {
      return;
    }
    entries.push({
      actionName: validation.actionName,
      allowedActions: validation.allowedActions,
      capability: input.capability,
      collectionName: input.collectionName,
      dataSourceKey: input.dataSourceKey,
      endpoint: input.endpoint,
      index: input.index,
      invalidReason: validation.invalidReason,
      resourceType: input.resourceType,
      suggestedMethod: input.actionName === "refresh" ? "refresh" : void 0
    });
  };
  const getActiveActionAliases = () => (0, import_static_values.trimAstAliasesAfterWrites)(actionAliases, writes, identifierBindings);
  const resolveApiResourceCollectionName = (resourceName, dataSourceKey) => resolveRunJsCollectionNameFromDottedResourceName(resourceName, context, dataSourceKey ?? defaultDataSourceKey) || resourceName;
  const getUniqueApiResourceCallSource = (node) => getUniqueApiResourceCallSourceFromCalls(
    (0, import_ctx_api.collectMaybeCtxApiResourceCallsFromAst)(node, ctxApiAliases, source, identifierBindings)
  );
  const getUniqueApiResourceCallSourceFromCalls = (resourceFactoryCalls) => {
    if (resourceFactoryCalls.length <= 1) {
      return resourceFactoryCalls[0];
    }
    const firstIdentity = getApiResourceCallSourceIdentity(resourceFactoryCalls[0]);
    if (!firstIdentity || resourceFactoryCalls.some((entry) => getApiResourceCallSourceIdentity(entry) !== firstIdentity)) {
      return void 0;
    }
    return resourceFactoryCalls[0];
  };
  const getApiResourceCallSourceIdentity = (resourceFactoryCall) => {
    var _a;
    const dataSourceKey = (0, import_request_config.getRunJsApiResourceCallDataSourceKey)(
      resourceFactoryCall.args,
      source,
      stringBindings,
      staticFilterValueBindings,
      identifierBindings
    );
    const resourceName = (0, import_static_values.resolveRunJsStaticString)(
      (_a = resourceFactoryCall.args) == null ? void 0 : _a[0],
      source,
      stringBindings,
      identifierBindings
    );
    const collectionName = resolveApiResourceCollectionName(resourceName, dataSourceKey);
    if (typeof collectionName !== "string" && typeof dataSourceKey !== "string") {
      return "";
    }
    return `${dataSourceKey ?? defaultDataSourceKey}:${collectionName ?? ""}`;
  };
  const addActionAlias = (name, actionSource, node, ancestors, isVar = false) => {
    if (!name) {
      return;
    }
    const scope = (0, import_bindings.getAstBindingScopeRange)(ancestors, source.length, isVar);
    actionAliases.push({
      ...actionSource,
      declarationStart: typeof (node == null ? void 0 : node.start) === "number" ? node.start : scope.start,
      executionScope: (0, import_bindings.getAstExecutionScopeRange)(ancestors, source.length),
      name,
      start: typeof (node == null ? void 0 : node.start) === "number" ? node.start : scope.start,
      end: scope.end
    });
  };
  const getApiResourceHandleSource = (node) => {
    var _a;
    const resourceFactoryCall = getUniqueApiResourceCallSource(node);
    if (resourceFactoryCall) {
      const dataSourceKey = (0, import_request_config.getRunJsApiResourceCallDataSourceKey)(
        resourceFactoryCall.args,
        source,
        stringBindings,
        staticFilterValueBindings,
        identifierBindings
      );
      const resourceName = (0, import_static_values.resolveRunJsStaticString)(
        (_a = resourceFactoryCall.args) == null ? void 0 : _a[0],
        source,
        stringBindings,
        identifierBindings
      );
      return {
        calleeSource: resourceFactoryCall.calleeSource,
        dataSourceKey,
        index: resourceFactoryCall.index,
        resourceName: resolveApiResourceCollectionName(resourceName, dataSourceKey)
      };
    }
    const handleAlias = (0, import_ctx_api.getMaybeCtxApiResourceHandleAliasFromAst)(
      node,
      ctxApiResourceAliases.handles,
      identifierBindings
    );
    return handleAlias ? {
      calleeSource: handleAlias.calleeSource,
      dataSourceKey: handleAlias.dataSourceKey,
      index: handleAlias.start,
      resourceName: resolveApiResourceCollectionName(handleAlias.resourceName, handleAlias.dataSourceKey)
    } : void 0;
  };
  const dedupeApiResourceActionSources = (sources) => {
    const seen = /* @__PURE__ */ new Set();
    return sources.filter((entry) => {
      const key = `${entry.actionName}:${entry.capability}:${entry.collectionName || ""}:${entry.dataSourceKey}`;
      if (seen.has(key)) {
        return false;
      }
      seen.add(key);
      return true;
    });
  };
  const getConsistentApiResourceActionSources = (sources) => {
    const dedupedSources = dedupeApiResourceActionSources(sources);
    if (dedupedSources.length <= 1) {
      return dedupedSources;
    }
    const firstIdentity = getApiResourceActionSourceIdentity(dedupedSources[0]);
    if (!firstIdentity || dedupedSources.some((entry) => getApiResourceActionSourceIdentity(entry) !== firstIdentity)) {
      return [];
    }
    return [dedupedSources[0]];
  };
  const getApiResourceActionSourceIdentity = (actionSource) => {
    if (!actionSource.actionName) {
      return "";
    }
    return `${actionSource.actionName}:${actionSource.collectionName ?? ""}:${actionSource.dataSourceKey ?? ""}`;
  };
  const resolveApiResourceActionAliasSources = (name, index) => {
    var _a;
    const candidates = getActiveActionAliases().filter(
      (entry) => entry.name === name && index >= entry.start && index < entry.end && !(0, import_static_values.hasAstShadowBinding)(name, index, entry, identifierBindings)
    ).sort((left, right) => right.start - left.start);
    const latestStart = (_a = candidates[0]) == null ? void 0 : _a.start;
    return candidates.filter((entry) => entry.start === latestStart).map((alias) => ({
      actionName: alias.actionName,
      capability: alias.capability,
      collectionName: alias.collectionName,
      dataSourceKey: alias.dataSourceKey
    }));
  };
  const getApiResourceActionSourcesFromAst = (node) => {
    const unwrapped = (0, import_bindings.unwrapAstChainExpression)(node);
    if (!unwrapped) {
      return [];
    }
    if (unwrapped.type === "Identifier") {
      return resolveApiResourceActionAliasSources(unwrapped.name, unwrapped.start || 0);
    }
    if (unwrapped.type === "MemberExpression") {
      const invocationMember = (0, import_static_values.getAstStaticPropertyName)(unwrapped);
      if (invocationMember === "call" || invocationMember === "apply" || invocationMember === "bind") {
        return getApiResourceActionSourcesFromAst(unwrapped.object).map((wrapped) => ({
          ...wrapped,
          capability: (0, import_source.getAstSource)(unwrapped, source) || wrapped.capability
        }));
      }
      const actionName = invocationMember;
      if (!actionName) {
        return [];
      }
      const handleSource = getApiResourceHandleSource(unwrapped.object);
      if (!handleSource) {
        return [];
      }
      return [
        {
          actionName,
          capability: handleSource.resourceName ? `${handleSource.calleeSource}('${handleSource.resourceName}').${actionName}` : `${handleSource.calleeSource}(...).${actionName}`,
          collectionName: handleSource.resourceName,
          dataSourceKey: handleSource.dataSourceKey ?? defaultDataSourceKey
        }
      ];
    }
    if (unwrapped.type === "ConditionalExpression") {
      return getConsistentApiResourceActionSources([
        ...getApiResourceActionSourcesFromAst(unwrapped.consequent),
        ...getApiResourceActionSourcesFromAst(unwrapped.alternate)
      ]);
    }
    if (unwrapped.type === "LogicalExpression") {
      const leftSources = getApiResourceActionSourcesFromAst(unwrapped.left);
      return getConsistentApiResourceActionSources([
        ...leftSources,
        ...getApiResourceActionSourcesFromAst(unwrapped.right)
      ]);
    }
    if (unwrapped.type === "SequenceExpression") {
      const expressions = unwrapped.expressions || [];
      return getApiResourceActionSourcesFromAst(expressions[expressions.length - 1]);
    }
    if (unwrapped.type === "AssignmentExpression" && (0, import_static_values.isAstCtxApiAliasAssignmentOperator)(unwrapped.operator)) {
      return getApiResourceActionSourcesFromAst(unwrapped.right);
    }
    return [];
  };
  const getRunJsStaticRequestResourceActionFromAst = (node, dataSourceKey) => {
    const objectArg = (0, import_request_config.getRunJsStaticRequestConfigObjectFromAst)(node, identifierBindings, staticFilterValueBindings);
    if (!objectArg) {
      return void 0;
    }
    const resourceProperty = (0, import_static_values.getRunJsObjectProperty)(
      objectArg,
      ["collection", "collectionName", "resource"],
      identifierBindings,
      staticFilterValueBindings
    );
    const actionProperty = (0, import_static_values.getRunJsObjectProperty)(objectArg, ["action"], identifierBindings, staticFilterValueBindings);
    const actionName = (0, import_static_values.resolveRunJsStaticString)(actionProperty == null ? void 0 : actionProperty.value, source, stringBindings, identifierBindings);
    if (!actionName) {
      return void 0;
    }
    const resourceName = (0, import_static_values.resolveRunJsStaticString)(resourceProperty == null ? void 0 : resourceProperty.value, source, stringBindings, identifierBindings);
    return {
      actionName,
      collectionName: resolveRunJsCollectionNameFromDottedResourceName(resourceName, context, dataSourceKey) || resourceName
    };
  };
  const collectApiResourceActionPatternAliases = (pattern, handleNode, ancestors, isVar = false) => {
    const handleSource = getApiResourceHandleSource(handleNode);
    if (!handleSource) {
      return;
    }
    (0, import_static_values.collectAstObjectPatternAliases)(pattern, (name, actionName, aliasNode) => {
      addActionAlias(
        name,
        {
          actionName,
          capability: handleSource.resourceName ? `${handleSource.calleeSource}('${handleSource.resourceName}').${actionName}` : `${handleSource.calleeSource}(...).${actionName}`,
          collectionName: handleSource.resourceName,
          dataSourceKey: handleSource.dataSourceKey ?? defaultDataSourceKey
        },
        aliasNode || pattern,
        ancestors,
        isVar
      );
    });
  };
  const collectApiResourceActions = (node) => {
    var _a, _b, _c;
    const resourceFactoryCall = (0, import_ctx_api.getCtxApiResourceCallFromAst)(node, ctxApiAliases, source, identifierBindings);
    if (resourceFactoryCall) {
      const rawResourceName = (0, import_static_values.resolveRunJsStaticString)((_a = node.arguments) == null ? void 0 : _a[0], source, stringBindings, identifierBindings);
      const actionName2 = resolveStaticStringArg((_b = node.arguments) == null ? void 0 : _b[1]);
      const dataSourceKey = (0, import_request_config.getRunJsApiResourceCallDataSourceKey)(
        resourceFactoryCall.args,
        source,
        stringBindings,
        staticFilterValueBindings,
        identifierBindings
      ) ?? defaultDataSourceKey;
      const resourceName = resolveApiResourceCollectionName(rawResourceName, dataSourceKey);
      addInvalidAction({
        actionName: actionName2,
        capability: resourceName ? `${resourceFactoryCall.calleeSource}('${resourceName}', '${actionName2 || ""}')` : `${resourceFactoryCall.calleeSource}(..., '${actionName2 || ""}')`,
        collectionName: resourceName,
        dataSourceKey,
        index: resourceFactoryCall.index
      });
    }
    const callee = (0, import_bindings.unwrapAstChainExpression)(node.callee);
    if (!callee || callee.type !== "MemberExpression") {
      return;
    }
    const actionName = (0, import_static_values.getAstStaticPropertyName)(callee);
    if (!actionName) {
      return;
    }
    const resourceFactory = getUniqueApiResourceCallSource(callee.object);
    if (resourceFactory) {
      const rawResourceName = (0, import_static_values.resolveRunJsStaticString)(
        (_c = resourceFactory.args) == null ? void 0 : _c[0],
        source,
        stringBindings,
        identifierBindings
      );
      const dataSourceKey = (0, import_request_config.getRunJsApiResourceCallDataSourceKey)(
        resourceFactory.args,
        source,
        stringBindings,
        staticFilterValueBindings,
        identifierBindings
      ) ?? defaultDataSourceKey;
      const resourceName = resolveApiResourceCollectionName(rawResourceName, dataSourceKey);
      addInvalidAction({
        actionName,
        capability: resourceName ? `${resourceFactory.calleeSource}('${resourceName}').${actionName}` : `${resourceFactory.calleeSource}(...).${actionName}`,
        collectionName: resourceName,
        dataSourceKey,
        index: resourceFactory.index
      });
      return;
    }
    const resourceHandleAlias = (0, import_ctx_api.getMaybeCtxApiResourceHandleAliasFromAst)(
      callee.object,
      ctxApiResourceAliases.handles,
      identifierBindings
    );
    if (resourceHandleAlias) {
      const dataSourceKey = resourceHandleAlias.dataSourceKey ?? defaultDataSourceKey;
      const collectionName = resolveApiResourceCollectionName(resourceHandleAlias.resourceName, dataSourceKey);
      addInvalidAction({
        actionName,
        capability: (0, import_source.getAstSource)(callee, source),
        collectionName,
        dataSourceKey,
        index: typeof callee.start === "number" ? callee.start : node.start || 0
      });
    }
  };
  const collectRequestEndpointAction = (node) => {
    const requestCapability = getRunJsCtxRequestCallCapabilityFromAst(
      node,
      ctxMethodAliases,
      ctxApiAliases,
      identifierBindings,
      source
    );
    if (!requestCapability) {
      return;
    }
    const dataSourceKey = (0, import_request_config.getRunJsStaticRequestDataSourceKeyFromAst)(
      node,
      source,
      stringBindings,
      staticFilterValueBindings,
      identifierBindings
    ) ?? defaultDataSourceKey;
    const endpoint = getRunJsStaticRequestEndpointFromAst(
      node,
      source,
      stringBindings,
      staticFilterValueBindings,
      identifierBindings
    );
    if (endpoint) {
      const parsed = parseRunJsResourceEndpoint(endpoint, context, dataSourceKey);
      if (parsed) {
        addInvalidAction({
          actionName: parsed.actionName,
          capability: requestCapability,
          collectionName: parsed.collectionName,
          dataSourceKey,
          endpoint: parsed.endpoint,
          index: node.start || 0,
          strictCollectionEndpoint: parsed.explicitCollectionPrefix
        });
      }
    }
    const requestResourceAction = getRunJsStaticRequestResourceActionFromAst(node, dataSourceKey);
    if (!requestResourceAction) {
      return;
    }
    addInvalidAction({
      actionName: requestResourceAction.actionName,
      capability: requestCapability,
      collectionName: requestResourceAction.collectionName,
      dataSourceKey,
      index: node.start || 0
    });
  };
  const collectRunjsEndpointAction = (node, method) => {
    var _a;
    if (method.method !== "runjs") {
      return;
    }
    const endpoint = resolveStaticStringArg((_a = node.arguments) == null ? void 0 : _a[0]);
    if (!endpoint) {
      return;
    }
    const parsed = parseRunJsResourceEndpoint(endpoint, context, defaultDataSourceKey);
    if (!parsed) {
      return;
    }
    addInvalidAction({
      actionName: parsed.actionName,
      capability: method.capability,
      collectionName: parsed.collectionName,
      dataSourceKey: defaultDataSourceKey,
      endpoint: parsed.endpoint,
      index: node.start || 0,
      strictCollectionEndpoint: parsed.explicitCollectionPrefix
    });
  };
  (0, import_walk.walkAstAncestor)(ast, {
    AssignmentExpression(node, ancestors) {
      var _a, _b, _c, _d;
      if (!(0, import_static_values.isAstCtxApiAliasAssignmentOperator)(node.operator)) {
        return;
      }
      if (((_a = node.left) == null ? void 0 : _a.type) === "Identifier") {
        getApiResourceActionSourcesFromAst(node.right).forEach(
          (actionSource) => addActionAlias(node.left.name, actionSource, node, ancestors)
        );
      }
      if (node.operator === "=" && ((_b = node.left) == null ? void 0 : _b.type) === "ObjectPattern") {
        collectApiResourceActionPatternAliases(node.left, node.right, ancestors);
      }
      const alwaysRuns = (0, import_bindings.isAstAlwaysExecutedInCurrentExecutionScope)(ancestors);
      const executionScope = (0, import_bindings.getAstExecutionScopeRange)(ancestors, source.length);
      if (((_c = node.left) == null ? void 0 : _c.type) === "Identifier") {
        events.push({
          type: "aliasBind",
          aliasName: node.left.name,
          alwaysRuns,
          end: typeof node.end === "number" ? node.end : node.start || 0,
          executionScope,
          index: node.start || 0,
          sourceNode: node.right
        });
        return;
      }
      if (((_d = node.left) == null ? void 0 : _d.type) === "ObjectPattern" && (0, import_static_values.isUnshadowedCtxIdentifier)(node.right, identifierBindings)) {
        (0, import_static_values.collectAstObjectPatternAliases)(node.left, (aliasName, member, aliasNode) => {
          if (member !== "resource") {
            return;
          }
          events.push({
            type: "ctxResourceAliasBind",
            aliasName,
            alwaysRuns,
            end: typeof (aliasNode == null ? void 0 : aliasNode.end) === "number" ? aliasNode.end : node.end || node.start || 0,
            executionScope,
            index: typeof (aliasNode == null ? void 0 : aliasNode.start) === "number" ? aliasNode.start : node.start || 0
          });
        });
      }
    },
    CallExpression(node, ancestors) {
      var _a;
      const executionScope = (0, import_bindings.getAstExecutionScopeRange)(ancestors, source.length);
      const alwaysRuns = (0, import_bindings.isAstAlwaysExecutedInCurrentExecutionScope)(ancestors);
      const ctxMethod = (0, import_static_values.resolveCtxMethodCall)(node, ctxMethodAliases, identifierBindings);
      if (ctxMethod) {
        if (ctxMethod.method === "initResource") {
          const resolved = ((_a = node.arguments) == null ? void 0 : _a[0]) ? (0, import_static_values.resolveAstResourceTypeExpression)(node.arguments[0], source, stringBindings, identifierBindings) : void 0;
          events.push({
            type: "initResource",
            alwaysRuns,
            end: typeof node.end === "number" ? node.end : node.start || 0,
            executionScope,
            index: node.start || 0,
            resourceType: (resolved == null ? void 0 : resolved.status) === "resolved" && import_constants.INIT_RESOURCE_CLASS_NAMES.has(resolved.value) ? resolved.value : "unknown"
          });
        }
        collectRunjsEndpointAction(node, ctxMethod);
      }
      getApiResourceActionSourcesFromAst(node.callee).forEach((apiResourceAction) => {
        addInvalidAction({
          actionName: apiResourceAction.actionName,
          capability: apiResourceAction.capability,
          collectionName: apiResourceAction.collectionName,
          dataSourceKey: apiResourceAction.dataSourceKey,
          index: node.start || 0
        });
      });
      collectApiResourceActions(node);
      collectRequestEndpointAction(node);
      if (!getResourceCallTarget(node, executionScope)) {
        return;
      }
      events.push({
        type: "resourceCall",
        alwaysRuns,
        end: typeof node.end === "number" ? node.end : node.start || 0,
        executionScope,
        index: node.start || 0,
        node
      });
    },
    VariableDeclarator(node, ancestors) {
      var _a, _b, _c;
      const alwaysRuns = (0, import_bindings.isAstAlwaysExecutedInCurrentExecutionScope)(ancestors);
      const executionScope = (0, import_bindings.getAstExecutionScopeRange)(ancestors, source.length);
      if (((_a = node.id) == null ? void 0 : _a.type) === "Identifier") {
        const actionSources = getApiResourceActionSourcesFromAst(node.init);
        if (actionSources.length) {
          const declaration = (0, import_bindings.findAstAncestor)(ancestors, "VariableDeclaration");
          actionSources.forEach(
            (actionSource) => addActionAlias(node.id.name, actionSource, node, ancestors, (declaration == null ? void 0 : declaration.kind) === "var")
          );
        }
        events.push({
          type: "aliasBind",
          aliasName: node.id.name,
          alwaysRuns,
          end: typeof node.end === "number" ? node.end : node.start || 0,
          executionScope,
          index: node.start || 0,
          sourceNode: node.init
        });
        return;
      }
      if (((_b = node.id) == null ? void 0 : _b.type) === "ObjectPattern" && (0, import_static_values.isUnshadowedCtxIdentifier)(node.init, identifierBindings)) {
        (0, import_static_values.collectAstObjectPatternAliases)(node.id, (aliasName, member, aliasNode) => {
          if (member !== "resource") {
            return;
          }
          events.push({
            type: "ctxResourceAliasBind",
            aliasName,
            alwaysRuns,
            end: typeof (aliasNode == null ? void 0 : aliasNode.end) === "number" ? aliasNode.end : node.end || node.start || 0,
            executionScope,
            index: typeof (aliasNode == null ? void 0 : aliasNode.start) === "number" ? aliasNode.start : node.start || 0
          });
        });
      }
      if (((_c = node.id) == null ? void 0 : _c.type) === "ObjectPattern") {
        const declaration = (0, import_bindings.findAstAncestor)(ancestors, "VariableDeclaration");
        collectApiResourceActionPatternAliases(node.id, node.init, ancestors, (declaration == null ? void 0 : declaration.kind) === "var");
      }
    }
  });
  ctxResourceStates.clear();
  aliasStates.clear();
  const actionScopes = Array.from(
    new Map(events.map((event) => [scopeKey(event.executionScope), event.executionScope])).values()
  );
  const actionScopeDepth = (scope) => actionScopes.filter(
    (candidate) => candidate.start < scope.start && candidate.end >= scope.end && !(0, import_bindings.isSameAstRange)(candidate, scope)
  ).length;
  events.sort(
    (left, right) => actionScopeDepth(left.executionScope) - actionScopeDepth(right.executionScope) || left.executionScope.start - right.executionScope.start || left.index - right.index || left.end - right.end
  ).forEach((event) => {
    var _a, _b, _c, _d, _e;
    if (event.type === "initResource") {
      if (!event.alwaysRuns) {
        return;
      }
      setCtxState(event.executionScope, {
        capability: "ctx.resource",
        dataSourceKey: defaultDataSourceKey,
        resourceType: event.resourceType
      });
      return;
    }
    if (event.type === "aliasBind") {
      if (!event.alwaysRuns) {
        return;
      }
      const alias = findDeclaredAlias(event.aliasName, event.index);
      const state = resolveExpressionState(event.sourceNode, event.executionScope);
      if (alias && state) {
        setAliasState(alias, state);
      }
      return;
    }
    if (event.type === "ctxResourceAliasBind") {
      if (!event.alwaysRuns) {
        return;
      }
      const alias = findDeclaredAlias(event.aliasName, event.index);
      if (alias) {
        setAliasState(alias, getCtxState(event.executionScope));
      }
      return;
    }
    const target = getResourceCallTarget(event.node, event.executionScope);
    if (!target) {
      return;
    }
    if (target.method === "setDataSourceKey" || target.method === "setResourceName") {
      if (!event.alwaysRuns) {
        return;
      }
      target.updateState(applyStaticResourceStateMethod(target.state, target.method, event.node));
      return;
    }
    if (target.method !== "runAction" && target.method !== "setRefreshAction") {
      return;
    }
    const actionName = resolveStaticStringArg((_a = event.node.arguments) == null ? void 0 : _a[0]);
    addInvalidAction({
      actionName,
      capability: target.capability,
      collectionName: target.state.collectionName,
      dataSourceKey: target.state.dataSourceKey,
      index: typeof ((_c = (_b = event.node.arguments) == null ? void 0 : _b[0]) == null ? void 0 : _c.start) === "number" ? event.node.arguments[0].start : typeof ((_e = (_d = event.node.callee) == null ? void 0 : _d.property) == null ? void 0 : _e.start) === "number" ? event.node.callee.property.start : event.index,
      resourceType: target.state.resourceType,
      strictCollectionEndpoint: true
    });
  });
  return entries;
}
function validateRunJsCollectionResourceAction(input) {
  const actionName = (0, import_surface.normalizeText)(input.actionName);
  if (!actionName || input.resourceType === "SQLResource") {
    return void 0;
  }
  const hasUnknownDataSource = input.dataSourceKey === "";
  const actionPolicy = getRunJsCollectionActionPolicy(
    input.context,
    hasUnknownDataSource ? void 0 : input.dataSourceKey || getRunJsDefaultDataSourceKey(input.context),
    input.collectionName
  );
  if (!actionPolicy.collectionResolved && !input.strictCollectionEndpoint && !hasUnknownDataSource) {
    return void 0;
  }
  if (!import_constants.RUNJS_COLLECTION_RESOURCE_ACTIONS.has(actionName)) {
    return {
      actionName,
      allowedActions: actionPolicy.allowedActions,
      invalidReason: actionName === "refresh" ? "refresh-is-flow-resource-method" : "unknown-collection-action"
    };
  }
  if (!hasUnknownDataSource && !actionPolicy.allowedActionSet.has(actionName)) {
    return {
      actionName,
      allowedActions: actionPolicy.allowedActions,
      invalidReason: "collection-action-unavailable"
    };
  }
  return void 0;
}
function getRunJsDefaultDataSourceKey(context) {
  return (0, import_surface.normalizeText)(context.currentDataSourceKey || context.hostDataSourceKey) || "main";
}
function getRunJsCollectionActionPolicy(context, dataSourceKey, collectionName) {
  let collection;
  if (context.getCollection && collectionName && dataSourceKey) {
    collection = context.getCollection(dataSourceKey || getRunJsDefaultDataSourceKey(context), collectionName);
  }
  const availableActions = getRunJsCollectionActionOptionList(collection, "availableActions");
  const unavailableActions = getRunJsCollectionActionOptionList(collection, "unavailableActions");
  const allowedActionSet = new Set(import_constants.RUNJS_COLLECTION_RESOURCE_ACTIONS);
  if (availableActions == null ? void 0 : availableActions.length) {
    [...allowedActionSet].forEach((actionName) => {
      if (!availableActions.some(
        (capabilityName) => isRunJsCollectionActionCoveredByCapability(actionName, capabilityName)
      )) {
        allowedActionSet.delete(actionName);
      }
    });
  }
  if (unavailableActions == null ? void 0 : unavailableActions.length) {
    [...allowedActionSet].forEach((actionName) => {
      if (unavailableActions.some(
        (capabilityName) => isRunJsCollectionActionCoveredByCapability(actionName, capabilityName)
      )) {
        allowedActionSet.delete(actionName);
      }
    });
  }
  const allowedActions = [...allowedActionSet].sort((left, right) => left.localeCompare(right));
  return {
    allowedActionSet,
    allowedActions,
    collectionResolved: Boolean(collection)
  };
}
function getRunJsCollectionActionOptionList(collection, key) {
  var _a;
  const directValue = collection == null ? void 0 : collection[key];
  const optionsValue = (_a = collection == null ? void 0 : collection.options) == null ? void 0 : _a[key];
  const value = typeof directValue === "function" ? directValue.call(collection) : directValue || optionsValue;
  return Array.isArray(value) ? value.map((item) => (0, import_surface.normalizeText)(item)).filter(Boolean) : void 0;
}
function isRunJsCollectionActionCoveredByCapability(actionName, capabilityName) {
  var _a;
  if (actionName === capabilityName) {
    return true;
  }
  return ((_a = import_constants.RUNJS_COLLECTION_RESOURCE_ACTION_ALIASES.get(capabilityName)) == null ? void 0 : _a.includes(actionName)) || false;
}
function getRunJsCtxRequestCallCapabilityFromAst(node, ctxMethodAliases, ctxApiAliases, identifierBindings, source) {
  const ctxMethod = (0, import_static_values.resolveCtxMethodCall)(node, ctxMethodAliases, identifierBindings);
  if ((ctxMethod == null ? void 0 : ctxMethod.method) === "request") {
    return ctxMethod.capability;
  }
  const callee = (0, import_bindings.unwrapAstChainExpression)(node.callee);
  const capability = (0, import_ctx_api.getCtxApiCapabilityFromAst)(callee, ctxApiAliases, identifierBindings) || (0, import_ctx_api.getMaybeCtxApiCapabilityFromAst)(callee, ctxApiAliases, identifierBindings);
  return capability === "ctx.api.request" ? (0, import_source.getAstSource)(callee, source) || "ctx.api.request" : "";
}
function getRunJsStaticRequestEndpointFromAst(node, source, stringBindings, staticFilterValueBindings, identifierBindings) {
  var _a;
  const firstArg = (_a = node.arguments) == null ? void 0 : _a[0];
  const firstArgUrl = (0, import_static_values.resolveRunJsStaticString)(firstArg, source, stringBindings, identifierBindings);
  if (firstArgUrl) {
    return firstArgUrl;
  }
  const objectArg = (0, import_request_config.getRunJsStaticRequestConfigObjectFromAst)(node, identifierBindings, staticFilterValueBindings);
  if (!objectArg) {
    return "";
  }
  const urlProperty = (0, import_static_values.getRunJsObjectProperty)(objectArg, ["url"], identifierBindings, staticFilterValueBindings);
  return (0, import_static_values.resolveRunJsStaticString)(urlProperty == null ? void 0 : urlProperty.value, source, stringBindings, identifierBindings) || "";
}
function parseRunJsResourceEndpoint(value, context, dataSourceKey) {
  const endpoint = (0, import_surface.normalizeText)(value);
  if (!endpoint || /^(?:https?:)?\/\//i.test(endpoint)) {
    return void 0;
  }
  const resourceUrl = endpoint.replace(/^\/api\//i, "").replace(/^\//, "");
  const match = resourceUrl.match(new RegExp(`^(.+?):(${import_constants.RUNJS_RESOURCE_ENDPOINT_ACTION_PATTERN})(?:$|[/?#])`));
  if (!match) {
    return void 0;
  }
  const resourcePathSegments = (0, import_surface.normalizeText)(match[1]).split("/").filter(Boolean);
  const resourceName = (0, import_surface.normalizeText)(resourcePathSegments[resourcePathSegments.length - 1]);
  const actionName = (0, import_surface.normalizeText)(match[2]);
  const explicitCollectionPrefix = resourceName === "collection" || resourceName === "resource";
  const collectionName = explicitCollectionPrefix ? void 0 : resolveRunJsCollectionNameFromEndpointResourcePath(resourcePathSegments, context, dataSourceKey) || resourceName;
  return {
    actionName,
    collectionName,
    endpoint,
    explicitCollectionPrefix
  };
}
function resolveRunJsCollectionNameFromEndpointResourcePath(resourcePathSegments, context, dataSourceKey) {
  if (!context.getCollection || resourcePathSegments.length < 3) {
    return "";
  }
  const sourceCollectionName = (0, import_surface.normalizeText)(resourcePathSegments[0]);
  const associationFieldName = (0, import_surface.normalizeText)(resourcePathSegments[resourcePathSegments.length - 1]);
  if (!sourceCollectionName || !associationFieldName) {
    return "";
  }
  const sourceCollection = context.getCollection(
    dataSourceKey || getRunJsDefaultDataSourceKey(context),
    sourceCollectionName
  );
  const associationField = (0, import_service_helpers.resolveFieldFromCollection)(sourceCollection, associationFieldName);
  const targetCollection = associationField ? (0, import_service_helpers.resolveFieldTargetCollection)(
    associationField,
    dataSourceKey || getRunJsDefaultDataSourceKey(context),
    context.getCollection
  ) : null;
  return (0, import_surface.normalizeText)((0, import_service_helpers.getCollectionName)(targetCollection));
}
function resolveRunJsCollectionNameFromDottedResourceName(resourceName, context, dataSourceKey) {
  const parts = (0, import_surface.normalizeText)(resourceName).split(".").filter(Boolean);
  if (!context.getCollection || !dataSourceKey || parts.length < 2) {
    return "";
  }
  let currentDataSourceKey = dataSourceKey;
  let currentCollection = context.getCollection(currentDataSourceKey, parts[0]);
  for (let index = 1; index < parts.length; index += 1) {
    const associationFieldName = parts[index];
    if (!currentCollection || !associationFieldName) {
      return "";
    }
    const associationField = (0, import_service_helpers.resolveFieldFromCollection)(currentCollection, associationFieldName);
    const targetCollection = associationField ? (0, import_service_helpers.resolveFieldTargetCollection)(
      associationField,
      (currentCollection == null ? void 0 : currentCollection.dataSourceKey) || currentDataSourceKey,
      context.getCollection
    ) : null;
    if (!targetCollection) {
      return "";
    }
    currentCollection = targetCollection;
    currentDataSourceKey = (targetCollection == null ? void 0 : targetCollection.dataSourceKey) || currentDataSourceKey;
  }
  return (0, import_surface.normalizeText)((0, import_service_helpers.getCollectionName)(currentCollection));
}
function getMaybeAstFlowResourceSourceFromAst(node, aliases, source, identifierBindings, ctxMethodAliases, stringBindings) {
  return selectAstFlowResourceSource(
    collectPossibleAstFlowResourceSourcesFromAst(
      node,
      aliases,
      source,
      identifierBindings,
      ctxMethodAliases,
      stringBindings
    )
  );
}
function collectPossibleAstFlowResourceSourcesFromAst(node, aliases, source, identifierBindings, ctxMethodAliases, stringBindings) {
  const direct = getDirectAstFlowResourceSourceFromAst(
    node,
    aliases,
    source,
    identifierBindings,
    ctxMethodAliases,
    stringBindings
  );
  if (direct) {
    return [direct];
  }
  const unwrapped = (0, import_bindings.unwrapAstChainExpression)(node);
  if (!unwrapped) {
    return [];
  }
  if (unwrapped.type === "ConditionalExpression") {
    return [
      ...collectPossibleAstFlowResourceSourcesFromAst(
        unwrapped.consequent,
        aliases,
        source,
        identifierBindings,
        ctxMethodAliases,
        stringBindings
      ),
      ...collectPossibleAstFlowResourceSourcesFromAst(
        unwrapped.alternate,
        aliases,
        source,
        identifierBindings,
        ctxMethodAliases,
        stringBindings
      )
    ];
  }
  if (unwrapped.type === "LogicalExpression") {
    return [
      ...collectPossibleAstFlowResourceSourcesFromAst(
        unwrapped.left,
        aliases,
        source,
        identifierBindings,
        ctxMethodAliases,
        stringBindings
      ),
      ...collectPossibleAstFlowResourceSourcesFromAst(
        unwrapped.right,
        aliases,
        source,
        identifierBindings,
        ctxMethodAliases,
        stringBindings
      )
    ];
  }
  if (unwrapped.type === "SequenceExpression") {
    const expressions = unwrapped.expressions || [];
    return collectPossibleAstFlowResourceSourcesFromAst(
      expressions[expressions.length - 1],
      aliases,
      source,
      identifierBindings,
      ctxMethodAliases,
      stringBindings
    );
  }
  if (unwrapped.type === "AssignmentExpression" && (0, import_static_values.isAstCtxApiAliasAssignmentOperator)(unwrapped.operator)) {
    return collectPossibleAstFlowResourceSourcesFromAst(
      unwrapped.right,
      aliases,
      source,
      identifierBindings,
      ctxMethodAliases,
      stringBindings
    );
  }
  return [];
}
function getDirectAstFlowResourceSourceFromAst(node, aliases, source, identifierBindings, ctxMethodAliases, stringBindings) {
  const unwrapped = (0, import_bindings.unwrapAstChainExpression)(node);
  if (!unwrapped) {
    return void 0;
  }
  if (unwrapped.type === "Identifier") {
    const alias = (0, import_static_values.resolveAstAliasBinding)(unwrapped.name, unwrapped.start || 0, aliases, identifierBindings);
    return alias ? {
      capability: alias.capability,
      index: typeof unwrapped.start === "number" ? unwrapped.start : alias.start,
      resourceType: alias.resourceType
    } : void 0;
  }
  if (isAstCtxResourceMember(unwrapped, identifierBindings)) {
    return {
      capability: "ctx.resource",
      index: typeof unwrapped.start === "number" ? unwrapped.start : 0,
      resourceType: "unknown"
    };
  }
  return getAstFlowResourceFactoryCallFromAst(unwrapped, ctxMethodAliases, source, stringBindings, identifierBindings);
}
function getAstFlowResourceFactoryCallFromAst(node, ctxMethodAliases, source, stringBindings, identifierBindings) {
  var _a;
  const call = (0, import_bindings.unwrapAstChainExpression)(node);
  if (!call || call.type !== "CallExpression") {
    return void 0;
  }
  const method = (0, import_static_values.resolveCtxMethodCall)(call, ctxMethodAliases, identifierBindings);
  if (!method || method.method !== "makeResource" && method.method !== "initResource") {
    return void 0;
  }
  const firstArg = (_a = call.arguments) == null ? void 0 : _a[0];
  if (!firstArg) {
    return void 0;
  }
  const resolved = (0, import_static_values.resolveAstResourceTypeExpression)(firstArg, source, stringBindings, identifierBindings);
  if (resolved.status !== "resolved") {
    return void 0;
  }
  const allowedResourceTypes = method.method === "initResource" ? import_constants.INIT_RESOURCE_CLASS_NAMES : import_constants.FLOW_RESOURCE_CLASS_NAMES;
  if (!allowedResourceTypes.has(resolved.value) || !isKnownFlowResourceInstanceType(resolved.value)) {
    return void 0;
  }
  return {
    capability: method.capability,
    index: typeof call.start === "number" ? call.start : 0,
    resourceType: resolved.value
  };
}
function isAstCtxResourceMember(node, identifierBindings) {
  const member = (0, import_bindings.unwrapAstChainExpression)(node);
  return (member == null ? void 0 : member.type) === "MemberExpression" && (0, import_static_values.getAstStaticPropertyName)(member) === "resource" && (0, import_static_values.isUnshadowedCtxIdentifier)(member.object, identifierBindings);
}
function collectAstSharedCtxResourceCallsInFunctions(ast, source, ctxMethodAliases, identifierBindings) {
  const entries = [];
  const seen = /* @__PURE__ */ new Set();
  const addEntry = (capability, index, ancestors) => {
    const functionNode = getNearestAstFunctionAncestor(ancestors);
    if (!functionNode) {
      return;
    }
    const functionName = getAstFunctionDisplayName(functionNode, ancestors);
    const key = `${capability}:${functionNode.start || 0}:${functionNode.end || source.length}`;
    if (seen.has(key)) {
      return;
    }
    seen.add(key);
    entries.push({
      capability,
      functionName,
      index
    });
  };
  (0, import_walk.walkAstAncestor)(ast, {
    CallExpression(node, ancestors) {
      const method = (0, import_static_values.resolveCtxMethodCall)(node, ctxMethodAliases, identifierBindings);
      if ((method == null ? void 0 : method.method) === "initResource") {
        addEntry(method.capability, node.start || 0, ancestors);
      }
    },
    MemberExpression(node, ancestors) {
      if (isAstCtxResourceMember(node, identifierBindings)) {
        addEntry("ctx.resource", node.start || 0, ancestors);
      }
    }
  });
  return entries.sort((left, right) => left.index - right.index);
}
function getNearestAstFunctionAncestor(ancestors) {
  for (let index = ancestors.length - 1; index >= 0; index -= 1) {
    const ancestor = ancestors[index];
    if ((0, import_bindings.isAstFunctionLike)(ancestor)) {
      return ancestor;
    }
  }
  return void 0;
}
function getAstFunctionDisplayName(functionNode, ancestors) {
  var _a, _b;
  if (((_a = functionNode == null ? void 0 : functionNode.id) == null ? void 0 : _a.type) === "Identifier") {
    return functionNode.id.name;
  }
  const functionIndex = ancestors.findIndex((ancestor) => ancestor === functionNode);
  const parent = functionIndex >= 0 ? ancestors[functionIndex - 1] : void 0;
  if ((parent == null ? void 0 : parent.type) === "VariableDeclarator" && ((_b = parent.id) == null ? void 0 : _b.type) === "Identifier") {
    return parent.id.name;
  }
  if ((parent == null ? void 0 : parent.type) === "Property") {
    const key = (0, import_static_values.getAstStaticPropertyName)(parent);
    if (key) {
      return key;
    }
  }
  return void 0;
}
function selectAstFlowResourceSource(sources) {
  if (!sources.length) {
    return void 0;
  }
  const resourceTypes = [...new Set(sources.map((entry) => entry.resourceType))];
  if (resourceTypes.length === 1) {
    return sources[0];
  }
  return {
    capability: sources.map((entry) => entry.capability).join("|"),
    index: Math.min(...sources.map((entry) => entry.index)),
    resourceType: "unknown"
  };
}
function getFlowResourceAllowedMethods(resourceType) {
  if (!resourceType || resourceType === "unknown") {
    return import_constants.UNKNOWN_FLOW_RESOURCE_METHODS;
  }
  return import_constants.FLOW_RESOURCE_METHODS_BY_TYPE[resourceType] || import_constants.UNKNOWN_FLOW_RESOURCE_METHODS;
}
function getSuggestedFlowResourceMethod(method) {
  const exactSuggestion = import_constants.FLOW_RESOURCE_METHOD_SUGGESTIONS.get(method);
  if (exactSuggestion) {
    return exactSuggestion;
  }
  if (method.endsWith("s")) {
    const singular = method.slice(0, -1);
    if (import_constants.UNKNOWN_FLOW_RESOURCE_METHODS.has(singular)) {
      return singular;
    }
  }
  return void 0;
}
function isKnownFlowResourceInstanceType(value) {
  return value in import_constants.FLOW_RESOURCE_METHODS_BY_TYPE;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  collectAstFlowResourceAliasesFromAst,
  collectAstInvalidFlowResourceMethodCall,
  collectAstInvalidResourceActionCalls,
  collectAstInvalidResourceTypeCall,
  collectAstSharedCtxResourceCallsInFunctions,
  collectPossibleAstFlowResourceSourcesFromAst,
  getAstFlowResourceFactoryCallFromAst,
  getDirectAstFlowResourceSourceFromAst,
  getMaybeAstFlowResourceSourceFromAst,
  getRunJsDefaultDataSourceKey,
  isAstCtxResourceMember
});
