@drkmttr/adhere 0.7.1 → 0.8.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 +156 -32
- package/package.json +13 -12
- package/presets/effect/basics/external-calls-are-resilient.md +1 -1
- package/presets/effect/testing/test-clock-for-time.md +1 -1
- package/skills/adhere/SKILL.md +3 -2
- package/src/cli.ts +39 -15
- package/src/excerpt.ts +255 -0
- package/src/highlight.ts +82 -20
- package/src/init.ts +10 -4
- package/src/main.ts +35 -4
- package/src/mechanical.ts +89 -0
- package/src/presets.ts +1 -2
- package/src/rules.ts +2 -0
- package/src/services/AdhereConfig.ts +13 -17
- package/src/services/AuditCache.ts +272 -23
- package/src/services/Jev.http.ts +92 -18
- package/src/services/Jev.ts +77 -7
- package/src/services/SourceWalker.ts +11 -4
- package/src/wording.ts +90 -0
- package/src/workflows/audit.ts +210 -30
- package/src/workflows/format.ts +77 -21
- package/presets/effect/basics/fn-for-named-effects.md +0 -19
- package/presets/effect/data/decode-json-with-schema.md +0 -18
- package/presets/effect/errors/domain-errors-are-tagged.md +0 -19
- package/presets/effect/platform/os-access-through-platform-services.md +0 -26
- package/presets/effect/services/methods-have-no-requirements.md +0 -20
- package/presets/effect/services/provide-at-entry.md +0 -23
- package/presets/effect/testing/test-random.md +0 -22
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: A named function that returns an Effect must be defined with Effect.fn so the call site is traced. An Effect held in a constant, such as `const program = Effect.gen(...)`, is not a function and is not in scope.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
const processUser = Effect.fn("processUser")(function* (userId: string) {
|
|
7
|
-
yield* Effect.logInfo(`Processing user ${userId}`);
|
|
8
|
-
const user = yield* getUser(userId);
|
|
9
|
-
return yield* processData(user);
|
|
10
|
-
});
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
```ts never
|
|
14
|
-
const loadUser = (id: string) =>
|
|
15
|
-
Effect.gen(function* () {
|
|
16
|
-
const repo = yield* UserRepo;
|
|
17
|
-
return yield* repo.find(id);
|
|
18
|
-
});
|
|
19
|
-
```
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: JSON crossing a boundary must be decoded with Schema.fromJsonString, never with JSON.parse followed by a cast.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
const MoveFromJson = Schema.fromJsonString(Move);
|
|
7
|
-
|
|
8
|
-
const program = Effect.gen(function* () {
|
|
9
|
-
const jsonString = '{"from":{"row":"A","column":"1"},"to":{"row":"B","column":"2"}}';
|
|
10
|
-
const move = yield* Schema.decodeUnknownEffect(MoveFromJson)(jsonString);
|
|
11
|
-
const json = yield* Schema.encodeEffect(MoveFromJson)(move);
|
|
12
|
-
return json;
|
|
13
|
-
});
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```ts never
|
|
17
|
-
const settings = JSON.parse(text) as Settings;
|
|
18
|
-
```
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: A domain failure must be a Schema.TaggedError with its own tag, never a bare Error or a plain object.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
class ValidationError extends Schema.TaggedError<ValidationError>()("ValidationError", {
|
|
7
|
-
field: Schema.String,
|
|
8
|
-
message: Schema.String,
|
|
9
|
-
}) {}
|
|
10
|
-
|
|
11
|
-
class NotFoundError extends Schema.TaggedError<NotFoundError>()("NotFoundError", {
|
|
12
|
-
resource: Schema.String,
|
|
13
|
-
id: Schema.String,
|
|
14
|
-
}) {}
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
```ts never
|
|
18
|
-
return yield* Effect.fail(new Error("Card declined"));
|
|
19
|
-
```
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: File, path, process, terminal, and HTTP access must go through Effect's platform services (FileSystem, Path, ChildProcess, Terminal, HttpClient, KeyValueStore), acquired with yield*, never through node: builtins, Bun globals, or fetch. The Bun implementations must be provided once at the entry point with BunServices.layer.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
import { Effect, FileSystem, Path } from "effect";
|
|
7
|
-
import { HttpClient, HttpClientResponse } from "effect/unstable/http";
|
|
8
|
-
import { BunRuntime, BunServices } from "@effect/platform-bun";
|
|
9
|
-
|
|
10
|
-
const program = Effect.gen(function* () {
|
|
11
|
-
const fs = yield* FileSystem.FileSystem;
|
|
12
|
-
const path = yield* Path.Path;
|
|
13
|
-
const config = yield* fs.readFileString(path.join(path.resolve(), "config.json"));
|
|
14
|
-
const response = yield* HttpClient.get("https://api.example.com/users");
|
|
15
|
-
const users = yield* HttpClientResponse.schemaBodyJson(Users)(response);
|
|
16
|
-
return { config, users };
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
program.pipe(Effect.provide(BunServices.layer), BunRuntime.runMain);
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
```ts never
|
|
23
|
-
import { readFileSync } from "node:fs";
|
|
24
|
-
|
|
25
|
-
const settings = readFileSync("settings.json", "utf8");
|
|
26
|
-
```
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Service method signatures must have no requirements. Dependencies must be acquired inside the layer, never declared on the method.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
class Database extends Context.Service<
|
|
7
|
-
Database,
|
|
8
|
-
{
|
|
9
|
-
readonly query: (sql: string) => Effect.Effect<unknown[]>;
|
|
10
|
-
readonly execute: (sql: string) => Effect.Effect<void>;
|
|
11
|
-
}
|
|
12
|
-
>()("@app/Database") {}
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
```ts never
|
|
16
|
-
class Orders extends Context.Service<
|
|
17
|
-
Orders,
|
|
18
|
-
{ readonly save: (order: Order) => Effect.Effect<void, SaveError, Database> }
|
|
19
|
-
>()("@app/Orders") {}
|
|
20
|
-
```
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Layers must be provided once at the program entry. A module that is not an entry point must never call Effect.provide.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
const appLayer = userServiceLayer.pipe(
|
|
7
|
-
Layer.provideMerge(databaseLayer),
|
|
8
|
-
Layer.provideMerge(loggerLayer),
|
|
9
|
-
Layer.provideMerge(configLayer),
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
const program = Effect.gen(function* () {
|
|
13
|
-
const users = yield* UserService;
|
|
14
|
-
yield* users.getUser();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const main = program.pipe(Effect.provide(appLayer));
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
```ts never
|
|
21
|
-
export const getUser = (id: string) =>
|
|
22
|
-
UserRepo.find(id).pipe(Effect.provide(UserRepo.layer));
|
|
23
|
-
```
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: A test that depends on randomness must control it with a fixed seed through Random.withSeed, never with Math.random or an unseeded Random.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
```ts must
|
|
6
|
-
const program = Effect.gen(function* () {
|
|
7
|
-
const value1 = yield* Random.next;
|
|
8
|
-
const value2 = yield* Random.next;
|
|
9
|
-
return [value1, value2];
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
await Effect.runPromise(
|
|
13
|
-
Effect.all([program.pipe(Random.withSeed("my-seed")), program.pipe(Random.withSeed("my-seed"))]),
|
|
14
|
-
); // => [[0.018368576514773527, 0.4010840628128671], [0.018368576514773527, 0.4010840628128671]]
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
```ts never
|
|
18
|
-
it("creates unique ids", () => {
|
|
19
|
-
const id = Math.random().toString(36).slice(2);
|
|
20
|
-
expect(id).toHaveLength(11);
|
|
21
|
-
});
|
|
22
|
-
```
|