@effect/language-service 0.65.0 → 0.66.1
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 +2 -0
- package/cli.js +723 -336
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +719 -332
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +719 -332
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +719 -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,184 @@ ${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))
|
|
4972
|
+
);
|
|
4973
|
+
};
|
|
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
|
+
() => succeed({ effectModuleName: sourceEffectModuleName, pipeArguments: [], generatorFunction: void 0 })
|
|
5002
|
+
)
|
|
4768
5003
|
);
|
|
5004
|
+
return {
|
|
5005
|
+
node,
|
|
5006
|
+
nameIdentifier,
|
|
5007
|
+
effectModuleName: opportunity.effectModuleName,
|
|
5008
|
+
traceName,
|
|
5009
|
+
pipeArguments: opportunity.pipeArguments,
|
|
5010
|
+
generatorFunction: opportunity.generatorFunction,
|
|
5011
|
+
hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
|
|
5012
|
+
};
|
|
5013
|
+
});
|
|
5014
|
+
const getFunctionBodyBlock = (node) => {
|
|
5015
|
+
if (ts.isArrowFunction(node)) {
|
|
5016
|
+
if (ts.isBlock(node.body)) {
|
|
5017
|
+
return node.body;
|
|
5018
|
+
}
|
|
5019
|
+
return ts.factory.createBlock([ts.factory.createReturnStatement(node.body)], true);
|
|
5020
|
+
}
|
|
5021
|
+
return node.body;
|
|
5022
|
+
};
|
|
5023
|
+
const isGeneratorFunction = (node) => {
|
|
5024
|
+
if (ts.isArrowFunction(node)) return false;
|
|
5025
|
+
return node.asteriskToken !== void 0;
|
|
4769
5026
|
};
|
|
4770
|
-
const createEffectFnNode = (originalNode,
|
|
4771
|
-
const
|
|
4772
|
-
const
|
|
5027
|
+
const createEffectFnNode = (originalNode, innerFunction, effectModuleName, traceName, pipeArguments2) => {
|
|
5028
|
+
const isGenerator = isGeneratorFunction(innerFunction);
|
|
5029
|
+
const newFunction = ts.factory.createFunctionExpression(
|
|
4773
5030
|
void 0,
|
|
4774
|
-
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
5031
|
+
isGenerator ? ts.factory.createToken(ts.SyntaxKind.AsteriskToken) : void 0,
|
|
4775
5032
|
void 0,
|
|
4776
5033
|
originalNode.typeParameters,
|
|
4777
5034
|
originalNode.parameters,
|
|
4778
|
-
|
|
4779
|
-
|
|
5035
|
+
void 0,
|
|
5036
|
+
getFunctionBodyBlock(innerFunction)
|
|
4780
5037
|
);
|
|
4781
5038
|
let fnExpression = ts.factory.createPropertyAccessExpression(
|
|
4782
5039
|
ts.factory.createIdentifier(effectModuleName),
|
|
@@ -4789,34 +5046,27 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
4789
5046
|
[ts.factory.createStringLiteral(traceName)]
|
|
4790
5047
|
);
|
|
4791
5048
|
}
|
|
4792
|
-
const effectFnCall = ts.factory.createCallExpression(
|
|
4793
|
-
fnExpression,
|
|
4794
|
-
void 0,
|
|
4795
|
-
[newGeneratorFunction, ...pipeArguments2]
|
|
4796
|
-
);
|
|
5049
|
+
const effectFnCall = ts.factory.createCallExpression(fnExpression, void 0, [newFunction, ...pipeArguments2]);
|
|
4797
5050
|
if (ts.isFunctionDeclaration(originalNode)) {
|
|
4798
5051
|
return tsUtils.tryPreserveDeclarationSemantics(originalNode, effectFnCall, false);
|
|
4799
5052
|
}
|
|
4800
5053
|
return effectFnCall;
|
|
4801
5054
|
};
|
|
4802
|
-
const createEffectFnUntracedNode = (originalNode,
|
|
4803
|
-
const
|
|
4804
|
-
const
|
|
5055
|
+
const createEffectFnUntracedNode = (originalNode, innerFunction, effectModuleName, pipeArguments2) => {
|
|
5056
|
+
const isGenerator = isGeneratorFunction(innerFunction);
|
|
5057
|
+
const newFunction = ts.factory.createFunctionExpression(
|
|
4805
5058
|
void 0,
|
|
4806
|
-
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
5059
|
+
isGenerator ? ts.factory.createToken(ts.SyntaxKind.AsteriskToken) : void 0,
|
|
4807
5060
|
void 0,
|
|
4808
5061
|
originalNode.typeParameters,
|
|
4809
5062
|
originalNode.parameters,
|
|
4810
|
-
|
|
4811
|
-
|
|
5063
|
+
void 0,
|
|
5064
|
+
getFunctionBodyBlock(innerFunction)
|
|
4812
5065
|
);
|
|
4813
5066
|
const effectFnCall = ts.factory.createCallExpression(
|
|
4814
|
-
ts.factory.createPropertyAccessExpression(
|
|
4815
|
-
ts.factory.createIdentifier(effectModuleName),
|
|
4816
|
-
"fnUntraced"
|
|
4817
|
-
),
|
|
5067
|
+
ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(effectModuleName), "fnUntraced"),
|
|
4818
5068
|
void 0,
|
|
4819
|
-
[
|
|
5069
|
+
[newFunction, ...pipeArguments2]
|
|
4820
5070
|
);
|
|
4821
5071
|
if (ts.isFunctionDeclaration(originalNode)) {
|
|
4822
5072
|
return tsUtils.tryPreserveDeclarationSemantics(originalNode, effectFnCall, false);
|
|
@@ -4832,88 +5082,41 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
4832
5082
|
while (nodeToVisit.length > 0) {
|
|
4833
5083
|
const node = nodeToVisit.shift();
|
|
4834
5084
|
ts.forEachChild(node, appendNodeToVisit);
|
|
4835
|
-
const target = yield* pipe(
|
|
4836
|
-
parseEffectFnOpportunityTarget(node, sourceFile),
|
|
4837
|
-
option
|
|
4838
|
-
);
|
|
5085
|
+
const target = yield* pipe(parseEffectFnOpportunityTarget(node), option);
|
|
4839
5086
|
if (isNone2(target)) continue;
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
generatorFunction,
|
|
4844
|
-
hasReturnTypeAnnotation,
|
|
4845
|
-
nameIdentifier,
|
|
4846
|
-
node: targetNode,
|
|
4847
|
-
pipeArguments: pipeArguments2,
|
|
4848
|
-
traceName
|
|
4849
|
-
} = target.value;
|
|
5087
|
+
if (target.value.hasParamsInPipeArgs) continue;
|
|
5088
|
+
const { effectModuleName, nameIdentifier, node: targetNode, pipeArguments: pipeArguments2, traceName } = target.value;
|
|
5089
|
+
const innerFunction = target.value.generatorFunction ?? targetNode;
|
|
4850
5090
|
const fixes = [];
|
|
4851
5091
|
fixes.push({
|
|
4852
5092
|
fixName: "effectFnOpportunity_toEffectFn",
|
|
4853
5093
|
description: traceName ? `Convert to Effect.fn("${traceName}")` : "Convert to Effect.fn",
|
|
4854
5094
|
apply: gen(function* () {
|
|
4855
5095
|
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
|
-
);
|
|
5096
|
+
const newNode = createEffectFnNode(targetNode, innerFunction, effectModuleName, traceName, pipeArguments2);
|
|
4879
5097
|
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
4880
5098
|
})
|
|
4881
5099
|
});
|
|
5100
|
+
if (target.value.generatorFunction) {
|
|
5101
|
+
fixes.push({
|
|
5102
|
+
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
5103
|
+
description: "Convert to Effect.fnUntraced",
|
|
5104
|
+
apply: gen(function* () {
|
|
5105
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5106
|
+
const newNode = createEffectFnUntracedNode(targetNode, innerFunction, effectModuleName, pipeArguments2);
|
|
5107
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
5108
|
+
})
|
|
5109
|
+
});
|
|
5110
|
+
}
|
|
5111
|
+
const pipeArgsSuffix = pipeArguments2.length > 0 ? ` Effect.fn also accepts the piped transformations as additional arguments.` : ``;
|
|
4882
5112
|
report({
|
|
4883
5113
|
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
|
|
5114
|
+
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
5115
|
fixes
|
|
4886
5116
|
});
|
|
4887
5117
|
}
|
|
4888
5118
|
})
|
|
4889
5119
|
});
|
|
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
5120
|
|
|
4918
5121
|
// src/diagnostics/effectGenUsesAdapter.ts
|
|
4919
5122
|
var effectGenUsesAdapter = createDiagnostic({
|
|
@@ -5676,6 +5879,52 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
5676
5879
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5677
5880
|
const typeParser = yield* service(TypeParser);
|
|
5678
5881
|
const options = yield* service(LanguageServicePluginOptions);
|
|
5882
|
+
const isSafelyPipeableCallee = (callee) => {
|
|
5883
|
+
if (ts.isCallExpression(callee)) {
|
|
5884
|
+
return true;
|
|
5885
|
+
}
|
|
5886
|
+
if (ts.isArrowFunction(callee)) {
|
|
5887
|
+
return true;
|
|
5888
|
+
}
|
|
5889
|
+
if (ts.isFunctionExpression(callee)) {
|
|
5890
|
+
return true;
|
|
5891
|
+
}
|
|
5892
|
+
if (ts.isParenthesizedExpression(callee)) {
|
|
5893
|
+
return isSafelyPipeableCallee(callee.expression);
|
|
5894
|
+
}
|
|
5895
|
+
if (ts.isIdentifier(callee)) {
|
|
5896
|
+
const symbol3 = typeChecker.getSymbolAtLocation(callee);
|
|
5897
|
+
if (!symbol3) return false;
|
|
5898
|
+
if (symbol3.flags & (ts.SymbolFlags.Module | ts.SymbolFlags.Namespace | ts.SymbolFlags.ValueModule)) {
|
|
5899
|
+
return true;
|
|
5900
|
+
}
|
|
5901
|
+
const declarations = symbol3.declarations;
|
|
5902
|
+
if (declarations && declarations.length > 0) {
|
|
5903
|
+
const decl = declarations[0];
|
|
5904
|
+
if (ts.isFunctionDeclaration(decl) || ts.isVariableDeclaration(decl) || ts.isImportSpecifier(decl) || ts.isImportClause(decl) || ts.isNamespaceImport(decl)) {
|
|
5905
|
+
return true;
|
|
5906
|
+
}
|
|
5907
|
+
}
|
|
5908
|
+
return false;
|
|
5909
|
+
}
|
|
5910
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
5911
|
+
const subject = callee.expression;
|
|
5912
|
+
const symbol3 = typeChecker.getSymbolAtLocation(subject);
|
|
5913
|
+
if (!symbol3) return false;
|
|
5914
|
+
if (symbol3.flags & (ts.SymbolFlags.Module | ts.SymbolFlags.Namespace | ts.SymbolFlags.ValueModule)) {
|
|
5915
|
+
return true;
|
|
5916
|
+
}
|
|
5917
|
+
const declarations = symbol3.declarations;
|
|
5918
|
+
if (declarations && declarations.length > 0) {
|
|
5919
|
+
const decl = declarations[0];
|
|
5920
|
+
if (ts.isNamespaceImport(decl) || ts.isSourceFile(decl) || ts.isModuleDeclaration(decl)) {
|
|
5921
|
+
return true;
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5924
|
+
return false;
|
|
5925
|
+
}
|
|
5926
|
+
return false;
|
|
5927
|
+
};
|
|
5679
5928
|
const flows = yield* typeParser.pipingFlows(false)(sourceFile);
|
|
5680
5929
|
for (const flow2 of flows) {
|
|
5681
5930
|
if (flow2.transformations.length < options.pipeableMinArgCount) {
|
|
@@ -5689,76 +5938,92 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
5689
5938
|
if (callSigs.length > 0) {
|
|
5690
5939
|
continue;
|
|
5691
5940
|
}
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5941
|
+
const isPipeableAtIndex = function* (index) {
|
|
5942
|
+
if (index === 0) {
|
|
5943
|
+
const subjectType = flow2.subject.outType;
|
|
5944
|
+
if (!subjectType) return false;
|
|
5945
|
+
const result = yield* pipe(
|
|
5946
|
+
typeParser.pipeableType(subjectType, flow2.subject.node),
|
|
5947
|
+
option
|
|
5948
|
+
);
|
|
5949
|
+
return result._tag === "Some";
|
|
5950
|
+
} else {
|
|
5951
|
+
const t = flow2.transformations[index - 1];
|
|
5952
|
+
if (!t.outType) return false;
|
|
5953
|
+
const result = yield* pipe(
|
|
5954
|
+
typeParser.pipeableType(t.outType, flow2.node),
|
|
5955
|
+
option
|
|
5956
|
+
);
|
|
5957
|
+
return result._tag === "Some";
|
|
5958
|
+
}
|
|
5959
|
+
};
|
|
5960
|
+
let searchStartIndex = 0;
|
|
5961
|
+
while (searchStartIndex <= flow2.transformations.length) {
|
|
5962
|
+
let firstPipeableIndex = -1;
|
|
5963
|
+
for (let i = searchStartIndex; i <= flow2.transformations.length; i++) {
|
|
5964
|
+
if (yield* isPipeableAtIndex(i)) {
|
|
5965
|
+
firstPipeableIndex = i;
|
|
5966
|
+
break;
|
|
5967
|
+
}
|
|
5968
|
+
}
|
|
5969
|
+
if (firstPipeableIndex === -1) {
|
|
5970
|
+
break;
|
|
5971
|
+
}
|
|
5972
|
+
const pipeableTransformations = [];
|
|
5973
|
+
for (let i = firstPipeableIndex; i < flow2.transformations.length; i++) {
|
|
5705
5974
|
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
|
-
}
|
|
5975
|
+
if (!isSafelyPipeableCallee(t.callee)) {
|
|
5976
|
+
break;
|
|
5715
5977
|
}
|
|
5978
|
+
pipeableTransformations.push(t);
|
|
5716
5979
|
}
|
|
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
|
-
|
|
5980
|
+
const callKindCount = pipeableTransformations.filter((t) => t.kind === "call").length;
|
|
5981
|
+
if (callKindCount >= options.pipeableMinArgCount) {
|
|
5982
|
+
const pipeableEndIndex = firstPipeableIndex + pipeableTransformations.length;
|
|
5983
|
+
const pipeableSubjectNode = firstPipeableIndex === 0 ? flow2.subject.node : typeParser.reconstructPipingFlow({
|
|
5984
|
+
subject: flow2.subject,
|
|
5985
|
+
transformations: flow2.transformations.slice(0, firstPipeableIndex)
|
|
5986
|
+
});
|
|
5987
|
+
const afterTransformations = flow2.transformations.slice(pipeableEndIndex);
|
|
5988
|
+
report({
|
|
5989
|
+
location: flow2.node,
|
|
5990
|
+
messageText: `Nested function calls can be converted to pipeable style for better readability.`,
|
|
5991
|
+
fixes: [{
|
|
5992
|
+
fixName: "missedPipeableOpportunity_fix",
|
|
5993
|
+
description: "Convert to pipe style",
|
|
5994
|
+
apply: gen(function* () {
|
|
5995
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5996
|
+
const pipeArgs = pipeableTransformations.map((t) => {
|
|
5997
|
+
if (t.args) {
|
|
5998
|
+
return ts.factory.createCallExpression(
|
|
5999
|
+
t.callee,
|
|
6000
|
+
void 0,
|
|
6001
|
+
t.args
|
|
6002
|
+
);
|
|
6003
|
+
} else {
|
|
6004
|
+
return t.callee;
|
|
6005
|
+
}
|
|
6006
|
+
});
|
|
6007
|
+
const pipeNode = ts.factory.createCallExpression(
|
|
6008
|
+
ts.factory.createPropertyAccessExpression(
|
|
6009
|
+
pipeableSubjectNode,
|
|
6010
|
+
"pipe"
|
|
6011
|
+
),
|
|
5743
6012
|
void 0,
|
|
5744
|
-
|
|
6013
|
+
pipeArgs
|
|
5745
6014
|
);
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
changeTracker.replaceNode(sourceFile, flow2.node, newNode);
|
|
5759
|
-
})
|
|
5760
|
-
}]
|
|
5761
|
-
});
|
|
6015
|
+
const newNode = afterTransformations.length > 0 ? typeParser.reconstructPipingFlow({
|
|
6016
|
+
subject: { node: pipeNode, outType: void 0 },
|
|
6017
|
+
transformations: afterTransformations
|
|
6018
|
+
}) : pipeNode;
|
|
6019
|
+
changeTracker.replaceNode(sourceFile, flow2.node, newNode);
|
|
6020
|
+
})
|
|
6021
|
+
}]
|
|
6022
|
+
});
|
|
6023
|
+
break;
|
|
6024
|
+
}
|
|
6025
|
+
searchStartIndex = firstPipeableIndex + pipeableTransformations.length + 1;
|
|
6026
|
+
}
|
|
5762
6027
|
}
|
|
5763
6028
|
})
|
|
5764
6029
|
});
|
|
@@ -7637,6 +7902,90 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
7637
7902
|
})
|
|
7638
7903
|
});
|
|
7639
7904
|
|
|
7905
|
+
// src/diagnostics/preferSchemaOverJson.ts
|
|
7906
|
+
var preferSchemaOverJson = createDiagnostic({
|
|
7907
|
+
name: "preferSchemaOverJson",
|
|
7908
|
+
code: 44,
|
|
7909
|
+
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
7910
|
+
severity: "suggestion",
|
|
7911
|
+
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
7912
|
+
const ts = yield* service(TypeScriptApi);
|
|
7913
|
+
const typeParser = yield* service(TypeParser);
|
|
7914
|
+
const parseJsonMethod = (node) => gen(function* () {
|
|
7915
|
+
if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
|
|
7916
|
+
const expression = node.expression;
|
|
7917
|
+
if (!ts.isPropertyAccessExpression(expression)) return yield* fail("expression is not a property access");
|
|
7918
|
+
const objectExpr = expression.expression;
|
|
7919
|
+
const methodName = ts.idText(expression.name);
|
|
7920
|
+
if (!ts.isIdentifier(objectExpr) || ts.idText(objectExpr) !== "JSON") {
|
|
7921
|
+
return yield* fail("object is not JSON");
|
|
7922
|
+
}
|
|
7923
|
+
if (methodName !== "parse" && methodName !== "stringify") {
|
|
7924
|
+
return yield* fail("method is not parse or stringify");
|
|
7925
|
+
}
|
|
7926
|
+
return { node, methodName };
|
|
7927
|
+
});
|
|
7928
|
+
const effectTrySimple = (node) => gen(function* () {
|
|
7929
|
+
if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
|
|
7930
|
+
yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
|
|
7931
|
+
if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
|
|
7932
|
+
const lazyFn = yield* typeParser.lazyExpression(node.arguments[0]);
|
|
7933
|
+
const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
|
|
7934
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
7935
|
+
});
|
|
7936
|
+
const effectTryObject = (node) => gen(function* () {
|
|
7937
|
+
if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
|
|
7938
|
+
yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
|
|
7939
|
+
if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
|
|
7940
|
+
const arg = node.arguments[0];
|
|
7941
|
+
if (!ts.isObjectLiteralExpression(arg)) return yield* fail("argument is not an object literal");
|
|
7942
|
+
const tryProp = arg.properties.find(
|
|
7943
|
+
(p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && ts.idText(p.name) === "try"
|
|
7944
|
+
);
|
|
7945
|
+
if (!tryProp) return yield* fail("object has no 'try' property");
|
|
7946
|
+
const lazyFn = yield* typeParser.lazyExpression(tryProp.initializer);
|
|
7947
|
+
const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
|
|
7948
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
7949
|
+
});
|
|
7950
|
+
const jsonMethodInEffectGen = (node) => gen(function* () {
|
|
7951
|
+
const jsonMethod = yield* parseJsonMethod(node);
|
|
7952
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
7953
|
+
if (!effectGen || effectGen.body.statements.length === 0) {
|
|
7954
|
+
return yield* fail("not inside an Effect generator");
|
|
7955
|
+
}
|
|
7956
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
7957
|
+
return yield* fail("inside a nested function scope");
|
|
7958
|
+
}
|
|
7959
|
+
return { node: jsonMethod.node, methodName: jsonMethod.methodName };
|
|
7960
|
+
});
|
|
7961
|
+
const nodeToVisit = [];
|
|
7962
|
+
const appendNodeToVisit = (node) => {
|
|
7963
|
+
nodeToVisit.push(node);
|
|
7964
|
+
return void 0;
|
|
7965
|
+
};
|
|
7966
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7967
|
+
while (nodeToVisit.length > 0) {
|
|
7968
|
+
const node = nodeToVisit.shift();
|
|
7969
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7970
|
+
const match2 = yield* pipe(
|
|
7971
|
+
firstSuccessOf([
|
|
7972
|
+
effectTrySimple(node),
|
|
7973
|
+
effectTryObject(node),
|
|
7974
|
+
jsonMethodInEffectGen(node)
|
|
7975
|
+
]),
|
|
7976
|
+
option
|
|
7977
|
+
);
|
|
7978
|
+
if (isSome2(match2)) {
|
|
7979
|
+
report({
|
|
7980
|
+
location: match2.value.node,
|
|
7981
|
+
messageText: "Consider using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify",
|
|
7982
|
+
fixes: []
|
|
7983
|
+
});
|
|
7984
|
+
}
|
|
7985
|
+
}
|
|
7986
|
+
})
|
|
7987
|
+
});
|
|
7988
|
+
|
|
7640
7989
|
// src/diagnostics/redundantSchemaTagIdentifier.ts
|
|
7641
7990
|
var redundantSchemaTagIdentifier = createDiagnostic({
|
|
7642
7991
|
name: "redundantSchemaTagIdentifier",
|
|
@@ -7789,108 +8138,91 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
7789
8138
|
option
|
|
7790
8139
|
);
|
|
7791
8140
|
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
|
|
8141
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
8142
|
+
if (effectGen && effectGen.body.statements.length > 0) {
|
|
8143
|
+
const nodeText = sourceFile.text.substring(
|
|
8144
|
+
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
8145
|
+
node.expression.end
|
|
7807
8146
|
);
|
|
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
|
-
}
|
|
8147
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
8148
|
+
const fixAddRuntime = gen(function* () {
|
|
8149
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
8150
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
8151
|
+
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
8152
|
+
let runtimeIdentifier = void 0;
|
|
8153
|
+
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
8154
|
+
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
8155
|
+
const declaration = statement.declarationList.declarations[0];
|
|
8156
|
+
if (declaration.initializer && ts.isYieldExpression(declaration.initializer) && declaration.initializer.asteriskToken && declaration.initializer.expression) {
|
|
8157
|
+
const yieldedExpression = declaration.initializer.expression;
|
|
8158
|
+
if (ts.isCallExpression(yieldedExpression)) {
|
|
8159
|
+
const maybeEffectRuntime = yield* pipe(
|
|
8160
|
+
typeParser.isNodeReferenceToEffectModuleApi("runtime")(yieldedExpression.expression),
|
|
8161
|
+
option
|
|
8162
|
+
);
|
|
8163
|
+
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
8164
|
+
runtimeIdentifier = ts.idText(declaration.name);
|
|
7832
8165
|
}
|
|
7833
8166
|
}
|
|
7834
8167
|
}
|
|
7835
8168
|
}
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
8169
|
+
}
|
|
8170
|
+
if (!runtimeIdentifier) {
|
|
8171
|
+
changeTracker.insertNodeAt(
|
|
8172
|
+
sourceFile,
|
|
8173
|
+
effectGen.body.statements[0].pos,
|
|
8174
|
+
ts.factory.createVariableStatement(
|
|
8175
|
+
void 0,
|
|
8176
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
8177
|
+
"effectRuntime",
|
|
7841
8178
|
void 0,
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
),
|
|
7853
|
-
[ts.factory.createTypeReferenceNode("never")],
|
|
7854
|
-
[]
|
|
7855
|
-
)
|
|
8179
|
+
void 0,
|
|
8180
|
+
ts.factory.createYieldExpression(
|
|
8181
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
8182
|
+
ts.factory.createCallExpression(
|
|
8183
|
+
ts.factory.createPropertyAccessExpression(
|
|
8184
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
8185
|
+
"runtime"
|
|
8186
|
+
),
|
|
8187
|
+
[ts.factory.createTypeReferenceNode("never")],
|
|
8188
|
+
[]
|
|
7856
8189
|
)
|
|
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"}, `
|
|
8190
|
+
)
|
|
8191
|
+
)], ts.NodeFlags.Const)
|
|
8192
|
+
),
|
|
8193
|
+
{
|
|
8194
|
+
prefix: "\n",
|
|
8195
|
+
suffix: "\n"
|
|
8196
|
+
}
|
|
7873
8197
|
);
|
|
8198
|
+
}
|
|
8199
|
+
changeTracker.deleteRange(sourceFile, {
|
|
8200
|
+
pos: ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
8201
|
+
end: node.arguments[0].pos
|
|
7874
8202
|
});
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
8203
|
+
changeTracker.insertText(
|
|
8204
|
+
sourceFile,
|
|
8205
|
+
node.arguments[0].pos,
|
|
8206
|
+
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
8207
|
+
);
|
|
8208
|
+
});
|
|
8209
|
+
report({
|
|
8210
|
+
location: node.expression,
|
|
8211
|
+
messageText: `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
|
|
7878
8212
|
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
|
-
}
|
|
8213
|
+
fixes: [{
|
|
8214
|
+
fixName: "runEffectInsideEffect_fix",
|
|
8215
|
+
description: "Use a runtime to run the Effect",
|
|
8216
|
+
apply: fixAddRuntime
|
|
8217
|
+
}]
|
|
8218
|
+
});
|
|
8219
|
+
} else {
|
|
8220
|
+
report({
|
|
8221
|
+
location: node.expression,
|
|
8222
|
+
messageText: `Using ${nodeText} inside an Effect is not recommended. Effects inside generators can usually just be yielded.`,
|
|
8223
|
+
fixes: []
|
|
8224
|
+
});
|
|
7892
8225
|
}
|
|
7893
|
-
currentParent = currentParent.parent;
|
|
7894
8226
|
}
|
|
7895
8227
|
}
|
|
7896
8228
|
})
|
|
@@ -7976,6 +8308,59 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
7976
8308
|
})
|
|
7977
8309
|
});
|
|
7978
8310
|
|
|
8311
|
+
// src/diagnostics/schemaSyncInEffect.ts
|
|
8312
|
+
var syncToEffectMethod = {
|
|
8313
|
+
decodeSync: "decode",
|
|
8314
|
+
decodeUnknownSync: "decodeUnknown",
|
|
8315
|
+
encodeSync: "encode",
|
|
8316
|
+
encodeUnknownSync: "encodeUnknown"
|
|
8317
|
+
};
|
|
8318
|
+
var schemaSyncInEffect = createDiagnostic({
|
|
8319
|
+
name: "schemaSyncInEffect",
|
|
8320
|
+
code: 43,
|
|
8321
|
+
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
8322
|
+
severity: "suggestion",
|
|
8323
|
+
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
8324
|
+
const ts = yield* service(TypeScriptApi);
|
|
8325
|
+
const typeParser = yield* service(TypeParser);
|
|
8326
|
+
const parseSchemaSyncMethod = (node, methodName) => pipe(
|
|
8327
|
+
typeParser.isNodeReferenceToEffectParseResultModuleApi(methodName)(node),
|
|
8328
|
+
map4(() => ({ node, methodName }))
|
|
8329
|
+
);
|
|
8330
|
+
const nodeToVisit = [];
|
|
8331
|
+
const appendNodeToVisit = (node) => {
|
|
8332
|
+
nodeToVisit.push(node);
|
|
8333
|
+
return void 0;
|
|
8334
|
+
};
|
|
8335
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
8336
|
+
while (nodeToVisit.length > 0) {
|
|
8337
|
+
const node = nodeToVisit.shift();
|
|
8338
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
8339
|
+
if (!ts.isCallExpression(node)) continue;
|
|
8340
|
+
const isSchemaSyncCall = yield* pipe(
|
|
8341
|
+
firstSuccessOf(
|
|
8342
|
+
Object.keys(syncToEffectMethod).map((methodName) => parseSchemaSyncMethod(node.expression, methodName))
|
|
8343
|
+
),
|
|
8344
|
+
option
|
|
8345
|
+
);
|
|
8346
|
+
if (isNone2(isSchemaSyncCall)) continue;
|
|
8347
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
8348
|
+
if (!effectGen || effectGen.body.statements.length === 0) continue;
|
|
8349
|
+
if (scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
8350
|
+
const nodeText = sourceFile.text.substring(
|
|
8351
|
+
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
8352
|
+
node.expression.end
|
|
8353
|
+
);
|
|
8354
|
+
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
8355
|
+
report({
|
|
8356
|
+
location: node.expression,
|
|
8357
|
+
messageText: `Using ${nodeText} inside an Effect generator is not recommended. Use Schema.${effectMethodName} instead to get properly typed ParseError in the error channel.`,
|
|
8358
|
+
fixes: []
|
|
8359
|
+
});
|
|
8360
|
+
}
|
|
8361
|
+
})
|
|
8362
|
+
});
|
|
8363
|
+
|
|
7979
8364
|
// src/diagnostics/schemaUnionOfLiterals.ts
|
|
7980
8365
|
var schemaUnionOfLiterals = createDiagnostic({
|
|
7981
8366
|
name: "schemaUnionOfLiterals",
|
|
@@ -8690,7 +9075,9 @@ var diagnostics = [
|
|
|
8690
9075
|
layerMergeAllWithDependencies,
|
|
8691
9076
|
effectMapVoid,
|
|
8692
9077
|
effectFnOpportunity,
|
|
8693
|
-
redundantSchemaTagIdentifier
|
|
9078
|
+
redundantSchemaTagIdentifier,
|
|
9079
|
+
schemaSyncInEffect,
|
|
9080
|
+
preferSchemaOverJson
|
|
8694
9081
|
];
|
|
8695
9082
|
|
|
8696
9083
|
// src/effect-lsp-patch-utils.ts
|