opencode-effect-enforcer 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +278 -0
- package/guidance/effect-first-development.md +1247 -0
- package/guidance/post__effect-and-the-near-inexpressible-majesty-of-layers.md +490 -0
- package/guidance/post__parse-dont-validate.md +109 -0
- package/guidance/progressive-disclosure-guidance.md +38 -0
- package/package.json +63 -0
- package/patterns/avoid-any.md +37 -0
- package/patterns/avoid-data-tagged-error.md +34 -0
- package/patterns/avoid-direct-json.md +51 -0
- package/patterns/avoid-direct-tag-checks.md +54 -0
- package/patterns/avoid-expect-in-if.md +52 -0
- package/patterns/avoid-mutable-state.md +70 -0
- package/patterns/avoid-native-fetch.md +61 -0
- package/patterns/avoid-node-imports.md +86 -0
- package/patterns/avoid-non-null-assertion.md +44 -0
- package/patterns/avoid-object-type.md +46 -0
- package/patterns/avoid-option-getorthrow.md +39 -0
- package/patterns/avoid-platform-coupling.md +43 -0
- package/patterns/avoid-process-env.md +43 -0
- package/patterns/avoid-react-hooks.md +73 -0
- package/patterns/avoid-schema-suffix.md +45 -0
- package/patterns/avoid-sync-fs.md +68 -0
- package/patterns/avoid-try-catch.md +47 -0
- package/patterns/avoid-ts-ignore.md +38 -0
- package/patterns/avoid-untagged-errors.md +67 -0
- package/patterns/avoid-yield-ref.md +46 -0
- package/patterns/casting-awareness.md +46 -0
- package/patterns/context-tag-extends.md +84 -0
- package/patterns/effect-catchall-default.md +61 -0
- package/patterns/effect-promise-vs-trypromise.md +47 -0
- package/patterns/effect-run-in-body.md +58 -0
- package/patterns/imperative-loops.md +76 -0
- package/patterns/prefer-arr-sort.md +52 -0
- package/patterns/prefer-duration-values.md +56 -0
- package/patterns/prefer-effect-fn.md +161 -0
- package/patterns/prefer-match-over-switch.md +48 -0
- package/patterns/prefer-option-over-null.md +56 -0
- package/patterns/prefer-redacted-config.md +70 -0
- package/patterns/prefer-schema-class.md +54 -0
- package/patterns/require-effect-concurrency.md +83 -0
- package/patterns/stream-large-files.md +63 -0
- package/patterns/throw-in-effect-gen.md +62 -0
- package/patterns/use-clock-service.md +45 -0
- package/patterns/use-command-executor-service.md +54 -0
- package/patterns/use-console-service.md +54 -0
- package/patterns/use-filesystem-service.md +59 -0
- package/patterns/use-http-client-service.md +77 -0
- package/patterns/use-path-service.md +53 -0
- package/patterns/use-random-service.md +45 -0
- package/patterns/use-temp-file-scoped.md +66 -0
- package/patterns/vm-in-wrong-file.md +51 -0
- package/patterns/yield-in-for-loop.md +61 -0
- package/skills/effect-ai-chat/SKILL.md +472 -0
- package/skills/effect-ai-language-model/SKILL.md +652 -0
- package/skills/effect-ai-prompt/SKILL.md +752 -0
- package/skills/effect-ai-provider/SKILL.md +668 -0
- package/skills/effect-ai-streaming/SKILL.md +418 -0
- package/skills/effect-ai-tool/SKILL.md +1132 -0
- package/skills/effect-atom-rpc/SKILL.md +488 -0
- package/skills/effect-atom-state/SKILL.md +640 -0
- package/skills/effect-batching/SKILL.md +614 -0
- package/skills/effect-cache/SKILL.md +570 -0
- package/skills/effect-cli/SKILL.md +523 -0
- package/skills/effect-command-executor/SKILL.md +675 -0
- package/skills/effect-concurrency-testing/SKILL.md +612 -0
- package/skills/effect-config/SKILL.md +580 -0
- package/skills/effect-context-witness/SKILL.md +274 -0
- package/skills/effect-domain-modeling/SKILL.md +1212 -0
- package/skills/effect-domain-predicates/SKILL.md +867 -0
- package/skills/effect-error-handling/SKILL.md +1581 -0
- package/skills/effect-fiber/SKILL.md +731 -0
- package/skills/effect-filesystem/SKILL.md +624 -0
- package/skills/effect-graph/SKILL.md +571 -0
- package/skills/effect-http-api/SKILL.md +1760 -0
- package/skills/effect-http-client/SKILL.md +989 -0
- package/skills/effect-http-server/SKILL.md +920 -0
- package/skills/effect-incremental-migration/SKILL.md +362 -0
- package/skills/effect-layer-design/SKILL.md +642 -0
- package/skills/effect-managed-runtime/SKILL.md +395 -0
- package/skills/effect-mcp-server/SKILL.md +608 -0
- package/skills/effect-observability/SKILL.md +719 -0
- package/skills/effect-optics/SKILL.md +554 -0
- package/skills/effect-parallelization/SKILL.md +668 -0
- package/skills/effect-path/SKILL.md +296 -0
- package/skills/effect-pattern-matching/SKILL.md +914 -0
- package/skills/effect-platform-abstraction/SKILL.md +1175 -0
- package/skills/effect-platform-layers/SKILL.md +514 -0
- package/skills/effect-pubsub-event-bus/SKILL.md +384 -0
- package/skills/effect-react-composition/SKILL.md +986 -0
- package/skills/effect-react-vm/SKILL.md +675 -0
- package/skills/effect-rpc-api/SKILL.md +624 -0
- package/skills/effect-rpc-client/SKILL.md +666 -0
- package/skills/effect-rpc-cluster/SKILL.md +1623 -0
- package/skills/effect-rpc-server/SKILL.md +767 -0
- package/skills/effect-scheduling/SKILL.md +124 -0
- package/skills/effect-schema-composition/SKILL.md +975 -0
- package/skills/effect-schema-v4/SKILL.md +691 -0
- package/skills/effect-scope/SKILL.md +682 -0
- package/skills/effect-service-implementation/SKILL.md +656 -0
- package/skills/effect-socket/SKILL.md +703 -0
- package/skills/effect-sql/SKILL.md +781 -0
- package/skills/effect-stream/SKILL.md +765 -0
- package/skills/effect-testing/SKILL.md +1331 -0
- package/skills/effect-typeclass-design/SKILL.md +161 -0
- package/skills/effect-wide-events/Article.md +66 -0
- package/skills/effect-wide-events/SKILL.md +95 -0
- package/skills/effect-workflow/SKILL.md +810 -0
- package/src/agent-policy.ts +22 -0
- package/src/enforcer.ts +104 -0
- package/src/frontmatter.ts +34 -0
- package/src/guidance.ts +66 -0
- package/src/index.ts +38 -0
- package/src/pattern-catalog.ts +115 -0
- package/src/pattern-matcher.ts +178 -0
- package/src/pattern.ts +97 -0
- package/src/skills.ts +29 -0
- package/src/write-projection.ts +66 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: effect-path
|
|
3
|
+
description: Use effect Path for platform-abstract file path operations including joining, resolving, and URL conversion.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# path
|
|
7
|
+
|
|
8
|
+
Use effect Path abstraction for platform-abstract file path operations. Apply this skill when working with file paths, joining segments, resolving absolute paths, or converting between file URLs and paths. `Path.layer` supplies POSIX semantics from `effect`; Node.js and Bun platform layers provide host-specific path semantics. `@effect/platform-browser` does not provide a `BrowserPath` layer, so browser code should provide `Path.layer` or a custom layer explicitly.
|
|
9
|
+
|
|
10
|
+
## Import Pattern
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { Path } from 'effect';
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Service Injection
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Path } from 'effect';
|
|
20
|
+
import { Effect } from 'effect';
|
|
21
|
+
|
|
22
|
+
const program = Effect.gen(function* () {
|
|
23
|
+
const path = yield* Path.Path;
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Path Separator
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { Path } from 'effect';
|
|
31
|
+
import { Effect } from 'effect';
|
|
32
|
+
|
|
33
|
+
// Get platform-specific separator
|
|
34
|
+
const program = Effect.gen(function* () {
|
|
35
|
+
const path = yield* Path.Path;
|
|
36
|
+
const separator = path.sep; // "/" on Unix, "\" on Windows
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Path Operations
|
|
41
|
+
|
|
42
|
+
### join - Combine path segments
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { Path } from 'effect';
|
|
46
|
+
import { Effect } from 'effect';
|
|
47
|
+
|
|
48
|
+
const program = Effect.gen(function* () {
|
|
49
|
+
const path = yield* Path.Path;
|
|
50
|
+
const fullPath = path.join('src', 'components', 'Button.tsx');
|
|
51
|
+
// "src/components/Button.tsx" on Unix
|
|
52
|
+
// "src\components\Button.tsx" on Windows
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### resolve - Convert to absolute path
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { Path } from 'effect';
|
|
60
|
+
import { Effect } from 'effect';
|
|
61
|
+
|
|
62
|
+
const program = Effect.gen(function* () {
|
|
63
|
+
const path = yield* Path.Path;
|
|
64
|
+
const absolutePath = path.resolve('src', 'index.ts');
|
|
65
|
+
// "/Users/username/project/src/index.ts" on Unix
|
|
66
|
+
// "C:\Users\username\project\src\index.ts" on Windows
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### normalize - Clean up path
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { Path } from 'effect';
|
|
74
|
+
import { Effect } from 'effect';
|
|
75
|
+
|
|
76
|
+
const program = Effect.gen(function* () {
|
|
77
|
+
const path = yield* Path.Path;
|
|
78
|
+
const clean = path.normalize('/foo/bar//baz/asdf/quux/..');
|
|
79
|
+
// "/foo/bar/baz/asdf"
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### dirname - Get directory portion
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { Path } from 'effect';
|
|
87
|
+
import { Effect } from 'effect';
|
|
88
|
+
|
|
89
|
+
const program = Effect.gen(function* () {
|
|
90
|
+
const path = yield* Path.Path;
|
|
91
|
+
const dir = path.dirname('/foo/bar/baz.txt');
|
|
92
|
+
// "/foo/bar"
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### basename - Get file name
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { Path } from 'effect';
|
|
100
|
+
import { Effect } from 'effect';
|
|
101
|
+
|
|
102
|
+
const program = Effect.gen(function* () {
|
|
103
|
+
const path = yield* Path.Path;
|
|
104
|
+
const name = path.basename('/foo/bar/baz.txt');
|
|
105
|
+
// "baz.txt"
|
|
106
|
+
|
|
107
|
+
const nameWithoutExt = path.basename('/foo/bar/baz.txt', '.txt');
|
|
108
|
+
// "baz"
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### extname - Get file extension
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { Path } from 'effect';
|
|
116
|
+
import { Effect } from 'effect';
|
|
117
|
+
|
|
118
|
+
const program = Effect.gen(function* () {
|
|
119
|
+
const path = yield* Path.Path;
|
|
120
|
+
const ext = path.extname('/foo/bar/baz.txt');
|
|
121
|
+
// ".txt"
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### parse - Decompose path into components
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Path } from 'effect';
|
|
129
|
+
import { Effect } from 'effect';
|
|
130
|
+
|
|
131
|
+
const program = Effect.gen(function* () {
|
|
132
|
+
const path = yield* Path.Path;
|
|
133
|
+
const parsed = path.parse('/home/user/dir/file.txt');
|
|
134
|
+
// {
|
|
135
|
+
// root: "/",
|
|
136
|
+
// dir: "/home/user/dir",
|
|
137
|
+
// base: "file.txt",
|
|
138
|
+
// ext: ".txt",
|
|
139
|
+
// name: "file"
|
|
140
|
+
// }
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### format - Construct path from components
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { Path } from 'effect';
|
|
148
|
+
import { Effect } from 'effect';
|
|
149
|
+
|
|
150
|
+
const program = Effect.gen(function* () {
|
|
151
|
+
const path = yield* Path.Path;
|
|
152
|
+
const fullPath = path.format({
|
|
153
|
+
root: '/',
|
|
154
|
+
dir: '/home/user/dir',
|
|
155
|
+
base: 'file.txt'
|
|
156
|
+
});
|
|
157
|
+
// "/home/user/dir/file.txt"
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### isAbsolute - Check if path is absolute
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { Path } from 'effect';
|
|
165
|
+
import { Effect } from 'effect';
|
|
166
|
+
|
|
167
|
+
const program = Effect.gen(function* () {
|
|
168
|
+
const path = yield* Path.Path;
|
|
169
|
+
const isAbs = path.isAbsolute('/foo/bar');
|
|
170
|
+
// true on Unix
|
|
171
|
+
const isRel = path.isAbsolute('foo/bar');
|
|
172
|
+
// false
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### relative - Get relative path
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { Path } from 'effect';
|
|
180
|
+
import { Effect } from 'effect';
|
|
181
|
+
|
|
182
|
+
const program = Effect.gen(function* () {
|
|
183
|
+
const path = yield* Path.Path;
|
|
184
|
+
const relPath = path.relative(
|
|
185
|
+
'/data/orandea/test/aaa',
|
|
186
|
+
'/data/orandea/impl/bbb'
|
|
187
|
+
);
|
|
188
|
+
// "../../impl/bbb"
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## URL Conversions (Effectful)
|
|
193
|
+
|
|
194
|
+
Both operations can fail with `BadArgument` error.
|
|
195
|
+
|
|
196
|
+
### fromFileUrl - Convert file URL to path
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { Path } from 'effect';
|
|
200
|
+
import { Effect } from 'effect';
|
|
201
|
+
|
|
202
|
+
const program = Effect.gen(function* () {
|
|
203
|
+
const path = yield* Path.Path;
|
|
204
|
+
const filePath = yield* path.fromFileUrl(
|
|
205
|
+
new URL('file:///home/user/file.txt')
|
|
206
|
+
);
|
|
207
|
+
// "/home/user/file.txt" on Unix
|
|
208
|
+
// "C:\home\user\file.txt" on Windows
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### toFileUrl - Convert path to file URL
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { Path } from 'effect';
|
|
216
|
+
import { Effect } from 'effect';
|
|
217
|
+
|
|
218
|
+
const program = Effect.gen(function* () {
|
|
219
|
+
const path = yield* Path.Path;
|
|
220
|
+
const fileUrl = yield* path.toFileUrl('/home/user/file.txt');
|
|
221
|
+
// URL object with href "file:///home/user/file.txt"
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Complete Example
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { Path } from 'effect';
|
|
229
|
+
import { Effect } from 'effect';
|
|
230
|
+
|
|
231
|
+
const buildOutputPath = Effect.gen(function* () {
|
|
232
|
+
const path = yield* Path.Path;
|
|
233
|
+
|
|
234
|
+
// Join segments
|
|
235
|
+
const srcPath = path.join('src', 'index.ts');
|
|
236
|
+
|
|
237
|
+
// Resolve to absolute
|
|
238
|
+
const absoluteSrc = path.resolve(srcPath);
|
|
239
|
+
|
|
240
|
+
// Get directory and basename
|
|
241
|
+
const dir = path.dirname(absoluteSrc);
|
|
242
|
+
const base = path.basename(absoluteSrc, '.ts');
|
|
243
|
+
|
|
244
|
+
// Build output path
|
|
245
|
+
const outputPath = path.join(dir, '..', 'dist', `${base}.js`);
|
|
246
|
+
|
|
247
|
+
// Normalize
|
|
248
|
+
return path.normalize(outputPath);
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## File-System Migration Loaders
|
|
253
|
+
|
|
254
|
+
In Effect v4, `Migrator.fromFileSystem(directory)` requires both `FileSystem.FileSystem` and `Path.Path`. Migration modules are imported through `path.toFileUrl(path.join(directory, file))` so absolute Windows paths are valid ESM specifiers.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { FileSystem, Path } from 'effect';
|
|
258
|
+
import * as Migrator from 'effect/unstable/sql/Migrator';
|
|
259
|
+
|
|
260
|
+
const loader: Migrator.Loader<FileSystem.FileSystem | Path.Path> =
|
|
261
|
+
Migrator.fromFileSystem('./migrations');
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Aggregate layers such as `NodeServices.layer` and `BunServices.layer` already provide both requirements. If wiring individual layers, provide both the file-system layer and the host-aware path layer. On Windows, do not use the core POSIX `Path.layer` for a Windows migration directory; use the runtime platform's path layer so drive letters and separators are converted correctly.
|
|
265
|
+
|
|
266
|
+
### toNamespacedPath - Convert to namespaced path
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { Path } from 'effect';
|
|
270
|
+
import { Effect } from 'effect';
|
|
271
|
+
|
|
272
|
+
const program = Effect.gen(function* () {
|
|
273
|
+
const path = yield* Path.Path;
|
|
274
|
+
// On POSIX, returns the path unchanged.
|
|
275
|
+
// On Windows, converts to a \\?\-prefixed namespaced path
|
|
276
|
+
// that allows longer path lengths.
|
|
277
|
+
const namespaced = path.toNamespacedPath('/foo/bar/baz.txt');
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## DO
|
|
282
|
+
|
|
283
|
+
- Import Path from effect
|
|
284
|
+
- Use `path.sep` for platform-specific separators
|
|
285
|
+
- Use `path.join()` to combine path segments
|
|
286
|
+
- Use `path.resolve()` to get absolute paths
|
|
287
|
+
- Handle errors from `fromFileUrl` and `toFileUrl` with Effect error handling
|
|
288
|
+
- Pass a `URL` object (not a string) to `fromFileUrl`
|
|
289
|
+
|
|
290
|
+
## DON'T
|
|
291
|
+
|
|
292
|
+
- Import `node:path` directly (breaks portability)
|
|
293
|
+
- Hardcode "/" or "\\" separators
|
|
294
|
+
- Manually concatenate paths with string operations
|
|
295
|
+
- Assume file URL format without using conversion utilities
|
|
296
|
+
- Pass a string to `fromFileUrl` — it requires a `URL` object
|