Claude-skill-registry deno-core
Essential Deno TypeScript practices for ALL Deno development: configuration, imports, testing, permissions, and anti-patterns. Read this skill for any Deno project setup, dependency management, or core development work.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/deno-core" ~/.claude/skills/majiayu000-claude-skill-registry-deno-core && rm -rf "$T"
skills/data/deno-core/SKILL.mdDeno Core Best Practices
When to Use This Skill
Use this skill for ALL Deno TypeScript development:
- Setting up new Deno projects
- Writing Deno applications or libraries
- Configuring build, test, and deployment
- Working with dependencies and imports
Core Deno Philosophy
One Tool, Zero Dependencies
- Deno is the only tool you need for TypeScript development
- Built-in tooling: typecheck, lint, format, test, coverage, benchmark
- Avoid
at all costs - reduce supply chain attack surfacenode_modules - No need for: tsc, eslint, prettier, jest, vitest, webpack, etc.
TypeScript Excellence
- Strict TypeScript adherence - not just "TS support"
- Bleeding-edge TypeScript features by default - no flags, no config needed
- No compilation step - just run your code
- Target ES2024+ with Stage 3 TC39 proposals
Security First
- Explicit permissions model (no implicit file system or network access)
- Supply chain security through minimal external dependencies
- First-class support for modern security patterns
Language & Compiler
TypeScript Configuration
- Do not use
- Deno usestsconfig.json
as the single source of truthdeno.json(c) - Type-checking powered by
/deno check
- do not rely on externaldeno testtsc - Default module format is ESM only - no CommonJS interop
- Prefer Deno's runtime-provided types (
, Web APIs, Fetch, URLPattern) over polyfillsDeno.*
Strictest Compiler Settings
Always use the strictest possible settings in
deno.json:
{ "compilerOptions": { "strict": true, "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, "noUnusedParameters": true, "exactOptionalPropertyTypes": true } }
Configuration & Tasks
deno.json - Single Source of Truth
Use
deno.json or deno.jsonc as the single configuration file for:
- Compiler options
- Linting and formatting rules
- Tasks (script aliases)
- Import maps (dependency management)
- Exclusions
Complete Configuration Example:
{ "compilerOptions": { "strict": true, "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, "noUnusedParameters": true }, "tasks": { "dev": "deno run --watch --allow-net --allow-read --allow-env src/main.ts", "test": "deno test --allow-net --allow-read --allow-env --coverage=coverage src/", "test:unit": "deno test --allow-net --allow-read --allow-env --coverage=coverage src/", "test:e2e": "deno test --allow-net --allow-read --allow-env tests/e2e/", "test:watch": "deno test --allow-net --allow-read --allow-env --watch --fail-fast", "coverage": "deno coverage coverage --html", "check": "deno check $(find src -name '*.ts' -not -name '*.sql')", "lint": "deno lint", "fmt": "deno fmt" }, "imports": { "@/": "./src/", "@/domain/": "./src/domain/", "@/infrastructure/": "./src/infrastructure/", "@/application/": "./src/application/", "@std/assert": "jsr:@std/assert@^1.0.14", "@std/fs": "jsr:@std/fs@^1.0.19", "@std/testing": "jsr:@std/testing@^1.0.15", "@std/ulid": "jsr:@std/ulid@1", "zod": "npm:zod@^3.23.8" }, "exclude": [ "coverage/", "node_modules/" ], "lock": true }
Essential Tasks
Define these
aliases at minimum:deno task
- Development with watch modedev
,test
- Testingtest:watch
- Generate coverage reportscoverage
- Type-check all filescheck
,lint
- Code qualityfmt
Lockfile Management
- Always commit
to version controldeno.lock - Run with
in CI--lock=deno.lock --lock-write=false - Update lockfile:
deno cache --lock=deno.lock --lock-write
Imports & Module Resolution
Import Strategy
CRITICAL: Never use direct JSR/npm imports in source files. All external dependencies MUST be declared in
deno.json import map.
Import Order in Source Files:
// 1. Standard library imports (via import map) import { assertEquals } from "@std/assert"; // 2. Third-party imports (via import map) import { z } from "zod"; // 3. Internal imports (absolute paths using import map) import { Agent } from "@/domain/agent.ts"; // 4. Relative imports (only within same module/context) import { validatePrompt } from "./validation.ts";
Dependency Source Priority
Use sources in this order:
-
registry (first choice for TypeScript modules)jsr:"@std/assert": "jsr:@std/assert@^1.0.14" -
specifier (when needed; prefer ESM-compatible)npm:"zod": "npm:zod@^3.23.8" -
URL imports (rarely needed with import maps)
Version Pinning
CRITICAL: Version pin all external imports. No floating
@latest in committed code.
{ "imports": { "zod": "npm:zod@^3.23.8", // GOOD - pinned "zod": "npm:zod", // BAD - no version "@std/assert": "jsr:@std/assert@1" // GOOD - pinned } }
Internal Path Aliases
Use import map aliases for clean internal imports:
{ "imports": { "@/": "./src/", "@/domain/": "./src/domain/", "@/infrastructure/": "./src/infrastructure/" } }
// GOOD - Clean, refactor-safe import { Agent } from "@/domain/agent.ts"; // BAD - Brittle relative paths import { Agent } from "../../../domain/agent.ts";
Type-Only Imports
Use type-only imports when importing types:
import type { Agent } from "@/domain/agent.ts"; import type { z } from "zod";
Testing
Test Organization
Unit Tests - Co-located with Source:
src/ └── domain/ ├── agent.ts └── agent.test.ts # Unit tests next to code
Integration & E2E Tests - Separate Directory:
tests/ ├── integration/ │ └── openai_provider.test.ts └── e2e/ └── workflow.test.ts
Why Co-location:
- Discoverability - tests next to code
- Maintenance - easy to keep in sync
- Deno convention - follows
discoverydeno test
Coverage Requirements
Non-Negotiable:
- Line coverage: 80%+ - MUST be met
- Branch coverage: 60-80% - MUST be met
deno test --coverage=coverage deno coverage coverage --html
Test Structure
Always use explicit AAA (Arrange-Act-Assert):
import { assertEquals } from "@std/assert"; Deno.test("agent should process valid input", () => { // Arrange const agent = new Agent({ name: "TestAgent" }); const input = "Hello, world!"; // Act const result = agent.process(input); // Assert assertEquals(result.status, "success"); });
Test Development
Red-Green-Refactor with fast feedback:
# Watch mode with fail-fast deno test --watch --fail-fast # Run specific file deno test src/domain/agent.test.ts --watch
Deterministic Tests
CRITICAL: All tests must be deterministic.
Test Flakiness Policy:
- Flakiness = highest priority bug
- Never ignore, retry, or "fix" with delays
- Action: investigate, quarantine, fix
- Do NOT merge flaky tests
Use stable seeds and fixtures:
import { FakeTime } from "@std/testing/time"; Deno.test("timer test", () => { using time = new FakeTime(); // Deterministic time control time.tick(1000); });
Test File Naming
All test files must end with
.test.ts:
agent.test.ts # GOOD agent_test.ts # BAD agent.spec.ts # BAD
Testing Tools
- Use
for assertions@std/assert - Use
for test doubles@std/testing/mock - Use
for time control@std/testing/time - Do NOT use Jest - use Deno's built-in runner
Permissions & Security
Principle of Least Privilege
Default to minimum required permissions:
# BAD deno run --allow-all script.ts # GOOD deno run --allow-read=./data --allow-net=api.example.com script.ts
Common Permission Flags
--allow-read[=<path>] # File system read --allow-write[=<path>] # File system write --allow-net[=<domain>] # Network access --allow-env[=<var>] # Environment variables --allow-run[=<program>] # Subprocess execution
Document Required Permissions
/** * Fetches data from API and caches locally. * * Required permissions: * - --allow-net=api.example.com * - --allow-read=./cache * - --allow-write=./cache */ export async function fetchData(): Promise<Data> { // ... }
Secrets Management
// BAD - Hardcoded const apiKey = "sk-1234"; // GOOD - From environment const apiKey = Deno.env.get("API_KEY"); if (!apiKey) { throw new Error("API_KEY required"); }
Run with:
deno run --allow-env=API_KEY script.ts
Anti-Patterns to Avoid
Import Anti-Patterns
// BAD - Direct JSR/npm imports in source import { z } from "npm:zod@^3.23.8"; // GOOD - Use import map import { z } from "zod";
// BAD - Floating versions "zod": "npm:zod" // GOOD - Pinned versions "zod": "npm:zod@^3.23.8"
Node.js Anti-Patterns
// BAD - Node.js APIs const fs = require("fs"); import * as fs from "node:fs"; // GOOD - Deno APIs await Deno.readTextFile("file.txt");
Testing Anti-Patterns
// BAD - Unnecessary delay await new Promise(r => setTimeout(r, 100)); // GOOD - Deterministic time import { FakeTime } from "@std/testing/time"; using time = new FakeTime(); time.tick(100);
Permission Anti-Patterns
# BAD - Overly broad deno run --allow-all script.ts # GOOD - Specific deno run --allow-read=./data script.ts
Async Anti-Patterns
// BAD - Unnecessary async async function validate(input: string): Promise<boolean> { return input.length > 0; } // GOOD - Remove async if no await function validate(input: string): boolean { return input.length > 0; }
Quick Command Reference
Development
# Run with watch deno run --watch src/main.ts # Type-check deno check src/**/*.ts # Format deno fmt # Lint deno lint
Testing
# Run all tests deno test # With coverage deno test --coverage=coverage deno coverage coverage --html # Watch mode deno test --watch --fail-fast
Dependencies
# Update dependencies deno cache --reload # Update lockfile deno cache --lock=deno.lock --lock-write
Tasks
# Run tasks from deno.json deno task dev deno task test deno task coverage
Key Principles Summary
- One tool - Deno replaces tsc, eslint, prettier, jest
- Security first - Explicit permissions, minimal dependencies
- Import maps - All deps in
, never direct importsdeno.json - Version pinning - No floating versions
- Co-located tests - Unit tests next to source
- 80%/60% coverage - Line/branch, non-negotiable
- No flakiness - Highest priority, never ignore
- AAA pattern - Explicit in every test
- Least privilege - Minimal permissions
- ESM only - No CommonJS
Additional Resources
- Deno Manual: https://docs.deno.com/
- Deno Standard Library: https://jsr.io/@std
- JSR Registry: https://jsr.io/