@effect/language-service 0.69.0 → 0.69.2
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/cli.js +137 -27
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +136 -26
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +136 -26
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +136 -26
- package/transform.js.map +1 -1
package/cli.js
CHANGED
|
@@ -30214,7 +30214,7 @@ var runMain3 = runMain2;
|
|
|
30214
30214
|
// package.json
|
|
30215
30215
|
var package_default = {
|
|
30216
30216
|
name: "@effect/language-service",
|
|
30217
|
-
version: "0.69.
|
|
30217
|
+
version: "0.69.2",
|
|
30218
30218
|
packageManager: "pnpm@8.11.0",
|
|
30219
30219
|
publishConfig: {
|
|
30220
30220
|
access: "public",
|
|
@@ -32039,6 +32039,7 @@ var defaults = {
|
|
|
32039
32039
|
}],
|
|
32040
32040
|
extendedKeyDetection: false,
|
|
32041
32041
|
pipeableMinArgCount: 2,
|
|
32042
|
+
effectFn: ["span"],
|
|
32042
32043
|
layerGraphFollowDepth: 0,
|
|
32043
32044
|
mermaidProvider: "mermaid.live"
|
|
32044
32045
|
};
|
|
@@ -32078,6 +32079,7 @@ function parse4(config2) {
|
|
|
32078
32079
|
keyPatterns: isObject(config2) && hasProperty(config2, "keyPatterns") && isArray(config2.keyPatterns) ? parseKeyPatterns(config2.keyPatterns) : defaults.keyPatterns,
|
|
32079
32080
|
extendedKeyDetection: isObject(config2) && hasProperty(config2, "extendedKeyDetection") && isBoolean(config2.extendedKeyDetection) ? config2.extendedKeyDetection : defaults.extendedKeyDetection,
|
|
32080
32081
|
pipeableMinArgCount: isObject(config2) && hasProperty(config2, "pipeableMinArgCount") && isNumber(config2.pipeableMinArgCount) ? config2.pipeableMinArgCount : defaults.pipeableMinArgCount,
|
|
32082
|
+
effectFn: isObject(config2) && hasProperty(config2, "effectFn") && isArray(config2.effectFn) && config2.effectFn.every(isString) ? config2.effectFn.map((_) => _.toLowerCase()) : defaults.effectFn,
|
|
32081
32083
|
layerGraphFollowDepth: isObject(config2) && hasProperty(config2, "layerGraphFollowDepth") && isNumber(config2.layerGraphFollowDepth) ? config2.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
|
|
32082
32084
|
mermaidProvider: isObject(config2) && hasProperty(config2, "mermaidProvider") && isString(config2.mermaidProvider) ? config2.mermaidProvider : defaults.mermaidProvider
|
|
32083
32085
|
};
|
|
@@ -33302,6 +33304,7 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
33302
33304
|
node
|
|
33303
33305
|
);
|
|
33304
33306
|
}
|
|
33307
|
+
const traceExpression = ts.isCallExpression(node.expression) && node.expression.arguments.length > 0 ? node.expression.arguments[0] : void 0;
|
|
33305
33308
|
const propertyAccess = expressionToTest;
|
|
33306
33309
|
const pipeArguments2 = node.arguments.slice(1);
|
|
33307
33310
|
return pipe(
|
|
@@ -33311,7 +33314,8 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
33311
33314
|
generatorFunction,
|
|
33312
33315
|
effectModule: propertyAccess.expression,
|
|
33313
33316
|
body: generatorFunction.body,
|
|
33314
|
-
pipeArguments: pipeArguments2
|
|
33317
|
+
pipeArguments: pipeArguments2,
|
|
33318
|
+
traceExpression
|
|
33315
33319
|
}))
|
|
33316
33320
|
);
|
|
33317
33321
|
},
|
|
@@ -33394,6 +33398,7 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
33394
33398
|
if (!ts.isPropertyAccessExpression(expressionToTest)) {
|
|
33395
33399
|
return typeParserIssue("Node is not a property access expression", void 0, node);
|
|
33396
33400
|
}
|
|
33401
|
+
const traceExpression = ts.isCallExpression(node.expression) && node.expression.arguments.length > 0 ? node.expression.arguments[0] : void 0;
|
|
33397
33402
|
const propertyAccess = expressionToTest;
|
|
33398
33403
|
const pipeArguments2 = node.arguments.slice(1);
|
|
33399
33404
|
return pipe(
|
|
@@ -33402,7 +33407,8 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
33402
33407
|
node,
|
|
33403
33408
|
effectModule: propertyAccess.expression,
|
|
33404
33409
|
regularFunction,
|
|
33405
|
-
pipeArguments: pipeArguments2
|
|
33410
|
+
pipeArguments: pipeArguments2,
|
|
33411
|
+
traceExpression
|
|
33406
33412
|
}))
|
|
33407
33413
|
);
|
|
33408
33414
|
},
|
|
@@ -36299,7 +36305,8 @@ var effectFnIife = createDiagnostic({
|
|
|
36299
36305
|
kind: "fn",
|
|
36300
36306
|
effectModule: result.effectModule,
|
|
36301
36307
|
generatorFunction: result.generatorFunction,
|
|
36302
|
-
pipeArguments: result.pipeArguments
|
|
36308
|
+
pipeArguments: result.pipeArguments,
|
|
36309
|
+
traceExpression: result.traceExpression
|
|
36303
36310
|
})),
|
|
36304
36311
|
orElse15(
|
|
36305
36312
|
() => pipe(
|
|
@@ -36308,7 +36315,8 @@ var effectFnIife = createDiagnostic({
|
|
|
36308
36315
|
kind: "fnUntraced",
|
|
36309
36316
|
effectModule: result.effectModule,
|
|
36310
36317
|
generatorFunction: result.generatorFunction,
|
|
36311
|
-
pipeArguments: result.pipeArguments
|
|
36318
|
+
pipeArguments: result.pipeArguments,
|
|
36319
|
+
traceExpression: void 0
|
|
36312
36320
|
}))
|
|
36313
36321
|
)
|
|
36314
36322
|
),
|
|
@@ -36319,14 +36327,15 @@ var effectFnIife = createDiagnostic({
|
|
|
36319
36327
|
kind: "fn",
|
|
36320
36328
|
effectModule: result.effectModule,
|
|
36321
36329
|
generatorFunction: void 0,
|
|
36322
|
-
pipeArguments: result.pipeArguments
|
|
36330
|
+
pipeArguments: result.pipeArguments,
|
|
36331
|
+
traceExpression: result.traceExpression
|
|
36323
36332
|
}))
|
|
36324
36333
|
)
|
|
36325
36334
|
),
|
|
36326
36335
|
option5
|
|
36327
36336
|
);
|
|
36328
36337
|
if (isNone2(parsed)) continue;
|
|
36329
|
-
const { effectModule, generatorFunction, kind, pipeArguments: pipeArguments2 } = parsed.value;
|
|
36338
|
+
const { effectModule, generatorFunction, kind, pipeArguments: pipeArguments2, traceExpression } = parsed.value;
|
|
36330
36339
|
const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : sourceEffectModuleName;
|
|
36331
36340
|
const fixes = [];
|
|
36332
36341
|
if (generatorFunction && generatorFunction.parameters.length === 0) {
|
|
@@ -36355,9 +36364,10 @@ var effectFnIife = createDiagnostic({
|
|
|
36355
36364
|
})
|
|
36356
36365
|
});
|
|
36357
36366
|
}
|
|
36367
|
+
const traceExpressionText = traceExpression ? sourceFile.text.slice(traceExpression.pos, traceExpression.end) : void 0;
|
|
36358
36368
|
report({
|
|
36359
36369
|
location: node,
|
|
36360
|
-
messageText: `${effectModuleName}.${kind} returns a reusable function that can take arguments, but here it's called immediately. Use Effect.gen instead
|
|
36370
|
+
messageText: `${effectModuleName}.${kind} returns a reusable function that can take arguments, but here it's called immediately. Use Effect.gen instead${traceExpressionText ? ` with Effect.withSpan(${traceExpressionText}) piped in the end to mantain tracing spans` : ``}.`,
|
|
36361
36371
|
fixes
|
|
36362
36372
|
});
|
|
36363
36373
|
}
|
|
@@ -36376,6 +36386,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36376
36386
|
const typeCheckerUtils = yield* service2(TypeCheckerUtils);
|
|
36377
36387
|
const typeParser = yield* service2(TypeParser);
|
|
36378
36388
|
const tsUtils = yield* service2(TypeScriptUtils);
|
|
36389
|
+
const pluginOptions = yield* service2(LanguageServicePluginOptions);
|
|
36379
36390
|
const sourceEffectModuleName = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
36380
36391
|
sourceFile,
|
|
36381
36392
|
"effect",
|
|
@@ -36452,6 +36463,18 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36452
36463
|
}
|
|
36453
36464
|
return false;
|
|
36454
36465
|
};
|
|
36466
|
+
const tryExtractWithSpanExpression = (expr) => gen3(function* () {
|
|
36467
|
+
if (!ts.isCallExpression(expr)) return void 0;
|
|
36468
|
+
const callee = expr.expression;
|
|
36469
|
+
const isWithSpan = yield* pipe(
|
|
36470
|
+
typeParser.isNodeReferenceToEffectModuleApi("withSpan")(callee),
|
|
36471
|
+
map34(() => true),
|
|
36472
|
+
orElse15(() => succeed17(false))
|
|
36473
|
+
);
|
|
36474
|
+
if (!isWithSpan) return void 0;
|
|
36475
|
+
if (expr.arguments.length === 0) return void 0;
|
|
36476
|
+
return expr.arguments[0];
|
|
36477
|
+
});
|
|
36455
36478
|
const tryParseGenOpportunity = (fnNode) => gen3(function* () {
|
|
36456
36479
|
const bodyExpression = getBodyExpression(fnNode);
|
|
36457
36480
|
if (!bodyExpression) return yield* TypeParserIssue.issue;
|
|
@@ -36462,7 +36485,15 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36462
36485
|
);
|
|
36463
36486
|
const { effectModule, generatorFunction } = yield* typeParser.effectGen(subject);
|
|
36464
36487
|
const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : sourceEffectModuleName;
|
|
36465
|
-
|
|
36488
|
+
let explicitTraceExpression;
|
|
36489
|
+
if (pipeArguments2.length > 0) {
|
|
36490
|
+
const lastArg = pipeArguments2[pipeArguments2.length - 1];
|
|
36491
|
+
const withSpanExpr = yield* tryExtractWithSpanExpression(lastArg);
|
|
36492
|
+
if (withSpanExpr) {
|
|
36493
|
+
explicitTraceExpression = withSpanExpr;
|
|
36494
|
+
}
|
|
36495
|
+
}
|
|
36496
|
+
return { effectModuleName, generatorFunction, pipeArguments: pipeArguments2, explicitTraceExpression };
|
|
36466
36497
|
});
|
|
36467
36498
|
const isInsideEffectFn = (fnNode) => {
|
|
36468
36499
|
const parent = fnNode.parent;
|
|
@@ -36490,6 +36521,9 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36490
36521
|
if (ts.isFunctionExpression(node) && node.name) {
|
|
36491
36522
|
return yield* TypeParserIssue.issue;
|
|
36492
36523
|
}
|
|
36524
|
+
if (node.type) {
|
|
36525
|
+
return yield* TypeParserIssue.issue;
|
|
36526
|
+
}
|
|
36493
36527
|
if (yield* isInsideEffectFn(node)) {
|
|
36494
36528
|
return yield* TypeParserIssue.issue;
|
|
36495
36529
|
}
|
|
@@ -36517,7 +36551,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36517
36551
|
return succeed17({
|
|
36518
36552
|
effectModuleName: sourceEffectModuleName,
|
|
36519
36553
|
pipeArguments: [],
|
|
36520
|
-
generatorFunction: void 0
|
|
36554
|
+
generatorFunction: void 0,
|
|
36555
|
+
explicitTraceExpression: void 0
|
|
36521
36556
|
});
|
|
36522
36557
|
})
|
|
36523
36558
|
);
|
|
@@ -36525,7 +36560,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36525
36560
|
node,
|
|
36526
36561
|
nameIdentifier,
|
|
36527
36562
|
effectModuleName: opportunity.effectModuleName,
|
|
36528
|
-
traceName,
|
|
36563
|
+
inferredTraceName: traceName,
|
|
36564
|
+
explicitTraceExpression: opportunity.explicitTraceExpression,
|
|
36529
36565
|
pipeArguments: opportunity.pipeArguments,
|
|
36530
36566
|
generatorFunction: opportunity.generatorFunction,
|
|
36531
36567
|
hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
|
|
@@ -36544,7 +36580,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36544
36580
|
if (ts.isArrowFunction(node)) return false;
|
|
36545
36581
|
return node.asteriskToken !== void 0;
|
|
36546
36582
|
};
|
|
36547
|
-
const createEffectFnNode = (originalNode, innerFunction, effectModuleName,
|
|
36583
|
+
const createEffectFnNode = (originalNode, innerFunction, effectModuleName, traceNameOrExpression, pipeArguments2) => {
|
|
36548
36584
|
const isGenerator = isGeneratorFunction2(innerFunction);
|
|
36549
36585
|
const newFunction = ts.factory.createFunctionExpression(
|
|
36550
36586
|
void 0,
|
|
@@ -36559,11 +36595,12 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36559
36595
|
ts.factory.createIdentifier(effectModuleName),
|
|
36560
36596
|
"fn"
|
|
36561
36597
|
);
|
|
36562
|
-
if (
|
|
36598
|
+
if (traceNameOrExpression) {
|
|
36599
|
+
const traceArg = typeof traceNameOrExpression === "string" ? ts.factory.createStringLiteral(traceNameOrExpression) : traceNameOrExpression;
|
|
36563
36600
|
fnExpression = ts.factory.createCallExpression(
|
|
36564
36601
|
fnExpression,
|
|
36565
36602
|
void 0,
|
|
36566
|
-
[
|
|
36603
|
+
[traceArg]
|
|
36567
36604
|
);
|
|
36568
36605
|
}
|
|
36569
36606
|
const effectFnCall = ts.factory.createCallExpression(fnExpression, void 0, [newFunction, ...pipeArguments2]);
|
|
@@ -36605,19 +36642,35 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36605
36642
|
const target = yield* pipe(parseEffectFnOpportunityTarget(node), option5);
|
|
36606
36643
|
if (isNone2(target)) continue;
|
|
36607
36644
|
if (target.value.hasParamsInPipeArgs) continue;
|
|
36608
|
-
const {
|
|
36645
|
+
const {
|
|
36646
|
+
effectModuleName,
|
|
36647
|
+
explicitTraceExpression,
|
|
36648
|
+
inferredTraceName,
|
|
36649
|
+
nameIdentifier,
|
|
36650
|
+
node: targetNode,
|
|
36651
|
+
pipeArguments: pipeArguments2
|
|
36652
|
+
} = target.value;
|
|
36609
36653
|
const innerFunction = target.value.generatorFunction ?? targetNode;
|
|
36610
36654
|
const fixes = [];
|
|
36611
|
-
|
|
36612
|
-
|
|
36613
|
-
|
|
36614
|
-
|
|
36615
|
-
|
|
36616
|
-
|
|
36617
|
-
|
|
36618
|
-
|
|
36619
|
-
|
|
36620
|
-
|
|
36655
|
+
if (pluginOptions.effectFn.includes("span") && explicitTraceExpression) {
|
|
36656
|
+
fixes.push({
|
|
36657
|
+
fixName: "effectFnOpportunity_toEffectFnWithSpan",
|
|
36658
|
+
description: "Convert to Effect.fn (with span from withSpan)",
|
|
36659
|
+
apply: gen3(function* () {
|
|
36660
|
+
const changeTracker = yield* service2(ChangeTracker);
|
|
36661
|
+
const finalPipeArguments = pipeArguments2.slice(0, -1);
|
|
36662
|
+
const newNode = createEffectFnNode(
|
|
36663
|
+
targetNode,
|
|
36664
|
+
innerFunction,
|
|
36665
|
+
effectModuleName,
|
|
36666
|
+
explicitTraceExpression,
|
|
36667
|
+
finalPipeArguments
|
|
36668
|
+
);
|
|
36669
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
36670
|
+
})
|
|
36671
|
+
});
|
|
36672
|
+
}
|
|
36673
|
+
if (pluginOptions.effectFn.includes("untraced") && target.value.generatorFunction) {
|
|
36621
36674
|
fixes.push({
|
|
36622
36675
|
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
36623
36676
|
description: "Convert to Effect.fnUntraced",
|
|
@@ -36628,10 +36681,67 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
36628
36681
|
})
|
|
36629
36682
|
});
|
|
36630
36683
|
}
|
|
36631
|
-
|
|
36684
|
+
if (pluginOptions.effectFn.includes("no-span")) {
|
|
36685
|
+
fixes.push({
|
|
36686
|
+
fixName: "effectFnOpportunity_toEffectFnNoSpan",
|
|
36687
|
+
description: "Convert to Effect.fn (no span)",
|
|
36688
|
+
apply: gen3(function* () {
|
|
36689
|
+
const changeTracker = yield* service2(ChangeTracker);
|
|
36690
|
+
const newNode = createEffectFnNode(targetNode, innerFunction, effectModuleName, void 0, pipeArguments2);
|
|
36691
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
36692
|
+
})
|
|
36693
|
+
});
|
|
36694
|
+
}
|
|
36695
|
+
if (pluginOptions.effectFn.includes("inferred-span") && inferredTraceName && !explicitTraceExpression) {
|
|
36696
|
+
fixes.push({
|
|
36697
|
+
fixName: "effectFnOpportunity_toEffectFnSpanInferred",
|
|
36698
|
+
description: `Convert to Effect.fn("${inferredTraceName}")`,
|
|
36699
|
+
apply: gen3(function* () {
|
|
36700
|
+
const changeTracker = yield* service2(ChangeTracker);
|
|
36701
|
+
const newNode = createEffectFnNode(
|
|
36702
|
+
targetNode,
|
|
36703
|
+
innerFunction,
|
|
36704
|
+
effectModuleName,
|
|
36705
|
+
inferredTraceName,
|
|
36706
|
+
pipeArguments2
|
|
36707
|
+
);
|
|
36708
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
36709
|
+
})
|
|
36710
|
+
});
|
|
36711
|
+
}
|
|
36712
|
+
if (fixes.length === 0) continue;
|
|
36713
|
+
const generateExpectedSignature = () => {
|
|
36714
|
+
const firstFix = fixes[0];
|
|
36715
|
+
if (!firstFix) return "Effect.fn(function*() { ... })";
|
|
36716
|
+
const typeParamNames = targetNode.typeParameters ? `<${targetNode.typeParameters.map((tp) => ts.idText(tp.name)).join(", ")}>` : "";
|
|
36717
|
+
const paramNames = targetNode.parameters.map((param) => {
|
|
36718
|
+
if (ts.isIdentifier(param.name)) {
|
|
36719
|
+
return ts.idText(param.name);
|
|
36720
|
+
}
|
|
36721
|
+
return "_";
|
|
36722
|
+
}).join(", ");
|
|
36723
|
+
const fnSignature = `function*${typeParamNames}(${paramNames}) { ... }`;
|
|
36724
|
+
const pipeArgsForWithSpan = pipeArguments2.slice(0, -1);
|
|
36725
|
+
const pipeArgsSuffix = (args3) => args3.length > 0 ? ", ...pipeTransformations" : "";
|
|
36726
|
+
switch (firstFix.fixName) {
|
|
36727
|
+
case "effectFnOpportunity_toEffectFnWithSpan": {
|
|
36728
|
+
const traceName = explicitTraceExpression ? sourceFile.text.slice(explicitTraceExpression.pos, explicitTraceExpression.end).trim() : void 0;
|
|
36729
|
+
return `${effectModuleName}.fn(${traceName})(${fnSignature}${pipeArgsSuffix(pipeArgsForWithSpan)})`;
|
|
36730
|
+
}
|
|
36731
|
+
case "effectFnOpportunity_toEffectFnUntraced":
|
|
36732
|
+
return `${effectModuleName}.fnUntraced(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
36733
|
+
case "effectFnOpportunity_toEffectFnNoSpan":
|
|
36734
|
+
return `${effectModuleName}.fn(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
36735
|
+
case "effectFnOpportunity_toEffectFnSpanInferred":
|
|
36736
|
+
return `${effectModuleName}.fn("${inferredTraceName}")(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
36737
|
+
default:
|
|
36738
|
+
return `${effectModuleName}.fn(${fnSignature})`;
|
|
36739
|
+
}
|
|
36740
|
+
};
|
|
36741
|
+
const expectedSignature = generateExpectedSignature();
|
|
36632
36742
|
report({
|
|
36633
36743
|
location: nameIdentifier ?? targetNode,
|
|
36634
|
-
messageText:
|
|
36744
|
+
messageText: `Can be rewritten as a reusable function: ${expectedSignature}`,
|
|
36635
36745
|
fixes
|
|
36636
36746
|
});
|
|
36637
36747
|
}
|