@effect/language-service 0.65.0 → 0.67.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 +5 -0
- package/cli.js +1254 -668
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +730 -332
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +730 -332
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +730 -332
- package/transform.js.map +1 -1
package/index.js
CHANGED
|
@@ -5437,6 +5437,97 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5437
5437
|
"TypeParser.effectFnGen",
|
|
5438
5438
|
(node) => node
|
|
5439
5439
|
);
|
|
5440
|
+
const findEnclosingScopes = fn("TypeParser.findEnclosingScopes")(function* (startNode) {
|
|
5441
|
+
let currentParent = startNode.parent;
|
|
5442
|
+
let scopeNode = void 0;
|
|
5443
|
+
let effectGenResult = void 0;
|
|
5444
|
+
while (currentParent) {
|
|
5445
|
+
const nodeToCheck = currentParent;
|
|
5446
|
+
if (!scopeNode) {
|
|
5447
|
+
if (ts.isFunctionExpression(nodeToCheck) || ts.isFunctionDeclaration(nodeToCheck) || ts.isMethodDeclaration(nodeToCheck) || ts.isArrowFunction(nodeToCheck) || ts.isGetAccessorDeclaration(nodeToCheck) || ts.isSetAccessorDeclaration(nodeToCheck)) {
|
|
5448
|
+
scopeNode = nodeToCheck;
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
if (!effectGenResult) {
|
|
5452
|
+
const isEffectGen = yield* pipe(
|
|
5453
|
+
effectGen(nodeToCheck),
|
|
5454
|
+
map8((result) => ({
|
|
5455
|
+
node: result.node,
|
|
5456
|
+
effectModule: result.effectModule,
|
|
5457
|
+
generatorFunction: result.generatorFunction,
|
|
5458
|
+
body: result.body
|
|
5459
|
+
})),
|
|
5460
|
+
orElse2(
|
|
5461
|
+
() => pipe(
|
|
5462
|
+
effectFnUntracedGen(nodeToCheck),
|
|
5463
|
+
map8((result) => ({
|
|
5464
|
+
node: result.node,
|
|
5465
|
+
effectModule: result.effectModule,
|
|
5466
|
+
generatorFunction: result.generatorFunction,
|
|
5467
|
+
body: result.body,
|
|
5468
|
+
pipeArguments: result.pipeArguments
|
|
5469
|
+
}))
|
|
5470
|
+
)
|
|
5471
|
+
),
|
|
5472
|
+
orElse2(
|
|
5473
|
+
() => pipe(
|
|
5474
|
+
effectFnGen(nodeToCheck),
|
|
5475
|
+
map8((result) => ({
|
|
5476
|
+
node: result.node,
|
|
5477
|
+
effectModule: result.effectModule,
|
|
5478
|
+
generatorFunction: result.generatorFunction,
|
|
5479
|
+
body: result.body,
|
|
5480
|
+
pipeArguments: result.pipeArguments
|
|
5481
|
+
}))
|
|
5482
|
+
)
|
|
5483
|
+
),
|
|
5484
|
+
option
|
|
5485
|
+
);
|
|
5486
|
+
if (isSome2(isEffectGen)) {
|
|
5487
|
+
effectGenResult = isEffectGen.value;
|
|
5488
|
+
}
|
|
5489
|
+
}
|
|
5490
|
+
if (scopeNode && effectGenResult) {
|
|
5491
|
+
break;
|
|
5492
|
+
}
|
|
5493
|
+
currentParent = nodeToCheck.parent;
|
|
5494
|
+
}
|
|
5495
|
+
return { scopeNode, effectGen: effectGenResult };
|
|
5496
|
+
});
|
|
5497
|
+
const effectFn = cachedBy(
|
|
5498
|
+
function(node) {
|
|
5499
|
+
if (!ts.isCallExpression(node)) {
|
|
5500
|
+
return typeParserIssue("Node is not a call expression", void 0, node);
|
|
5501
|
+
}
|
|
5502
|
+
if (node.arguments.length === 0) {
|
|
5503
|
+
return typeParserIssue("Node has no arguments", void 0, node);
|
|
5504
|
+
}
|
|
5505
|
+
const regularFunction = node.arguments[0];
|
|
5506
|
+
if (!ts.isFunctionExpression(regularFunction) && !ts.isArrowFunction(regularFunction)) {
|
|
5507
|
+
return typeParserIssue("Node is not a function expression or arrow function", void 0, node);
|
|
5508
|
+
}
|
|
5509
|
+
if (ts.isFunctionExpression(regularFunction) && regularFunction.asteriskToken !== void 0) {
|
|
5510
|
+
return typeParserIssue("Node is a generator function, not a regular function", void 0, node);
|
|
5511
|
+
}
|
|
5512
|
+
const expressionToTest = ts.isCallExpression(node.expression) ? node.expression.expression : node.expression;
|
|
5513
|
+
if (!ts.isPropertyAccessExpression(expressionToTest)) {
|
|
5514
|
+
return typeParserIssue("Node is not a property access expression", void 0, node);
|
|
5515
|
+
}
|
|
5516
|
+
const propertyAccess = expressionToTest;
|
|
5517
|
+
const pipeArguments2 = node.arguments.slice(1);
|
|
5518
|
+
return pipe(
|
|
5519
|
+
isNodeReferenceToEffectModuleApi("fn")(propertyAccess),
|
|
5520
|
+
map8(() => ({
|
|
5521
|
+
node,
|
|
5522
|
+
effectModule: propertyAccess.expression,
|
|
5523
|
+
regularFunction,
|
|
5524
|
+
pipeArguments: pipeArguments2
|
|
5525
|
+
}))
|
|
5526
|
+
);
|
|
5527
|
+
},
|
|
5528
|
+
"TypeParser.effectFn",
|
|
5529
|
+
(node) => node
|
|
5530
|
+
);
|
|
5440
5531
|
const unnecessaryEffectGen2 = cachedBy(
|
|
5441
5532
|
fn("TypeParser.unnecessaryEffectGen")(function* (node) {
|
|
5442
5533
|
const { body } = yield* effectGen(node);
|
|
@@ -5548,6 +5639,28 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5548
5639
|
`TypeParser.isNodeReferenceToEffectSchemaModuleApi(${memberName})`,
|
|
5549
5640
|
(node) => node
|
|
5550
5641
|
);
|
|
5642
|
+
const isEffectParseResultSourceFile = cachedBy(
|
|
5643
|
+
fn("TypeParser.isEffectParseResultSourceFile")(function* (sourceFile) {
|
|
5644
|
+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
5645
|
+
if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
|
|
5646
|
+
const parseIssueSymbol = typeChecker.tryGetMemberInModuleExports("ParseIssue", moduleSymbol);
|
|
5647
|
+
if (!parseIssueSymbol) return yield* typeParserIssue("ParseIssue type not found", void 0, sourceFile);
|
|
5648
|
+
const decodeSyncSymbol = typeChecker.tryGetMemberInModuleExports("decodeSync", moduleSymbol);
|
|
5649
|
+
if (!decodeSyncSymbol) return yield* typeParserIssue("decodeSync not found", void 0, sourceFile);
|
|
5650
|
+
const encodeSyncSymbol = typeChecker.tryGetMemberInModuleExports("encodeSync", moduleSymbol);
|
|
5651
|
+
if (!encodeSyncSymbol) return yield* typeParserIssue("encodeSync not found", void 0, sourceFile);
|
|
5652
|
+
return sourceFile;
|
|
5653
|
+
}),
|
|
5654
|
+
"TypeParser.isEffectParseResultSourceFile",
|
|
5655
|
+
(sourceFile) => sourceFile
|
|
5656
|
+
);
|
|
5657
|
+
const isNodeReferenceToEffectParseResultModuleApi = (memberName) => cachedBy(
|
|
5658
|
+
fn("TypeParser.isNodeReferenceToEffectParseResultModuleApi")(function* (node) {
|
|
5659
|
+
return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectParseResultSourceFile, memberName);
|
|
5660
|
+
}),
|
|
5661
|
+
`TypeParser.isNodeReferenceToEffectParseResultModuleApi(${memberName})`,
|
|
5662
|
+
(node) => node
|
|
5663
|
+
);
|
|
5551
5664
|
const contextTagVarianceStruct = (type, atLocation) => map8(
|
|
5552
5665
|
all(
|
|
5553
5666
|
varianceStructInvariantType(type, atLocation, "_Identifier"),
|
|
@@ -6328,11 +6441,65 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
6328
6441
|
if (includeEffectFn) {
|
|
6329
6442
|
const effectFnGenParsed = yield* pipe(effectFnGen(node), option);
|
|
6330
6443
|
const effectFnUntracedGenParsed = isNone2(effectFnGenParsed) ? yield* pipe(effectFnUntracedGen(node), option) : none2();
|
|
6331
|
-
const
|
|
6332
|
-
const
|
|
6333
|
-
const
|
|
6334
|
-
|
|
6335
|
-
|
|
6444
|
+
const effectFnNonGenParsed = isNone2(effectFnGenParsed) && isNone2(effectFnUntracedGenParsed) ? yield* pipe(effectFn(node), option) : none2();
|
|
6445
|
+
const isEffectFnGen = isSome2(effectFnGenParsed);
|
|
6446
|
+
const isEffectFnUntracedGen = isSome2(effectFnUntracedGenParsed);
|
|
6447
|
+
const isEffectFnNonGen = isSome2(effectFnNonGenParsed);
|
|
6448
|
+
const transformationKind = isEffectFnUntracedGen ? "effectFnUntraced" : "effectFn";
|
|
6449
|
+
if (isEffectFnGen || isEffectFnUntracedGen) {
|
|
6450
|
+
const effectFnParsed = isEffectFnGen ? effectFnGenParsed : effectFnUntracedGenParsed;
|
|
6451
|
+
if (isSome2(effectFnParsed) && effectFnParsed.value.pipeArguments.length > 0) {
|
|
6452
|
+
const fnResult = effectFnParsed.value;
|
|
6453
|
+
const pipeArgs = fnResult.pipeArguments;
|
|
6454
|
+
const transformations = [];
|
|
6455
|
+
let subjectType;
|
|
6456
|
+
for (let i = 0; i < pipeArgs.length; i++) {
|
|
6457
|
+
const arg = pipeArgs[i];
|
|
6458
|
+
const contextualType = typeChecker.getContextualType(arg);
|
|
6459
|
+
const callSigs = contextualType ? typeChecker.getSignaturesOfType(contextualType, ts.SignatureKind.Call) : [];
|
|
6460
|
+
const outType = callSigs.length > 0 ? typeChecker.getReturnTypeOfSignature(callSigs[0]) : void 0;
|
|
6461
|
+
if (i === 0 && callSigs.length > 0) {
|
|
6462
|
+
const params = callSigs[0].parameters;
|
|
6463
|
+
if (params.length > 0) {
|
|
6464
|
+
subjectType = typeChecker.getTypeOfSymbol(params[0]);
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6467
|
+
if (ts.isCallExpression(arg)) {
|
|
6468
|
+
transformations.push({
|
|
6469
|
+
callee: arg.expression,
|
|
6470
|
+
args: Array.from(arg.arguments),
|
|
6471
|
+
outType,
|
|
6472
|
+
kind: transformationKind
|
|
6473
|
+
});
|
|
6474
|
+
} else {
|
|
6475
|
+
transformations.push({
|
|
6476
|
+
callee: arg,
|
|
6477
|
+
args: void 0,
|
|
6478
|
+
outType,
|
|
6479
|
+
kind: transformationKind
|
|
6480
|
+
});
|
|
6481
|
+
}
|
|
6482
|
+
}
|
|
6483
|
+
const newFlow = {
|
|
6484
|
+
node,
|
|
6485
|
+
subject: {
|
|
6486
|
+
node,
|
|
6487
|
+
outType: subjectType
|
|
6488
|
+
},
|
|
6489
|
+
transformations
|
|
6490
|
+
};
|
|
6491
|
+
result.push(newFlow);
|
|
6492
|
+
workQueue.push([fnResult.body, void 0]);
|
|
6493
|
+
for (const arg of pipeArgs) {
|
|
6494
|
+
ts.forEachChild(arg, (c) => {
|
|
6495
|
+
workQueue.push([c, void 0]);
|
|
6496
|
+
});
|
|
6497
|
+
}
|
|
6498
|
+
continue;
|
|
6499
|
+
}
|
|
6500
|
+
}
|
|
6501
|
+
if (isEffectFnNonGen && isSome2(effectFnNonGenParsed) && effectFnNonGenParsed.value.pipeArguments.length > 0) {
|
|
6502
|
+
const fnResult = effectFnNonGenParsed.value;
|
|
6336
6503
|
const pipeArgs = fnResult.pipeArguments;
|
|
6337
6504
|
const transformations = [];
|
|
6338
6505
|
let subjectType;
|
|
@@ -6352,14 +6519,14 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
6352
6519
|
callee: arg.expression,
|
|
6353
6520
|
args: Array.from(arg.arguments),
|
|
6354
6521
|
outType,
|
|
6355
|
-
kind:
|
|
6522
|
+
kind: "effectFn"
|
|
6356
6523
|
});
|
|
6357
6524
|
} else {
|
|
6358
6525
|
transformations.push({
|
|
6359
6526
|
callee: arg,
|
|
6360
6527
|
args: void 0,
|
|
6361
6528
|
outType,
|
|
6362
|
-
kind:
|
|
6529
|
+
kind: "effectFn"
|
|
6363
6530
|
});
|
|
6364
6531
|
}
|
|
6365
6532
|
}
|
|
@@ -6372,7 +6539,16 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
6372
6539
|
transformations
|
|
6373
6540
|
};
|
|
6374
6541
|
result.push(newFlow);
|
|
6375
|
-
|
|
6542
|
+
const regularFn = fnResult.regularFunction;
|
|
6543
|
+
if (ts.isArrowFunction(regularFn)) {
|
|
6544
|
+
if (ts.isBlock(regularFn.body)) {
|
|
6545
|
+
workQueue.push([regularFn.body, void 0]);
|
|
6546
|
+
} else {
|
|
6547
|
+
workQueue.push([regularFn.body, void 0]);
|
|
6548
|
+
}
|
|
6549
|
+
} else if (regularFn.body) {
|
|
6550
|
+
workQueue.push([regularFn.body, void 0]);
|
|
6551
|
+
}
|
|
6376
6552
|
for (const arg of pipeArgs) {
|
|
6377
6553
|
ts.forEachChild(arg, (c) => {
|
|
6378
6554
|
workQueue.push([c, void 0]);
|
|
@@ -6435,6 +6611,7 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
6435
6611
|
return {
|
|
6436
6612
|
isNodeReferenceToEffectModuleApi,
|
|
6437
6613
|
isNodeReferenceToEffectSchemaModuleApi,
|
|
6614
|
+
isNodeReferenceToEffectParseResultModuleApi,
|
|
6438
6615
|
isNodeReferenceToEffectDataModuleApi,
|
|
6439
6616
|
isNodeReferenceToEffectContextModuleApi,
|
|
6440
6617
|
isNodeReferenceToEffectSqlModelModuleApi,
|
|
@@ -6448,6 +6625,8 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
6448
6625
|
effectGen,
|
|
6449
6626
|
effectFnUntracedGen,
|
|
6450
6627
|
effectFnGen,
|
|
6628
|
+
findEnclosingScopes,
|
|
6629
|
+
effectFn,
|
|
6451
6630
|
extendsCauseYieldableError,
|
|
6452
6631
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
6453
6632
|
effectSchemaType,
|
|
@@ -8147,106 +8326,195 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
8147
8326
|
});
|
|
8148
8327
|
|
|
8149
8328
|
// src/diagnostics/effectFnOpportunity.ts
|
|
8150
|
-
var parseEffectFnOpportunityTarget = (node, sourceFile) => gen(function* () {
|
|
8151
|
-
const ts = yield* service(TypeScriptApi);
|
|
8152
|
-
const typeChecker = yield* service(TypeCheckerApi);
|
|
8153
|
-
const typeParser = yield* service(TypeParser);
|
|
8154
|
-
const tsUtils = yield* service(TypeScriptUtils);
|
|
8155
|
-
if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
|
|
8156
|
-
return yield* TypeParserIssue.issue;
|
|
8157
|
-
}
|
|
8158
|
-
if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
|
|
8159
|
-
return yield* TypeParserIssue.issue;
|
|
8160
|
-
}
|
|
8161
|
-
if (ts.isFunctionExpression(node) && node.name) {
|
|
8162
|
-
return yield* TypeParserIssue.issue;
|
|
8163
|
-
}
|
|
8164
|
-
let bodyExpression;
|
|
8165
|
-
if (ts.isArrowFunction(node)) {
|
|
8166
|
-
if (ts.isBlock(node.body)) {
|
|
8167
|
-
const returnStatement = findSingleReturnStatement(ts, node.body);
|
|
8168
|
-
if (returnStatement?.expression) {
|
|
8169
|
-
bodyExpression = returnStatement.expression;
|
|
8170
|
-
}
|
|
8171
|
-
} else {
|
|
8172
|
-
bodyExpression = node.body;
|
|
8173
|
-
}
|
|
8174
|
-
} else if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.body) {
|
|
8175
|
-
const returnStatement = findSingleReturnStatement(ts, node.body);
|
|
8176
|
-
if (returnStatement?.expression) {
|
|
8177
|
-
bodyExpression = returnStatement.expression;
|
|
8178
|
-
}
|
|
8179
|
-
}
|
|
8180
|
-
if (!bodyExpression) return yield* TypeParserIssue.issue;
|
|
8181
|
-
const { pipeArguments: pipeArguments2, subject } = yield* pipe(
|
|
8182
|
-
typeParser.pipeCall(bodyExpression),
|
|
8183
|
-
map8(({ args: args2, subject: subject2 }) => ({ subject: subject2, pipeArguments: args2 })),
|
|
8184
|
-
orElse2(() => succeed({ subject: bodyExpression, pipeArguments: [] }))
|
|
8185
|
-
);
|
|
8186
|
-
const { effectModule, generatorFunction } = yield* typeParser.effectGen(subject);
|
|
8187
|
-
const functionType = typeChecker.getTypeAtLocation(node);
|
|
8188
|
-
if (!functionType) return yield* TypeParserIssue.issue;
|
|
8189
|
-
const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
|
|
8190
|
-
if (callSignatures.length !== 1) return yield* TypeParserIssue.issue;
|
|
8191
|
-
const signature = callSignatures[0];
|
|
8192
|
-
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
8193
|
-
const { A, E, R } = yield* typeParser.strictEffectType(returnType, node);
|
|
8194
|
-
const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
8195
|
-
sourceFile,
|
|
8196
|
-
"effect",
|
|
8197
|
-
"Effect"
|
|
8198
|
-
) || "Effect";
|
|
8199
|
-
const nameIdentifier = getNameIdentifier(ts, node);
|
|
8200
|
-
const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
|
|
8201
|
-
const hasReturnTypeAnnotation = !!node.type;
|
|
8202
|
-
return {
|
|
8203
|
-
node,
|
|
8204
|
-
nameIdentifier,
|
|
8205
|
-
effectModule,
|
|
8206
|
-
generatorFunction,
|
|
8207
|
-
effectModuleName,
|
|
8208
|
-
traceName,
|
|
8209
|
-
hasReturnTypeAnnotation,
|
|
8210
|
-
effectTypes: { A, E, R },
|
|
8211
|
-
pipeArguments: pipeArguments2
|
|
8212
|
-
};
|
|
8213
|
-
});
|
|
8214
8329
|
var effectFnOpportunity = createDiagnostic({
|
|
8215
8330
|
name: "effectFnOpportunity",
|
|
8216
8331
|
code: 41,
|
|
8217
|
-
description: "Suggests using Effect.fn for functions that
|
|
8332
|
+
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
8218
8333
|
severity: "suggestion",
|
|
8219
8334
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
8220
8335
|
const ts = yield* service(TypeScriptApi);
|
|
8221
8336
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
8337
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
8338
|
+
const typeParser = yield* service(TypeParser);
|
|
8222
8339
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
8223
|
-
const
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
)
|
|
8237
|
-
|
|
8340
|
+
const sourceEffectModuleName = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
8341
|
+
sourceFile,
|
|
8342
|
+
"effect",
|
|
8343
|
+
"Effect"
|
|
8344
|
+
) || "Effect";
|
|
8345
|
+
const findSingleReturnStatement = (block) => {
|
|
8346
|
+
if (block.statements.length !== 1) return void 0;
|
|
8347
|
+
const statement = block.statements[0];
|
|
8348
|
+
if (!ts.isReturnStatement(statement)) return void 0;
|
|
8349
|
+
return statement;
|
|
8350
|
+
};
|
|
8351
|
+
const getBodyExpression = (fnNode) => {
|
|
8352
|
+
if (ts.isArrowFunction(fnNode)) {
|
|
8353
|
+
if (ts.isBlock(fnNode.body)) {
|
|
8354
|
+
return findSingleReturnStatement(fnNode.body)?.expression;
|
|
8355
|
+
}
|
|
8356
|
+
return fnNode.body;
|
|
8357
|
+
} else if ((ts.isFunctionExpression(fnNode) || ts.isFunctionDeclaration(fnNode)) && fnNode.body) {
|
|
8358
|
+
return findSingleReturnStatement(fnNode.body)?.expression;
|
|
8359
|
+
}
|
|
8360
|
+
return void 0;
|
|
8361
|
+
};
|
|
8362
|
+
const getNameIdentifier = (node) => {
|
|
8363
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
8364
|
+
return node.name;
|
|
8365
|
+
}
|
|
8366
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
8367
|
+
return node.parent.name;
|
|
8368
|
+
}
|
|
8369
|
+
if (node.parent && ts.isPropertyAssignment(node.parent)) {
|
|
8370
|
+
const name = node.parent.name;
|
|
8371
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
8372
|
+
return name;
|
|
8373
|
+
}
|
|
8374
|
+
}
|
|
8375
|
+
if (node.parent && ts.isPropertyDeclaration(node.parent)) {
|
|
8376
|
+
const name = node.parent.name;
|
|
8377
|
+
if (ts.isIdentifier(name)) {
|
|
8378
|
+
return name;
|
|
8379
|
+
}
|
|
8380
|
+
}
|
|
8381
|
+
return void 0;
|
|
8382
|
+
};
|
|
8383
|
+
const areParametersReferencedIn = (fnNode, nodes2) => {
|
|
8384
|
+
if (fnNode.parameters.length === 0 || nodes2.length === 0) return false;
|
|
8385
|
+
const firstParam = fnNode.parameters[0];
|
|
8386
|
+
const lastParam = fnNode.parameters[fnNode.parameters.length - 1];
|
|
8387
|
+
const paramsStart = firstParam.pos;
|
|
8388
|
+
const paramsEnd = lastParam.end;
|
|
8389
|
+
const isSymbolDeclaredInParams = (symbol3) => {
|
|
8390
|
+
const declarations = symbol3.declarations;
|
|
8391
|
+
if (!declarations) return false;
|
|
8392
|
+
return declarations.some((decl) => decl.pos >= paramsStart && decl.end <= paramsEnd);
|
|
8393
|
+
};
|
|
8394
|
+
const nodesToVisit = [...nodes2];
|
|
8395
|
+
while (nodesToVisit.length > 0) {
|
|
8396
|
+
const node = nodesToVisit.shift();
|
|
8397
|
+
if (ts.isIdentifier(node)) {
|
|
8398
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node);
|
|
8399
|
+
if (symbol3 && isSymbolDeclaredInParams(symbol3)) {
|
|
8400
|
+
return true;
|
|
8401
|
+
}
|
|
8402
|
+
}
|
|
8403
|
+
if (ts.isShorthandPropertyAssignment(node)) {
|
|
8404
|
+
const valueSymbol = typeChecker.getShorthandAssignmentValueSymbol(node);
|
|
8405
|
+
if (valueSymbol && isSymbolDeclaredInParams(valueSymbol)) {
|
|
8406
|
+
return true;
|
|
8407
|
+
}
|
|
8408
|
+
}
|
|
8409
|
+
ts.forEachChild(node, (child) => {
|
|
8410
|
+
nodesToVisit.push(child);
|
|
8411
|
+
return void 0;
|
|
8412
|
+
});
|
|
8413
|
+
}
|
|
8414
|
+
return false;
|
|
8415
|
+
};
|
|
8416
|
+
const tryParseGenOpportunity = (fnNode) => gen(function* () {
|
|
8417
|
+
const bodyExpression = getBodyExpression(fnNode);
|
|
8418
|
+
if (!bodyExpression) return yield* TypeParserIssue.issue;
|
|
8419
|
+
const { pipeArguments: pipeArguments2, subject } = yield* pipe(
|
|
8420
|
+
typeParser.pipeCall(bodyExpression),
|
|
8421
|
+
map8(({ args: args2, subject: subject2 }) => ({ subject: subject2, pipeArguments: args2 })),
|
|
8422
|
+
orElse2(() => succeed({ subject: bodyExpression, pipeArguments: [] }))
|
|
8423
|
+
);
|
|
8424
|
+
const { effectModule, generatorFunction } = yield* typeParser.effectGen(subject);
|
|
8425
|
+
const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : sourceEffectModuleName;
|
|
8426
|
+
return { effectModuleName, generatorFunction, pipeArguments: pipeArguments2 };
|
|
8427
|
+
});
|
|
8428
|
+
const isInsideEffectFn = (fnNode) => {
|
|
8429
|
+
const parent = fnNode.parent;
|
|
8430
|
+
if (!parent || !ts.isCallExpression(parent)) {
|
|
8431
|
+
return succeed(false);
|
|
8432
|
+
}
|
|
8433
|
+
if (parent.arguments[0] !== fnNode) {
|
|
8434
|
+
return succeed(false);
|
|
8435
|
+
}
|
|
8436
|
+
return pipe(
|
|
8437
|
+
typeParser.effectFn(parent),
|
|
8438
|
+
orElse2(() => typeParser.effectFnGen(parent)),
|
|
8439
|
+
orElse2(() => typeParser.effectFnUntracedGen(parent)),
|
|
8440
|
+
map8(() => true),
|
|
8441
|
+
orElse2(() => succeed(false))
|
|
8238
8442
|
);
|
|
8239
8443
|
};
|
|
8240
|
-
const
|
|
8241
|
-
|
|
8242
|
-
|
|
8444
|
+
const parseEffectFnOpportunityTarget = (node) => gen(function* () {
|
|
8445
|
+
if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
|
|
8446
|
+
return yield* TypeParserIssue.issue;
|
|
8447
|
+
}
|
|
8448
|
+
if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
|
|
8449
|
+
return yield* TypeParserIssue.issue;
|
|
8450
|
+
}
|
|
8451
|
+
if (ts.isFunctionExpression(node) && node.name) {
|
|
8452
|
+
return yield* TypeParserIssue.issue;
|
|
8453
|
+
}
|
|
8454
|
+
if (yield* isInsideEffectFn(node)) {
|
|
8455
|
+
return yield* TypeParserIssue.issue;
|
|
8456
|
+
}
|
|
8457
|
+
const functionType = typeChecker.getTypeAtLocation(node);
|
|
8458
|
+
if (!functionType) return yield* TypeParserIssue.issue;
|
|
8459
|
+
const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
|
|
8460
|
+
if (callSignatures.length !== 1) return yield* TypeParserIssue.issue;
|
|
8461
|
+
const signature = callSignatures[0];
|
|
8462
|
+
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
8463
|
+
const unionMembers = typeCheckerUtils.unrollUnionMembers(returnType);
|
|
8464
|
+
yield* all(...unionMembers.map((member) => typeParser.strictEffectType(member, node)));
|
|
8465
|
+
const nameIdentifier = getNameIdentifier(node);
|
|
8466
|
+
const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
|
|
8467
|
+
if (!traceName) return yield* TypeParserIssue.issue;
|
|
8468
|
+
const opportunity = yield* pipe(
|
|
8469
|
+
tryParseGenOpportunity(node),
|
|
8470
|
+
orElse2(() => {
|
|
8471
|
+
if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
|
|
8472
|
+
return TypeParserIssue.issue;
|
|
8473
|
+
}
|
|
8474
|
+
const body = ts.isArrowFunction(node) ? node.body : node.body;
|
|
8475
|
+
if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
|
|
8476
|
+
return TypeParserIssue.issue;
|
|
8477
|
+
}
|
|
8478
|
+
return succeed({
|
|
8479
|
+
effectModuleName: sourceEffectModuleName,
|
|
8480
|
+
pipeArguments: [],
|
|
8481
|
+
generatorFunction: void 0
|
|
8482
|
+
});
|
|
8483
|
+
})
|
|
8484
|
+
);
|
|
8485
|
+
return {
|
|
8486
|
+
node,
|
|
8487
|
+
nameIdentifier,
|
|
8488
|
+
effectModuleName: opportunity.effectModuleName,
|
|
8489
|
+
traceName,
|
|
8490
|
+
pipeArguments: opportunity.pipeArguments,
|
|
8491
|
+
generatorFunction: opportunity.generatorFunction,
|
|
8492
|
+
hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
|
|
8493
|
+
};
|
|
8494
|
+
});
|
|
8495
|
+
const getFunctionBodyBlock = (node) => {
|
|
8496
|
+
if (ts.isArrowFunction(node)) {
|
|
8497
|
+
if (ts.isBlock(node.body)) {
|
|
8498
|
+
return node.body;
|
|
8499
|
+
}
|
|
8500
|
+
return ts.factory.createBlock([ts.factory.createReturnStatement(node.body)], true);
|
|
8501
|
+
}
|
|
8502
|
+
return node.body;
|
|
8503
|
+
};
|
|
8504
|
+
const isGeneratorFunction = (node) => {
|
|
8505
|
+
if (ts.isArrowFunction(node)) return false;
|
|
8506
|
+
return node.asteriskToken !== void 0;
|
|
8507
|
+
};
|
|
8508
|
+
const createEffectFnNode = (originalNode, innerFunction, effectModuleName, traceName, pipeArguments2) => {
|
|
8509
|
+
const isGenerator = isGeneratorFunction(innerFunction);
|
|
8510
|
+
const newFunction = ts.factory.createFunctionExpression(
|
|
8243
8511
|
void 0,
|
|
8244
|
-
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
8512
|
+
isGenerator ? ts.factory.createToken(ts.SyntaxKind.AsteriskToken) : void 0,
|
|
8245
8513
|
void 0,
|
|
8246
8514
|
originalNode.typeParameters,
|
|
8247
8515
|
originalNode.parameters,
|
|
8248
|
-
|
|
8249
|
-
|
|
8516
|
+
void 0,
|
|
8517
|
+
getFunctionBodyBlock(innerFunction)
|
|
8250
8518
|
);
|
|
8251
8519
|
let fnExpression = ts.factory.createPropertyAccessExpression(
|
|
8252
8520
|
ts.factory.createIdentifier(effectModuleName),
|
|
@@ -8259,34 +8527,27 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
8259
8527
|
[ts.factory.createStringLiteral(traceName)]
|
|
8260
8528
|
);
|
|
8261
8529
|
}
|
|
8262
|
-
const effectFnCall = ts.factory.createCallExpression(
|
|
8263
|
-
fnExpression,
|
|
8264
|
-
void 0,
|
|
8265
|
-
[newGeneratorFunction, ...pipeArguments2]
|
|
8266
|
-
);
|
|
8530
|
+
const effectFnCall = ts.factory.createCallExpression(fnExpression, void 0, [newFunction, ...pipeArguments2]);
|
|
8267
8531
|
if (ts.isFunctionDeclaration(originalNode)) {
|
|
8268
8532
|
return tsUtils.tryPreserveDeclarationSemantics(originalNode, effectFnCall, false);
|
|
8269
8533
|
}
|
|
8270
8534
|
return effectFnCall;
|
|
8271
8535
|
};
|
|
8272
|
-
const createEffectFnUntracedNode = (originalNode,
|
|
8273
|
-
const
|
|
8274
|
-
const
|
|
8536
|
+
const createEffectFnUntracedNode = (originalNode, innerFunction, effectModuleName, pipeArguments2) => {
|
|
8537
|
+
const isGenerator = isGeneratorFunction(innerFunction);
|
|
8538
|
+
const newFunction = ts.factory.createFunctionExpression(
|
|
8275
8539
|
void 0,
|
|
8276
|
-
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
8540
|
+
isGenerator ? ts.factory.createToken(ts.SyntaxKind.AsteriskToken) : void 0,
|
|
8277
8541
|
void 0,
|
|
8278
8542
|
originalNode.typeParameters,
|
|
8279
8543
|
originalNode.parameters,
|
|
8280
|
-
|
|
8281
|
-
|
|
8544
|
+
void 0,
|
|
8545
|
+
getFunctionBodyBlock(innerFunction)
|
|
8282
8546
|
);
|
|
8283
8547
|
const effectFnCall = ts.factory.createCallExpression(
|
|
8284
|
-
ts.factory.createPropertyAccessExpression(
|
|
8285
|
-
ts.factory.createIdentifier(effectModuleName),
|
|
8286
|
-
"fnUntraced"
|
|
8287
|
-
),
|
|
8548
|
+
ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(effectModuleName), "fnUntraced"),
|
|
8288
8549
|
void 0,
|
|
8289
|
-
[
|
|
8550
|
+
[newFunction, ...pipeArguments2]
|
|
8290
8551
|
);
|
|
8291
8552
|
if (ts.isFunctionDeclaration(originalNode)) {
|
|
8292
8553
|
return tsUtils.tryPreserveDeclarationSemantics(originalNode, effectFnCall, false);
|
|
@@ -8302,88 +8563,41 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
8302
8563
|
while (nodeToVisit.length > 0) {
|
|
8303
8564
|
const node = nodeToVisit.shift();
|
|
8304
8565
|
ts.forEachChild(node, appendNodeToVisit);
|
|
8305
|
-
const target = yield* pipe(
|
|
8306
|
-
parseEffectFnOpportunityTarget(node, sourceFile),
|
|
8307
|
-
option
|
|
8308
|
-
);
|
|
8566
|
+
const target = yield* pipe(parseEffectFnOpportunityTarget(node), option);
|
|
8309
8567
|
if (isNone2(target)) continue;
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
generatorFunction,
|
|
8314
|
-
hasReturnTypeAnnotation,
|
|
8315
|
-
nameIdentifier,
|
|
8316
|
-
node: targetNode,
|
|
8317
|
-
pipeArguments: pipeArguments2,
|
|
8318
|
-
traceName
|
|
8319
|
-
} = target.value;
|
|
8568
|
+
if (target.value.hasParamsInPipeArgs) continue;
|
|
8569
|
+
const { effectModuleName, nameIdentifier, node: targetNode, pipeArguments: pipeArguments2, traceName } = target.value;
|
|
8570
|
+
const innerFunction = target.value.generatorFunction ?? targetNode;
|
|
8320
8571
|
const fixes = [];
|
|
8321
8572
|
fixes.push({
|
|
8322
8573
|
fixName: "effectFnOpportunity_toEffectFn",
|
|
8323
8574
|
description: traceName ? `Convert to Effect.fn("${traceName}")` : "Convert to Effect.fn",
|
|
8324
8575
|
apply: gen(function* () {
|
|
8325
8576
|
const changeTracker = yield* service(ChangeTracker);
|
|
8326
|
-
const newNode = createEffectFnNode(
|
|
8327
|
-
targetNode,
|
|
8328
|
-
generatorFunction,
|
|
8329
|
-
effectModuleName,
|
|
8330
|
-
traceName,
|
|
8331
|
-
hasReturnTypeAnnotation ? effectTypes : void 0,
|
|
8332
|
-
pipeArguments2
|
|
8333
|
-
);
|
|
8334
|
-
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
8335
|
-
})
|
|
8336
|
-
});
|
|
8337
|
-
fixes.push({
|
|
8338
|
-
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
8339
|
-
description: "Convert to Effect.fnUntraced",
|
|
8340
|
-
apply: gen(function* () {
|
|
8341
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
8342
|
-
const newNode = createEffectFnUntracedNode(
|
|
8343
|
-
targetNode,
|
|
8344
|
-
generatorFunction,
|
|
8345
|
-
effectModuleName,
|
|
8346
|
-
hasReturnTypeAnnotation ? effectTypes : void 0,
|
|
8347
|
-
pipeArguments2
|
|
8348
|
-
);
|
|
8577
|
+
const newNode = createEffectFnNode(targetNode, innerFunction, effectModuleName, traceName, pipeArguments2);
|
|
8349
8578
|
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
8350
8579
|
})
|
|
8351
8580
|
});
|
|
8581
|
+
if (target.value.generatorFunction) {
|
|
8582
|
+
fixes.push({
|
|
8583
|
+
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
8584
|
+
description: "Convert to Effect.fnUntraced",
|
|
8585
|
+
apply: gen(function* () {
|
|
8586
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
8587
|
+
const newNode = createEffectFnUntracedNode(targetNode, innerFunction, effectModuleName, pipeArguments2);
|
|
8588
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
8589
|
+
})
|
|
8590
|
+
});
|
|
8591
|
+
}
|
|
8592
|
+
const pipeArgsSuffix = pipeArguments2.length > 0 ? ` Effect.fn also accepts the piped transformations as additional arguments.` : ``;
|
|
8352
8593
|
report({
|
|
8353
8594
|
location: nameIdentifier ?? targetNode,
|
|
8354
|
-
messageText: `This function could benefit from Effect.fn's automatic tracing and concise syntax, or Effect.fnUntraced to get just a more concise syntax
|
|
8595
|
+
messageText: target.value.generatorFunction ? `This function could benefit from Effect.fn's automatic tracing and concise syntax, or Effect.fnUntraced to get just a more concise syntax.${pipeArgsSuffix}` : `This function could benefit from Effect.fn's automatic tracing and concise syntax.${pipeArgsSuffix}`,
|
|
8355
8596
|
fixes
|
|
8356
8597
|
});
|
|
8357
8598
|
}
|
|
8358
8599
|
})
|
|
8359
8600
|
});
|
|
8360
|
-
function findSingleReturnStatement(ts, block) {
|
|
8361
|
-
if (block.statements.length !== 1) return void 0;
|
|
8362
|
-
const statement = block.statements[0];
|
|
8363
|
-
if (!ts.isReturnStatement(statement)) return void 0;
|
|
8364
|
-
return statement;
|
|
8365
|
-
}
|
|
8366
|
-
function getNameIdentifier(ts, node) {
|
|
8367
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
8368
|
-
return node.name;
|
|
8369
|
-
}
|
|
8370
|
-
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
8371
|
-
return node.parent.name;
|
|
8372
|
-
}
|
|
8373
|
-
if (node.parent && ts.isPropertyAssignment(node.parent)) {
|
|
8374
|
-
const name = node.parent.name;
|
|
8375
|
-
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
8376
|
-
return name;
|
|
8377
|
-
}
|
|
8378
|
-
}
|
|
8379
|
-
if (node.parent && ts.isPropertyDeclaration(node.parent)) {
|
|
8380
|
-
const name = node.parent.name;
|
|
8381
|
-
if (ts.isIdentifier(name)) {
|
|
8382
|
-
return name;
|
|
8383
|
-
}
|
|
8384
|
-
}
|
|
8385
|
-
return void 0;
|
|
8386
|
-
}
|
|
8387
8601
|
|
|
8388
8602
|
// src/diagnostics/effectGenUsesAdapter.ts
|
|
8389
8603
|
var effectGenUsesAdapter = createDiagnostic({
|
|
@@ -9146,6 +9360,52 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
9146
9360
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
9147
9361
|
const typeParser = yield* service(TypeParser);
|
|
9148
9362
|
const options = yield* service(LanguageServicePluginOptions);
|
|
9363
|
+
const isSafelyPipeableCallee = (callee) => {
|
|
9364
|
+
if (ts.isCallExpression(callee)) {
|
|
9365
|
+
return true;
|
|
9366
|
+
}
|
|
9367
|
+
if (ts.isArrowFunction(callee)) {
|
|
9368
|
+
return true;
|
|
9369
|
+
}
|
|
9370
|
+
if (ts.isFunctionExpression(callee)) {
|
|
9371
|
+
return true;
|
|
9372
|
+
}
|
|
9373
|
+
if (ts.isParenthesizedExpression(callee)) {
|
|
9374
|
+
return isSafelyPipeableCallee(callee.expression);
|
|
9375
|
+
}
|
|
9376
|
+
if (ts.isIdentifier(callee)) {
|
|
9377
|
+
const symbol3 = typeChecker.getSymbolAtLocation(callee);
|
|
9378
|
+
if (!symbol3) return false;
|
|
9379
|
+
if (symbol3.flags & (ts.SymbolFlags.Module | ts.SymbolFlags.Namespace | ts.SymbolFlags.ValueModule)) {
|
|
9380
|
+
return true;
|
|
9381
|
+
}
|
|
9382
|
+
const declarations = symbol3.declarations;
|
|
9383
|
+
if (declarations && declarations.length > 0) {
|
|
9384
|
+
const decl = declarations[0];
|
|
9385
|
+
if (ts.isFunctionDeclaration(decl) || ts.isVariableDeclaration(decl) || ts.isImportSpecifier(decl) || ts.isImportClause(decl) || ts.isNamespaceImport(decl)) {
|
|
9386
|
+
return true;
|
|
9387
|
+
}
|
|
9388
|
+
}
|
|
9389
|
+
return false;
|
|
9390
|
+
}
|
|
9391
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
9392
|
+
const subject = callee.expression;
|
|
9393
|
+
const symbol3 = typeChecker.getSymbolAtLocation(subject);
|
|
9394
|
+
if (!symbol3) return false;
|
|
9395
|
+
if (symbol3.flags & (ts.SymbolFlags.Module | ts.SymbolFlags.Namespace | ts.SymbolFlags.ValueModule)) {
|
|
9396
|
+
return true;
|
|
9397
|
+
}
|
|
9398
|
+
const declarations = symbol3.declarations;
|
|
9399
|
+
if (declarations && declarations.length > 0) {
|
|
9400
|
+
const decl = declarations[0];
|
|
9401
|
+
if (ts.isNamespaceImport(decl) || ts.isSourceFile(decl) || ts.isModuleDeclaration(decl)) {
|
|
9402
|
+
return true;
|
|
9403
|
+
}
|
|
9404
|
+
}
|
|
9405
|
+
return false;
|
|
9406
|
+
}
|
|
9407
|
+
return false;
|
|
9408
|
+
};
|
|
9149
9409
|
const flows = yield* typeParser.pipingFlows(false)(sourceFile);
|
|
9150
9410
|
for (const flow2 of flows) {
|
|
9151
9411
|
if (flow2.transformations.length < options.pipeableMinArgCount) {
|
|
@@ -9159,76 +9419,92 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
9159
9419
|
if (callSigs.length > 0) {
|
|
9160
9420
|
continue;
|
|
9161
9421
|
}
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9422
|
+
const isPipeableAtIndex = function* (index) {
|
|
9423
|
+
if (index === 0) {
|
|
9424
|
+
const subjectType = flow2.subject.outType;
|
|
9425
|
+
if (!subjectType) return false;
|
|
9426
|
+
const result = yield* pipe(
|
|
9427
|
+
typeParser.pipeableType(subjectType, flow2.subject.node),
|
|
9428
|
+
option
|
|
9429
|
+
);
|
|
9430
|
+
return result._tag === "Some";
|
|
9431
|
+
} else {
|
|
9432
|
+
const t = flow2.transformations[index - 1];
|
|
9433
|
+
if (!t.outType) return false;
|
|
9434
|
+
const result = yield* pipe(
|
|
9435
|
+
typeParser.pipeableType(t.outType, flow2.node),
|
|
9436
|
+
option
|
|
9437
|
+
);
|
|
9438
|
+
return result._tag === "Some";
|
|
9439
|
+
}
|
|
9440
|
+
};
|
|
9441
|
+
let searchStartIndex = 0;
|
|
9442
|
+
while (searchStartIndex <= flow2.transformations.length) {
|
|
9443
|
+
let firstPipeableIndex = -1;
|
|
9444
|
+
for (let i = searchStartIndex; i <= flow2.transformations.length; i++) {
|
|
9445
|
+
if (yield* isPipeableAtIndex(i)) {
|
|
9446
|
+
firstPipeableIndex = i;
|
|
9447
|
+
break;
|
|
9448
|
+
}
|
|
9449
|
+
}
|
|
9450
|
+
if (firstPipeableIndex === -1) {
|
|
9451
|
+
break;
|
|
9452
|
+
}
|
|
9453
|
+
const pipeableTransformations = [];
|
|
9454
|
+
for (let i = firstPipeableIndex; i < flow2.transformations.length; i++) {
|
|
9175
9455
|
const t = flow2.transformations[i];
|
|
9176
|
-
if (t.
|
|
9177
|
-
|
|
9178
|
-
typeParser.pipeableType(t.outType, flow2.node),
|
|
9179
|
-
option
|
|
9180
|
-
);
|
|
9181
|
-
if (isPipeable._tag === "Some") {
|
|
9182
|
-
firstPipeableIndex = i + 1;
|
|
9183
|
-
break;
|
|
9184
|
-
}
|
|
9456
|
+
if (!isSafelyPipeableCallee(t.callee)) {
|
|
9457
|
+
break;
|
|
9185
9458
|
}
|
|
9459
|
+
pipeableTransformations.push(t);
|
|
9186
9460
|
}
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9461
|
+
const callKindCount = pipeableTransformations.filter((t) => t.kind === "call").length;
|
|
9462
|
+
if (callKindCount >= options.pipeableMinArgCount) {
|
|
9463
|
+
const pipeableEndIndex = firstPipeableIndex + pipeableTransformations.length;
|
|
9464
|
+
const pipeableSubjectNode = firstPipeableIndex === 0 ? flow2.subject.node : typeParser.reconstructPipingFlow({
|
|
9465
|
+
subject: flow2.subject,
|
|
9466
|
+
transformations: flow2.transformations.slice(0, firstPipeableIndex)
|
|
9467
|
+
});
|
|
9468
|
+
const afterTransformations = flow2.transformations.slice(pipeableEndIndex);
|
|
9469
|
+
report({
|
|
9470
|
+
location: flow2.node,
|
|
9471
|
+
messageText: `Nested function calls can be converted to pipeable style for better readability.`,
|
|
9472
|
+
fixes: [{
|
|
9473
|
+
fixName: "missedPipeableOpportunity_fix",
|
|
9474
|
+
description: "Convert to pipe style",
|
|
9475
|
+
apply: gen(function* () {
|
|
9476
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
9477
|
+
const pipeArgs = pipeableTransformations.map((t) => {
|
|
9478
|
+
if (t.args) {
|
|
9479
|
+
return ts.factory.createCallExpression(
|
|
9480
|
+
t.callee,
|
|
9481
|
+
void 0,
|
|
9482
|
+
t.args
|
|
9483
|
+
);
|
|
9484
|
+
} else {
|
|
9485
|
+
return t.callee;
|
|
9486
|
+
}
|
|
9487
|
+
});
|
|
9488
|
+
const pipeNode = ts.factory.createCallExpression(
|
|
9489
|
+
ts.factory.createPropertyAccessExpression(
|
|
9490
|
+
pipeableSubjectNode,
|
|
9491
|
+
"pipe"
|
|
9492
|
+
),
|
|
9213
9493
|
void 0,
|
|
9214
|
-
|
|
9494
|
+
pipeArgs
|
|
9215
9495
|
);
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
changeTracker.replaceNode(sourceFile, flow2.node, newNode);
|
|
9229
|
-
})
|
|
9230
|
-
}]
|
|
9231
|
-
});
|
|
9496
|
+
const newNode = afterTransformations.length > 0 ? typeParser.reconstructPipingFlow({
|
|
9497
|
+
subject: { node: pipeNode, outType: void 0 },
|
|
9498
|
+
transformations: afterTransformations
|
|
9499
|
+
}) : pipeNode;
|
|
9500
|
+
changeTracker.replaceNode(sourceFile, flow2.node, newNode);
|
|
9501
|
+
})
|
|
9502
|
+
}]
|
|
9503
|
+
});
|
|
9504
|
+
break;
|
|
9505
|
+
}
|
|
9506
|
+
searchStartIndex = firstPipeableIndex + pipeableTransformations.length + 1;
|
|
9507
|
+
}
|
|
9232
9508
|
}
|
|
9233
9509
|
})
|
|
9234
9510
|
});
|
|
@@ -10074,6 +10350,90 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
10074
10350
|
})
|
|
10075
10351
|
});
|
|
10076
10352
|
|
|
10353
|
+
// src/diagnostics/preferSchemaOverJson.ts
|
|
10354
|
+
var preferSchemaOverJson = createDiagnostic({
|
|
10355
|
+
name: "preferSchemaOverJson",
|
|
10356
|
+
code: 44,
|
|
10357
|
+
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
10358
|
+
severity: "suggestion",
|
|
10359
|
+
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
10360
|
+
const ts = yield* service(TypeScriptApi);
|
|
10361
|
+
const typeParser = yield* service(TypeParser);
|
|
10362
|
+
const parseJsonMethod = (node) => gen(function* () {
|
|
10363
|
+
if (!ts.isCallExpression(node)) return yield* fail3("node is not a call expression");
|
|
10364
|
+
const expression = node.expression;
|
|
10365
|
+
if (!ts.isPropertyAccessExpression(expression)) return yield* fail3("expression is not a property access");
|
|
10366
|
+
const objectExpr = expression.expression;
|
|
10367
|
+
const methodName = ts.idText(expression.name);
|
|
10368
|
+
if (!ts.isIdentifier(objectExpr) || ts.idText(objectExpr) !== "JSON") {
|
|
10369
|
+
return yield* fail3("object is not JSON");
|
|
10370
|
+
}
|
|
10371
|
+
if (methodName !== "parse" && methodName !== "stringify") {
|
|
10372
|
+
return yield* fail3("method is not parse or stringify");
|
|
10373
|
+
}
|
|
10374
|
+
return { node, methodName };
|
|
10375
|
+
});
|
|
10376
|
+
const effectTrySimple = (node) => gen(function* () {
|
|
10377
|
+
if (!ts.isCallExpression(node)) return yield* fail3("node is not a call expression");
|
|
10378
|
+
yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
|
|
10379
|
+
if (node.arguments.length === 0) return yield* fail3("Effect.try has no arguments");
|
|
10380
|
+
const lazyFn = yield* typeParser.lazyExpression(node.arguments[0]);
|
|
10381
|
+
const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
|
|
10382
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
10383
|
+
});
|
|
10384
|
+
const effectTryObject = (node) => gen(function* () {
|
|
10385
|
+
if (!ts.isCallExpression(node)) return yield* fail3("node is not a call expression");
|
|
10386
|
+
yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
|
|
10387
|
+
if (node.arguments.length === 0) return yield* fail3("Effect.try has no arguments");
|
|
10388
|
+
const arg = node.arguments[0];
|
|
10389
|
+
if (!ts.isObjectLiteralExpression(arg)) return yield* fail3("argument is not an object literal");
|
|
10390
|
+
const tryProp = arg.properties.find(
|
|
10391
|
+
(p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && ts.idText(p.name) === "try"
|
|
10392
|
+
);
|
|
10393
|
+
if (!tryProp) return yield* fail3("object has no 'try' property");
|
|
10394
|
+
const lazyFn = yield* typeParser.lazyExpression(tryProp.initializer);
|
|
10395
|
+
const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
|
|
10396
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
10397
|
+
});
|
|
10398
|
+
const jsonMethodInEffectGen = (node) => gen(function* () {
|
|
10399
|
+
const jsonMethod = yield* parseJsonMethod(node);
|
|
10400
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
10401
|
+
if (!effectGen || effectGen.body.statements.length === 0) {
|
|
10402
|
+
return yield* fail3("not inside an Effect generator");
|
|
10403
|
+
}
|
|
10404
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
10405
|
+
return yield* fail3("inside a nested function scope");
|
|
10406
|
+
}
|
|
10407
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
10408
|
+
});
|
|
10409
|
+
const nodeToVisit = [];
|
|
10410
|
+
const appendNodeToVisit = (node) => {
|
|
10411
|
+
nodeToVisit.push(node);
|
|
10412
|
+
return void 0;
|
|
10413
|
+
};
|
|
10414
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
10415
|
+
while (nodeToVisit.length > 0) {
|
|
10416
|
+
const node = nodeToVisit.shift();
|
|
10417
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
10418
|
+
const match3 = yield* pipe(
|
|
10419
|
+
firstSuccessOf([
|
|
10420
|
+
effectTrySimple(node),
|
|
10421
|
+
effectTryObject(node),
|
|
10422
|
+
jsonMethodInEffectGen(node)
|
|
10423
|
+
]),
|
|
10424
|
+
option
|
|
10425
|
+
);
|
|
10426
|
+
if (isSome2(match3)) {
|
|
10427
|
+
report({
|
|
10428
|
+
location: match3.value.node,
|
|
10429
|
+
messageText: "Consider using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify",
|
|
10430
|
+
fixes: []
|
|
10431
|
+
});
|
|
10432
|
+
}
|
|
10433
|
+
}
|
|
10434
|
+
})
|
|
10435
|
+
});
|
|
10436
|
+
|
|
10077
10437
|
// src/diagnostics/redundantSchemaTagIdentifier.ts
|
|
10078
10438
|
var redundantSchemaTagIdentifier = createDiagnostic({
|
|
10079
10439
|
name: "redundantSchemaTagIdentifier",
|
|
@@ -10226,108 +10586,91 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10226
10586
|
option
|
|
10227
10587
|
);
|
|
10228
10588
|
if (isNone2(isEffectRunCall)) continue;
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
if (ts.isFunctionExpression(possiblyEffectGen) || ts.isFunctionDeclaration(possiblyEffectGen) || ts.isMethodDeclaration(possiblyEffectGen) || ts.isArrowFunction(possiblyEffectGen)) {
|
|
10235
|
-
nodeIntroduceScope = possiblyEffectGen;
|
|
10236
|
-
continue;
|
|
10237
|
-
}
|
|
10238
|
-
}
|
|
10239
|
-
const isInEffectGen = yield* pipe(
|
|
10240
|
-
typeParser.effectGen(possiblyEffectGen),
|
|
10241
|
-
orElse2(() => typeParser.effectFnUntracedGen(possiblyEffectGen)),
|
|
10242
|
-
orElse2(() => typeParser.effectFnGen(possiblyEffectGen)),
|
|
10243
|
-
option
|
|
10589
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
10590
|
+
if (effectGen && effectGen.body.statements.length > 0) {
|
|
10591
|
+
const nodeText = sourceFile.text.substring(
|
|
10592
|
+
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
10593
|
+
node.expression.end
|
|
10244
10594
|
);
|
|
10245
|
-
if (
|
|
10246
|
-
const
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
const
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
if (ts.
|
|
10262
|
-
|
|
10263
|
-
typeParser.isNodeReferenceToEffectModuleApi("runtime")(yieldedExpression.expression),
|
|
10264
|
-
option
|
|
10265
|
-
);
|
|
10266
|
-
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
10267
|
-
runtimeIdentifier = ts.idText(declaration.name);
|
|
10268
|
-
}
|
|
10595
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
10596
|
+
const fixAddRuntime = gen(function* () {
|
|
10597
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
10598
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
10599
|
+
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
10600
|
+
let runtimeIdentifier = void 0;
|
|
10601
|
+
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
10602
|
+
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
10603
|
+
const declaration = statement.declarationList.declarations[0];
|
|
10604
|
+
if (declaration.initializer && ts.isYieldExpression(declaration.initializer) && declaration.initializer.asteriskToken && declaration.initializer.expression) {
|
|
10605
|
+
const yieldedExpression = declaration.initializer.expression;
|
|
10606
|
+
if (ts.isCallExpression(yieldedExpression)) {
|
|
10607
|
+
const maybeEffectRuntime = yield* pipe(
|
|
10608
|
+
typeParser.isNodeReferenceToEffectModuleApi("runtime")(yieldedExpression.expression),
|
|
10609
|
+
option
|
|
10610
|
+
);
|
|
10611
|
+
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
10612
|
+
runtimeIdentifier = ts.idText(declaration.name);
|
|
10269
10613
|
}
|
|
10270
10614
|
}
|
|
10271
10615
|
}
|
|
10272
10616
|
}
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10617
|
+
}
|
|
10618
|
+
if (!runtimeIdentifier) {
|
|
10619
|
+
changeTracker.insertNodeAt(
|
|
10620
|
+
sourceFile,
|
|
10621
|
+
effectGen.body.statements[0].pos,
|
|
10622
|
+
ts.factory.createVariableStatement(
|
|
10623
|
+
void 0,
|
|
10624
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
10625
|
+
"effectRuntime",
|
|
10278
10626
|
void 0,
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
),
|
|
10290
|
-
[ts.factory.createTypeReferenceNode("never")],
|
|
10291
|
-
[]
|
|
10292
|
-
)
|
|
10627
|
+
void 0,
|
|
10628
|
+
ts.factory.createYieldExpression(
|
|
10629
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
10630
|
+
ts.factory.createCallExpression(
|
|
10631
|
+
ts.factory.createPropertyAccessExpression(
|
|
10632
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
10633
|
+
"runtime"
|
|
10634
|
+
),
|
|
10635
|
+
[ts.factory.createTypeReferenceNode("never")],
|
|
10636
|
+
[]
|
|
10293
10637
|
)
|
|
10294
|
-
)
|
|
10295
|
-
),
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
}
|
|
10302
|
-
changeTracker.deleteRange(sourceFile, {
|
|
10303
|
-
pos: ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
10304
|
-
end: node.arguments[0].pos
|
|
10305
|
-
});
|
|
10306
|
-
changeTracker.insertText(
|
|
10307
|
-
sourceFile,
|
|
10308
|
-
node.arguments[0].pos,
|
|
10309
|
-
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
10638
|
+
)
|
|
10639
|
+
)], ts.NodeFlags.Const)
|
|
10640
|
+
),
|
|
10641
|
+
{
|
|
10642
|
+
prefix: "\n",
|
|
10643
|
+
suffix: "\n"
|
|
10644
|
+
}
|
|
10310
10645
|
);
|
|
10646
|
+
}
|
|
10647
|
+
changeTracker.deleteRange(sourceFile, {
|
|
10648
|
+
pos: ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
10649
|
+
end: node.arguments[0].pos
|
|
10311
10650
|
});
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10651
|
+
changeTracker.insertText(
|
|
10652
|
+
sourceFile,
|
|
10653
|
+
node.arguments[0].pos,
|
|
10654
|
+
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
10655
|
+
);
|
|
10656
|
+
});
|
|
10657
|
+
report({
|
|
10658
|
+
location: node.expression,
|
|
10659
|
+
messageText: `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
|
|
10315
10660
|
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
}
|
|
10661
|
+
fixes: [{
|
|
10662
|
+
fixName: "runEffectInsideEffect_fix",
|
|
10663
|
+
description: "Use a runtime to run the Effect",
|
|
10664
|
+
apply: fixAddRuntime
|
|
10665
|
+
}]
|
|
10666
|
+
});
|
|
10667
|
+
} else {
|
|
10668
|
+
report({
|
|
10669
|
+
location: node.expression,
|
|
10670
|
+
messageText: `Using ${nodeText} inside an Effect is not recommended. Effects inside generators can usually just be yielded.`,
|
|
10671
|
+
fixes: []
|
|
10672
|
+
});
|
|
10329
10673
|
}
|
|
10330
|
-
currentParent = currentParent.parent;
|
|
10331
10674
|
}
|
|
10332
10675
|
}
|
|
10333
10676
|
})
|
|
@@ -10413,6 +10756,59 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
10413
10756
|
})
|
|
10414
10757
|
});
|
|
10415
10758
|
|
|
10759
|
+
// src/diagnostics/schemaSyncInEffect.ts
|
|
10760
|
+
var syncToEffectMethod = {
|
|
10761
|
+
decodeSync: "decode",
|
|
10762
|
+
decodeUnknownSync: "decodeUnknown",
|
|
10763
|
+
encodeSync: "encode",
|
|
10764
|
+
encodeUnknownSync: "encodeUnknown"
|
|
10765
|
+
};
|
|
10766
|
+
var schemaSyncInEffect = createDiagnostic({
|
|
10767
|
+
name: "schemaSyncInEffect",
|
|
10768
|
+
code: 43,
|
|
10769
|
+
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
10770
|
+
severity: "suggestion",
|
|
10771
|
+
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
10772
|
+
const ts = yield* service(TypeScriptApi);
|
|
10773
|
+
const typeParser = yield* service(TypeParser);
|
|
10774
|
+
const parseSchemaSyncMethod = (node, methodName) => pipe(
|
|
10775
|
+
typeParser.isNodeReferenceToEffectParseResultModuleApi(methodName)(node),
|
|
10776
|
+
map8(() => ({ node, methodName }))
|
|
10777
|
+
);
|
|
10778
|
+
const nodeToVisit = [];
|
|
10779
|
+
const appendNodeToVisit = (node) => {
|
|
10780
|
+
nodeToVisit.push(node);
|
|
10781
|
+
return void 0;
|
|
10782
|
+
};
|
|
10783
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
10784
|
+
while (nodeToVisit.length > 0) {
|
|
10785
|
+
const node = nodeToVisit.shift();
|
|
10786
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
10787
|
+
if (!ts.isCallExpression(node)) continue;
|
|
10788
|
+
const isSchemaSyncCall = yield* pipe(
|
|
10789
|
+
firstSuccessOf(
|
|
10790
|
+
Object.keys(syncToEffectMethod).map((methodName) => parseSchemaSyncMethod(node.expression, methodName))
|
|
10791
|
+
),
|
|
10792
|
+
option
|
|
10793
|
+
);
|
|
10794
|
+
if (isNone2(isSchemaSyncCall)) continue;
|
|
10795
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
10796
|
+
if (!effectGen || effectGen.body.statements.length === 0) continue;
|
|
10797
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
10798
|
+
const nodeText = sourceFile.text.substring(
|
|
10799
|
+
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
10800
|
+
node.expression.end
|
|
10801
|
+
);
|
|
10802
|
+
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
10803
|
+
report({
|
|
10804
|
+
location: node.expression,
|
|
10805
|
+
messageText: `Using ${nodeText} inside an Effect generator is not recommended. Use Schema.${effectMethodName} instead to get properly typed ParseError in the error channel.`,
|
|
10806
|
+
fixes: []
|
|
10807
|
+
});
|
|
10808
|
+
}
|
|
10809
|
+
})
|
|
10810
|
+
});
|
|
10811
|
+
|
|
10416
10812
|
// src/diagnostics/schemaUnionOfLiterals.ts
|
|
10417
10813
|
var schemaUnionOfLiterals = createDiagnostic({
|
|
10418
10814
|
name: "schemaUnionOfLiterals",
|
|
@@ -11127,7 +11523,9 @@ var diagnostics = [
|
|
|
11127
11523
|
layerMergeAllWithDependencies,
|
|
11128
11524
|
effectMapVoid,
|
|
11129
11525
|
effectFnOpportunity,
|
|
11130
|
-
redundantSchemaTagIdentifier
|
|
11526
|
+
redundantSchemaTagIdentifier,
|
|
11527
|
+
schemaSyncInEffect,
|
|
11528
|
+
preferSchemaOverJson
|
|
11131
11529
|
];
|
|
11132
11530
|
|
|
11133
11531
|
// src/completions/effectDiagnosticsComment.ts
|