@doubleloop-io/oxlint-plugin-effect 0.1.0-rc.2 → 0.1.1

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +16 -199
  3. package/docs/user-guide/README.md +24 -0
  4. package/docs/user-guide/alongside-effect-tsgo.md +23 -0
  5. package/docs/user-guide/common-limits.md +10 -0
  6. package/docs/user-guide/configuration.md +43 -0
  7. package/docs/user-guide/default-configuration.md +88 -0
  8. package/docs/user-guide/installation.md +12 -0
  9. package/docs/user-guide/rules/adapter-import-boundary.md +27 -0
  10. package/docs/user-guide/rules/all-errors-handled-at-boundary.md +30 -0
  11. package/docs/user-guide/rules/anti-slop-no-manual-effect-error-tag.md +26 -0
  12. package/docs/user-guide/rules/anti-slop-no-service-constructor-imports.md +32 -0
  13. package/docs/user-guide/rules/anti-slop-prefer-effect-match.md +30 -0
  14. package/docs/user-guide/rules/exported-schema-identifier.md +26 -0
  15. package/docs/user-guide/rules/no-asymmetric-match-handlers.md +30 -0
  16. package/docs/user-guide/rules/no-effect-promise.md +26 -0
  17. package/docs/user-guide/rules/no-effect-return-type.md +29 -0
  18. package/docs/user-guide/rules/no-inline-schema-codec.md +26 -0
  19. package/docs/user-guide/rules/no-inline-yield-star.md +29 -0
  20. package/docs/user-guide/rules/no-manual-discriminant-comparison.md +36 -0
  21. package/docs/user-guide/rules/no-manual-discriminant-construction.md +32 -0
  22. package/docs/user-guide/rules/no-nested-match.md +44 -0
  23. package/docs/user-guide/rules/no-parameterless-catch-all.md +28 -0
  24. package/docs/user-guide/rules/no-provide-on-definition.md +27 -0
  25. package/docs/user-guide/rules/no-throw-or-primitive-failure.md +34 -0
  26. package/docs/user-guide/rules/no-transport-types-in-generator.md +41 -0
  27. package/docs/user-guide/rules/no-yielded-match.md +35 -0
  28. package/docs/user-guide/rules/prefer-effect-fn.md +31 -0
  29. package/docs/user-guide/rules/prefer-effect-vitest.md +30 -0
  30. package/docs/user-guide/rules/provide-named-layer.md +27 -0
  31. package/docs/user-guide/rules/redacted-secret-names.md +31 -0
  32. package/docs/user-guide/rules/run-only-in-runner.md +32 -0
  33. package/docs/user-guide/rules/service-built-with-of.md +36 -0
  34. package/docs/user-guide/rules/service-key-matches-name.md +29 -0
  35. package/docs/user-guide/rules/service-port-shape-only.md +27 -0
  36. package/docs/user-guide/rules/single-style-per-function.md +36 -0
  37. package/docs/user-guide/rules/split-success-path-from-error-handling.md +37 -0
  38. package/docs/user-guide/rules/try-object-form.md +27 -0
  39. package/docs/user-guide/rules/untraced-recursion.md +31 -0
  40. package/docs/user-guide/rules.md +26 -0
  41. package/docs/user-guide/shared-settings.md +65 -0
  42. package/docs/user-guide/troubleshooting.md +30 -0
  43. package/docs/user-guide/versioning.md +8 -0
  44. package/package.json +15 -9
  45. package/RULES.md +0 -1056
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: service-key-matches-name
3
+ group: Services and Layers
4
+ ---
5
+
6
+ **Intent**: a service's key is its class name, alone or after a path prefix.
7
+
8
+ ```ts
9
+ // ❌ no
10
+ export class GeocodingApis extends Context.Service<GeocodingApis, Shape>()("GeocodingAPIs") {}
11
+
12
+ // ✅ yes
13
+ export class GeocodingApis extends Context.Service<GeocodingApis, Shape>()("GeocodingApis") {}
14
+
15
+ // ✅ yes
16
+ export class GeocodingApis extends Context.Service<GeocodingApis, Shape>()(
17
+ "app/geo/GeocodingApis",
18
+ ) {}
19
+ ```
20
+
21
+ **Trigger**: `class X extends Context.Service<…>()("key")`, or the v3 `Context.Tag("key")<…>()` and `Effect.Service<X>()("key", …)`, with a literal key that is neither `"X"` nor ends with `"/X"`.
22
+
23
+ **Exemptions and blind spots**: keys that are not literals (variables, templates with expressions). A `Context.Service` assigned to a variable is not seen: see `service-not-as-class` (effecttsgo). `deterministic-keys` (effecttsgo) with the `default` or `package-identifier` formula produces keys this rule accepts; with `default-hashed` the two contradict each other: enable only one.
24
+
25
+ **Why**: the key is the service's identity in errors, traces and `Context` lookups; a key that drifts from the name, as after a rename, makes it hard to find the class behind a message.
26
+
27
+ **Options**: none
28
+
29
+ **Fix**: suggestion that replaces the last segment of the key with the class name
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: service-port-shape-only
3
+ group: Services and Layers
4
+ ---
5
+
6
+ **Intent**: a port is a shape-only `Context.Service` (v3: `Context.Tag`), with no implementation attached.
7
+
8
+ ```ts
9
+ // ❌ no
10
+ class Agent extends Context.Service<Agent, Shape>()("app/Agent", { make: makeAgent }) {}
11
+
12
+ // ✅ yes
13
+ export class Agent extends Context.Service<
14
+ Agent,
15
+ { readonly search: (name: string) => Effect.Effect<RaceCard, AgentError> }
16
+ >()("app/agent/Agent") {}
17
+ ```
18
+
19
+ **Trigger**: the second argument of `Context.Service<…>()(id, opts)`; a `static layer`, `static Default` or `static Live` member on a `Context.Service` or v3 `Context.Tag(id)<…>()` class; any `Effect.Service`.
20
+
21
+ **Exemptions and blind spots**: a `Context.Service` or v3 `Context.GenericTag` assigned to a variable is not seen: see `service-not-as-class` (effecttsgo). Statics with other names slip through.
22
+
23
+ **Why**: `make` and a static layer tie the port to a default implementation, while the port must stay a contract any adapter can satisfy. It is a convention, not Effect's idiom: Effect's own docs put `static readonly layer` on the service.
24
+
25
+ **Options**: none
26
+
27
+ **Fix**: none
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: single-style-per-function
3
+ group: Effectful functions
4
+ ---
5
+
6
+ **Intent**: a function is entirely Effect or not Effect at all.
7
+
8
+ ```ts
9
+ // ❌ no
10
+ export const POST = async (request: Request) => {
11
+ const form = await request.formData()
12
+ const created = await Effect.runPromise(Effect.result(createEvent(form)))
13
+ // …
14
+ }
15
+
16
+ // ✅ yes: promises lifted with Effect.tryPromise
17
+ const createEvent = Effect.fn("events.create")(function* (request: Request) {
18
+ const form = yield* Effect.tryPromise({
19
+ try: () => request.formData(),
20
+ catch: () => new BadRequest({ message: "invalid form data" }),
21
+ })
22
+ // …
23
+ })
24
+ ```
25
+
26
+ **Trigger**: `async`, `await` and `.then(` in a function that builds Effects: an Effect generator, or a function using an `Effect.*` member. A `test`/`it` callback (`.only`, `.each(…)` and the like included) or a `beforeAll`/`afterAll`/`beforeEach`/`afterEach` hook, and in test files any other function except an Effect generator, is reported once, on the function, when more than one of its `await`s, or any `.then(`, involves Effect: has an `Effect.*` member in its expression, nested callbacks and `Effect.run*` included.
27
+
28
+ **Exemptions and blind spots**: `Effect.run*` alone does not make a function effectful: it is how an async boundary hands over to Effect, and where it may appear is decided by [`run-only-in-runner`](run-only-in-runner.md). An `async` function that renders JSX itself, not only in nested callbacks, is a Server Component: how it turns failures into UI is left to the application. A test, hook or test helper may await promise-based fixtures (a container, an identity provider), then one Effect program, and assert on its result. A step that reaches Effect only through a helper (`await run(seed)`) is not counted.
29
+
30
+ **Why**: errors travel on two channels, exceptions and Effect, and neither sees them all.
31
+
32
+ **Options**:
33
+
34
+ - `testFiles`: shared setting, see [Shared settings](../shared-settings.md).
35
+
36
+ **Fix**: none
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: split-success-path-from-error-handling
3
+ group: Error channel
4
+ ---
5
+
6
+ **Intent**: the generator holds only the happy path; error handling lives in the second argument of `Effect.fn`.
7
+
8
+ ```ts
9
+ // ❌ no
10
+ function* () {
11
+ const x = yield* fetchThing.pipe(Effect.catchTag("NotFound", () => Effect.succeed(fallback)))
12
+ }
13
+
14
+ // ✅ yes: naming the error or giving an alternative is not handling
15
+ function* () {
16
+ const x = yield* fetchThing.pipe(Effect.orElseSucceed(() => fallback))
17
+ const y = yield* decode(raw).pipe(Effect.mapError((error) => new BadRequest({ message: error.message })))
18
+ }
19
+
20
+ // ✅ yes: translation in the second argument, which also receives the original arguments
21
+ const createEvent = Effect.fn("events.create")(
22
+ function* (request: Request) { /* success only */ },
23
+ (effect, request) => effect.pipe(Effect.catchTags({ BadRequest: (e) => refused(400, e.message) })),
24
+ )
25
+ ```
26
+
27
+ **Trigger**: inside a generator passed to `Effect.gen`/`Effect.fn`, callbacks passed to `Effect.*` combinators included, calls to `Effect.catch*` (`catch`, `catchAll`, `catchTag`, `catchTags`, `catchIf`, `catchCause`, `catchDefect`, `catchReason`, …), `either`, `result`, `exit`, `match*` and `sandbox`.
28
+
29
+ **Exemptions and blind spots**: pipeables of a nested `Effect.fn`. Handlers inside the callback of an iteration (`forEach`, `filter`, `reduce`, `partition`, `validate`, `findFirst`, …): they handle each element on its own, and in the pipeables the first failure would stop the rest. Functions the generator only defines, such as an `HttpApiBuilder` handler or a service method: they are programs of their own. Test files, where the failure is the outcome under observation (`yield* Effect.result(op)` then `expect`). A `catch`, `catchTag`, `catchTags`, `catchIf` or `catchFilter` whose handlers only die (`Effect.die` passed directly or as the sole return): it is a selective `orDie`, declaring the case untracked rather than handling it; a die behind a wrapper or a condition is still reported. A `.pipe(Effect.catch…)` appended to an `Effect.gen` escapes; [`prefer-effect-fn`](prefer-effect-fn.md) closes that gap.
30
+
31
+ **Why**: translation becomes a single exhaustive point instead of catches scattered along the flow.
32
+
33
+ **Options**:
34
+
35
+ - `testFiles`: shared setting, see [Shared settings](../shared-settings.md).
36
+
37
+ **Fix**: none
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: try-object-form
3
+ group: Error channel
4
+ ---
5
+
6
+ **Intent**: `Effect.try` and `Effect.tryPromise` take `{ try, catch }`, with `catch` producing a tagged error.
7
+
8
+ ```ts
9
+ // ❌ no
10
+ Effect.tryPromise(() => api.spreadsheets.get({ spreadsheetId }))
11
+
12
+ // ✅ yes
13
+ Effect.tryPromise({
14
+ try: () => api.spreadsheets.get({ spreadsheetId }),
15
+ catch: toSheetError(spreadsheetId),
16
+ })
17
+ ```
18
+
19
+ **Trigger**: `Effect.try` and `Effect.tryPromise` whose argument is not an object literal.
20
+
21
+ **Exemptions and blind spots**: an options object held in a variable is reported too.
22
+
23
+ **Why**: the thunk form types the error as `Cause.UnknownError` (`UnknownException` in v3), which no caller can handle by tag.
24
+
25
+ **Options**: none
26
+
27
+ **Fix**: none
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: untraced-recursion
3
+ group: Effectful functions
4
+ ---
5
+
6
+ **Intent**: a recursive effectful function uses `Effect.fnUntraced`; the entry point that starts the recursion is traced.
7
+
8
+ ```ts
9
+ // ❌ no
10
+ const walk = Effect.fn("walk")(function* (node: Node) {
11
+ for (const child of node.children) yield* walk(child)
12
+ })
13
+
14
+ // ✅ yes
15
+ const walk = Effect.fnUntraced(function* (node: Node) {
16
+ for (const child of node.children) yield* walk(child)
17
+ })
18
+ export const scan = Effect.fn("scan")(function* (root: Node) {
19
+ return yield* walk(root)
20
+ })
21
+ ```
22
+
23
+ **Trigger**: an `Effect.fn` assigned to a variable that its own body calls again, even by passing it as a callback.
24
+
25
+ **Exemptions and blind spots**: mutual recursion, recursion in pipeables.
26
+
27
+ **Why**: with `Effect.fn` every level opens a span nested in the previous one.
28
+
29
+ **Options**: none
30
+
31
+ **Fix**: none
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: Rules overview
3
+ ---
4
+
5
+ What each rule reports and why is on its page. Report false positives and missed cases in the [GitHub issues](https://github.com/doubleloop-io/oxlint-plugin-effect/issues).
6
+
7
+ | Topic | Rules |
8
+ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | Error channel | [`no-throw-or-primitive-failure`](rules/no-throw-or-primitive-failure.md), [`try-object-form`](rules/try-object-form.md), [`no-effect-promise`](rules/no-effect-promise.md), [`no-parameterless-catch-all`](rules/no-parameterless-catch-all.md), [`split-success-path-from-error-handling`](rules/split-success-path-from-error-handling.md), [`anti-slop-no-manual-effect-error-tag`](rules/anti-slop-no-manual-effect-error-tag.md) |
10
+ | Tagged values | [`no-manual-discriminant-comparison`](rules/no-manual-discriminant-comparison.md), [`no-manual-discriminant-construction`](rules/no-manual-discriminant-construction.md) |
11
+ | Services and Layers | [`service-port-shape-only`](rules/service-port-shape-only.md), [`service-key-matches-name`](rules/service-key-matches-name.md), [`service-built-with-of`](rules/service-built-with-of.md), [`provide-named-layer`](rules/provide-named-layer.md), [`no-provide-on-definition`](rules/no-provide-on-definition.md), [`anti-slop-no-service-constructor-imports`](rules/anti-slop-no-service-constructor-imports.md) |
12
+ | Runtime and entry point | [`run-only-in-runner`](rules/run-only-in-runner.md), [`prefer-effect-vitest`](rules/prefer-effect-vitest.md), [`all-errors-handled-at-boundary`](rules/all-errors-handled-at-boundary.md) |
13
+ | Design and boundaries | [`adapter-import-boundary`](rules/adapter-import-boundary.md), [`no-transport-types-in-generator`](rules/no-transport-types-in-generator.md) |
14
+ | Effectful functions | [`prefer-effect-fn`](rules/prefer-effect-fn.md), [`untraced-recursion`](rules/untraced-recursion.md), [`single-style-per-function`](rules/single-style-per-function.md) |
15
+ | Code shape | [`no-nested-match`](rules/no-nested-match.md), [`no-yielded-match`](rules/no-yielded-match.md), [`no-inline-yield-star`](rules/no-inline-yield-star.md), [`no-effect-return-type`](rules/no-effect-return-type.md), [`no-asymmetric-match-handlers`](rules/no-asymmetric-match-handlers.md), [`anti-slop-prefer-effect-match`](rules/anti-slop-prefer-effect-match.md) |
16
+ | Schema | [`exported-schema-identifier`](rules/exported-schema-identifier.md), [`no-inline-schema-codec`](rules/no-inline-schema-codec.md) |
17
+ | Config and secrets | [`redacted-secret-names`](rules/redacted-secret-names.md) |
18
+
19
+ ## Absorbed from anti-slop
20
+
21
+ Some rules come from the Effect rules of [`dmmulroy/anti-slop`](https://github.com/dmmulroy/anti-slop), MIT-licensed: see [`LICENSE.anti-slop`](../../LICENSE.anti-slop).
22
+
23
+ | Status | Rules |
24
+ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
25
+ | Imported | [`anti-slop-no-manual-effect-error-tag`](rules/anti-slop-no-manual-effect-error-tag.md), [`anti-slop-no-service-constructor-imports`](rules/anti-slop-no-service-constructor-imports.md), [`anti-slop-prefer-effect-match`](rules/anti-slop-prefer-effect-match.md) |
26
+ | Superseded | `no-manual-tag-comparison` → [`no-manual-discriminant-comparison`](rules/no-manual-discriminant-comparison.md), `no-manual-tagged-construction` → [`no-manual-discriminant-construction`](rules/no-manual-discriminant-construction.md) |
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Shared settings
3
+ order: 3
4
+ ---
5
+
6
+ Three settings describe your project, not a rule, so they are declared once under `settings["dl-effect"]` in the oxlint config and every rule that uses them reads them from there. Their defaults fit a Node CLI; on another layout (Next.js, a monorepo) set them before reading the warnings.
7
+
8
+ ## The settings
9
+
10
+ | Setting | Default | Used by |
11
+ | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
12
+ | `entryFiles`: the files allowed to run Effects and import adapters | `**/main.ts`, `**/cli.ts`, `**/bin/**` | [`run-only-in-runner`](rules/run-only-in-runner.md), [`adapter-import-boundary`](rules/adapter-import-boundary.md) |
13
+ | `testFiles`: the test files, exempt from the rules that tests legitimately break | `**/*.test.*`, `**/*.spec.*`, `**/__tests__/**`, `**/test/**`, `**/tests/**` | [`run-only-in-runner`](rules/run-only-in-runner.md), [`adapter-import-boundary`](rules/adapter-import-boundary.md), [`no-effect-promise`](rules/no-effect-promise.md), [`provide-named-layer`](rules/provide-named-layer.md), [`no-provide-on-definition`](rules/no-provide-on-definition.md), [`split-success-path-from-error-handling`](rules/split-success-path-from-error-handling.md), [`all-errors-handled-at-boundary`](rules/all-errors-handled-at-boundary.md), [`anti-slop-no-service-constructor-imports`](rules/anti-slop-no-service-constructor-imports.md), [`no-throw-or-primitive-failure`](rules/no-throw-or-primitive-failure.md), [`single-style-per-function`](rules/single-style-per-function.md), [`prefer-effect-vitest`](rules/prefer-effect-vitest.md) |
14
+ | `discriminants`: the fields that discriminate a closed union | `_tag` | [`no-manual-discriminant-comparison`](rules/no-manual-discriminant-comparison.md), [`no-manual-discriminant-construction`](rules/no-manual-discriminant-construction.md) |
15
+
16
+ The default `entryFiles` leave out `index.ts` on purpose: it is usually a barrel, and exempting it would let adapters reach the rest of the application through re-exports.
17
+
18
+ Most rules skip `testFiles` entirely. Three use them differently: [`no-throw-or-primitive-failure`](rules/no-throw-or-primitive-failure.md) skips only primitive failures there, [`single-style-per-function`](rules/single-style-per-function.md) treats their helpers like tests, and [`prefer-effect-vitest`](rules/prefer-effect-vitest.md) checks only them. A helper directory such as `src/testing/` does not count as tests: it is support code.
19
+
20
+ Add to `discriminants` the fields your unions discriminate on, such as `type` or `kind`.
21
+
22
+ File globs are matched against the path relative to oxlint's working directory, with `/` on every platform.
23
+
24
+ ## Setting a value
25
+
26
+ Set one only where its default does not fit: it **replaces** the default instead of extending it. To extend a default in a TypeScript config, spread the one the package exports: `defaultEntryFiles`, `defaultTestFiles` or `defaultDiscriminants`. A JSON config cannot import them: copy the default from the table above. An unknown key or a value that is not an array of strings stops the lint with an error, so a typo is never silently ignored.
27
+
28
+ ```ts
29
+ import { defaultTestFiles } from "@doubleloop-io/oxlint-plugin-effect"
30
+ import dlEffectAll from "@doubleloop-io/oxlint-plugin-effect/presets/all"
31
+ import { defineConfig } from "oxlint"
32
+
33
+ export default defineConfig({
34
+ extends: [dlEffectAll],
35
+ settings: {
36
+ "dl-effect": {
37
+ entryFiles: ["apps/web/src/app/**/route.ts", "apps/web/src/runtime.ts"],
38
+ testFiles: [...defaultTestFiles, "e2e/**"],
39
+ },
40
+ },
41
+ })
42
+ ```
43
+
44
+ ```json
45
+ {
46
+ "extends": ["./node_modules/@doubleloop-io/oxlint-plugin-effect/dist/presets/all.json"],
47
+ "settings": {
48
+ "dl-effect": {
49
+ "entryFiles": ["apps/web/src/app/**/route.ts", "apps/web/src/runtime.ts"],
50
+ "testFiles": [
51
+ "**/*.test.*",
52
+ "**/*.spec.*",
53
+ "**/__tests__/**",
54
+ "**/test/**",
55
+ "**/tests/**",
56
+ "e2e/**"
57
+ ]
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## Where settings go
64
+
65
+ Settings belong to the config that lints: oxlint does not inherit them from a preset in `extends`, and rejects them in `overrides`. For a value that differs by group of files, use `overrides` on the rules instead.
@@ -0,0 +1,30 @@
1
+ ---
2
+ title: Troubleshooting
3
+ order: 8
4
+ ---
5
+
6
+ The problems most often hit when adopting the plugin: each states the symptom, the cause and the fix.
7
+
8
+ ## The lint stops with a settings error
9
+
10
+ - **Symptom**: oxlint exits with an error naming a `dl-effect` setting before reporting anything.
11
+ - **Cause**: a key under `settings["dl-effect"]` is not one of the shared settings, or its value is not an array of strings.
12
+ - **Fix**: correct the key or the value as described in [Shared settings](shared-settings.md#setting-a-value).
13
+
14
+ ## Settings are ignored or rejected
15
+
16
+ - **Symptom**: settings put in a preset in `extends` have no effect, or oxlint rejects settings put in `overrides`.
17
+ - **Cause**: oxlint reads settings only from the config that lints.
18
+ - **Fix**: move them to that config, as described in [Where settings go](shared-settings.md#where-settings-go).
19
+
20
+ ## Many warnings on correct code
21
+
22
+ - **Symptom**: on a layout that is not a Node CLI, such as Next.js or a monorepo, many warnings look like false positives, for example Effects run or adapters imported outside the entry files.
23
+ - **Cause**: the defaults of `entryFiles` and `testFiles` fit a Node CLI.
24
+ - **Fix**: set both for your layout, as described in [Shared settings](shared-settings.md#the-settings).
25
+
26
+ ## No warnings on code that uses aliases
27
+
28
+ - **Symptom**: a file that breaks the rules gets no warnings.
29
+ - **Cause**: the rules recognize literal names only: see [Common limits](common-limits.md).
30
+ - **Fix**: import Effect modules under their own names where you want the rules to check the code.
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Versioning
3
+ order: 7
4
+ ---
5
+
6
+ Versions are `0.x`: any minor release may add, remove or change rules, options, settings and messages.
7
+
8
+ Supported oxlint is the `peerDependencies` range, `^1.82.0`; CI tests the tarball against `1.82.0`. oxlint's JS plugin API is still experimental, so a newer oxlint minor may break the plugin before the range is narrowed.
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@doubleloop-io/oxlint-plugin-effect",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.1",
4
4
  "description": "Oxlint rules for Effect 4 code",
5
+ "homepage": "https://doubleloop-io.github.io/oxlint-plugin-effect/",
5
6
  "license": "MIT",
6
7
  "repository": {
7
8
  "type": "git",
@@ -9,8 +10,9 @@
9
10
  },
10
11
  "files": [
11
12
  "dist/",
12
- "RULES.md",
13
+ "docs/user-guide/",
13
14
  "README.md",
15
+ "CHANGELOG.md",
14
16
  "LICENSE",
15
17
  "LICENSE.anti-slop"
16
18
  ],
@@ -33,6 +35,8 @@
33
35
  "@oxlint/plugins": "^1.82.0"
34
36
  },
35
37
  "devDependencies": {
38
+ "@changesets/changelog-github": "^1.0.1",
39
+ "@changesets/cli": "^3.0.3",
36
40
  "@types/node": "^24.13.6",
37
41
  "oxfmt": "0.67.0",
38
42
  "oxlint": "1.82.0",
@@ -50,14 +54,16 @@
50
54
  "format:check": "oxfmt --check",
51
55
  "typecheck": "tsc --noEmit",
52
56
  "lint": "oxlint --deny-warnings",
53
- "test": "node --test rules-md.test.ts rules/*.test.ts shared/*.test.ts scripts/*.test.ts",
57
+ "test": "node --test src/rule-files.test.ts src/rules/*.test.ts src/shared/*.test.ts",
54
58
  "check": "pnpm format:check && pnpm typecheck && pnpm lint && pnpm test",
55
- "build": "rm -rf dist && tsc -p tsconfig.build.json && node presets/all-json.ts",
56
- "build:w": "node --watch-path=index.ts --watch-path=rules --watch-path=presets --watch-path=shared --watch-path=tsconfig.build.json scripts/build.ts",
57
- "pack:check": "node --test presets/all-dist.test.ts && node scripts/pack-check.ts",
58
- "build-and-pack": "pnpm check && pnpm build && pnpm pack:check && pnpm smoke-test",
59
- "smoke-test": "node scripts/smoke-test.ts",
60
- "release": "node scripts/release.ts",
59
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/preset-all-json.ts",
60
+ "build:w": "node --watch-path=src --watch-path=tsconfig.build.json scripts/build.ts",
61
+ "pack:check": "node --test scripts/preset-all-dist-check.ts && node scripts/pack-check.ts",
62
+ "build-and-pack": "pnpm check && pnpm build && pnpm pack:check && pnpm consumer-test",
63
+ "consumer-test": "node scripts/consumer-test.ts",
64
+ "changeset-version": "changeset version && pnpm format",
65
+ "changeset-publish": "pnpm build-and-pack && changeset publish",
66
+ "changeset-status": "changeset status --verbose",
61
67
  "consumer:link": "./scripts/link-consumer.sh link",
62
68
  "consumer:unlink": "./scripts/link-consumer.sh unlink"
63
69
  }