Claude
Skills
Sign in
Back

deno-scripting

Included with Lifetime
$97 forever

Guidelines for developing standalone Deno CLI scripts using TypeScript for troubleshooting, diagnostics, batch processing, and automation. Use when creating CLI tools, data processing scripts, reports, migration utilities, or any standalone TypeScript script running on Deno.

General

What this skill does


# Deno CLI Scripting

You are an expert in Deno and TypeScript development with deep knowledge of
building standalone CLI scripts, batch processing tools, and diagnostic
utilities using Deno's native TypeScript support and built-in tooling.

## TypeScript General Guidelines

### Basic Principles

- Use English for all code and documentation
- Always declare types for variables and functions (parameters and return
  values)
- Avoid using `any` type - create necessary types instead
- Use JSDoc to document public classes and methods
- Write concise, maintainable, and technically accurate code
- Use functional and declarative programming patterns
- No configuration needed - Deno runs TypeScript natively

### Nomenclature

- Use PascalCase for types and interfaces
- Use camelCase for variables, functions, and methods
- Use kebab-case for file and directory names
- Use UPPERCASE for environment variables
- Use descriptive variable names with auxiliary verbs: `isLoading`, `hasError`,
  `canDelete`
- Start each function with a verb

### Functions

- Write short functions with a single purpose
- Use arrow functions for simple operations and consistency
- Use async/await for asynchronous operations
- Prefer the RO-RO pattern (Receive Object, Return Object) for multiple
  parameters

### Types and Interfaces

- Prefer `type` over `interface` for object shapes in scripts
- Avoid enums; use const objects with `as const`
- Use Zod for runtime validation when needed
- Use `readonly` for immutable properties

### Type Organization

**Guide**: For projects with multiple scripts sharing types, organize types in a
dedicated directory.

#### When to Use Separate Type Files

| Project Size                  | Recommendation                      |
| ----------------------------- | ----------------------------------- |
| Single script                 | Keep types inline in the script     |
| 2-3 scripts with shared types | Create `types/index.ts`             |
| Larger projects               | Create `types/` with multiple files |

#### Directory Structure

```
project/
├── main.ts              # Config, utilities, re-exports types
├── types/
│   └── index.ts         # All shared type definitions
└── scripts/
    ├── script-a.ts      # Imports types from main.ts or types/
    └── script-b.ts
```

#### Type File Pattern

```typescript
// types/index.ts
/**
 * Shared Type Definitions
 *
 * Domain types used across multiple scripts.
 */

// =============================================================================
// Domain Types
// =============================================================================

/** User record from database */
export type User = {
  readonly id: string;
  readonly name: string;
  readonly email: string;
};

/** User with computed fields */
export type UserWithBalance = User & {
  readonly balance: string;
};

// =============================================================================
// API Response Types
// =============================================================================

export type ApiResponse<T> = {
  readonly success: boolean;
  readonly data?: T;
  readonly error?: string;
};

// =============================================================================
// Script-Specific Types (export for reuse)
// =============================================================================

/** Result of a batch operation */
export type BatchResult<T> =
  | { success: true; data: T }
  | { success: false; error: string };
```

#### Re-exporting from main.ts

```typescript
// main.ts
import "@std/dotenv/load";

// Re-export all types for convenient imports
export type {
  ApiResponse,
  BatchResult,
  User,
  UserWithBalance,
} from "./types/index.ts";

// ... rest of main.ts (config, utilities)
```

#### Importing in Scripts

```typescript
// scripts/process-users.ts
import {
  type BatchResult,
  config,
  type User,
  type UserWithBalance,
} from "../main.ts";

// Script-specific types can stay inline if not shared
type ProcessingStats = {
  total: number;
  processed: number;
  failed: number;
};
```

#### Type Naming Conventions

| Type Category   | Naming Pattern    | Example                       |
| --------------- | ----------------- | ----------------------------- |
| Domain entities | PascalCase noun   | `User`, `Transaction`         |
| With additions  | `EntityWithX`     | `UserWithBalance`             |
| API responses   | `EntityResponse`  | `TransactionResponse`         |
| State objects   | `EntityState`     | `AirdropState`                |
| Results         | `OperationResult` | `SubmitResult`, `FetchResult` |
| Status enums    | `EntityStatus`    | `TransactionStatus`           |

---

## Questions to Ask First

Before implementing, clarify these with the user to determine which patterns to
apply:

1. **Input format**: "What is the input format - JSON file, CSV file, or text
   file with one item per line?"
2. **Output format**: "Should the output be JSON, CSV, or both? Do you need a
   human-readable summary?"
3. **Environment**: "Will this run against staging/testnet or
   production/mainnet? Do you need environment switching?"
4. **Batch processing**: "How many items should be processed in parallel per
   batch? (default: 50)"
5. **Resumability**: "Should the script be resumable if interrupted? (saves
   state after each operation)"
6. **Dry run**: "Do you want a --dry-run flag to preview without making
   changes?"

---

## Guides

The following sections are **templates and patterns** to apply based on the
user's answers above. Adapt them to the specific use case.

---

## Project Structure

```
project/
├── deno.json                 # Configuration, tasks, and imports
├── .env                      # Environment variables (gitignored)
├── .env.example              # Environment variables template
├── main.ts                   # Shared configuration and utilities
└── scripts/
    ├── <script-name>.ts      # Script files
    └── ...
```

## deno.json Configuration

```json
{
  "tasks": {
    "check": "deno fmt --check && deno check scripts/*.ts",
    "<task-name>": "deno run --allow-net --allow-read --allow-write --allow-env scripts/<script-name>.ts"
  },
  "imports": {
    "@std/cli": "jsr:@std/cli@1",
    "@std/dotenv": "jsr:@std/[email protected]"
  }
}
```

**Add imports based on needs:**

```bash
# Always needed
deno add jsr:@std/dotenv

# If using CLI arguments
deno add jsr:@std/cli

# If reading/writing CSV
deno add jsr:@std/csv
```

## Quality Checks

Always run before committing:

```bash
deno fmt
deno check scripts/*.ts

# Or use task
deno task check
```

## Environment Configuration

**Guide**: Always use `@std/dotenv` for environment variables. Never hardcode
secrets.

```typescript
// main.ts
import "@std/dotenv/load";

// Environment selection (if user needs staging/production switching)
export const ENV = Deno.env.get("ENV") || "production";
export const isStaging = ENV === "staging";

// Validation helper
const assertEnv = (name: string): string => {
  const value = Deno.env.get(name);
  if (!value) {
    console.error(`Error: ${name} environment variable is required`);
    Deno.exit(1);
  }
  return value;
};

// Load required env vars
export const API_KEY = assertEnv("API_KEY");

// Environment-aware URLs (if needed)
export const API_BASE = isStaging
  ? "https://staging.api.example.com"
  : "https://api.example.com";

// Environment-aware file naming (if user needs environment switching)
export const getInputFile = (baseName: string): string =>
  isStaging ? `./${baseName}.staging.json` : `./${baseName}.production.json`;

export const getOutputFile = (baseName: string): string =>
  isStaging ? `./${baseName}.staging.json` : `./${baseName}.production.json`;
```

**.env.example:**

```
ENV="production"
API_KEY="your_api_key_here"
```

## Script Structure

**Guide**: Use arrow functions throughout. Organize with clear sections.

```typescript
import "@std/dotenv/load";
import { parseArgs } from
Files: 1
Size: 19.2 KB
Complexity: 24/100
Category: General

Related in General