// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
/**
 * Helpers for interacting with Deno's permissions system.
 *
 * @deprecated Use the
 * {@link https://deno.land/api?s=Deno.Permissions | Deno Permissions API}
 * directly instead. This module will be removed once the Standard Library
 * migrates to {@link https://jsr.io/ | JSR}.
 *
 * @module
 */

const { PermissionDenied } = Deno.errors;

function getPermissionString(descriptors: Deno.PermissionDescriptor[]): string {
  return descriptors.length
    ? `  ${
      descriptors
        .map((pd) => {
          switch (pd.name) {
            case "read":
            case "write":
              return pd.path
                ? `--allow-${pd.name}=${pd.path}`
                : `--allow-${pd.name}`;
            case "net":
              return pd.host
                ? `--allow-${pd.name}=${pd.host}`
                : `--allow-${pd.name}`;
            default:
              return `--allow-${pd.name}`;
          }
        })
        .join("\n  ")
    }`
    : "";
}

/** Attempts to grant a set of permissions, resolving with the descriptors of
 * the permissions that are granted.
 *
 * ```ts
 *      import { grant } from "@std/permissions";
 *      const perms = await grant({ name: "net" }, { name: "read" });
 *      if (perms && perms.length === 2) {
 *        // do something cool that connects to the net and reads files
 *      } else {
 *        // notify user of missing permissions
 *      }
 * ```
 *
 * If one of the permissions requires a prompt, the function will attempt to
 * prompt for it.  The function resolves with all of the granted permissions.
 *
 * @deprecated Use the
 * {@link https://deno.land/api?s=Deno.Permissions | Deno Permissions API}
 * directly instead. This module will be removed once the Standard Library
 * migrates to {@link https://jsr.io/ | JSR}.
 */
export async function grant(
  ...descriptors: Deno.PermissionDescriptor[]
): Promise<void | Deno.PermissionDescriptor[]>;
/** Attempts to grant a set of permissions, resolving with the descriptors of
 * the permissions that are granted.
 *
 * ```ts
 *      import { grant } from "@std/permissions";
 *      const perms = await grant([{ name: "net" }, { name: "read" }]);
 *      if (perms && perms.length === 2) {
 *        // do something cool that connects to the net and reads files
 *      } else {
 *        // notify user of missing permissions
 *      }
 * ```
 *
 * If one of the permissions requires a prompt, the function will attempt to
 * prompt for it.  The function resolves with all of the granted permissions.
 *
 * @deprecated Use the
 * {@link https://deno.land/api?s=Deno.Permissions | Deno Permissions API}
 * directly instead. This module will be removed once the Standard Library
 * migrates to {@link https://jsr.io/ | JSR}.
 */
export async function grant(
  descriptors: Deno.PermissionDescriptor[],
): Promise<void | Deno.PermissionDescriptor[]>;
export async function grant(
  descriptor: Deno.PermissionDescriptor[] | Deno.PermissionDescriptor,
  ...descriptors: Deno.PermissionDescriptor[]
): Promise<void | Deno.PermissionDescriptor[]> {
  const result: Deno.PermissionDescriptor[] = [];
  descriptors = Array.isArray(descriptor)
    ? descriptor
    : [descriptor, ...descriptors];
  for (const descriptor of descriptors) {
    let state = (await Deno.permissions.query(descriptor)).state;
    if (state === "prompt") {
      state = (await Deno.permissions.request(descriptor)).state;
    }
    if (state === "granted") {
      result.push(descriptor);
    }
  }
  return result.length ? result : undefined;
}

/** Attempts to grant a set of permissions or rejects.
 *
 * ```ts
 *      import { grantOrThrow } from "@std/permissions";
 *      await grantOrThrow({ name: "env" }, { name: "net" });
 * ```
 *
 * If the permission can be prompted for, the function will attempt to prompt.
 * If any of the permissions are denied, the function will reject for the first
 * permission that is denied.  If all permissions are granted, the function
 * will resolve.
 *
 * @deprecated Use the
 * {@link https://deno.land/api?s=Deno.Permissions | Deno Permissions API}
 * directly instead. This module will be removed once the Standard Library
 * migrates to {@link https://jsr.io/ | JSR}.
 */
export async function grantOrThrow(
  ...descriptors: Deno.PermissionDescriptor[]
): Promise<void>;
/** Attempts to grant a set of permissions or rejects.
 *
 * ```ts
 *      import { grantOrThrow } from "@std/permissions";
 *      await grantOrThrow([{ name: "env" }, { name: "net" }]);
 * ```
 *
 * If the permission can be prompted for, the function will attempt to prompt.
 * If any of the permissions are denied, the function will reject mentioning the
 * the denied permissions.  If all permissions are granted, the function will
 * resolve.
 *
 * @deprecated Use the
 * {@link https://deno.land/api?s=Deno.Permissions | Deno Permissions API}
 * directly instead. This module will be removed once the Standard Library
 * migrates to {@link https://jsr.io/ | JSR}.
 */
export async function grantOrThrow(
  descriptors: Deno.PermissionDescriptor[],
): Promise<void>;
export async function grantOrThrow(
  descriptor: Deno.PermissionDescriptor[] | Deno.PermissionDescriptor,
  ...descriptors: Deno.PermissionDescriptor[]
) {
  const denied: Deno.PermissionDescriptor[] = [];
  descriptors = Array.isArray(descriptor)
    ? descriptor
    : [descriptor, ...descriptors];
  for (const descriptor of descriptors) {
    const { state } = await Deno.permissions.request(descriptor);
    if (state !== "granted") {
      denied.push(descriptor);
    }
  }
  if (denied.length) {
    throw new PermissionDenied(
      `The following permissions have not been granted:\n${
        getPermissionString(
          denied,
        )
      }`,
    );
  }
}

// denoCacheMetadata={"headers":{"content-length":"5850","access-control-allow-origin":"*","cache-control":"public, max-age=31536000, immutable","x-jsr-backend":"modules","x-robots-tag":"noindex","cf-ray":"a223e6564ea97db6-LAX","alt-svc":"h3=\":443\"; ma=86400","content-security-policy":"default-src 'none'; script-src 'none'; style-src 'none'; img-src 'none'; font-src 'none'; connect-src 'none'; frame-src 'none'; object-src 'none'; frame-ancestors 'none'; sandbox; form-action 'none';","date":"Tue, 28 Jul 2026 12:31:15 GMT","vary":"Origin","etag":"\"305cbbb1e28dafbf8050d0b1845a0345\"","set-cookie":"__cf_bm=S8kOcVNOcejNeGrkPWhZPH3CCorkyD5T_.zeSbzkL2U-1785241874.9380124-1.0.1.1-9Q5edGGlaDb3.wUSdUwUlJqFAOU__Ud2IFOVNwhmRNwG0w9qMpy7FWbLihRNinJGUjZ22aGxYAI5.fFaTTZMUPNARsqkDLZsV6.SRUh3HWTqq4wI5F9s8fOeb8vX3RjM; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","cross-origin-resource-policy":"cross-origin","x-content-type-options":"nosniff","server":"cloudflare","content-type":"text/typescript","access-control-expose-headers":"*","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=9Q0%2BaKRcbVDzcKXCcnabLcpyVfdAd7G%2FrXHWSBRNnZNwXjeUdivkluPQ%2BafRvW9Wxb1%2B2wt8rgw3GpUKdXiVQ7rBSRwWCazl6A8fzwLexoH3fuSvUdZLYt8%3D\"}]}"},"url":"https://jsr.io/@std/permissions/0.224.0/mod.ts","time":1785241875}