@effect/language-service 0.23.5 → 0.24.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 +11 -11
- package/index.js +226 -24
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +228 -24
- package/transform.js.map +1 -1
package/package.json
CHANGED
package/transform.js
CHANGED
|
@@ -739,6 +739,7 @@ var isNonEmptyArray = (self) => self.length > 0;
|
|
|
739
739
|
|
|
740
740
|
// node_modules/.pnpm/effect@3.16.5/node_modules/effect/dist/esm/Order.js
|
|
741
741
|
var make = (compare) => (self, that) => self === that ? 0 : compare(self, that);
|
|
742
|
+
var string2 = /* @__PURE__ */ make((self, that) => self < that ? -1 : 1);
|
|
742
743
|
|
|
743
744
|
// node_modules/.pnpm/effect@3.16.5/node_modules/effect/dist/esm/Option.js
|
|
744
745
|
var none2 = () => none;
|
|
@@ -921,6 +922,7 @@ var orElse2 = (f) => (fa) => make2((ctx) => {
|
|
|
921
922
|
if (result._tag === "Left") return f(result.value).run(ctx);
|
|
922
923
|
return result;
|
|
923
924
|
});
|
|
925
|
+
var firstSuccessOf = (arr) => arr.slice(1).reduce((arr2, fa) => orElse2(() => fa)(arr2), arr[0]);
|
|
924
926
|
var service = (tag) => make2(
|
|
925
927
|
(ctx) => tag.key in ctx.value ? ctx.value[tag.key] : makeInternalDefect(`Cannot find service ${tag.key}`)
|
|
926
928
|
);
|
|
@@ -2027,22 +2029,16 @@ function make3(ts, typeChecker) {
|
|
|
2027
2029
|
);
|
|
2028
2030
|
const effectType = cachedBy(
|
|
2029
2031
|
fn("TypeParser.effectType")(function* (type, atLocation) {
|
|
2030
|
-
|
|
2032
|
+
let result = typeParserIssue("Type has no effect variance struct", type, atLocation);
|
|
2031
2033
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2032
|
-
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
|
|
2034
|
+
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
|
|
2033
2035
|
);
|
|
2034
2036
|
propertiesSymbols.sort((a, b) => b.name.indexOf("EffectTypeId") - a.name.indexOf("EffectTypeId"));
|
|
2035
2037
|
for (const propertySymbol of propertiesSymbols) {
|
|
2036
2038
|
const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
|
|
2037
|
-
|
|
2038
|
-
propertyType,
|
|
2039
|
-
atLocation
|
|
2040
|
-
));
|
|
2041
|
-
if (isSome2(varianceArgs)) {
|
|
2042
|
-
return varianceArgs.value;
|
|
2043
|
-
}
|
|
2039
|
+
result = pipe(result, orElse2(() => effectVarianceStruct(propertyType, atLocation)));
|
|
2044
2040
|
}
|
|
2045
|
-
return yield*
|
|
2041
|
+
return yield* result;
|
|
2046
2042
|
}),
|
|
2047
2043
|
"TypeParser.effectType",
|
|
2048
2044
|
(type) => type
|
|
@@ -2061,7 +2057,7 @@ function make3(ts, typeChecker) {
|
|
|
2061
2057
|
fn("TypeParser.layerType")(function* (type, atLocation) {
|
|
2062
2058
|
yield* pipeableType(type, atLocation);
|
|
2063
2059
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2064
|
-
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
|
|
2060
|
+
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
|
|
2065
2061
|
);
|
|
2066
2062
|
propertiesSymbols.sort((a, b) => b.name.indexOf("LayerTypeId") - a.name.indexOf("LayerTypeId"));
|
|
2067
2063
|
for (const propertySymbol of propertiesSymbols) {
|
|
@@ -2345,7 +2341,7 @@ function make3(ts, typeChecker) {
|
|
|
2345
2341
|
const ast = typeChecker.getPropertyOfType(type, "ast");
|
|
2346
2342
|
if (!ast) return yield* typeParserIssue("Has no 'ast' property", type, atLocation);
|
|
2347
2343
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2348
|
-
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
|
|
2344
|
+
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
|
|
2349
2345
|
);
|
|
2350
2346
|
propertiesSymbols.sort((a, b) => b.name.indexOf("TypeId") - a.name.indexOf("TypeId"));
|
|
2351
2347
|
for (const propertySymbol of propertiesSymbols) {
|
|
@@ -2374,7 +2370,7 @@ function make3(ts, typeChecker) {
|
|
|
2374
2370
|
fn("TypeParser.contextTag")(function* (type, atLocation) {
|
|
2375
2371
|
yield* pipeableType(type, atLocation);
|
|
2376
2372
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2377
|
-
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
|
|
2373
|
+
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
|
|
2378
2374
|
);
|
|
2379
2375
|
propertiesSymbols.sort((a, b) => b.name.indexOf("TypeId") - a.name.indexOf("TypeId"));
|
|
2380
2376
|
for (const propertySymbol of propertiesSymbols) {
|
|
@@ -2406,6 +2402,25 @@ function make3(ts, typeChecker) {
|
|
|
2406
2402
|
"TypeParser.pipeCall",
|
|
2407
2403
|
(node) => node
|
|
2408
2404
|
);
|
|
2405
|
+
const scopeType = cachedBy(
|
|
2406
|
+
fn("TypeParser.scopeType")(function* (type, atLocation) {
|
|
2407
|
+
yield* pipeableType(type, atLocation);
|
|
2408
|
+
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2409
|
+
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
|
|
2410
|
+
);
|
|
2411
|
+
propertiesSymbols.sort((a, b) => b.name.indexOf("ScopeTypeId") - a.name.indexOf("ScopeTypeId"));
|
|
2412
|
+
for (const propertySymbol of propertiesSymbols) {
|
|
2413
|
+
const computedPropertyExpression = propertySymbol.valueDeclaration.name;
|
|
2414
|
+
const symbol3 = typeChecker.getSymbolAtLocation(computedPropertyExpression.expression);
|
|
2415
|
+
if (symbol3 && symbol3.name === "ScopeTypeId") {
|
|
2416
|
+
return type;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
return yield* typeParserIssue("Type has no scope type id", type, atLocation);
|
|
2420
|
+
}),
|
|
2421
|
+
"TypeParser.scopeType",
|
|
2422
|
+
(type) => type
|
|
2423
|
+
);
|
|
2409
2424
|
return {
|
|
2410
2425
|
effectType,
|
|
2411
2426
|
strictEffectType,
|
|
@@ -2419,7 +2434,8 @@ function make3(ts, typeChecker) {
|
|
|
2419
2434
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
2420
2435
|
effectSchemaType,
|
|
2421
2436
|
contextTag,
|
|
2422
|
-
pipeCall
|
|
2437
|
+
pipeCall,
|
|
2438
|
+
scopeType
|
|
2423
2439
|
};
|
|
2424
2440
|
}
|
|
2425
2441
|
|
|
@@ -2860,18 +2876,39 @@ var missingEffectError = createDiagnostic({
|
|
|
2860
2876
|
code: 1,
|
|
2861
2877
|
severity: "error",
|
|
2862
2878
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
2879
|
+
const ts = yield* service(TypeScriptApi);
|
|
2863
2880
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
2864
2881
|
const typeParser = yield* service(TypeParser);
|
|
2865
2882
|
const typeOrder = yield* deterministicTypeOrder;
|
|
2883
|
+
const effectModuleIdentifier = yield* pipe(
|
|
2884
|
+
findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
2885
|
+
sourceFile,
|
|
2886
|
+
"effect",
|
|
2887
|
+
"Effect"
|
|
2888
|
+
),
|
|
2889
|
+
map3((_) => _.text),
|
|
2890
|
+
orElse2(() => succeed("Effect"))
|
|
2891
|
+
);
|
|
2892
|
+
const createDieMessage = (message) => ts.factory.createCallExpression(
|
|
2893
|
+
ts.factory.createPropertyAccessExpression(
|
|
2894
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
2895
|
+
"dieMessage"
|
|
2896
|
+
),
|
|
2897
|
+
void 0,
|
|
2898
|
+
[ts.factory.createStringLiteral(message)]
|
|
2899
|
+
);
|
|
2866
2900
|
const checkForMissingErrorTypes = (node, expectedType, valueNode, realType) => pipe(
|
|
2867
2901
|
all(
|
|
2868
2902
|
typeParser.effectType(expectedType, node),
|
|
2869
2903
|
typeParser.effectType(realType, valueNode)
|
|
2870
2904
|
),
|
|
2871
2905
|
flatMap2(
|
|
2872
|
-
([expectedEffect, realEffect]) =>
|
|
2873
|
-
|
|
2874
|
-
|
|
2906
|
+
([expectedEffect, realEffect]) => pipe(
|
|
2907
|
+
getMissingTypeEntriesInTargetType(
|
|
2908
|
+
realEffect.E,
|
|
2909
|
+
expectedEffect.E
|
|
2910
|
+
),
|
|
2911
|
+
map3((missingErrorTypes) => ({ missingErrorTypes, expectedErrorType: expectedEffect.E }))
|
|
2875
2912
|
)
|
|
2876
2913
|
)
|
|
2877
2914
|
);
|
|
@@ -2886,15 +2923,79 @@ var missingEffectError = createDiagnostic({
|
|
|
2886
2923
|
valueNode,
|
|
2887
2924
|
realType
|
|
2888
2925
|
),
|
|
2889
|
-
map3(
|
|
2890
|
-
(
|
|
2926
|
+
map3((result) => {
|
|
2927
|
+
if (result.missingErrorTypes.length === 0) return;
|
|
2928
|
+
const fixes = [];
|
|
2929
|
+
if (ts.isExpression(valueNode) && result.expectedErrorType.flags & ts.TypeFlags.Never) {
|
|
2930
|
+
fixes.push({
|
|
2931
|
+
fixName: "missingEffectError_catchAll",
|
|
2932
|
+
description: "Catch all errors with Effect.catchAll",
|
|
2933
|
+
apply: gen(function* () {
|
|
2934
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
2935
|
+
changeTracker.insertText(sourceFile, valueNode.getStart(), effectModuleIdentifier + ".catchAll(");
|
|
2936
|
+
changeTracker.insertText(sourceFile, valueNode.getEnd(), ", () => ");
|
|
2937
|
+
changeTracker.insertNodeAt(
|
|
2938
|
+
sourceFile,
|
|
2939
|
+
valueNode.getEnd(),
|
|
2940
|
+
createDieMessage("TODO: catchAll not implemented")
|
|
2941
|
+
);
|
|
2942
|
+
changeTracker.insertText(sourceFile, valueNode.getEnd(), ")");
|
|
2943
|
+
})
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
if (ts.isExpression(valueNode)) {
|
|
2947
|
+
const propertyAssignments = pipe(
|
|
2948
|
+
result.missingErrorTypes,
|
|
2949
|
+
map2((_) => typeChecker.getPropertyOfType(_, "_tag")),
|
|
2950
|
+
filter((_) => !!_),
|
|
2951
|
+
map2((_) => typeChecker.getTypeOfSymbolAtLocation(_, valueNode)),
|
|
2952
|
+
filter((_) => !!(_.flags & ts.TypeFlags.Literal)),
|
|
2953
|
+
map2((_) => typeChecker.typeToTypeNode(_, void 0, ts.NodeBuilderFlags.NoTruncation)),
|
|
2954
|
+
filter((_) => !!_ && ts.isLiteralTypeNode(_)),
|
|
2955
|
+
map2((_) => _.literal),
|
|
2956
|
+
filter((_) => ts.isLiteralExpression(_)),
|
|
2957
|
+
map2((_) => _.text),
|
|
2958
|
+
sort(string2),
|
|
2959
|
+
map2(
|
|
2960
|
+
(_) => ts.factory.createPropertyAssignment(
|
|
2961
|
+
ts.factory.createIdentifier(_),
|
|
2962
|
+
ts.factory.createArrowFunction(
|
|
2963
|
+
void 0,
|
|
2964
|
+
void 0,
|
|
2965
|
+
[],
|
|
2966
|
+
void 0,
|
|
2967
|
+
void 0,
|
|
2968
|
+
createDieMessage(`TODO: catchTags() not implemented for ${_}`)
|
|
2969
|
+
)
|
|
2970
|
+
)
|
|
2971
|
+
)
|
|
2972
|
+
);
|
|
2973
|
+
if (propertyAssignments.length === result.missingErrorTypes.length) {
|
|
2974
|
+
fixes.push({
|
|
2975
|
+
fixName: "missingEffectError_tagged",
|
|
2976
|
+
description: "Catch unexpected errors with Effect.catchTag",
|
|
2977
|
+
apply: gen(function* () {
|
|
2978
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
2979
|
+
changeTracker.insertText(sourceFile, valueNode.getStart(), effectModuleIdentifier + ".catchTags(");
|
|
2980
|
+
changeTracker.insertText(sourceFile, valueNode.getEnd(), ", ");
|
|
2981
|
+
changeTracker.insertNodeAt(
|
|
2982
|
+
sourceFile,
|
|
2983
|
+
valueNode.getEnd(),
|
|
2984
|
+
ts.factory.createObjectLiteralExpression(propertyAssignments)
|
|
2985
|
+
);
|
|
2986
|
+
changeTracker.insertText(sourceFile, valueNode.getEnd(), ")");
|
|
2987
|
+
})
|
|
2988
|
+
});
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
report(
|
|
2891
2992
|
{
|
|
2892
2993
|
node,
|
|
2893
|
-
messageText: `Missing '${sortTypes(
|
|
2894
|
-
fixes
|
|
2994
|
+
messageText: `Missing '${sortTypes(result.missingErrorTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Effect errors.`,
|
|
2995
|
+
fixes
|
|
2895
2996
|
}
|
|
2896
|
-
)
|
|
2897
|
-
),
|
|
2997
|
+
);
|
|
2998
|
+
}),
|
|
2898
2999
|
ignore
|
|
2899
3000
|
);
|
|
2900
3001
|
}
|
|
@@ -3106,6 +3207,108 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
3106
3207
|
})
|
|
3107
3208
|
});
|
|
3108
3209
|
|
|
3210
|
+
// src/diagnostics/scopeInLayerEffect.ts
|
|
3211
|
+
var scopeInLayerEffect = createDiagnostic({
|
|
3212
|
+
name: "scopeInLayerEffect",
|
|
3213
|
+
code: 13,
|
|
3214
|
+
severity: "warning",
|
|
3215
|
+
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
3216
|
+
const ts = yield* service(TypeScriptApi);
|
|
3217
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
3218
|
+
const typeParser = yield* service(TypeParser);
|
|
3219
|
+
const layerModuleIdentifier = yield* pipe(
|
|
3220
|
+
findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
3221
|
+
sourceFile,
|
|
3222
|
+
"effect",
|
|
3223
|
+
"Layer"
|
|
3224
|
+
),
|
|
3225
|
+
map3((_) => _.text),
|
|
3226
|
+
orElse2(() => succeed("Layer"))
|
|
3227
|
+
);
|
|
3228
|
+
function parseLayerEffectApiCall(node) {
|
|
3229
|
+
if (!ts.isCallExpression(node)) return;
|
|
3230
|
+
const expression = node.expression;
|
|
3231
|
+
if (!ts.isPropertyAccessExpression(expression)) return;
|
|
3232
|
+
const calledModule = expression.expression;
|
|
3233
|
+
if (!(ts.isIdentifier(calledModule) && calledModule.text === layerModuleIdentifier)) return;
|
|
3234
|
+
const methodIdentifier = expression.name;
|
|
3235
|
+
if (!(ts.isIdentifier(methodIdentifier) && methodIdentifier.text.toLowerCase().startsWith("effect"))) return;
|
|
3236
|
+
return { methodIdentifier };
|
|
3237
|
+
}
|
|
3238
|
+
const reportIfLayerRequireScope = (type, node, methodIdentifier) => {
|
|
3239
|
+
let toCheck = [type];
|
|
3240
|
+
const entries = [];
|
|
3241
|
+
while (toCheck.length > 0) {
|
|
3242
|
+
const type2 = toCheck.pop();
|
|
3243
|
+
if (type2.isUnion()) {
|
|
3244
|
+
toCheck = toCheck.concat(type2.types);
|
|
3245
|
+
} else {
|
|
3246
|
+
entries.push(type2);
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
return pipe(
|
|
3250
|
+
firstSuccessOf(entries.map((type2) => typeParser.scopeType(type2, node))),
|
|
3251
|
+
map3(
|
|
3252
|
+
() => report({
|
|
3253
|
+
node,
|
|
3254
|
+
messageText: `Seems like you are constructing a layer with a scope in the requirements.
|
|
3255
|
+
Consider using "scoped" instead to get ride of the scope in the requirements.`,
|
|
3256
|
+
fixes: methodIdentifier ? [{
|
|
3257
|
+
fixName: "scopeInLayerEffect_scoped",
|
|
3258
|
+
description: "Use scoped for Layer creation",
|
|
3259
|
+
apply: gen(function* () {
|
|
3260
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
3261
|
+
changeTracker.replaceNode(
|
|
3262
|
+
sourceFile,
|
|
3263
|
+
methodIdentifier,
|
|
3264
|
+
ts.factory.createIdentifier("scoped")
|
|
3265
|
+
);
|
|
3266
|
+
})
|
|
3267
|
+
}] : []
|
|
3268
|
+
})
|
|
3269
|
+
),
|
|
3270
|
+
ignore
|
|
3271
|
+
);
|
|
3272
|
+
};
|
|
3273
|
+
const nodeToVisit = [];
|
|
3274
|
+
const appendNodeToVisit = (node) => {
|
|
3275
|
+
nodeToVisit.push(node);
|
|
3276
|
+
return void 0;
|
|
3277
|
+
};
|
|
3278
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3279
|
+
while (nodeToVisit.length > 0) {
|
|
3280
|
+
const node = nodeToVisit.shift();
|
|
3281
|
+
const layerEffectApiCall = parseLayerEffectApiCall(node);
|
|
3282
|
+
if (layerEffectApiCall) {
|
|
3283
|
+
const type = typeChecker.getTypeAtLocation(node);
|
|
3284
|
+
yield* pipe(
|
|
3285
|
+
typeParser.layerType(type, node),
|
|
3286
|
+
flatMap2(({ RIn }) => reportIfLayerRequireScope(RIn, node, layerEffectApiCall.methodIdentifier)),
|
|
3287
|
+
ignore
|
|
3288
|
+
);
|
|
3289
|
+
continue;
|
|
3290
|
+
}
|
|
3291
|
+
if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
3292
|
+
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
3293
|
+
if (classSym) {
|
|
3294
|
+
const classType = typeChecker.getTypeOfSymbol(classSym);
|
|
3295
|
+
const defaultLayer = typeChecker.getPropertyOfType(classType, "Default");
|
|
3296
|
+
if (defaultLayer) {
|
|
3297
|
+
const type = typeChecker.getTypeOfSymbolAtLocation(defaultLayer, node);
|
|
3298
|
+
yield* pipe(
|
|
3299
|
+
typeParser.layerType(type, node),
|
|
3300
|
+
flatMap2(({ RIn }) => reportIfLayerRequireScope(RIn, node, void 0)),
|
|
3301
|
+
ignore
|
|
3302
|
+
);
|
|
3303
|
+
continue;
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3308
|
+
}
|
|
3309
|
+
})
|
|
3310
|
+
});
|
|
3311
|
+
|
|
3109
3312
|
// src/diagnostics/unnecessaryEffectGen.ts
|
|
3110
3313
|
var unnecessaryEffectGen = createDiagnostic({
|
|
3111
3314
|
name: "unnecessaryEffectGen",
|
|
@@ -3207,7 +3410,8 @@ var diagnostics = [
|
|
|
3207
3410
|
unnecessaryPipe,
|
|
3208
3411
|
genericEffectServices,
|
|
3209
3412
|
returnEffectInGen,
|
|
3210
|
-
importFromBarrel
|
|
3413
|
+
importFromBarrel,
|
|
3414
|
+
scopeInLayerEffect
|
|
3211
3415
|
];
|
|
3212
3416
|
|
|
3213
3417
|
// src/transform.ts
|