# Compatibilidade APIs Node.js - Path

O módulo `path` no Node.js fornece utilitários para trabalhar com caminhos de arquivos e diretórios. Ele oferece um conjunto de funções que ajudam desenvolvedores a manipular e normalizar caminhos, facilitando o tratamento de operações de sistema de arquivos entre diferentes sistemas operacionais. Este módulo está disponível no Azion Runtime através da compatibilidade com Node.js, sendo comumente usado em functions para construir ou normalizar caminhos, por exemplo ao rotear requisições ou compor referências de assets.

---

## Exemplo: Operações básicas com path

O exemplo abaixo mostra como usar o módulo `path` em uma function:

```javascript
/**
 * An example of using the Node.js Path API in an Azion Function.
 * Support:
 * - Partially supported (Extended by library `path-browserify`)
 * @module runtime-apis/nodejs/path/main
 * @example
 * // Execute with Azion Bundler:
 * npx edge-functions build
 * npx edge-functions dev
 */
import path from "node:path";

/**
 * An example of using the Node.js Path API in an Azion Function.
 * @param {*} event
 * @returns {Promise<Response>}
 */
const main = async (event) => {
  const pathName = path.join("/", "images", "image.jpg");
  console.log("Path", pathName);
  return new Response(`Path: ${pathName}`);
};

export default main;
```

---

## Exemplo: Roteamento de URL com path

Use métodos de path para analisar e construir caminhos de URL para roteamento:

```javascript
import path from "node:path";

const main = async (event) => {
  const requestUrl = new URL(event.request.url);
  const pathname = requestUrl.pathname;

  // Extract path components
  const dirname = path.dirname(pathname);
  const basename = path.basename(pathname);
  const extname = path.extname(pathname);

  console.log("Directory:", dirname);
  console.log("Filename:", basename);
  console.log("Extension:", extname);

  // Build a new path for routing
  const apiPath = path.join("/api", "v1", "users", basename);
  console.log("API path:", apiPath);

  // Note: path.resolve() works for path string manipulation in edge runtimes,
  // but doesn't interact with an actual filesystem
  const absolutePath = path.resolve("/app", "public", "images", "logo.png");
  console.log("Absolute path:", absolutePath);

  return new Response(JSON.stringify({
    original: pathname,
    dirname,
    basename,
    extname,
    apiPath,
    absolutePath
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

---

## Exemplo: Normalização e análise de caminhos

Normalize caminhos e extraia informações detalhadas:

```javascript
import path from "node:path";

const main = async (event) => {
  // Normalize messy paths
  const messyPath = "/users/../public/./images//photo.jpg";
  const normalizedPath = path.normalize(messyPath);
  console.log("Normalized:", normalizedPath);
  // /public/images/photo.jpg

  // Parse path into components (using edge-runtime-neutral paths)
  const filePath = "/assets/css/styles.css";
  const parsed = path.parse(filePath);
  console.log("Parsed:", parsed);
  // { root: '/', dir: '/assets/css', base: 'styles.css', ext: '.css', name: 'styles' }

  // Format path from object
  const formatted = path.format({
    root: "/",
    dir: "/data/documents",
    base: "report.pdf"
  });
  console.log("Formatted:", formatted);

  // Check if path is absolute
  const isAbs1 = path.isAbsolute("/assets/app.js");
  const isAbs2 = path.isAbsolute("../relative/path");
  console.log("Is absolute:", isAbs1, isAbs2);

  return new Response(JSON.stringify({
    normalizedPath,
    parsed,
    formatted,
    isAbsolute: { absolute: isAbs1, relative: isAbs2 }
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

---

## Exemplo: Construção de caminhos para assets estáticos

Construa caminhos para assets estáticos e entrega de conteúdo:

```javascript
import path from "node:path";

const main = async (event) => {
  const request = event.request;
  const url = new URL(request.url);

  // Base directory for static files
  const staticBase = "/static";

  // Get requested file path
  const requestedPath = url.pathname.replace(/^\/static/, "");

  // Build full path
  const fullPath = path.join(staticBase, requestedPath);
  console.log("Full path:", fullPath);

  // Security: Validate that the resolved path stays within staticBase
  // This prevents path traversal attacks (e.g., /static/../sensitive/file)
  const resolvedPath = path.resolve(staticBase, requestedPath);
  if (!resolvedPath.startsWith(staticBase)) {
    return new Response("Forbidden", { status: 403 });
  }

  // Determine content type based on extension
  const ext = path.extname(fullPath).toLowerCase();
  const contentTypes = {
    ".html": "text/html",
    ".css": "text/css",
    ".js": "application/javascript",
    ".json": "application/json",
    ".png": "image/png",
    ".jpg": "image/jpeg",
    ".svg": "image/svg+xml"
  };

  const contentType = contentTypes[ext] || "application/octet-stream";
  console.log("Content-Type:", contentType);

  // Build relative path from current location
  const relativePath = path.relative("/static/images", fullPath);
  console.log("Relative path:", relativePath);

  return new Response(JSON.stringify({
    fullPath,
    resolvedPath,
    extension: ext,
    contentType,
    relativePath
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

---

## Exemplo: Tratamento de caminhos multiplataforma

Manipule caminhos de forma consistente entre diferentes ambientes:

```javascript
import path from "node:path";

const main = async (event) => {
  // Default path methods (platform-specific)
  const defaultJoin = path.join("folder", "subfolder", "file.txt");
  const defaultSep = path.sep;

  // Force POSIX-style paths (forward slashes)
  // Note: path.posix and path.win32 are properties of the main module
  const posixJoin = path.posix.join("folder", "subfolder", "file.txt");
  const posixSep = path.posix.sep;

  // Force Windows-style paths (backslashes)
  const win32Join = path.win32.join("folder", "subfolder", "file.txt");
  const win32Sep = path.win32.sep;

  console.log("Default join:", defaultJoin);
  console.log("POSIX join:", posixJoin);
  console.log("Windows join:", win32Join);

  // Get delimiter for PATH environment variable
  const delimiter = path.delimiter;
  console.log("Path delimiter:", delimiter);

  return new Response(JSON.stringify({
    default: { join: defaultJoin, sep: defaultSep },
    posix: { join: posixJoin, sep: posixSep },
    win32: { join: win32Join, sep: win32Sep },
    delimiter
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

---

## APIs com suporte

| API | Status |
|-----|--------|
| `path.basename()` | 🟢 Com suporte |
| `path.dirname()` | 🟢 Com suporte |
| `path.extname()` | 🟢 Com suporte |
| `path.format()` | 🟢 Com suporte |
| `path.isAbsolute()` | 🟢 Com suporte |
| `path.join()` | 🟢 Com suporte |
| `path.normalize()` | 🟢 Com suporte |
| `path.parse()` | 🟢 Com suporte |
| `path.relative()` | 🟢 Com suporte |
| `path.resolve()` | 🟢 Com suporte |
| `path.sep` | 🟢 Com suporte |
| `path.delimiter` | 🟢 Com suporte |
| `path.posix` | 🟢 Com suporte |
| `path.win32` | 🟢 Com suporte |

:::note
Embora todas as APIs de `path` tenham suporte, elas operam apenas em strings de caminho. O Azion Runtime não fornece acesso a um sistema de arquivos real, então métodos como `path.resolve()` realizam manipulação de strings sem interação com o sistema de arquivos. Para manipulação de caminhos de URL, considere usar a API Web `URL` junto com `node:path`.
:::

---

## Recursos relacionados

- [Documentação do `path` no Node.js](https://nodejs.org/api/path.html)