@effect/language-service 0.67.0 → 0.68.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/README.md +1 -0
- package/cli.js +132 -11
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +74 -4
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +74 -4
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +74 -4
- package/transform.js.map +1 -1
package/README.md
CHANGED
|
@@ -82,6 +82,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
|
|
|
82
82
|
- Warn when `Layer.mergeAll` contains layers with interdependencies (where one layer provides a service that another layer in the same call requires)
|
|
83
83
|
- Suggest using `Effect.fn` for functions that return `Effect.gen` for better tracing and concise syntax
|
|
84
84
|
- Suggest removing redundant identifier argument when it equals the tag value in `Schema.TaggedClass`, `Schema.TaggedError`, or `Schema.TaggedRequest`
|
|
85
|
+
- Suggest using `Schema.is` instead of `instanceof` for Effect Schema types
|
|
85
86
|
|
|
86
87
|
### Completions
|
|
87
88
|
|
package/cli.js
CHANGED
|
@@ -26161,6 +26161,7 @@ var text7 = (name) => makeSingle(name, empty2(), text6);
|
|
|
26161
26161
|
var getHelp3 = (self) => getHelpInternal2(self);
|
|
26162
26162
|
var getUsage = (self) => getUsageInternal(self);
|
|
26163
26163
|
var map29 = /* @__PURE__ */ dual(2, (self, f) => makeMap(self, (a) => right2(f(a))));
|
|
26164
|
+
var mapEffect5 = /* @__PURE__ */ dual(2, (self, f) => makeMap(self, f));
|
|
26164
26165
|
var optional3 = (self) => withDefault2(map29(self, some2), none2());
|
|
26165
26166
|
var orElse14 = /* @__PURE__ */ dual(2, (self, that) => orElseEither4(self, that).pipe(map29(merge)));
|
|
26166
26167
|
var orElseEither4 = /* @__PURE__ */ dual(2, (self, that) => makeOrElse(self, that));
|
|
@@ -27122,6 +27123,7 @@ var directory2 = directory;
|
|
|
27122
27123
|
var file3 = file2;
|
|
27123
27124
|
var integer5 = integer4;
|
|
27124
27125
|
var text8 = text7;
|
|
27126
|
+
var mapEffect6 = mapEffect5;
|
|
27125
27127
|
var optional4 = optional3;
|
|
27126
27128
|
var repeated4 = repeated3;
|
|
27127
27129
|
var withDefault3 = withDefault2;
|
|
@@ -27173,8 +27175,8 @@ var none11 = /* @__PURE__ */ (() => {
|
|
|
27173
27175
|
})();
|
|
27174
27176
|
var getHelp4 = (self) => getHelpInternal3(self);
|
|
27175
27177
|
var getUsage2 = (self) => getUsageInternal2(self);
|
|
27176
|
-
var map30 = /* @__PURE__ */ dual(2, (self, f) =>
|
|
27177
|
-
var
|
|
27178
|
+
var map30 = /* @__PURE__ */ dual(2, (self, f) => mapEffect7(self, (a) => succeed7(f(a))));
|
|
27179
|
+
var mapEffect7 = /* @__PURE__ */ dual(2, (self, f) => makeMap2(self, f));
|
|
27178
27180
|
var validate5 = /* @__PURE__ */ dual(3, (self, args3, config2) => validateInternal2(self, args3, config2));
|
|
27179
27181
|
var wizard3 = /* @__PURE__ */ dual(2, (self, config2) => wizardInternal3(self, config2));
|
|
27180
27182
|
var allTupled2 = (arg) => {
|
|
@@ -27615,8 +27617,8 @@ var getFishCompletions4 = (self, executable) => getFishCompletionsInternal(self,
|
|
|
27615
27617
|
var getZshCompletions4 = (self, executable) => getZshCompletionsInternal(self, executable);
|
|
27616
27618
|
var getSubcommands = (self) => fromIterable6(getSubcommandsInternal(self));
|
|
27617
27619
|
var getUsage3 = (self) => getUsageInternal3(self);
|
|
27618
|
-
var map32 = /* @__PURE__ */ dual(2, (self, f) =>
|
|
27619
|
-
var
|
|
27620
|
+
var map32 = /* @__PURE__ */ dual(2, (self, f) => mapEffect8(self, (a) => right2(f(a))));
|
|
27621
|
+
var mapEffect8 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
27620
27622
|
const op = Object.create(proto23);
|
|
27621
27623
|
op._tag = "Map";
|
|
27622
27624
|
op.command = self;
|
|
@@ -27921,7 +27923,7 @@ var withDescriptionInternal = (self, description) => {
|
|
|
27921
27923
|
return op;
|
|
27922
27924
|
}
|
|
27923
27925
|
case "Map": {
|
|
27924
|
-
return
|
|
27926
|
+
return mapEffect8(withDescriptionInternal(self.command, description), self.f);
|
|
27925
27927
|
}
|
|
27926
27928
|
case "Subcommands": {
|
|
27927
27929
|
const op = Object.create(proto23);
|
|
@@ -28147,6 +28149,7 @@ var helpRequestedError = (command) => {
|
|
|
28147
28149
|
|
|
28148
28150
|
// node_modules/.pnpm/@effect+cli@0.73.0_@effect+platform@0.94.1_@effect+printer-ansi@0.47.0_@effect+printer@0.47.0_effect@3.19.14/node_modules/@effect/cli/dist/esm/ValidationError.js
|
|
28149
28151
|
var helpRequested = helpRequestedError;
|
|
28152
|
+
var invalidValue2 = invalidValue;
|
|
28150
28153
|
|
|
28151
28154
|
// node_modules/.pnpm/effect@3.19.14/node_modules/effect/dist/esm/Logger.js
|
|
28152
28155
|
var withMinimumLogLevel2 = withMinimumLogLevel;
|
|
@@ -30211,7 +30214,7 @@ var runMain3 = runMain2;
|
|
|
30211
30214
|
// package.json
|
|
30212
30215
|
var package_default = {
|
|
30213
30216
|
name: "@effect/language-service",
|
|
30214
|
-
version: "0.
|
|
30217
|
+
version: "0.68.0",
|
|
30215
30218
|
packageManager: "pnpm@8.11.0",
|
|
30216
30219
|
publishConfig: {
|
|
30217
30220
|
access: "public",
|
|
@@ -37030,6 +37033,69 @@ var importFromBarrel = createDiagnostic({
|
|
|
37030
37033
|
})
|
|
37031
37034
|
});
|
|
37032
37035
|
|
|
37036
|
+
// src/diagnostics/instanceOfSchema.ts
|
|
37037
|
+
var instanceOfSchema = createDiagnostic({
|
|
37038
|
+
name: "instanceOfSchema",
|
|
37039
|
+
code: 45,
|
|
37040
|
+
description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
37041
|
+
severity: "off",
|
|
37042
|
+
apply: fn2("instanceOfSchema.apply")(function* (sourceFile, report) {
|
|
37043
|
+
const ts = yield* service2(TypeScriptApi);
|
|
37044
|
+
const typeParser = yield* service2(TypeParser);
|
|
37045
|
+
const typeCheckerUtils = yield* service2(TypeCheckerUtils);
|
|
37046
|
+
const nodeToVisit = [];
|
|
37047
|
+
const appendNodeToVisit = (node) => {
|
|
37048
|
+
nodeToVisit.push(node);
|
|
37049
|
+
return void 0;
|
|
37050
|
+
};
|
|
37051
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
37052
|
+
while (nodeToVisit.length > 0) {
|
|
37053
|
+
const node = nodeToVisit.shift();
|
|
37054
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword) {
|
|
37055
|
+
const leftExpr = node.left;
|
|
37056
|
+
const rightExpr = node.right;
|
|
37057
|
+
const rightType = typeCheckerUtils.getTypeAtLocation(rightExpr);
|
|
37058
|
+
if (!rightType) {
|
|
37059
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
37060
|
+
continue;
|
|
37061
|
+
}
|
|
37062
|
+
const isSchemaType = yield* pipe(
|
|
37063
|
+
typeParser.effectSchemaType(rightType, rightExpr),
|
|
37064
|
+
option5
|
|
37065
|
+
);
|
|
37066
|
+
if (isSchemaType._tag === "Some") {
|
|
37067
|
+
report({
|
|
37068
|
+
location: node,
|
|
37069
|
+
messageText: "Consider using Schema.is instead of instanceof for Effect Schema types.",
|
|
37070
|
+
fixes: [{
|
|
37071
|
+
fixName: "instanceOfSchema_fix",
|
|
37072
|
+
description: "Replace with Schema.is",
|
|
37073
|
+
apply: gen3(function* () {
|
|
37074
|
+
const changeTracker = yield* service2(ChangeTracker);
|
|
37075
|
+
const schemaIsCall = ts.factory.createCallExpression(
|
|
37076
|
+
ts.factory.createPropertyAccessExpression(
|
|
37077
|
+
ts.factory.createIdentifier("Schema"),
|
|
37078
|
+
"is"
|
|
37079
|
+
),
|
|
37080
|
+
void 0,
|
|
37081
|
+
[rightExpr]
|
|
37082
|
+
);
|
|
37083
|
+
const fullCall = ts.factory.createCallExpression(
|
|
37084
|
+
schemaIsCall,
|
|
37085
|
+
void 0,
|
|
37086
|
+
[leftExpr]
|
|
37087
|
+
);
|
|
37088
|
+
changeTracker.replaceNode(sourceFile, node, fullCall);
|
|
37089
|
+
})
|
|
37090
|
+
}]
|
|
37091
|
+
});
|
|
37092
|
+
}
|
|
37093
|
+
}
|
|
37094
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
37095
|
+
}
|
|
37096
|
+
})
|
|
37097
|
+
});
|
|
37098
|
+
|
|
37033
37099
|
// src/diagnostics/layerMergeAllWithDependencies.ts
|
|
37034
37100
|
var layerMergeAllWithDependencies = createDiagnostic({
|
|
37035
37101
|
name: "layerMergeAllWithDependencies",
|
|
@@ -37237,12 +37303,18 @@ var leakingRequirements = createDiagnostic({
|
|
|
37237
37303
|
);
|
|
37238
37304
|
function reportLeakingRequirements(node, requirements) {
|
|
37239
37305
|
if (requirements.length === 0) return;
|
|
37306
|
+
const requirementsStr = requirements.map((_) => typeChecker.typeToString(_)).join(" | ");
|
|
37240
37307
|
report({
|
|
37241
37308
|
location: node,
|
|
37242
|
-
messageText: `
|
|
37243
|
-
|
|
37244
|
-
|
|
37245
|
-
|
|
37309
|
+
messageText: `Methods of this Service require \`${requirementsStr}\` from every caller.
|
|
37310
|
+
|
|
37311
|
+
This leaks implementation details into the service's public type \u2014 callers shouldn't need to know *how* the service works internally, only *what* it provides.
|
|
37312
|
+
|
|
37313
|
+
Resolve these dependencies at Layer creation and provide them to each method, so the service's type reflects its purpose, not its implementation.
|
|
37314
|
+
|
|
37315
|
+
To suppress this diagnostic for specific dependency types that are intentionally passed through (e.g., HttpServerRequest), add \`@effect-leakable-service\` JSDoc to their interface declarations (e.g., the \`${typeChecker.typeToString(requirements[0])}\` interface), not to this service.
|
|
37316
|
+
|
|
37317
|
+
More info and examples at https://effect.website/docs/requirements-management/layers/#avoiding-requirement-leakage`,
|
|
37246
37318
|
fixes: []
|
|
37247
37319
|
});
|
|
37248
37320
|
}
|
|
@@ -39420,6 +39492,7 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
39420
39492
|
// src/diagnostics.ts
|
|
39421
39493
|
var diagnostics = [
|
|
39422
39494
|
anyUnknownInErrorContext,
|
|
39495
|
+
instanceOfSchema,
|
|
39423
39496
|
catchAllToMapError,
|
|
39424
39497
|
catchUnfailableEffect,
|
|
39425
39498
|
classSelfMismatch,
|
|
@@ -41702,6 +41775,14 @@ var renderCodeActions = (result, assessmentState) => gen2(function* () {
|
|
|
41702
41775
|
});
|
|
41703
41776
|
|
|
41704
41777
|
// src/cli/quickfixes.ts
|
|
41778
|
+
var validDiagnosticNames = new Set(diagnostics.map((_) => _.name));
|
|
41779
|
+
var validDiagnosticCodes = new Set(diagnostics.map((_) => String(_.code)));
|
|
41780
|
+
var diagnosticCodeByName = new Map(diagnostics.map((_) => [_.name, _.code]));
|
|
41781
|
+
var ColumnRequiresLineError = class extends TaggedError("ColumnRequiresLineError") {
|
|
41782
|
+
get message() {
|
|
41783
|
+
return "The --column option requires --line to be specified.";
|
|
41784
|
+
}
|
|
41785
|
+
};
|
|
41705
41786
|
var isSkipFix = (fixName) => fixName.endsWith("_skipNextLine") || fixName.endsWith("_skipFile");
|
|
41706
41787
|
var renderQuickFix = (sourceFile, fix) => {
|
|
41707
41788
|
const lines3 = [];
|
|
@@ -41767,9 +41848,42 @@ var quickfixes = make58(
|
|
|
41767
41848
|
project: file3("project").pipe(
|
|
41768
41849
|
optional4,
|
|
41769
41850
|
withDescription3("The full path of the project tsconfig.json file to check for quick fixes.")
|
|
41851
|
+
),
|
|
41852
|
+
code: text8("code").pipe(
|
|
41853
|
+
withDescription3("Filter by diagnostic name or code (e.g., 'floatingEffect' or '5')."),
|
|
41854
|
+
mapEffect6((value5) => {
|
|
41855
|
+
if (validDiagnosticNames.has(value5)) {
|
|
41856
|
+
return succeed7(diagnosticCodeByName.get(value5));
|
|
41857
|
+
}
|
|
41858
|
+
if (validDiagnosticCodes.has(value5)) {
|
|
41859
|
+
return succeed7(Number(value5));
|
|
41860
|
+
}
|
|
41861
|
+
const validValues = [...validDiagnosticNames].sort().join(", ");
|
|
41862
|
+
return fail7(
|
|
41863
|
+
invalidValue2(
|
|
41864
|
+
p2(`Invalid diagnostic code '${value5}'. Valid values: ${validValues}`)
|
|
41865
|
+
)
|
|
41866
|
+
);
|
|
41867
|
+
}),
|
|
41868
|
+
optional4
|
|
41869
|
+
),
|
|
41870
|
+
line: integer5("line").pipe(
|
|
41871
|
+
withDescription3("Filter by line number (1-based)."),
|
|
41872
|
+
optional4
|
|
41873
|
+
),
|
|
41874
|
+
column: integer5("column").pipe(
|
|
41875
|
+
withDescription3("Filter by column number (1-based). Requires --line to be specified."),
|
|
41876
|
+
optional4
|
|
41877
|
+
),
|
|
41878
|
+
fix: text8("fix").pipe(
|
|
41879
|
+
withDescription3("Filter by fix name (e.g., 'floatingEffect_yieldStar')."),
|
|
41880
|
+
optional4
|
|
41770
41881
|
)
|
|
41771
41882
|
},
|
|
41772
|
-
fn("quickfixes")(function* ({ file: file5, project: project3 }) {
|
|
41883
|
+
fn("quickfixes")(function* ({ code: code2, column: column3, file: file5, fix, line: line4, project: project3 }) {
|
|
41884
|
+
if (isSome2(column3) && isNone2(line4)) {
|
|
41885
|
+
return yield* new ColumnRequiresLineError();
|
|
41886
|
+
}
|
|
41773
41887
|
const path2 = yield* Path2;
|
|
41774
41888
|
const tsInstance = yield* TypeScriptContext;
|
|
41775
41889
|
const filesToCheck = isSome2(project3) ? yield* getFileNamesInTsConfig(project3.value) : /* @__PURE__ */ new Set();
|
|
@@ -41813,6 +41927,12 @@ var quickfixes = make58(
|
|
|
41813
41927
|
const diagnosticMap = /* @__PURE__ */ new Map();
|
|
41814
41928
|
for (const diagnostic of result.diagnostics) {
|
|
41815
41929
|
if (diagnostic.start === void 0) continue;
|
|
41930
|
+
if (isSome2(code2) && diagnostic.code !== code2.value) continue;
|
|
41931
|
+
if (isSome2(line4)) {
|
|
41932
|
+
const pos = tsInstance.getLineAndCharacterOfPosition(sourceFile, diagnostic.start);
|
|
41933
|
+
if (pos.line !== line4.value - 1) continue;
|
|
41934
|
+
if (isSome2(column3) && pos.character !== column3.value - 1) continue;
|
|
41935
|
+
}
|
|
41816
41936
|
const key = `${diagnostic.start}-${diagnostic.start + (diagnostic.length ?? 0)}-${diagnostic.code}`;
|
|
41817
41937
|
const ruleName = Object.values(diagnostics).find((_) => _.code === diagnostic.code)?.name ?? `unknown(${diagnostic.code})`;
|
|
41818
41938
|
if (!diagnosticMap.has(key)) {
|
|
@@ -41834,6 +41954,7 @@ var quickfixes = make58(
|
|
|
41834
41954
|
);
|
|
41835
41955
|
for (const codeFix of result.codeFixes) {
|
|
41836
41956
|
if (isSkipFix(codeFix.fixName)) continue;
|
|
41957
|
+
if (isSome2(fix) && codeFix.fixName !== fix.value) continue;
|
|
41837
41958
|
const key = `${codeFix.start}-${codeFix.end}-${codeFix.code}`;
|
|
41838
41959
|
const info2 = diagnosticMap.get(key);
|
|
41839
41960
|
if (!info2) continue;
|