@effect/language-service 0.38.4 → 0.40.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 +3 -1
- package/effect-lsp-patch-utils.js +105 -11
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +234 -71
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +105 -11
- package/transform.js.map +1 -1
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
|
|
|
55
55
|
- Warn on subsequent `Effect.provide` anti-pattern
|
|
56
56
|
- Detect wrong `Self` type parameter for APIs like `Effect.Service` or `Schema.TaggedError` and similar
|
|
57
57
|
- Unnecessary usages of `Effect.gen` or `pipe()`
|
|
58
|
+
- Warn when using `Effect.gen` with the old generator adapter pattern
|
|
58
59
|
- Warn when importing from a barrel file instead of from the module directly
|
|
59
60
|
- Warn on usage of try/catch inside `Effect.gen` and family
|
|
60
61
|
- Detect unnecessary pipe chains like `X.pipe(Y).pipe(Z)`
|
|
@@ -116,7 +117,8 @@ Few options can be provided alongside the initialization of the Language Service
|
|
|
116
117
|
"barrelImportPackages": [], // package names that should be preferred as imported from the top level barrel file (default: [])
|
|
117
118
|
"namespaceImportPackages": [], // package names that should be preferred as imported with namespace imports e.g. ["effect", "@effect/*"] (default: [])
|
|
118
119
|
"topLevelNamedReexports": "ignore", // for namespaceImportPackages, how should top level named re-exports (e.g. {pipe} from "effect") be treated? "ignore" will leave them as is, "follow" will rewrite them to the re-exported module (e.g. {pipe} from "effect/Function")
|
|
119
|
-
"importAliases": { "Array": "Arr" } // allows to chose some different names for import name aliases (only when not chosing to import the whole module) (default: {})
|
|
120
|
+
"importAliases": { "Array": "Arr" }, // allows to chose some different names for import name aliases (only when not chosing to import the whole module) (default: {})
|
|
121
|
+
"noExternal": false // disables features that provides links to external websites (such as links to mermaidchart.com) (default: false)
|
|
120
122
|
}
|
|
121
123
|
]
|
|
122
124
|
}
|
|
@@ -1182,7 +1182,8 @@ var defaults = {
|
|
|
1182
1182
|
topLevelNamedReexports: "ignore",
|
|
1183
1183
|
barrelImportPackages: [],
|
|
1184
1184
|
importAliases: {},
|
|
1185
|
-
renames: true
|
|
1185
|
+
renames: true,
|
|
1186
|
+
noExternal: false
|
|
1186
1187
|
};
|
|
1187
1188
|
function parse(config) {
|
|
1188
1189
|
return {
|
|
@@ -1199,7 +1200,8 @@ function parse(config) {
|
|
|
1199
1200
|
barrelImportPackages: isObject(config) && hasProperty(config, "barrelImportPackages") && isArray(config.barrelImportPackages) && config.barrelImportPackages.every(isString) ? config.barrelImportPackages.map((_) => _.toLowerCase()) : defaults.barrelImportPackages,
|
|
1200
1201
|
importAliases: isObject(config) && hasProperty(config, "importAliases") && isRecord(config.importAliases) ? map2(config.importAliases, (value) => String(value)) : defaults.importAliases,
|
|
1201
1202
|
topLevelNamedReexports: isObject(config) && hasProperty(config, "topLevelNamedReexports") && isString(config.topLevelNamedReexports) && ["ignore", "follow"].includes(config.topLevelNamedReexports.toLowerCase()) ? config.topLevelNamedReexports.toLowerCase() : defaults.topLevelNamedReexports,
|
|
1202
|
-
renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames
|
|
1203
|
+
renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames,
|
|
1204
|
+
noExternal: isObject(config) && hasProperty(config, "noExternal") && isBoolean(config.noExternal) ? config.noExternal : defaults.noExternal
|
|
1203
1205
|
};
|
|
1204
1206
|
}
|
|
1205
1207
|
|
|
@@ -2462,13 +2464,28 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
2462
2464
|
);
|
|
2463
2465
|
const importedSchemaModule = cachedBy(
|
|
2464
2466
|
fn("TypeParser.importedSchemaModule")(function* (node) {
|
|
2467
|
+
if (!ts.isIdentifier(node)) {
|
|
2468
|
+
return yield* typeParserIssue("Node is not an expression", void 0, node);
|
|
2469
|
+
}
|
|
2465
2470
|
const type = typeChecker.getTypeAtLocation(node);
|
|
2466
2471
|
const propertySymbol = typeChecker.getPropertyOfType(type, "Class");
|
|
2467
2472
|
if (!propertySymbol) {
|
|
2468
2473
|
return yield* typeParserIssue("Type has no 'Class' property", type, node);
|
|
2469
2474
|
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2475
|
+
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2476
|
+
if (!sourceFile) {
|
|
2477
|
+
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
2478
|
+
}
|
|
2479
|
+
const schemaIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
2480
|
+
sourceFile,
|
|
2481
|
+
"effect",
|
|
2482
|
+
"Schema"
|
|
2483
|
+
);
|
|
2484
|
+
if (!schemaIdentifier) {
|
|
2485
|
+
return yield* typeParserIssue("Schema module not found", void 0, node);
|
|
2486
|
+
}
|
|
2487
|
+
if (ts.idText(node) !== schemaIdentifier) {
|
|
2488
|
+
return yield* typeParserIssue("Node is not a schema module reference", void 0, node);
|
|
2472
2489
|
}
|
|
2473
2490
|
return node;
|
|
2474
2491
|
}),
|
|
@@ -2482,8 +2499,23 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
2482
2499
|
if (!propertySymbol) {
|
|
2483
2500
|
return yield* typeParserIssue("Type has no 'Tag' property", type, node);
|
|
2484
2501
|
}
|
|
2485
|
-
if (!ts.
|
|
2486
|
-
return yield* typeParserIssue("Node is not an
|
|
2502
|
+
if (!ts.isIdentifier(node)) {
|
|
2503
|
+
return yield* typeParserIssue("Node is not an identifier", type, node);
|
|
2504
|
+
}
|
|
2505
|
+
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2506
|
+
if (!sourceFile) {
|
|
2507
|
+
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
2508
|
+
}
|
|
2509
|
+
const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
2510
|
+
sourceFile,
|
|
2511
|
+
"effect",
|
|
2512
|
+
"Context"
|
|
2513
|
+
);
|
|
2514
|
+
if (!contextIdentifier) {
|
|
2515
|
+
return yield* typeParserIssue("Context module not found", void 0, node);
|
|
2516
|
+
}
|
|
2517
|
+
if (ts.idText(node) !== contextIdentifier) {
|
|
2518
|
+
return yield* typeParserIssue("Node is not a context module reference", void 0, node);
|
|
2487
2519
|
}
|
|
2488
2520
|
return node;
|
|
2489
2521
|
}),
|
|
@@ -2514,9 +2546,24 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
2514
2546
|
if (!propertySymbol) {
|
|
2515
2547
|
return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
|
|
2516
2548
|
}
|
|
2517
|
-
if (!ts.
|
|
2549
|
+
if (!ts.isIdentifier(node)) {
|
|
2518
2550
|
return yield* typeParserIssue("Node is not an expression", type, node);
|
|
2519
2551
|
}
|
|
2552
|
+
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2553
|
+
if (!sourceFile) {
|
|
2554
|
+
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
2555
|
+
}
|
|
2556
|
+
const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
2557
|
+
sourceFile,
|
|
2558
|
+
"effect",
|
|
2559
|
+
"Data"
|
|
2560
|
+
);
|
|
2561
|
+
if (!dataIdentifier) {
|
|
2562
|
+
return yield* typeParserIssue("Data module not found", void 0, node);
|
|
2563
|
+
}
|
|
2564
|
+
if (ts.idText(node) !== dataIdentifier) {
|
|
2565
|
+
return yield* typeParserIssue("Node is not a data module reference", void 0, node);
|
|
2566
|
+
}
|
|
2520
2567
|
return node;
|
|
2521
2568
|
}),
|
|
2522
2569
|
"TypeParser.importedDataModule",
|
|
@@ -2879,8 +2926,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
2879
2926
|
const selfTypeNode = schemaCall.typeArguments[0];
|
|
2880
2927
|
const schemaIdentifier = schemaCall.expression;
|
|
2881
2928
|
if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "Class") {
|
|
2929
|
+
const expressionType = typeChecker.getTypeAtLocation(expression);
|
|
2882
2930
|
const parsedSchemaModule = yield* pipe(
|
|
2883
|
-
|
|
2931
|
+
effectSchemaType(expressionType, expression),
|
|
2932
|
+
flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
|
|
2884
2933
|
option
|
|
2885
2934
|
);
|
|
2886
2935
|
if (isSome2(parsedSchemaModule)) {
|
|
@@ -2920,8 +2969,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
2920
2969
|
const selfTypeNode = schemaTaggedClassTCall.typeArguments[0];
|
|
2921
2970
|
const schemaIdentifier = schemaTaggedClassTCall.expression;
|
|
2922
2971
|
if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedClass") {
|
|
2972
|
+
const expressionType = typeChecker.getTypeAtLocation(expression);
|
|
2923
2973
|
const parsedSchemaModule = yield* pipe(
|
|
2924
|
-
|
|
2974
|
+
effectSchemaType(expressionType, expression),
|
|
2975
|
+
flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
|
|
2925
2976
|
option
|
|
2926
2977
|
);
|
|
2927
2978
|
if (isSome2(parsedSchemaModule)) {
|
|
@@ -2963,8 +3014,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
2963
3014
|
const selfTypeNode = schemaTaggedErrorTCall.typeArguments[0];
|
|
2964
3015
|
const schemaIdentifier = schemaTaggedErrorTCall.expression;
|
|
2965
3016
|
if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedError") {
|
|
3017
|
+
const expressionType = typeChecker.getTypeAtLocation(expression);
|
|
2966
3018
|
const parsedSchemaModule = yield* pipe(
|
|
2967
|
-
|
|
3019
|
+
effectSchemaType(expressionType, expression),
|
|
3020
|
+
flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
|
|
2968
3021
|
option
|
|
2969
3022
|
);
|
|
2970
3023
|
if (isSome2(parsedSchemaModule)) {
|
|
@@ -3082,8 +3135,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
|
|
|
3082
3135
|
const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
|
|
3083
3136
|
const schemaIdentifier = schemaTaggedRequestTCall.expression;
|
|
3084
3137
|
if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedRequest") {
|
|
3138
|
+
const expressionType = typeChecker.getTypeAtLocation(expression);
|
|
3085
3139
|
const parsedSchemaModule = yield* pipe(
|
|
3086
|
-
|
|
3140
|
+
effectSchemaType(expressionType, expression),
|
|
3141
|
+
flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
|
|
3087
3142
|
option
|
|
3088
3143
|
);
|
|
3089
3144
|
if (isSome2(parsedSchemaModule)) {
|
|
@@ -3317,6 +3372,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
3317
3372
|
const result = yield* pipe(
|
|
3318
3373
|
typeParser.extendsEffectService(node),
|
|
3319
3374
|
orElse2(() => typeParser.extendsContextTag(node)),
|
|
3375
|
+
orElse2(() => typeParser.extendsEffectTag(node)),
|
|
3320
3376
|
orElse2(() => typeParser.extendsSchemaClass(node)),
|
|
3321
3377
|
orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
|
|
3322
3378
|
orElse2(() => typeParser.extendsSchemaTaggedError(node)),
|
|
@@ -3409,6 +3465,43 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
3409
3465
|
})
|
|
3410
3466
|
});
|
|
3411
3467
|
|
|
3468
|
+
// src/diagnostics/effectGenUsesAdapter.ts
|
|
3469
|
+
var effectGenUsesAdapter = createDiagnostic({
|
|
3470
|
+
name: "effectGenUsesAdapter",
|
|
3471
|
+
code: 23,
|
|
3472
|
+
severity: "warning",
|
|
3473
|
+
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
3474
|
+
const ts = yield* service(TypeScriptApi);
|
|
3475
|
+
const typeParser = yield* service(TypeParser);
|
|
3476
|
+
const nodeToVisit = [];
|
|
3477
|
+
const appendNodeToVisit = (node) => {
|
|
3478
|
+
nodeToVisit.push(node);
|
|
3479
|
+
return void 0;
|
|
3480
|
+
};
|
|
3481
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3482
|
+
while (nodeToVisit.length > 0) {
|
|
3483
|
+
const node = nodeToVisit.shift();
|
|
3484
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3485
|
+
if (ts.isCallExpression(node)) {
|
|
3486
|
+
yield* pipe(
|
|
3487
|
+
typeParser.effectGen(node),
|
|
3488
|
+
map4(({ generatorFunction }) => {
|
|
3489
|
+
if (generatorFunction.parameters.length > 0) {
|
|
3490
|
+
const adapter = generatorFunction.parameters[0];
|
|
3491
|
+
report({
|
|
3492
|
+
location: adapter,
|
|
3493
|
+
messageText: `The adapter of Effect.gen is not required anymore, it is now just an alias of pipe.`,
|
|
3494
|
+
fixes: []
|
|
3495
|
+
});
|
|
3496
|
+
}
|
|
3497
|
+
}),
|
|
3498
|
+
ignore
|
|
3499
|
+
);
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
})
|
|
3503
|
+
});
|
|
3504
|
+
|
|
3412
3505
|
// src/diagnostics/effectInVoidSuccess.ts
|
|
3413
3506
|
var effectInVoidSuccess = createDiagnostic({
|
|
3414
3507
|
name: "effectInVoidSuccess",
|
|
@@ -5217,6 +5310,7 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
5217
5310
|
var diagnostics = [
|
|
5218
5311
|
classSelfMismatch,
|
|
5219
5312
|
duplicatePackage,
|
|
5313
|
+
effectGenUsesAdapter,
|
|
5220
5314
|
missingEffectContext,
|
|
5221
5315
|
missingEffectError,
|
|
5222
5316
|
missingEffectServiceDependency,
|