Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-runners-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/language-service": patch
---

Update Effect v4 compatibility to 4.0.0-rc.115 and allow `Effect.provide` at recognized application entry points.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ specs/
.context/
.cuggino.json
.cuggino/
.zvec-grep
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
},
"pnpm": {
"overrides": {
"@effect/platform-node-shared": "4.0.0-beta.107"
"@effect/platform-node-shared": "4.0.0-rc.115"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
strictEffectProvide_skipNextLine from 667 to 714
strictEffectProvide_skipFile from 667 to 714
strictEffectProvide_skipNextLine from 525 to 559
strictEffectProvide_skipFile from 525 to 559
strictEffectProvide_skipNextLine from 833 to 867
strictEffectProvide_skipFile from 833 to 867
strictEffectProvide_skipNextLine from 991 to 1061
strictEffectProvide_skipFile from 991 to 1061
strictEffectProvide_skipNextLine from 2432 to 2466
strictEffectProvide_skipFile from 2432 to 2466
strictEffectProvide_skipNextLine from 769 to 816
strictEffectProvide_skipFile from 769 to 816
strictEffectProvide_skipNextLine from 627 to 661
strictEffectProvide_skipFile from 627 to 661
strictEffectProvide_skipNextLine from 935 to 969
strictEffectProvide_skipFile from 935 to 969
strictEffectProvide_skipNextLine from 1093 to 1163
strictEffectProvide_skipFile from 1093 to 1163
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
Effect.provide(MyService1.Default)
18:2 - 18:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)
20:2 - 20:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)

Effect.provide(Effect.void, MyService1.Default)
22:29 - 22:76 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)
24:29 - 24:76 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)

Effect.provide(MyService1.Default)
27:2 - 27:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)
29:2 - 29:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)

Effect.provide(Layer.mergeAll(MyService1.Default, MyService2.Default))
33:2 - 33:72 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)
35:2 - 35:72 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)

Effect.provide(MyService1.Default)
79:17 - 79:51 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// @effect-diagnostics strictEffectProvide:warning
import { BunRuntime } from "@effect/platform-bun"
import { NodeRuntime } from "@effect/platform-node"
import { Context, Effect, Layer } from "effect"

class MyService1 extends Context.Service<MyService1>()("MyService1", {
Expand Down Expand Up @@ -49,3 +51,29 @@ export const shouldNotReport3 = Effect.gen(function*() {
const ctx = yield* Effect.context<MyService1>()
return yield* Effect.provide(Effect.void, ctx)
})

// Should NOT report: entry-point runners
Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.runPromise
)

Effect.runSync(
Effect.void.pipe(Effect.provide(MyService1.Default))
)

Effect.runFork(Effect.provide(Effect.void, MyService1.Default))
Effect.runPromiseExit(Effect.void.pipe(Effect.provide(MyService1.Default)))
Effect.runSyncExit(Effect.void.pipe(Effect.provide(MyService1.Default)))

NodeRuntime.runMain(
Effect.void.pipe(Effect.provide(MyService1.Default))
)

BunRuntime.runMain(
Effect.void.pipe(Effect.provide(MyService1.Default))
)

// Should report: a similarly named local function is not an entry point
const FakeEffect = { runPromise: <A>(value: A) => value }
Effect.void.pipe(Effect.provide(MyService1.Default), FakeEffect.runPromise)
4 changes: 3 additions & 1 deletion packages/harness-effect-v4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"check": "tsc -b tsconfig.json"
},
"dependencies": {
"@effect/platform-bun": "4.0.0-rc.115",
"@effect/platform-node": "4.0.0-rc.115",
"@standard-schema/spec": "^1.1.0",
"effect": "4.0.0-beta.107"
"effect": "4.0.0-rc.115"
},
"devDependencies": {
"@types/node": "^25.0.6"
Expand Down
4 changes: 2 additions & 2 deletions packages/language-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@
"perf": "tsx test/perf.ts"
},
"devDependencies": {
"@effect/platform-node": "4.0.0-beta.107",
"@effect/platform-node": "4.0.0-rc.115",
"@types/pako": "^2.0.4",
"@typescript-eslint/project-service": "^8.52.0",
"effect": "4.0.0-beta.107",
"effect": "4.0.0-rc.115",
"pako": "^2.1.0",
"ts-patch": "^3.3.0"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/language-service/src/cli/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { extractAppliedEffectLspPatches, getModuleFilePath, getPackageJsonData,

const LOCAL_TYPESCRIPT_DIR = "./node_modules/typescript"

const dirPath = Flag.directory("dir").pipe(
const dirPath = Flag.Directory("dir").pipe(
Flag.withDefault(LOCAL_TYPESCRIPT_DIR),
Flag.withDescription("The directory of the typescript package to patch.")
)
Expand Down
8 changes: 4 additions & 4 deletions packages/language-service/src/cli/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ export class NoFilesToCodegenError extends Data.TaggedError("NoFilesToCodegenErr
}
}

const file = Flag.file("file").pipe(
const file = Flag.File("file").pipe(
Flag.optional,
Flag.withDescription("The full path of the file to codegen.")
)

const project = Flag.file("project").pipe(
const project = Flag.File("project").pipe(
Flag.optional,
Flag.withDescription("The full path of the project tsconfig.json file to codegen.")
)

const verbose = Flag.boolean("verbose").pipe(
const verbose = Flag.Boolean("verbose").pipe(
Flag.withDefault(false),
Flag.withDescription("Verbose output.")
)

const force = Flag.boolean("force").pipe(
const force = Flag.Boolean("force").pipe(
Flag.withDefault(false),
Flag.withDescription("Force codegen even if no changes are needed.")
)
Expand Down
14 changes: 7 additions & 7 deletions packages/language-service/src/cli/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,35 +289,35 @@ const BATCH_SIZE = 50
export const diagnostics = Command.make(
"diagnostics",
{
file: Flag.file("file").pipe(
file: Flag.File("file").pipe(
Flag.optional,
Flag.withDescription("The full path of the file to check for diagnostics.")
),
project: Flag.file("project").pipe(
project: Flag.File("project").pipe(
Flag.optional,
Flag.withDescription("The full path of the project tsconfig.json file to check for diagnostics.")
),

format: Flag.choice("format", ["json", "pretty", "text", "github-actions"] as ReadonlyArray<OutputFormat>)
format: Flag.Literals("format", ["json", "pretty", "text", "github-actions"] as ReadonlyArray<OutputFormat>)
.pipe(
Flag.withDefault("pretty" as const),
Flag.withDescription(
"Output format: json (machine-readable), pretty (colored with context), text (plain text), github-actions (workflow commands)"
)
),
strict: Flag.boolean("strict").pipe(
strict: Flag.Boolean("strict").pipe(
Flag.withDefault(false),
Flag.withDescription("Treat warnings as errors (affects exit code)")
),
severity: Flag.string("severity").pipe(
severity: Flag.String("severity").pipe(
Flag.optional,
Flag.withDescription("Filter by severity levels (comma-separated: error,warning,message)")
),
progress: Flag.boolean("progress").pipe(
progress: Flag.Boolean("progress").pipe(
Flag.withDefault(false),
Flag.withDescription("Show progress as files are checked (outputs to stderr)")
),
lspconfig: Flag.string("lspconfig").pipe(
lspconfig: Flag.String("lspconfig").pipe(
Flag.optional,
Flag.withDescription(
"An optional inline JSON lsp config that replaces the current project lsp config. e.g. '{ \"effectFn\": [\"untraced\"] }'"
Expand Down
6 changes: 3 additions & 3 deletions packages/language-service/src/cli/layerinfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,13 +423,13 @@ const parseOutputIndices = (outputs: Option.Option<string>): ReadonlyArray<numbe
export const layerInfo = Command.make(
"layerinfo",
{
file: Flag.file("file").pipe(
file: Flag.File("file").pipe(
Flag.withDescription("The full path of the file containing the layer.")
),
name: Flag.string("name").pipe(
name: Flag.String("name").pipe(
Flag.withDescription("The name of the exported layer to inspect.")
),
outputs: Flag.string("outputs").pipe(
outputs: Flag.String("outputs").pipe(
Flag.withDescription(
"Comma-separated list of output indices to include in suggested composition (e.g., 1,2,3). If not specified, all outputs are included."
),
Expand Down
6 changes: 3 additions & 3 deletions packages/language-service/src/cli/overview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,15 +417,15 @@ const collectAllItems = (
export const overview = Command.make(
"overview",
{
file: Flag.file("file").pipe(
file: Flag.File("file").pipe(
Flag.optional,
Flag.withDescription("The full path of the file to analyze.")
),
project: Flag.file("project").pipe(
project: Flag.File("project").pipe(
Flag.optional,
Flag.withDescription("The full path of the project tsconfig.json file to analyze.")
),
maxSymbolDepth: Flag.integer("max-symbol-depth").pipe(
maxSymbolDepth: Flag.Int("max-symbol-depth").pipe(
Flag.withDefault(3),
Flag.withDescription(
"Maximum depth to traverse nested symbol properties. 0 = only root exports, 1 = root + one level, etc."
Expand Down
6 changes: 3 additions & 3 deletions packages/language-service/src/cli/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ export class UnableToFindPositionToPatchError extends Data.TaggedError("UnableTo

const LOCAL_TYPESCRIPT_DIR = "./node_modules/typescript"

const dirPath = Flag.directory("dir").pipe(
const dirPath = Flag.Directory("dir").pipe(
Flag.withDefault(LOCAL_TYPESCRIPT_DIR),
Flag.withDescription("The directory of the typescript package to patch.")
)

const moduleNames = Flag.choice("module", [
const moduleNames = Flag.Literals("module", [
"tsc",
"typescript"
]).pipe(
Flag.atLeast(0),
Flag.withDescription("The name of the module to patch.")
)

const force = Flag.boolean("force").pipe(
const force = Flag.Boolean("force").pipe(
Flag.withDefault(false),
Flag.withDescription("Force patch even if already patched.")
)
Expand Down
12 changes: 6 additions & 6 deletions packages/language-service/src/cli/quickfixes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ const BATCH_SIZE = 50
export const quickfixes = Command.make(
"quickfixes",
{
file: Flag.file("file").pipe(
file: Flag.File("file").pipe(
Flag.optional,
Flag.withDescription("The full path of the file to check for quick fixes.")
),
project: Flag.file("project").pipe(
project: Flag.File("project").pipe(
Flag.optional,
Flag.withDescription("The full path of the project tsconfig.json file to check for quick fixes.")
),
code: Flag.string("code").pipe(
code: Flag.String("code").pipe(
Flag.withDescription("Filter by diagnostic name or code (e.g., 'floatingEffect' or '5')."),
Flag.mapEffect((value) => {
// Validate that the code is a known diagnostic name or code
Expand All @@ -147,15 +147,15 @@ export const quickfixes = Command.make(
}),
Flag.optional
),
line: Flag.integer("line").pipe(
line: Flag.Int("line").pipe(
Flag.withDescription("Filter by line number (1-based)."),
Flag.optional
),
column: Flag.integer("column").pipe(
column: Flag.Int("column").pipe(
Flag.withDescription("Filter by column number (1-based). Requires --line to be specified."),
Flag.optional
),
fix: Flag.string("fix").pipe(
fix: Flag.String("fix").pipe(
Flag.withDescription("Filter by fix name (e.g., 'floatingEffect_yieldStar')."),
Flag.optional
)
Expand Down
2 changes: 1 addition & 1 deletion packages/language-service/src/cli/setup/changes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,7 @@ export const reviewAndApplyChanges = (
return
}

const shouldProceed = yield* Prompt.confirm({
const shouldProceed = yield* Prompt.Confirm({
message: options?.confirmMessage ?? "Apply all changes?",
initial: true
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ export function createDiagnosticPrompt(
): Prompt.Prompt<Record<string, DiagnosticSeverity | "off">> {
const entries = getPromptEntries(diagnostics)

return Prompt.custom(buildState(entries, 0, "", initialSeverities), {
return Prompt.Custom(buildState(entries, 0, "", initialSeverities), {
render: (state, action) => {
switch (action._tag) {
case "Beep":
Expand Down
8 changes: 4 additions & 4 deletions packages/language-service/src/cli/setup/target-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const gatherTargetState = (
})

// Ask what user wants to do
const lspDependencyType = yield* Prompt.select({
const lspDependencyType = yield* Prompt.Select({
message: "Language service installation:",
choices: [
{
Expand Down Expand Up @@ -73,7 +73,7 @@ export const gatherTargetState = (
onSome: (options) => options.diagnosticSeverity
})

const selectedDiagnosticModes = yield* Prompt.multiSelect({
const selectedDiagnosticModes = yield* Prompt.MultiSelect({
message: "Which diagnostic presets would you like to use?",
choices: [
{
Expand Down Expand Up @@ -113,7 +113,7 @@ export const gatherTargetState = (
onSome: (script) => script.hasPatch
})

const prepareScript = yield* Prompt.select({
const prepareScript = yield* Prompt.Select({
message: "Enable language service diagnostics during TypeScript compilation?",
choices: [
{
Expand All @@ -136,7 +136,7 @@ export const gatherTargetState = (
// Pre-select VSCode if .vscode/settings.json exists
const hasVscodeSettings = Option.isSome(assessment.vscodeSettings)

const editors = yield* Prompt.multiSelect({
const editors = yield* Prompt.MultiSelect({
message: "Which editors do you use?",
choices: [
{
Expand Down
4 changes: 2 additions & 2 deletions packages/language-service/src/cli/setup/tsconfig-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const findTsConfigFiles = (
})

const promptForTsConfigPath = (currentDir: string) =>
Prompt.file({
Prompt.File({
type: "file",
message: "Select tsconfig to configure",
startingPath: currentDir,
Expand Down Expand Up @@ -65,7 +65,7 @@ export const selectTsConfigFile = (
}
]

const selected = yield* Prompt.select({
const selected = yield* Prompt.Select({
message: "Select tsconfig to configure",
choices
})
Expand Down
4 changes: 2 additions & 2 deletions packages/language-service/src/cli/unpatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { getModuleFilePath, getSourceFileText, getUnpatchedSourceFile } from "./

const LOCAL_TYPESCRIPT_DIR = "./node_modules/typescript"

const dirPath = Flag.directory("dir").pipe(
const dirPath = Flag.Directory("dir").pipe(
Flag.withDefault(LOCAL_TYPESCRIPT_DIR),
Flag.withDescription("The directory of the typescript package to patch.")
)

const moduleNames = Flag.choice("module", [
const moduleNames = Flag.Literals("module", [
"tsc",
"typescript"
]).pipe(
Expand Down
Loading
Loading