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