@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
|
@@ -3095,6 +3095,97 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3095
3095
|
"TypeParser.effectFnGen",
|
|
3096
3096
|
(node) => node
|
|
3097
3097
|
);
|
|
3098
|
+
const findEnclosingScopes = fn("TypeParser.findEnclosingScopes")(function* (startNode) {
|
|
3099
|
+
let currentParent = startNode.parent;
|
|
3100
|
+
let scopeNode = void 0;
|
|
3101
|
+
let effectGenResult = void 0;
|
|
3102
|
+
while (currentParent) {
|
|
3103
|
+
const nodeToCheck = currentParent;
|
|
3104
|
+
if (!scopeNode) {
|
|
3105
|
+
if (ts.isFunctionExpression(nodeToCheck) || ts.isFunctionDeclaration(nodeToCheck) || ts.isMethodDeclaration(nodeToCheck) || ts.isArrowFunction(nodeToCheck) || ts.isGetAccessorDeclaration(nodeToCheck) || ts.isSetAccessorDeclaration(nodeToCheck)) {
|
|
3106
|
+
scopeNode = nodeToCheck;
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
if (!effectGenResult) {
|
|
3110
|
+
const isEffectGen = yield* pipe(
|
|
3111
|
+
effectGen(nodeToCheck),
|
|
3112
|
+
map4((result) => ({
|
|
3113
|
+
node: result.node,
|
|
3114
|
+
effectModule: result.effectModule,
|
|
3115
|
+
generatorFunction: result.generatorFunction,
|
|
3116
|
+
body: result.body
|
|
3117
|
+
})),
|
|
3118
|
+
orElse2(
|
|
3119
|
+
() => pipe(
|
|
3120
|
+
effectFnUntracedGen(nodeToCheck),
|
|
3121
|
+
map4((result) => ({
|
|
3122
|
+
node: result.node,
|
|
3123
|
+
effectModule: result.effectModule,
|
|
3124
|
+
generatorFunction: result.generatorFunction,
|
|
3125
|
+
body: result.body,
|
|
3126
|
+
pipeArguments: result.pipeArguments
|
|
3127
|
+
}))
|
|
3128
|
+
)
|
|
3129
|
+
),
|
|
3130
|
+
orElse2(
|
|
3131
|
+
() => pipe(
|
|
3132
|
+
effectFnGen(nodeToCheck),
|
|
3133
|
+
map4((result) => ({
|
|
3134
|
+
node: result.node,
|
|
3135
|
+
effectModule: result.effectModule,
|
|
3136
|
+
generatorFunction: result.generatorFunction,
|
|
3137
|
+
body: result.body,
|
|
3138
|
+
pipeArguments: result.pipeArguments
|
|
3139
|
+
}))
|
|
3140
|
+
)
|
|
3141
|
+
),
|
|
3142
|
+
option
|
|
3143
|
+
);
|
|
3144
|
+
if (isSome2(isEffectGen)) {
|
|
3145
|
+
effectGenResult = isEffectGen.value;
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
if (scopeNode && effectGenResult) {
|
|
3149
|
+
break;
|
|
3150
|
+
}
|
|
3151
|
+
currentParent = nodeToCheck.parent;
|
|
3152
|
+
}
|
|
3153
|
+
return { scopeNode, effectGen: effectGenResult };
|
|
3154
|
+
});
|
|
3155
|
+
const effectFn = cachedBy(
|
|
3156
|
+
function(node) {
|
|
3157
|
+
if (!ts.isCallExpression(node)) {
|
|
3158
|
+
return typeParserIssue("Node is not a call expression", void 0, node);
|
|
3159
|
+
}
|
|
3160
|
+
if (node.arguments.length === 0) {
|
|
3161
|
+
return typeParserIssue("Node has no arguments", void 0, node);
|
|
3162
|
+
}
|
|
3163
|
+
const regularFunction = node.arguments[0];
|
|
3164
|
+
if (!ts.isFunctionExpression(regularFunction) && !ts.isArrowFunction(regularFunction)) {
|
|
3165
|
+
return typeParserIssue("Node is not a function expression or arrow function", void 0, node);
|
|
3166
|
+
}
|
|
3167
|
+
if (ts.isFunctionExpression(regularFunction) && regularFunction.asteriskToken !== void 0) {
|
|
3168
|
+
return typeParserIssue("Node is a generator function, not a regular function", void 0, node);
|
|
3169
|
+
}
|
|
3170
|
+
const expressionToTest = ts.isCallExpression(node.expression) ? node.expression.expression : node.expression;
|
|
3171
|
+
if (!ts.isPropertyAccessExpression(expressionToTest)) {
|
|
3172
|
+
return typeParserIssue("Node is not a property access expression", void 0, node);
|
|
3173
|
+
}
|
|
3174
|
+
const propertyAccess = expressionToTest;
|
|
3175
|
+
const pipeArguments2 = node.arguments.slice(1);
|
|
3176
|
+
return pipe(
|
|
3177
|
+
isNodeReferenceToEffectModuleApi("fn")(propertyAccess),
|
|
3178
|
+
map4(() => ({
|
|
3179
|
+
node,
|
|
3180
|
+
effectModule: propertyAccess.expression,
|
|
3181
|
+
regularFunction,
|
|
3182
|
+
pipeArguments: pipeArguments2
|
|
3183
|
+
}))
|
|
3184
|
+
);
|
|
3185
|
+
},
|
|
3186
|
+
"TypeParser.effectFn",
|
|
3187
|
+
(node) => node
|
|
3188
|
+
);
|
|
3098
3189
|
const unnecessaryEffectGen2 = cachedBy(
|
|
3099
3190
|
fn("TypeParser.unnecessaryEffectGen")(function* (node) {
|
|
3100
3191
|
const { body } = yield* effectGen(node);
|
|
@@ -3206,6 +3297,28 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3206
3297
|
`TypeParser.isNodeReferenceToEffectSchemaModuleApi(${memberName})`,
|
|
3207
3298
|
(node) => node
|
|
3208
3299
|
);
|
|
3300
|
+
const isEffectParseResultSourceFile = cachedBy(
|
|
3301
|
+
fn("TypeParser.isEffectParseResultSourceFile")(function* (sourceFile) {
|
|
3302
|
+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
3303
|
+
if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
|
|
3304
|
+
const parseIssueSymbol = typeChecker.tryGetMemberInModuleExports("ParseIssue", moduleSymbol);
|
|
3305
|
+
if (!parseIssueSymbol) return yield* typeParserIssue("ParseIssue type not found", void 0, sourceFile);
|
|
3306
|
+
const decodeSyncSymbol = typeChecker.tryGetMemberInModuleExports("decodeSync", moduleSymbol);
|
|
3307
|
+
if (!decodeSyncSymbol) return yield* typeParserIssue("decodeSync not found", void 0, sourceFile);
|
|
3308
|
+
const encodeSyncSymbol = typeChecker.tryGetMemberInModuleExports("encodeSync", moduleSymbol);
|
|
3309
|
+
if (!encodeSyncSymbol) return yield* typeParserIssue("encodeSync not found", void 0, sourceFile);
|
|
3310
|
+
return sourceFile;
|
|
3311
|
+
}),
|
|
3312
|
+
"TypeParser.isEffectParseResultSourceFile",
|
|
3313
|
+
(sourceFile) => sourceFile
|
|
3314
|
+
);
|
|
3315
|
+
const isNodeReferenceToEffectParseResultModuleApi = (memberName) => cachedBy(
|
|
3316
|
+
fn("TypeParser.isNodeReferenceToEffectParseResultModuleApi")(function* (node) {
|
|
3317
|
+
return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectParseResultSourceFile, memberName);
|
|
3318
|
+
}),
|
|
3319
|
+
`TypeParser.isNodeReferenceToEffectParseResultModuleApi(${memberName})`,
|
|
3320
|
+
(node) => node
|
|
3321
|
+
);
|
|
3209
3322
|
const contextTagVarianceStruct = (type, atLocation) => map4(
|
|
3210
3323
|
all(
|
|
3211
3324
|
varianceStructInvariantType(type, atLocation, "_Identifier"),
|
|
@@ -3986,11 +4099,65 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3986
4099
|
if (includeEffectFn) {
|
|
3987
4100
|
const effectFnGenParsed = yield* pipe(effectFnGen(node), option);
|
|
3988
4101
|
const effectFnUntracedGenParsed = isNone2(effectFnGenParsed) ? yield* pipe(effectFnUntracedGen(node), option) : none2();
|
|
3989
|
-
const
|
|
3990
|
-
const
|
|
3991
|
-
const
|
|
3992
|
-
|
|
3993
|
-
|
|
4102
|
+
const effectFnNonGenParsed = isNone2(effectFnGenParsed) && isNone2(effectFnUntracedGenParsed) ? yield* pipe(effectFn(node), option) : none2();
|
|
4103
|
+
const isEffectFnGen = isSome2(effectFnGenParsed);
|
|
4104
|
+
const isEffectFnUntracedGen = isSome2(effectFnUntracedGenParsed);
|
|
4105
|
+
const isEffectFnNonGen = isSome2(effectFnNonGenParsed);
|
|
4106
|
+
const transformationKind = isEffectFnUntracedGen ? "effectFnUntraced" : "effectFn";
|
|
4107
|
+
if (isEffectFnGen || isEffectFnUntracedGen) {
|
|
4108
|
+
const effectFnParsed = isEffectFnGen ? effectFnGenParsed : effectFnUntracedGenParsed;
|
|
4109
|
+
if (isSome2(effectFnParsed) && effectFnParsed.value.pipeArguments.length > 0) {
|
|
4110
|
+
const fnResult = effectFnParsed.value;
|
|
4111
|
+
const pipeArgs = fnResult.pipeArguments;
|
|
4112
|
+
const transformations = [];
|
|
4113
|
+
let subjectType;
|
|
4114
|
+
for (let i = 0; i < pipeArgs.length; i++) {
|
|
4115
|
+
const arg = pipeArgs[i];
|
|
4116
|
+
const contextualType = typeChecker.getContextualType(arg);
|
|
4117
|
+
const callSigs = contextualType ? typeChecker.getSignaturesOfType(contextualType, ts.SignatureKind.Call) : [];
|
|
4118
|
+
const outType = callSigs.length > 0 ? typeChecker.getReturnTypeOfSignature(callSigs[0]) : void 0;
|
|
4119
|
+
if (i === 0 && callSigs.length > 0) {
|
|
4120
|
+
const params = callSigs[0].parameters;
|
|
4121
|
+
if (params.length > 0) {
|
|
4122
|
+
subjectType = typeChecker.getTypeOfSymbol(params[0]);
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
if (ts.isCallExpression(arg)) {
|
|
4126
|
+
transformations.push({
|
|
4127
|
+
callee: arg.expression,
|
|
4128
|
+
args: Array.from(arg.arguments),
|
|
4129
|
+
outType,
|
|
4130
|
+
kind: transformationKind
|
|
4131
|
+
});
|
|
4132
|
+
} else {
|
|
4133
|
+
transformations.push({
|
|
4134
|
+
callee: arg,
|
|
4135
|
+
args: void 0,
|
|
4136
|
+
outType,
|
|
4137
|
+
kind: transformationKind
|
|
4138
|
+
});
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
const newFlow = {
|
|
4142
|
+
node,
|
|
4143
|
+
subject: {
|
|
4144
|
+
node,
|
|
4145
|
+
outType: subjectType
|
|
4146
|
+
},
|
|
4147
|
+
transformations
|
|
4148
|
+
};
|
|
4149
|
+
result.push(newFlow);
|
|
4150
|
+
workQueue.push([fnResult.body, void 0]);
|
|
4151
|
+
for (const arg of pipeArgs) {
|
|
4152
|
+
ts.forEachChild(arg, (c) => {
|
|
4153
|
+
workQueue.push([c, void 0]);
|
|
4154
|
+
});
|
|
4155
|
+
}
|
|
4156
|
+
continue;
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
if (isEffectFnNonGen && isSome2(effectFnNonGenParsed) && effectFnNonGenParsed.value.pipeArguments.length > 0) {
|
|
4160
|
+
const fnResult = effectFnNonGenParsed.value;
|
|
3994
4161
|
const pipeArgs = fnResult.pipeArguments;
|
|
3995
4162
|
const transformations = [];
|
|
3996
4163
|
let subjectType;
|
|
@@ -4010,14 +4177,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4010
4177
|
callee: arg.expression,
|
|
4011
4178
|
args: Array.from(arg.arguments),
|
|
4012
4179
|
outType,
|
|
4013
|
-
kind:
|
|
4180
|
+
kind: "effectFn"
|
|
4014
4181
|
});
|
|
4015
4182
|
} else {
|
|
4016
4183
|
transformations.push({
|
|
4017
4184
|
callee: arg,
|
|
4018
4185
|
args: void 0,
|
|
4019
4186
|
outType,
|
|
4020
|
-
kind:
|
|
4187
|
+
kind: "effectFn"
|
|
4021
4188
|
});
|
|
4022
4189
|
}
|
|
4023
4190
|
}
|
|
@@ -4030,7 +4197,16 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4030
4197
|
transformations
|
|
4031
4198
|
};
|
|
4032
4199
|
result.push(newFlow);
|
|
4033
|
-
|
|
4200
|
+
const regularFn = fnResult.regularFunction;
|
|
4201
|
+
if (ts.isArrowFunction(regularFn)) {
|
|
4202
|
+
if (ts.isBlock(regularFn.body)) {
|
|
4203
|
+
workQueue.push([regularFn.body, void 0]);
|
|
4204
|
+
} else {
|
|
4205
|
+
workQueue.push([regularFn.body, void 0]);
|
|
4206
|
+
}
|
|
4207
|
+
} else if (regularFn.body) {
|
|
4208
|
+
workQueue.push([regularFn.body, void 0]);
|
|
4209
|
+
}
|
|
4034
4210
|
for (const arg of pipeArgs) {
|
|
4035
4211
|
ts.forEachChild(arg, (c) => {
|
|
4036
4212
|
workQueue.push([c, void 0]);
|
|
@@ -4093,6 +4269,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4093
4269
|
return {
|
|
4094
4270
|
isNodeReferenceToEffectModuleApi,
|
|
4095
4271
|
isNodeReferenceToEffectSchemaModuleApi,
|
|
4272
|
+
isNodeReferenceToEffectParseResultModuleApi,
|
|
4096
4273
|
isNodeReferenceToEffectDataModuleApi,
|
|
4097
4274
|
isNodeReferenceToEffectContextModuleApi,
|
|
4098
4275
|
isNodeReferenceToEffectSqlModelModuleApi,
|
|
@@ -4106,6 +4283,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4106
4283
|
effectGen,
|
|
4107
4284
|
effectFnUntracedGen,
|
|
4108
4285
|
effectFnGen,
|
|
4286
|
+
findEnclosingScopes,
|
|
4287
|
+
effectFn,
|
|
4109
4288
|
extendsCauseYieldableError,
|
|
4110
4289
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
4111
4290
|
effectSchemaType,
|
|
@@ -4677,106 +4856,195 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
4677
4856
|
});
|
|
4678
4857
|
|
|
4679
4858
|
// src/diagnostics/effectFnOpportunity.ts
|
|
4680
|
-
var parseEffectFnOpportunityTarget = (node, sourceFile) => gen(function* () {
|
|
4681
|
-
const ts = yield* service(TypeScriptApi);
|
|
4682
|
-
const typeChecker = yield* service(TypeCheckerApi);
|
|
4683
|
-
const typeParser = yield* service(TypeParser);
|
|
4684
|
-
const tsUtils = yield* service(TypeScriptUtils);
|
|
4685
|
-
if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
|
|
4686
|
-
return yield* TypeParserIssue.issue;
|
|
4687
|
-
}
|
|
4688
|
-
if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
|
|
4689
|
-
return yield* TypeParserIssue.issue;
|
|
4690
|
-
}
|
|
4691
|
-
if (ts.isFunctionExpression(node) && node.name) {
|
|
4692
|
-
return yield* TypeParserIssue.issue;
|
|
4693
|
-
}
|
|
4694
|
-
let bodyExpression;
|
|
4695
|
-
if (ts.isArrowFunction(node)) {
|
|
4696
|
-
if (ts.isBlock(node.body)) {
|
|
4697
|
-
const returnStatement = findSingleReturnStatement(ts, node.body);
|
|
4698
|
-
if (returnStatement?.expression) {
|
|
4699
|
-
bodyExpression = returnStatement.expression;
|
|
4700
|
-
}
|
|
4701
|
-
} else {
|
|
4702
|
-
bodyExpression = node.body;
|
|
4703
|
-
}
|
|
4704
|
-
} else if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.body) {
|
|
4705
|
-
const returnStatement = findSingleReturnStatement(ts, node.body);
|
|
4706
|
-
if (returnStatement?.expression) {
|
|
4707
|
-
bodyExpression = returnStatement.expression;
|
|
4708
|
-
}
|
|
4709
|
-
}
|
|
4710
|
-
if (!bodyExpression) return yield* TypeParserIssue.issue;
|
|
4711
|
-
const { pipeArguments: pipeArguments2, subject } = yield* pipe(
|
|
4712
|
-
typeParser.pipeCall(bodyExpression),
|
|
4713
|
-
map4(({ args: args2, subject: subject2 }) => ({ subject: subject2, pipeArguments: args2 })),
|
|
4714
|
-
orElse2(() => succeed({ subject: bodyExpression, pipeArguments: [] }))
|
|
4715
|
-
);
|
|
4716
|
-
const { effectModule, generatorFunction } = yield* typeParser.effectGen(subject);
|
|
4717
|
-
const functionType = typeChecker.getTypeAtLocation(node);
|
|
4718
|
-
if (!functionType) return yield* TypeParserIssue.issue;
|
|
4719
|
-
const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
|
|
4720
|
-
if (callSignatures.length !== 1) return yield* TypeParserIssue.issue;
|
|
4721
|
-
const signature = callSignatures[0];
|
|
4722
|
-
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
4723
|
-
const { A, E, R } = yield* typeParser.strictEffectType(returnType, node);
|
|
4724
|
-
const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
4725
|
-
sourceFile,
|
|
4726
|
-
"effect",
|
|
4727
|
-
"Effect"
|
|
4728
|
-
) || "Effect";
|
|
4729
|
-
const nameIdentifier = getNameIdentifier(ts, node);
|
|
4730
|
-
const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
|
|
4731
|
-
const hasReturnTypeAnnotation = !!node.type;
|
|
4732
|
-
return {
|
|
4733
|
-
node,
|
|
4734
|
-
nameIdentifier,
|
|
4735
|
-
effectModule,
|
|
4736
|
-
generatorFunction,
|
|
4737
|
-
effectModuleName,
|
|
4738
|
-
traceName,
|
|
4739
|
-
hasReturnTypeAnnotation,
|
|
4740
|
-
effectTypes: { A, E, R },
|
|
4741
|
-
pipeArguments: pipeArguments2
|
|
4742
|
-
};
|
|
4743
|
-
});
|
|
4744
4859
|
var effectFnOpportunity = createDiagnostic({
|
|
4745
4860
|
name: "effectFnOpportunity",
|
|
4746
4861
|
code: 41,
|
|
4747
|
-
description: "Suggests using Effect.fn for functions that
|
|
4862
|
+
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
4748
4863
|
severity: "suggestion",
|
|
4749
4864
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
4750
4865
|
const ts = yield* service(TypeScriptApi);
|
|
4751
4866
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
4867
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4868
|
+
const typeParser = yield* service(TypeParser);
|
|
4752
4869
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
4753
|
-
const
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
)
|
|
4767
|
-
|
|
4870
|
+
const sourceEffectModuleName = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
4871
|
+
sourceFile,
|
|
4872
|
+
"effect",
|
|
4873
|
+
"Effect"
|
|
4874
|
+
) || "Effect";
|
|
4875
|
+
const findSingleReturnStatement = (block) => {
|
|
4876
|
+
if (block.statements.length !== 1) return void 0;
|
|
4877
|
+
const statement = block.statements[0];
|
|
4878
|
+
if (!ts.isReturnStatement(statement)) return void 0;
|
|
4879
|
+
return statement;
|
|
4880
|
+
};
|
|
4881
|
+
const getBodyExpression = (fnNode) => {
|
|
4882
|
+
if (ts.isArrowFunction(fnNode)) {
|
|
4883
|
+
if (ts.isBlock(fnNode.body)) {
|
|
4884
|
+
return findSingleReturnStatement(fnNode.body)?.expression;
|
|
4885
|
+
}
|
|
4886
|
+
return fnNode.body;
|
|
4887
|
+
} else if ((ts.isFunctionExpression(fnNode) || ts.isFunctionDeclaration(fnNode)) && fnNode.body) {
|
|
4888
|
+
return findSingleReturnStatement(fnNode.body)?.expression;
|
|
4889
|
+
}
|
|
4890
|
+
return void 0;
|
|
4891
|
+
};
|
|
4892
|
+
const getNameIdentifier = (node) => {
|
|
4893
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
4894
|
+
return node.name;
|
|
4895
|
+
}
|
|
4896
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
4897
|
+
return node.parent.name;
|
|
4898
|
+
}
|
|
4899
|
+
if (node.parent && ts.isPropertyAssignment(node.parent)) {
|
|
4900
|
+
const name = node.parent.name;
|
|
4901
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
4902
|
+
return name;
|
|
4903
|
+
}
|
|
4904
|
+
}
|
|
4905
|
+
if (node.parent && ts.isPropertyDeclaration(node.parent)) {
|
|
4906
|
+
const name = node.parent.name;
|
|
4907
|
+
if (ts.isIdentifier(name)) {
|
|
4908
|
+
return name;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
return void 0;
|
|
4912
|
+
};
|
|
4913
|
+
const areParametersReferencedIn = (fnNode, nodes) => {
|
|
4914
|
+
if (fnNode.parameters.length === 0 || nodes.length === 0) return false;
|
|
4915
|
+
const firstParam = fnNode.parameters[0];
|
|
4916
|
+
const lastParam = fnNode.parameters[fnNode.parameters.length - 1];
|
|
4917
|
+
const paramsStart = firstParam.pos;
|
|
4918
|
+
const paramsEnd = lastParam.end;
|
|
4919
|
+
const isSymbolDeclaredInParams = (symbol3) => {
|
|
4920
|
+
const declarations = symbol3.declarations;
|
|
4921
|
+
if (!declarations) return false;
|
|
4922
|
+
return declarations.some((decl) => decl.pos >= paramsStart && decl.end <= paramsEnd);
|
|
4923
|
+
};
|
|
4924
|
+
const nodesToVisit = [...nodes];
|
|
4925
|
+
while (nodesToVisit.length > 0) {
|
|
4926
|
+
const node = nodesToVisit.shift();
|
|
4927
|
+
if (ts.isIdentifier(node)) {
|
|
4928
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node);
|
|
4929
|
+
if (symbol3 && isSymbolDeclaredInParams(symbol3)) {
|
|
4930
|
+
return true;
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
if (ts.isShorthandPropertyAssignment(node)) {
|
|
4934
|
+
const valueSymbol = typeChecker.getShorthandAssignmentValueSymbol(node);
|
|
4935
|
+
if (valueSymbol && isSymbolDeclaredInParams(valueSymbol)) {
|
|
4936
|
+
return true;
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
ts.forEachChild(node, (child) => {
|
|
4940
|
+
nodesToVisit.push(child);
|
|
4941
|
+
return void 0;
|
|
4942
|
+
});
|
|
4943
|
+
}
|
|
4944
|
+
return false;
|
|
4945
|
+
};
|
|
4946
|
+
const tryParseGenOpportunity = (fnNode) => gen(function* () {
|
|
4947
|
+
const bodyExpression = getBodyExpression(fnNode);
|
|
4948
|
+
if (!bodyExpression) return yield* TypeParserIssue.issue;
|
|
4949
|
+
const { pipeArguments: pipeArguments2, subject } = yield* pipe(
|
|
4950
|
+
typeParser.pipeCall(bodyExpression),
|
|
4951
|
+
map4(({ args: args2, subject: subject2 }) => ({ subject: subject2, pipeArguments: args2 })),
|
|
4952
|
+
orElse2(() => succeed({ subject: bodyExpression, pipeArguments: [] }))
|
|
4953
|
+
);
|
|
4954
|
+
const { effectModule, generatorFunction } = yield* typeParser.effectGen(subject);
|
|
4955
|
+
const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : sourceEffectModuleName;
|
|
4956
|
+
return { effectModuleName, generatorFunction, pipeArguments: pipeArguments2 };
|
|
4957
|
+
});
|
|
4958
|
+
const isInsideEffectFn = (fnNode) => {
|
|
4959
|
+
const parent = fnNode.parent;
|
|
4960
|
+
if (!parent || !ts.isCallExpression(parent)) {
|
|
4961
|
+
return succeed(false);
|
|
4962
|
+
}
|
|
4963
|
+
if (parent.arguments[0] !== fnNode) {
|
|
4964
|
+
return succeed(false);
|
|
4965
|
+
}
|
|
4966
|
+
return pipe(
|
|
4967
|
+
typeParser.effectFn(parent),
|
|
4968
|
+
orElse2(() => typeParser.effectFnGen(parent)),
|
|
4969
|
+
orElse2(() => typeParser.effectFnUntracedGen(parent)),
|
|
4970
|
+
map4(() => true),
|
|
4971
|
+
orElse2(() => succeed(false))
|
|
4768
4972
|
);
|
|
4769
4973
|
};
|
|
4770
|
-
const
|
|
4771
|
-
|
|
4772
|
-
|
|
4974
|
+
const parseEffectFnOpportunityTarget = (node) => gen(function* () {
|
|
4975
|
+
if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
|
|
4976
|
+
return yield* TypeParserIssue.issue;
|
|
4977
|
+
}
|
|
4978
|
+
if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
|
|
4979
|
+
return yield* TypeParserIssue.issue;
|
|
4980
|
+
}
|
|
4981
|
+
if (ts.isFunctionExpression(node) && node.name) {
|
|
4982
|
+
return yield* TypeParserIssue.issue;
|
|
4983
|
+
}
|
|
4984
|
+
if (yield* isInsideEffectFn(node)) {
|
|
4985
|
+
return yield* TypeParserIssue.issue;
|
|
4986
|
+
}
|
|
4987
|
+
const functionType = typeChecker.getTypeAtLocation(node);
|
|
4988
|
+
if (!functionType) return yield* TypeParserIssue.issue;
|
|
4989
|
+
const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
|
|
4990
|
+
if (callSignatures.length !== 1) return yield* TypeParserIssue.issue;
|
|
4991
|
+
const signature = callSignatures[0];
|
|
4992
|
+
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
4993
|
+
const unionMembers = typeCheckerUtils.unrollUnionMembers(returnType);
|
|
4994
|
+
yield* all(...unionMembers.map((member) => typeParser.strictEffectType(member, node)));
|
|
4995
|
+
const nameIdentifier = getNameIdentifier(node);
|
|
4996
|
+
const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
|
|
4997
|
+
if (!traceName) return yield* TypeParserIssue.issue;
|
|
4998
|
+
const opportunity = yield* pipe(
|
|
4999
|
+
tryParseGenOpportunity(node),
|
|
5000
|
+
orElse2(() => {
|
|
5001
|
+
if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
|
|
5002
|
+
return TypeParserIssue.issue;
|
|
5003
|
+
}
|
|
5004
|
+
const body = ts.isArrowFunction(node) ? node.body : node.body;
|
|
5005
|
+
if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
|
|
5006
|
+
return TypeParserIssue.issue;
|
|
5007
|
+
}
|
|
5008
|
+
return succeed({
|
|
5009
|
+
effectModuleName: sourceEffectModuleName,
|
|
5010
|
+
pipeArguments: [],
|
|
5011
|
+
generatorFunction: void 0
|
|
5012
|
+
});
|
|
5013
|
+
})
|
|
5014
|
+
);
|
|
5015
|
+
return {
|
|
5016
|
+
node,
|
|
5017
|
+
nameIdentifier,
|
|
5018
|
+
effectModuleName: opportunity.effectModuleName,
|
|
5019
|
+
traceName,
|
|
5020
|
+
pipeArguments: opportunity.pipeArguments,
|
|
5021
|
+
generatorFunction: opportunity.generatorFunction,
|
|
5022
|
+
hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
|
|
5023
|
+
};
|
|
5024
|
+
});
|
|
5025
|
+
const getFunctionBodyBlock = (node) => {
|
|
5026
|
+
if (ts.isArrowFunction(node)) {
|
|
5027
|
+
if (ts.isBlock(node.body)) {
|
|
5028
|
+
return node.body;
|
|
5029
|
+
}
|
|
5030
|
+
return ts.factory.createBlock([ts.factory.createReturnStatement(node.body)], true);
|
|
5031
|
+
}
|
|
5032
|
+
return node.body;
|
|
5033
|
+
};
|
|
5034
|
+
const isGeneratorFunction = (node) => {
|
|
5035
|
+
if (ts.isArrowFunction(node)) return false;
|
|
5036
|
+
return node.asteriskToken !== void 0;
|
|
5037
|
+
};
|
|
5038
|
+
const createEffectFnNode = (originalNode, innerFunction, effectModuleName, traceName, pipeArguments2) => {
|
|
5039
|
+
const isGenerator = isGeneratorFunction(innerFunction);
|
|
5040
|
+
const newFunction = ts.factory.createFunctionExpression(
|
|
4773
5041
|
void 0,
|
|
4774
|
-
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
5042
|
+
isGenerator ? ts.factory.createToken(ts.SyntaxKind.AsteriskToken) : void 0,
|
|
4775
5043
|
void 0,
|
|
4776
5044
|
originalNode.typeParameters,
|
|
4777
5045
|
originalNode.parameters,
|
|
4778
|
-
|
|
4779
|
-
|
|
5046
|
+
void 0,
|
|
5047
|
+
getFunctionBodyBlock(innerFunction)
|
|
4780
5048
|
);
|
|
4781
5049
|
let fnExpression = ts.factory.createPropertyAccessExpression(
|
|
4782
5050
|
ts.factory.createIdentifier(effectModuleName),
|
|
@@ -4789,34 +5057,27 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
4789
5057
|
[ts.factory.createStringLiteral(traceName)]
|
|
4790
5058
|
);
|
|
4791
5059
|
}
|
|
4792
|
-
const effectFnCall = ts.factory.createCallExpression(
|
|
4793
|
-
fnExpression,
|
|
4794
|
-
void 0,
|
|
4795
|
-
[newGeneratorFunction, ...pipeArguments2]
|
|
4796
|
-
);
|
|
5060
|
+
const effectFnCall = ts.factory.createCallExpression(fnExpression, void 0, [newFunction, ...pipeArguments2]);
|
|
4797
5061
|
if (ts.isFunctionDeclaration(originalNode)) {
|
|
4798
5062
|
return tsUtils.tryPreserveDeclarationSemantics(originalNode, effectFnCall, false);
|
|
4799
5063
|
}
|
|
4800
5064
|
return effectFnCall;
|
|
4801
5065
|
};
|
|
4802
|
-
const createEffectFnUntracedNode = (originalNode,
|
|
4803
|
-
const
|
|
4804
|
-
const
|
|
5066
|
+
const createEffectFnUntracedNode = (originalNode, innerFunction, effectModuleName, pipeArguments2) => {
|
|
5067
|
+
const isGenerator = isGeneratorFunction(innerFunction);
|
|
5068
|
+
const newFunction = ts.factory.createFunctionExpression(
|
|
4805
5069
|
void 0,
|
|
4806
|
-
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
5070
|
+
isGenerator ? ts.factory.createToken(ts.SyntaxKind.AsteriskToken) : void 0,
|
|
4807
5071
|
void 0,
|
|
4808
5072
|
originalNode.typeParameters,
|
|
4809
5073
|
originalNode.parameters,
|
|
4810
|
-
|
|
4811
|
-
|
|
5074
|
+
void 0,
|
|
5075
|
+
getFunctionBodyBlock(innerFunction)
|
|
4812
5076
|
);
|
|
4813
5077
|
const effectFnCall = ts.factory.createCallExpression(
|
|
4814
|
-
ts.factory.createPropertyAccessExpression(
|
|
4815
|
-
ts.factory.createIdentifier(effectModuleName),
|
|
4816
|
-
"fnUntraced"
|
|
4817
|
-
),
|
|
5078
|
+
ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(effectModuleName), "fnUntraced"),
|
|
4818
5079
|
void 0,
|
|
4819
|
-
[
|
|
5080
|
+
[newFunction, ...pipeArguments2]
|
|
4820
5081
|
);
|
|
4821
5082
|
if (ts.isFunctionDeclaration(originalNode)) {
|
|
4822
5083
|
return tsUtils.tryPreserveDeclarationSemantics(originalNode, effectFnCall, false);
|
|
@@ -4832,88 +5093,41 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
4832
5093
|
while (nodeToVisit.length > 0) {
|
|
4833
5094
|
const node = nodeToVisit.shift();
|
|
4834
5095
|
ts.forEachChild(node, appendNodeToVisit);
|
|
4835
|
-
const target = yield* pipe(
|
|
4836
|
-
parseEffectFnOpportunityTarget(node, sourceFile),
|
|
4837
|
-
option
|
|
4838
|
-
);
|
|
5096
|
+
const target = yield* pipe(parseEffectFnOpportunityTarget(node), option);
|
|
4839
5097
|
if (isNone2(target)) continue;
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
generatorFunction,
|
|
4844
|
-
hasReturnTypeAnnotation,
|
|
4845
|
-
nameIdentifier,
|
|
4846
|
-
node: targetNode,
|
|
4847
|
-
pipeArguments: pipeArguments2,
|
|
4848
|
-
traceName
|
|
4849
|
-
} = target.value;
|
|
5098
|
+
if (target.value.hasParamsInPipeArgs) continue;
|
|
5099
|
+
const { effectModuleName, nameIdentifier, node: targetNode, pipeArguments: pipeArguments2, traceName } = target.value;
|
|
5100
|
+
const innerFunction = target.value.generatorFunction ?? targetNode;
|
|
4850
5101
|
const fixes = [];
|
|
4851
5102
|
fixes.push({
|
|
4852
5103
|
fixName: "effectFnOpportunity_toEffectFn",
|
|
4853
5104
|
description: traceName ? `Convert to Effect.fn("${traceName}")` : "Convert to Effect.fn",
|
|
4854
5105
|
apply: gen(function* () {
|
|
4855
5106
|
const changeTracker = yield* service(ChangeTracker);
|
|
4856
|
-
const newNode = createEffectFnNode(
|
|
4857
|
-
targetNode,
|
|
4858
|
-
generatorFunction,
|
|
4859
|
-
effectModuleName,
|
|
4860
|
-
traceName,
|
|
4861
|
-
hasReturnTypeAnnotation ? effectTypes : void 0,
|
|
4862
|
-
pipeArguments2
|
|
4863
|
-
);
|
|
4864
|
-
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
4865
|
-
})
|
|
4866
|
-
});
|
|
4867
|
-
fixes.push({
|
|
4868
|
-
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
4869
|
-
description: "Convert to Effect.fnUntraced",
|
|
4870
|
-
apply: gen(function* () {
|
|
4871
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
4872
|
-
const newNode = createEffectFnUntracedNode(
|
|
4873
|
-
targetNode,
|
|
4874
|
-
generatorFunction,
|
|
4875
|
-
effectModuleName,
|
|
4876
|
-
hasReturnTypeAnnotation ? effectTypes : void 0,
|
|
4877
|
-
pipeArguments2
|
|
4878
|
-
);
|
|
5107
|
+
const newNode = createEffectFnNode(targetNode, innerFunction, effectModuleName, traceName, pipeArguments2);
|
|
4879
5108
|
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
4880
5109
|
})
|
|
4881
5110
|
});
|
|
5111
|
+
if (target.value.generatorFunction) {
|
|
5112
|
+
fixes.push({
|
|
5113
|
+
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
5114
|
+
description: "Convert to Effect.fnUntraced",
|
|
5115
|
+
apply: gen(function* () {
|
|
5116
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5117
|
+
const newNode = createEffectFnUntracedNode(targetNode, innerFunction, effectModuleName, pipeArguments2);
|
|
5118
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
5119
|
+
})
|
|
5120
|
+
});
|
|
5121
|
+
}
|
|
5122
|
+
const pipeArgsSuffix = pipeArguments2.length > 0 ? ` Effect.fn also accepts the piped transformations as additional arguments.` : ``;
|
|
4882
5123
|
report({
|
|
4883
5124
|
location: nameIdentifier ?? targetNode,
|
|
4884
|
-
messageText: `This function could benefit from Effect.fn's automatic tracing and concise syntax, or Effect.fnUntraced to get just a more concise syntax
|
|
5125
|
+
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}`,
|
|
4885
5126
|
fixes
|
|
4886
5127
|
});
|
|
4887
5128
|
}
|
|
4888
5129
|
})
|
|
4889
5130
|
});
|
|
4890
|
-
function findSingleReturnStatement(ts, block) {
|
|
4891
|
-
if (block.statements.length !== 1) return void 0;
|
|
4892
|
-
const statement = block.statements[0];
|
|
4893
|
-
if (!ts.isReturnStatement(statement)) return void 0;
|
|
4894
|
-
return statement;
|
|
4895
|
-
}
|
|
4896
|
-
function getNameIdentifier(ts, node) {
|
|
4897
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
4898
|
-
return node.name;
|
|
4899
|
-
}
|
|
4900
|
-
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
4901
|
-
return node.parent.name;
|
|
4902
|
-
}
|
|
4903
|
-
if (node.parent && ts.isPropertyAssignment(node.parent)) {
|
|
4904
|
-
const name = node.parent.name;
|
|
4905
|
-
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
4906
|
-
return name;
|
|
4907
|
-
}
|
|
4908
|
-
}
|
|
4909
|
-
if (node.parent && ts.isPropertyDeclaration(node.parent)) {
|
|
4910
|
-
const name = node.parent.name;
|
|
4911
|
-
if (ts.isIdentifier(name)) {
|
|
4912
|
-
return name;
|
|
4913
|
-
}
|
|
4914
|
-
}
|
|
4915
|
-
return void 0;
|
|
4916
|
-
}
|
|
4917
5131
|
|
|
4918
5132
|
// src/diagnostics/effectGenUsesAdapter.ts
|
|
4919
5133
|
var effectGenUsesAdapter = createDiagnostic({
|
|
@@ -5676,6 +5890,52 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
5676
5890
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5677
5891
|
const typeParser = yield* service(TypeParser);
|
|
5678
5892
|
const options = yield* service(LanguageServicePluginOptions);
|
|
5893
|
+
const isSafelyPipeableCallee = (callee) => {
|
|
5894
|
+
if (ts.isCallExpression(callee)) {
|
|
5895
|
+
return true;
|
|
5896
|
+
}
|
|
5897
|
+
if (ts.isArrowFunction(callee)) {
|
|
5898
|
+
return true;
|
|
5899
|
+
}
|
|
5900
|
+
if (ts.isFunctionExpression(callee)) {
|
|
5901
|
+
return true;
|
|
5902
|
+
}
|
|
5903
|
+
if (ts.isParenthesizedExpression(callee)) {
|
|
5904
|
+
return isSafelyPipeableCallee(callee.expression);
|
|
5905
|
+
}
|
|
5906
|
+
if (ts.isIdentifier(callee)) {
|
|
5907
|
+
const symbol3 = typeChecker.getSymbolAtLocation(callee);
|
|
5908
|
+
if (!symbol3) return false;
|
|
5909
|
+
if (symbol3.flags & (ts.SymbolFlags.Module | ts.SymbolFlags.Namespace | ts.SymbolFlags.ValueModule)) {
|
|
5910
|
+
return true;
|
|
5911
|
+
}
|
|
5912
|
+
const declarations = symbol3.declarations;
|
|
5913
|
+
if (declarations && declarations.length > 0) {
|
|
5914
|
+
const decl = declarations[0];
|
|
5915
|
+
if (ts.isFunctionDeclaration(decl) || ts.isVariableDeclaration(decl) || ts.isImportSpecifier(decl) || ts.isImportClause(decl) || ts.isNamespaceImport(decl)) {
|
|
5916
|
+
return true;
|
|
5917
|
+
}
|
|
5918
|
+
}
|
|
5919
|
+
return false;
|
|
5920
|
+
}
|
|
5921
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
5922
|
+
const subject = callee.expression;
|
|
5923
|
+
const symbol3 = typeChecker.getSymbolAtLocation(subject);
|
|
5924
|
+
if (!symbol3) return false;
|
|
5925
|
+
if (symbol3.flags & (ts.SymbolFlags.Module | ts.SymbolFlags.Namespace | ts.SymbolFlags.ValueModule)) {
|
|
5926
|
+
return true;
|
|
5927
|
+
}
|
|
5928
|
+
const declarations = symbol3.declarations;
|
|
5929
|
+
if (declarations && declarations.length > 0) {
|
|
5930
|
+
const decl = declarations[0];
|
|
5931
|
+
if (ts.isNamespaceImport(decl) || ts.isSourceFile(decl) || ts.isModuleDeclaration(decl)) {
|
|
5932
|
+
return true;
|
|
5933
|
+
}
|
|
5934
|
+
}
|
|
5935
|
+
return false;
|
|
5936
|
+
}
|
|
5937
|
+
return false;
|
|
5938
|
+
};
|
|
5679
5939
|
const flows = yield* typeParser.pipingFlows(false)(sourceFile);
|
|
5680
5940
|
for (const flow2 of flows) {
|
|
5681
5941
|
if (flow2.transformations.length < options.pipeableMinArgCount) {
|
|
@@ -5689,76 +5949,92 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
5689
5949
|
if (callSigs.length > 0) {
|
|
5690
5950
|
continue;
|
|
5691
5951
|
}
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5952
|
+
const isPipeableAtIndex = function* (index) {
|
|
5953
|
+
if (index === 0) {
|
|
5954
|
+
const subjectType = flow2.subject.outType;
|
|
5955
|
+
if (!subjectType) return false;
|
|
5956
|
+
const result = yield* pipe(
|
|
5957
|
+
typeParser.pipeableType(subjectType, flow2.subject.node),
|
|
5958
|
+
option
|
|
5959
|
+
);
|
|
5960
|
+
return result._tag === "Some";
|
|
5961
|
+
} else {
|
|
5962
|
+
const t = flow2.transformations[index - 1];
|
|
5963
|
+
if (!t.outType) return false;
|
|
5964
|
+
const result = yield* pipe(
|
|
5965
|
+
typeParser.pipeableType(t.outType, flow2.node),
|
|
5966
|
+
option
|
|
5967
|
+
);
|
|
5968
|
+
return result._tag === "Some";
|
|
5969
|
+
}
|
|
5970
|
+
};
|
|
5971
|
+
let searchStartIndex = 0;
|
|
5972
|
+
while (searchStartIndex <= flow2.transformations.length) {
|
|
5973
|
+
let firstPipeableIndex = -1;
|
|
5974
|
+
for (let i = searchStartIndex; i <= flow2.transformations.length; i++) {
|
|
5975
|
+
if (yield* isPipeableAtIndex(i)) {
|
|
5976
|
+
firstPipeableIndex = i;
|
|
5977
|
+
break;
|
|
5978
|
+
}
|
|
5979
|
+
}
|
|
5980
|
+
if (firstPipeableIndex === -1) {
|
|
5981
|
+
break;
|
|
5982
|
+
}
|
|
5983
|
+
const pipeableTransformations = [];
|
|
5984
|
+
for (let i = firstPipeableIndex; i < flow2.transformations.length; i++) {
|
|
5705
5985
|
const t = flow2.transformations[i];
|
|
5706
|
-
if (t.
|
|
5707
|
-
|
|
5708
|
-
typeParser.pipeableType(t.outType, flow2.node),
|
|
5709
|
-
option
|
|
5710
|
-
);
|
|
5711
|
-
if (isPipeable._tag === "Some") {
|
|
5712
|
-
firstPipeableIndex = i + 1;
|
|
5713
|
-
break;
|
|
5714
|
-
}
|
|
5986
|
+
if (!isSafelyPipeableCallee(t.callee)) {
|
|
5987
|
+
break;
|
|
5715
5988
|
}
|
|
5989
|
+
pipeableTransformations.push(t);
|
|
5716
5990
|
}
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5991
|
+
const callKindCount = pipeableTransformations.filter((t) => t.kind === "call").length;
|
|
5992
|
+
if (callKindCount >= options.pipeableMinArgCount) {
|
|
5993
|
+
const pipeableEndIndex = firstPipeableIndex + pipeableTransformations.length;
|
|
5994
|
+
const pipeableSubjectNode = firstPipeableIndex === 0 ? flow2.subject.node : typeParser.reconstructPipingFlow({
|
|
5995
|
+
subject: flow2.subject,
|
|
5996
|
+
transformations: flow2.transformations.slice(0, firstPipeableIndex)
|
|
5997
|
+
});
|
|
5998
|
+
const afterTransformations = flow2.transformations.slice(pipeableEndIndex);
|
|
5999
|
+
report({
|
|
6000
|
+
location: flow2.node,
|
|
6001
|
+
messageText: `Nested function calls can be converted to pipeable style for better readability.`,
|
|
6002
|
+
fixes: [{
|
|
6003
|
+
fixName: "missedPipeableOpportunity_fix",
|
|
6004
|
+
description: "Convert to pipe style",
|
|
6005
|
+
apply: gen(function* () {
|
|
6006
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6007
|
+
const pipeArgs = pipeableTransformations.map((t) => {
|
|
6008
|
+
if (t.args) {
|
|
6009
|
+
return ts.factory.createCallExpression(
|
|
6010
|
+
t.callee,
|
|
6011
|
+
void 0,
|
|
6012
|
+
t.args
|
|
6013
|
+
);
|
|
6014
|
+
} else {
|
|
6015
|
+
return t.callee;
|
|
6016
|
+
}
|
|
6017
|
+
});
|
|
6018
|
+
const pipeNode = ts.factory.createCallExpression(
|
|
6019
|
+
ts.factory.createPropertyAccessExpression(
|
|
6020
|
+
pipeableSubjectNode,
|
|
6021
|
+
"pipe"
|
|
6022
|
+
),
|
|
5743
6023
|
void 0,
|
|
5744
|
-
|
|
6024
|
+
pipeArgs
|
|
5745
6025
|
);
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
changeTracker.replaceNode(sourceFile, flow2.node, newNode);
|
|
5759
|
-
})
|
|
5760
|
-
}]
|
|
5761
|
-
});
|
|
6026
|
+
const newNode = afterTransformations.length > 0 ? typeParser.reconstructPipingFlow({
|
|
6027
|
+
subject: { node: pipeNode, outType: void 0 },
|
|
6028
|
+
transformations: afterTransformations
|
|
6029
|
+
}) : pipeNode;
|
|
6030
|
+
changeTracker.replaceNode(sourceFile, flow2.node, newNode);
|
|
6031
|
+
})
|
|
6032
|
+
}]
|
|
6033
|
+
});
|
|
6034
|
+
break;
|
|
6035
|
+
}
|
|
6036
|
+
searchStartIndex = firstPipeableIndex + pipeableTransformations.length + 1;
|
|
6037
|
+
}
|
|
5762
6038
|
}
|
|
5763
6039
|
})
|
|
5764
6040
|
});
|
|
@@ -7637,6 +7913,90 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
7637
7913
|
})
|
|
7638
7914
|
});
|
|
7639
7915
|
|
|
7916
|
+
// src/diagnostics/preferSchemaOverJson.ts
|
|
7917
|
+
var preferSchemaOverJson = createDiagnostic({
|
|
7918
|
+
name: "preferSchemaOverJson",
|
|
7919
|
+
code: 44,
|
|
7920
|
+
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
7921
|
+
severity: "suggestion",
|
|
7922
|
+
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
7923
|
+
const ts = yield* service(TypeScriptApi);
|
|
7924
|
+
const typeParser = yield* service(TypeParser);
|
|
7925
|
+
const parseJsonMethod = (node) => gen(function* () {
|
|
7926
|
+
if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
|
|
7927
|
+
const expression = node.expression;
|
|
7928
|
+
if (!ts.isPropertyAccessExpression(expression)) return yield* fail("expression is not a property access");
|
|
7929
|
+
const objectExpr = expression.expression;
|
|
7930
|
+
const methodName = ts.idText(expression.name);
|
|
7931
|
+
if (!ts.isIdentifier(objectExpr) || ts.idText(objectExpr) !== "JSON") {
|
|
7932
|
+
return yield* fail("object is not JSON");
|
|
7933
|
+
}
|
|
7934
|
+
if (methodName !== "parse" && methodName !== "stringify") {
|
|
7935
|
+
return yield* fail("method is not parse or stringify");
|
|
7936
|
+
}
|
|
7937
|
+
return { node, methodName };
|
|
7938
|
+
});
|
|
7939
|
+
const effectTrySimple = (node) => gen(function* () {
|
|
7940
|
+
if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
|
|
7941
|
+
yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
|
|
7942
|
+
if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
|
|
7943
|
+
const lazyFn = yield* typeParser.lazyExpression(node.arguments[0]);
|
|
7944
|
+
const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
|
|
7945
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
7946
|
+
});
|
|
7947
|
+
const effectTryObject = (node) => gen(function* () {
|
|
7948
|
+
if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
|
|
7949
|
+
yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
|
|
7950
|
+
if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
|
|
7951
|
+
const arg = node.arguments[0];
|
|
7952
|
+
if (!ts.isObjectLiteralExpression(arg)) return yield* fail("argument is not an object literal");
|
|
7953
|
+
const tryProp = arg.properties.find(
|
|
7954
|
+
(p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && ts.idText(p.name) === "try"
|
|
7955
|
+
);
|
|
7956
|
+
if (!tryProp) return yield* fail("object has no 'try' property");
|
|
7957
|
+
const lazyFn = yield* typeParser.lazyExpression(tryProp.initializer);
|
|
7958
|
+
const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
|
|
7959
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
7960
|
+
});
|
|
7961
|
+
const jsonMethodInEffectGen = (node) => gen(function* () {
|
|
7962
|
+
const jsonMethod = yield* parseJsonMethod(node);
|
|
7963
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
7964
|
+
if (!effectGen || effectGen.body.statements.length === 0) {
|
|
7965
|
+
return yield* fail("not inside an Effect generator");
|
|
7966
|
+
}
|
|
7967
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
7968
|
+
return yield* fail("inside a nested function scope");
|
|
7969
|
+
}
|
|
7970
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
7971
|
+
});
|
|
7972
|
+
const nodeToVisit = [];
|
|
7973
|
+
const appendNodeToVisit = (node) => {
|
|
7974
|
+
nodeToVisit.push(node);
|
|
7975
|
+
return void 0;
|
|
7976
|
+
};
|
|
7977
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7978
|
+
while (nodeToVisit.length > 0) {
|
|
7979
|
+
const node = nodeToVisit.shift();
|
|
7980
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7981
|
+
const match2 = yield* pipe(
|
|
7982
|
+
firstSuccessOf([
|
|
7983
|
+
effectTrySimple(node),
|
|
7984
|
+
effectTryObject(node),
|
|
7985
|
+
jsonMethodInEffectGen(node)
|
|
7986
|
+
]),
|
|
7987
|
+
option
|
|
7988
|
+
);
|
|
7989
|
+
if (isSome2(match2)) {
|
|
7990
|
+
report({
|
|
7991
|
+
location: match2.value.node,
|
|
7992
|
+
messageText: "Consider using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify",
|
|
7993
|
+
fixes: []
|
|
7994
|
+
});
|
|
7995
|
+
}
|
|
7996
|
+
}
|
|
7997
|
+
})
|
|
7998
|
+
});
|
|
7999
|
+
|
|
7640
8000
|
// src/diagnostics/redundantSchemaTagIdentifier.ts
|
|
7641
8001
|
var redundantSchemaTagIdentifier = createDiagnostic({
|
|
7642
8002
|
name: "redundantSchemaTagIdentifier",
|
|
@@ -7789,108 +8149,91 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
7789
8149
|
option
|
|
7790
8150
|
);
|
|
7791
8151
|
if (isNone2(isEffectRunCall)) continue;
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
if (ts.isFunctionExpression(possiblyEffectGen) || ts.isFunctionDeclaration(possiblyEffectGen) || ts.isMethodDeclaration(possiblyEffectGen) || ts.isArrowFunction(possiblyEffectGen)) {
|
|
7798
|
-
nodeIntroduceScope = possiblyEffectGen;
|
|
7799
|
-
continue;
|
|
7800
|
-
}
|
|
7801
|
-
}
|
|
7802
|
-
const isInEffectGen = yield* pipe(
|
|
7803
|
-
typeParser.effectGen(possiblyEffectGen),
|
|
7804
|
-
orElse2(() => typeParser.effectFnUntracedGen(possiblyEffectGen)),
|
|
7805
|
-
orElse2(() => typeParser.effectFnGen(possiblyEffectGen)),
|
|
7806
|
-
option
|
|
8152
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
8153
|
+
if (effectGen && effectGen.body.statements.length > 0) {
|
|
8154
|
+
const nodeText = sourceFile.text.substring(
|
|
8155
|
+
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
8156
|
+
node.expression.end
|
|
7807
8157
|
);
|
|
7808
|
-
if (
|
|
7809
|
-
const
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
const
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
if (ts.
|
|
7825
|
-
|
|
7826
|
-
typeParser.isNodeReferenceToEffectModuleApi("runtime")(yieldedExpression.expression),
|
|
7827
|
-
option
|
|
7828
|
-
);
|
|
7829
|
-
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
7830
|
-
runtimeIdentifier = ts.idText(declaration.name);
|
|
7831
|
-
}
|
|
8158
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
8159
|
+
const fixAddRuntime = gen(function* () {
|
|
8160
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
8161
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
8162
|
+
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
8163
|
+
let runtimeIdentifier = void 0;
|
|
8164
|
+
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
8165
|
+
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
8166
|
+
const declaration = statement.declarationList.declarations[0];
|
|
8167
|
+
if (declaration.initializer && ts.isYieldExpression(declaration.initializer) && declaration.initializer.asteriskToken && declaration.initializer.expression) {
|
|
8168
|
+
const yieldedExpression = declaration.initializer.expression;
|
|
8169
|
+
if (ts.isCallExpression(yieldedExpression)) {
|
|
8170
|
+
const maybeEffectRuntime = yield* pipe(
|
|
8171
|
+
typeParser.isNodeReferenceToEffectModuleApi("runtime")(yieldedExpression.expression),
|
|
8172
|
+
option
|
|
8173
|
+
);
|
|
8174
|
+
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
8175
|
+
runtimeIdentifier = ts.idText(declaration.name);
|
|
7832
8176
|
}
|
|
7833
8177
|
}
|
|
7834
8178
|
}
|
|
7835
8179
|
}
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
8180
|
+
}
|
|
8181
|
+
if (!runtimeIdentifier) {
|
|
8182
|
+
changeTracker.insertNodeAt(
|
|
8183
|
+
sourceFile,
|
|
8184
|
+
effectGen.body.statements[0].pos,
|
|
8185
|
+
ts.factory.createVariableStatement(
|
|
8186
|
+
void 0,
|
|
8187
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
8188
|
+
"effectRuntime",
|
|
7841
8189
|
void 0,
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
),
|
|
7853
|
-
[ts.factory.createTypeReferenceNode("never")],
|
|
7854
|
-
[]
|
|
7855
|
-
)
|
|
8190
|
+
void 0,
|
|
8191
|
+
ts.factory.createYieldExpression(
|
|
8192
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
8193
|
+
ts.factory.createCallExpression(
|
|
8194
|
+
ts.factory.createPropertyAccessExpression(
|
|
8195
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
8196
|
+
"runtime"
|
|
8197
|
+
),
|
|
8198
|
+
[ts.factory.createTypeReferenceNode("never")],
|
|
8199
|
+
[]
|
|
7856
8200
|
)
|
|
7857
|
-
)
|
|
7858
|
-
),
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
}
|
|
7865
|
-
changeTracker.deleteRange(sourceFile, {
|
|
7866
|
-
pos: ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
7867
|
-
end: node.arguments[0].pos
|
|
7868
|
-
});
|
|
7869
|
-
changeTracker.insertText(
|
|
7870
|
-
sourceFile,
|
|
7871
|
-
node.arguments[0].pos,
|
|
7872
|
-
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
8201
|
+
)
|
|
8202
|
+
)], ts.NodeFlags.Const)
|
|
8203
|
+
),
|
|
8204
|
+
{
|
|
8205
|
+
prefix: "\n",
|
|
8206
|
+
suffix: "\n"
|
|
8207
|
+
}
|
|
7873
8208
|
);
|
|
8209
|
+
}
|
|
8210
|
+
changeTracker.deleteRange(sourceFile, {
|
|
8211
|
+
pos: ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
8212
|
+
end: node.arguments[0].pos
|
|
7874
8213
|
});
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
8214
|
+
changeTracker.insertText(
|
|
8215
|
+
sourceFile,
|
|
8216
|
+
node.arguments[0].pos,
|
|
8217
|
+
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
8218
|
+
);
|
|
8219
|
+
});
|
|
8220
|
+
report({
|
|
8221
|
+
location: node.expression,
|
|
8222
|
+
messageText: `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
|
|
7878
8223
|
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
}
|
|
8224
|
+
fixes: [{
|
|
8225
|
+
fixName: "runEffectInsideEffect_fix",
|
|
8226
|
+
description: "Use a runtime to run the Effect",
|
|
8227
|
+
apply: fixAddRuntime
|
|
8228
|
+
}]
|
|
8229
|
+
});
|
|
8230
|
+
} else {
|
|
8231
|
+
report({
|
|
8232
|
+
location: node.expression,
|
|
8233
|
+
messageText: `Using ${nodeText} inside an Effect is not recommended. Effects inside generators can usually just be yielded.`,
|
|
8234
|
+
fixes: []
|
|
8235
|
+
});
|
|
7892
8236
|
}
|
|
7893
|
-
currentParent = currentParent.parent;
|
|
7894
8237
|
}
|
|
7895
8238
|
}
|
|
7896
8239
|
})
|
|
@@ -7976,6 +8319,59 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
7976
8319
|
})
|
|
7977
8320
|
});
|
|
7978
8321
|
|
|
8322
|
+
// src/diagnostics/schemaSyncInEffect.ts
|
|
8323
|
+
var syncToEffectMethod = {
|
|
8324
|
+
decodeSync: "decode",
|
|
8325
|
+
decodeUnknownSync: "decodeUnknown",
|
|
8326
|
+
encodeSync: "encode",
|
|
8327
|
+
encodeUnknownSync: "encodeUnknown"
|
|
8328
|
+
};
|
|
8329
|
+
var schemaSyncInEffect = createDiagnostic({
|
|
8330
|
+
name: "schemaSyncInEffect",
|
|
8331
|
+
code: 43,
|
|
8332
|
+
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
8333
|
+
severity: "suggestion",
|
|
8334
|
+
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
8335
|
+
const ts = yield* service(TypeScriptApi);
|
|
8336
|
+
const typeParser = yield* service(TypeParser);
|
|
8337
|
+
const parseSchemaSyncMethod = (node, methodName) => pipe(
|
|
8338
|
+
typeParser.isNodeReferenceToEffectParseResultModuleApi(methodName)(node),
|
|
8339
|
+
map4(() => ({ node, methodName }))
|
|
8340
|
+
);
|
|
8341
|
+
const nodeToVisit = [];
|
|
8342
|
+
const appendNodeToVisit = (node) => {
|
|
8343
|
+
nodeToVisit.push(node);
|
|
8344
|
+
return void 0;
|
|
8345
|
+
};
|
|
8346
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
8347
|
+
while (nodeToVisit.length > 0) {
|
|
8348
|
+
const node = nodeToVisit.shift();
|
|
8349
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
8350
|
+
if (!ts.isCallExpression(node)) continue;
|
|
8351
|
+
const isSchemaSyncCall = yield* pipe(
|
|
8352
|
+
firstSuccessOf(
|
|
8353
|
+
Object.keys(syncToEffectMethod).map((methodName) => parseSchemaSyncMethod(node.expression, methodName))
|
|
8354
|
+
),
|
|
8355
|
+
option
|
|
8356
|
+
);
|
|
8357
|
+
if (isNone2(isSchemaSyncCall)) continue;
|
|
8358
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
8359
|
+
if (!effectGen || effectGen.body.statements.length === 0) continue;
|
|
8360
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
8361
|
+
const nodeText = sourceFile.text.substring(
|
|
8362
|
+
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
8363
|
+
node.expression.end
|
|
8364
|
+
);
|
|
8365
|
+
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
8366
|
+
report({
|
|
8367
|
+
location: node.expression,
|
|
8368
|
+
messageText: `Using ${nodeText} inside an Effect generator is not recommended. Use Schema.${effectMethodName} instead to get properly typed ParseError in the error channel.`,
|
|
8369
|
+
fixes: []
|
|
8370
|
+
});
|
|
8371
|
+
}
|
|
8372
|
+
})
|
|
8373
|
+
});
|
|
8374
|
+
|
|
7979
8375
|
// src/diagnostics/schemaUnionOfLiterals.ts
|
|
7980
8376
|
var schemaUnionOfLiterals = createDiagnostic({
|
|
7981
8377
|
name: "schemaUnionOfLiterals",
|
|
@@ -8690,7 +9086,9 @@ var diagnostics = [
|
|
|
8690
9086
|
layerMergeAllWithDependencies,
|
|
8691
9087
|
effectMapVoid,
|
|
8692
9088
|
effectFnOpportunity,
|
|
8693
|
-
redundantSchemaTagIdentifier
|
|
9089
|
+
redundantSchemaTagIdentifier,
|
|
9090
|
+
schemaSyncInEffect,
|
|
9091
|
+
preferSchemaOverJson
|
|
8694
9092
|
];
|
|
8695
9093
|
|
|
8696
9094
|
// src/effect-lsp-patch-utils.ts
|