@effect/language-service 0.62.4 → 0.63.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 -1
- package/cli.js +2756 -676
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +345 -148
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +462 -204
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +345 -148
- package/transform.js.map +1 -1
|
@@ -26,7 +26,7 @@ __export(effect_lsp_patch_utils_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(effect_lsp_patch_utils_exports);
|
|
28
28
|
|
|
29
|
-
// node_modules/.pnpm/effect@3.19.
|
|
29
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Function.js
|
|
30
30
|
var isFunction = (input) => typeof input === "function";
|
|
31
31
|
var dual = function(arity, body) {
|
|
32
32
|
if (typeof arity === "function") {
|
|
@@ -122,7 +122,7 @@ function pipe(a, ab, bc, cd, de, ef, fg, gh, hi) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
// node_modules/.pnpm/effect@3.19.
|
|
125
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/GlobalValue.js
|
|
126
126
|
var globalStoreId = `effect/GlobalValue`;
|
|
127
127
|
var globalStore;
|
|
128
128
|
var globalValue = (id, compute) => {
|
|
@@ -136,7 +136,7 @@ var globalValue = (id, compute) => {
|
|
|
136
136
|
return globalStore.get(id);
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
-
// node_modules/.pnpm/effect@3.19.
|
|
139
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Predicate.js
|
|
140
140
|
var isString = (input) => typeof input === "string";
|
|
141
141
|
var isNumber = (input) => typeof input === "number";
|
|
142
142
|
var isBoolean = (input) => typeof input === "boolean";
|
|
@@ -146,7 +146,7 @@ var isObject = (input) => isRecordOrArray(input) || isFunction2(input);
|
|
|
146
146
|
var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObject(self) && property in self);
|
|
147
147
|
var isRecord = (input) => isRecordOrArray(input) && !Array.isArray(input);
|
|
148
148
|
|
|
149
|
-
// node_modules/.pnpm/effect@3.19.
|
|
149
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Utils.js
|
|
150
150
|
var GenKindTypeId = /* @__PURE__ */ Symbol.for("effect/Gen/GenKind");
|
|
151
151
|
var GenKindImpl = class {
|
|
152
152
|
value;
|
|
@@ -268,7 +268,7 @@ var internalCall = isNotOptimizedAway ? standard.effect_internal_function : forc
|
|
|
268
268
|
var genConstructor = function* () {
|
|
269
269
|
}.constructor;
|
|
270
270
|
|
|
271
|
-
// node_modules/.pnpm/effect@3.19.
|
|
271
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Hash.js
|
|
272
272
|
var randomHashCache = /* @__PURE__ */ globalValue(/* @__PURE__ */ Symbol.for("effect/Hash/randomHashCache"), () => /* @__PURE__ */ new WeakMap());
|
|
273
273
|
var symbol = /* @__PURE__ */ Symbol.for("effect/Hash");
|
|
274
274
|
var hash = (self) => {
|
|
@@ -293,6 +293,9 @@ var hash = (self) => {
|
|
|
293
293
|
if (self === null) {
|
|
294
294
|
return string("null");
|
|
295
295
|
} else if (self instanceof Date) {
|
|
296
|
+
if (Number.isNaN(self.getTime())) {
|
|
297
|
+
return string("Invalid Date");
|
|
298
|
+
}
|
|
296
299
|
return hash(self.toISOString());
|
|
297
300
|
} else if (self instanceof URL) {
|
|
298
301
|
return hash(self.href);
|
|
@@ -367,7 +370,7 @@ var cached = function() {
|
|
|
367
370
|
return hash2;
|
|
368
371
|
};
|
|
369
372
|
|
|
370
|
-
// node_modules/.pnpm/effect@3.19.
|
|
373
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Equal.js
|
|
371
374
|
var symbol2 = /* @__PURE__ */ Symbol.for("effect/Equal");
|
|
372
375
|
function equals() {
|
|
373
376
|
if (arguments.length === 1) {
|
|
@@ -392,7 +395,9 @@ function compareBoth(self, that) {
|
|
|
392
395
|
return structuralRegionState.enabled && structuralRegionState.tester ? structuralRegionState.tester(self, that) : false;
|
|
393
396
|
}
|
|
394
397
|
} else if (self instanceof Date && that instanceof Date) {
|
|
395
|
-
|
|
398
|
+
const t1 = self.getTime();
|
|
399
|
+
const t2 = that.getTime();
|
|
400
|
+
return t1 === t2 || Number.isNaN(t1) && Number.isNaN(t2);
|
|
396
401
|
} else if (self instanceof URL && that instanceof URL) {
|
|
397
402
|
return self.href === that.href;
|
|
398
403
|
}
|
|
@@ -421,7 +426,7 @@ function compareBoth(self, that) {
|
|
|
421
426
|
var isEqual = (u) => hasProperty(u, symbol2);
|
|
422
427
|
var equivalence = () => equals;
|
|
423
428
|
|
|
424
|
-
// node_modules/.pnpm/effect@3.19.
|
|
429
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Inspectable.js
|
|
425
430
|
var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
426
431
|
var toJSON = (x) => {
|
|
427
432
|
try {
|
|
@@ -473,7 +478,7 @@ var redact = (u) => {
|
|
|
473
478
|
return u;
|
|
474
479
|
};
|
|
475
480
|
|
|
476
|
-
// node_modules/.pnpm/effect@3.19.
|
|
481
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Pipeable.js
|
|
477
482
|
var pipeArguments = (self, args2) => {
|
|
478
483
|
switch (args2.length) {
|
|
479
484
|
case 0:
|
|
@@ -506,14 +511,14 @@ var pipeArguments = (self, args2) => {
|
|
|
506
511
|
}
|
|
507
512
|
};
|
|
508
513
|
|
|
509
|
-
// node_modules/.pnpm/effect@3.19.
|
|
514
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/opCodes/effect.js
|
|
510
515
|
var OP_COMMIT = "Commit";
|
|
511
516
|
|
|
512
|
-
// node_modules/.pnpm/effect@3.19.
|
|
513
|
-
var moduleVersion = "3.19.
|
|
517
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/version.js
|
|
518
|
+
var moduleVersion = "3.19.13";
|
|
514
519
|
var getCurrentVersion = () => moduleVersion;
|
|
515
520
|
|
|
516
|
-
// node_modules/.pnpm/effect@3.19.
|
|
521
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/effectable.js
|
|
517
522
|
var EffectTypeId = /* @__PURE__ */ Symbol.for("effect/Effect");
|
|
518
523
|
var StreamTypeId = /* @__PURE__ */ Symbol.for("effect/Stream");
|
|
519
524
|
var SinkTypeId = /* @__PURE__ */ Symbol.for("effect/Sink");
|
|
@@ -600,7 +605,7 @@ var StructuralCommitPrototype = {
|
|
|
600
605
|
...StructuralPrototype
|
|
601
606
|
};
|
|
602
607
|
|
|
603
|
-
// node_modules/.pnpm/effect@3.19.
|
|
608
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/option.js
|
|
604
609
|
var TypeId = /* @__PURE__ */ Symbol.for("effect/Option");
|
|
605
610
|
var CommonProto = {
|
|
606
611
|
...EffectPrototype,
|
|
@@ -658,7 +663,7 @@ var some = (value) => {
|
|
|
658
663
|
return a;
|
|
659
664
|
};
|
|
660
665
|
|
|
661
|
-
// node_modules/.pnpm/effect@3.19.
|
|
666
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/either.js
|
|
662
667
|
var TypeId2 = /* @__PURE__ */ Symbol.for("effect/Either");
|
|
663
668
|
var CommonProto2 = {
|
|
664
669
|
...EffectPrototype,
|
|
@@ -720,7 +725,7 @@ var right = (right3) => {
|
|
|
720
725
|
return a;
|
|
721
726
|
};
|
|
722
727
|
|
|
723
|
-
// node_modules/.pnpm/effect@3.19.
|
|
728
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Either.js
|
|
724
729
|
var right2 = right;
|
|
725
730
|
var left2 = left;
|
|
726
731
|
var isLeft2 = isLeft;
|
|
@@ -728,14 +733,14 @@ var isRight2 = isRight;
|
|
|
728
733
|
var map = /* @__PURE__ */ dual(2, (self, f) => isRight2(self) ? right2(f(self.right)) : left2(self.left));
|
|
729
734
|
var getOrElse = /* @__PURE__ */ dual(2, (self, onLeft) => isLeft2(self) ? onLeft(self.left) : self.right);
|
|
730
735
|
|
|
731
|
-
// node_modules/.pnpm/effect@3.19.
|
|
736
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/array.js
|
|
732
737
|
var isNonEmptyArray = (self) => self.length > 0;
|
|
733
738
|
|
|
734
|
-
// node_modules/.pnpm/effect@3.19.
|
|
739
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Order.js
|
|
735
740
|
var make = (compare) => (self, that) => self === that ? 0 : compare(self, that);
|
|
736
741
|
var string2 = /* @__PURE__ */ make((self, that) => self < that ? -1 : 1);
|
|
737
742
|
|
|
738
|
-
// node_modules/.pnpm/effect@3.19.
|
|
743
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Option.js
|
|
739
744
|
var none2 = () => none;
|
|
740
745
|
var some2 = some;
|
|
741
746
|
var isNone2 = isNone;
|
|
@@ -745,7 +750,7 @@ var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : se
|
|
|
745
750
|
var fromNullable = (nullableValue) => nullableValue == null ? none2() : some2(nullableValue);
|
|
746
751
|
var getOrUndefined = /* @__PURE__ */ getOrElse2(constUndefined);
|
|
747
752
|
|
|
748
|
-
// node_modules/.pnpm/effect@3.19.
|
|
753
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Record.js
|
|
749
754
|
var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
750
755
|
const out = {
|
|
751
756
|
...self
|
|
@@ -757,7 +762,7 @@ var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
757
762
|
});
|
|
758
763
|
var keys = (self) => Object.keys(self);
|
|
759
764
|
|
|
760
|
-
// node_modules/.pnpm/effect@3.19.
|
|
765
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Array.js
|
|
761
766
|
var fromIterable = (collection) => Array.isArray(collection) ? collection : Array.from(collection);
|
|
762
767
|
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
763
768
|
var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable(self).concat(fromIterable(that)));
|
|
@@ -797,7 +802,10 @@ var containsWith = (isEquivalent) => dual(2, (self, a) => {
|
|
|
797
802
|
var _equivalence = /* @__PURE__ */ equivalence();
|
|
798
803
|
var intersectionWith = (isEquivalent) => {
|
|
799
804
|
const has = containsWith(isEquivalent);
|
|
800
|
-
return dual(2, (self, that) =>
|
|
805
|
+
return dual(2, (self, that) => {
|
|
806
|
+
const bs = fromIterable(that);
|
|
807
|
+
return fromIterable(self).filter((a) => has(bs, a));
|
|
808
|
+
});
|
|
801
809
|
};
|
|
802
810
|
var intersection = /* @__PURE__ */ intersectionWith(_equivalence);
|
|
803
811
|
var empty = () => [];
|
|
@@ -875,12 +883,12 @@ var SingleShotGen2 = class _SingleShotGen {
|
|
|
875
883
|
return new _SingleShotGen(this.self);
|
|
876
884
|
}
|
|
877
885
|
};
|
|
878
|
-
var evaluate = Symbol.for("Nano.evaluate");
|
|
879
|
-
var contA = Symbol.for("Nano.contA");
|
|
880
|
-
var contE = Symbol.for("Nano.contE");
|
|
881
|
-
var contAll = Symbol.for("Nano.contAll");
|
|
882
|
-
var NanoYield = Symbol.for("Nano.yield");
|
|
883
|
-
var args = Symbol.for("Nano.args");
|
|
886
|
+
var evaluate = /* @__PURE__ */ Symbol.for("Nano.evaluate");
|
|
887
|
+
var contA = /* @__PURE__ */ Symbol.for("Nano.contA");
|
|
888
|
+
var contE = /* @__PURE__ */ Symbol.for("Nano.contE");
|
|
889
|
+
var contAll = /* @__PURE__ */ Symbol.for("Nano.contAll");
|
|
890
|
+
var NanoYield = /* @__PURE__ */ Symbol.for("Nano.yield");
|
|
891
|
+
var args = /* @__PURE__ */ Symbol.for("Nano.args");
|
|
884
892
|
var NanoDefectException = class {
|
|
885
893
|
constructor(message, lastSpan) {
|
|
886
894
|
this.message = message;
|
|
@@ -1687,7 +1695,9 @@ function makeTypeScriptUtils(ts) {
|
|
|
1687
1695
|
} else {
|
|
1688
1696
|
return;
|
|
1689
1697
|
}
|
|
1690
|
-
|
|
1698
|
+
const importDeclaration = ts.findAncestor(accessedObject, ts.isImportDeclaration);
|
|
1699
|
+
if (importDeclaration) return;
|
|
1700
|
+
return { accessedObject, outerNode, replacementSpan, insideImportDeclaration: !!importDeclaration };
|
|
1691
1701
|
}
|
|
1692
1702
|
function parseDataForExtendsClassCompletion(sourceFile, position) {
|
|
1693
1703
|
const maybeInfos = parseAccessedExpressionForCompletion(sourceFile, position);
|
|
@@ -2191,6 +2201,8 @@ var nanoLayer2 = (fa) => pipe(
|
|
|
2191
2201
|
function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
2192
2202
|
const readonlyArraySymbol = typeChecker.resolveName("ReadonlyArray", void 0, ts.SymbolFlags.Type, false);
|
|
2193
2203
|
const globalReadonlyArrayType = readonlyArraySymbol ? typeChecker.getDeclaredTypeOfSymbol(readonlyArraySymbol) : void 0;
|
|
2204
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
2205
|
+
const globalErrorType = errorSymbol ? typeChecker.getDeclaredTypeOfSymbol(errorSymbol) : void 0;
|
|
2194
2206
|
function isUnion(type) {
|
|
2195
2207
|
return !!(type.flags & ts.TypeFlags.Union);
|
|
2196
2208
|
}
|
|
@@ -2439,6 +2451,10 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2439
2451
|
function typeToSimplifiedTypeNode(type, enclosingNode, flags) {
|
|
2440
2452
|
return typeToSimplifiedTypeNodeWorker(type, enclosingNode, flags, 0);
|
|
2441
2453
|
}
|
|
2454
|
+
function isGlobalErrorType(type) {
|
|
2455
|
+
if (!globalErrorType) return false;
|
|
2456
|
+
return typeChecker.isTypeAssignableTo(type, globalErrorType) && typeChecker.isTypeAssignableTo(globalErrorType, type);
|
|
2457
|
+
}
|
|
2442
2458
|
function typeToSimplifiedTypeNodeWorker(type, enclosingNode, flags, depth) {
|
|
2443
2459
|
const fallbackStandard = () => {
|
|
2444
2460
|
const typeNode = typeChecker.typeToTypeNode(type, enclosingNode, flags);
|
|
@@ -2508,6 +2524,15 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2508
2524
|
}
|
|
2509
2525
|
return fallbackStandard();
|
|
2510
2526
|
}
|
|
2527
|
+
function getTypeAtLocation(node) {
|
|
2528
|
+
if (node.parent && ts.isJsxSelfClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
2529
|
+
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
2530
|
+
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
2531
|
+
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
2532
|
+
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
2533
|
+
return typeChecker.getTypeAtLocation(node);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2511
2536
|
return {
|
|
2512
2537
|
isUnion,
|
|
2513
2538
|
isReadonlyArrayType,
|
|
@@ -2519,7 +2544,9 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2519
2544
|
deterministicTypeOrder,
|
|
2520
2545
|
getInferredReturnType,
|
|
2521
2546
|
expectedAndRealType,
|
|
2522
|
-
typeToSimplifiedTypeNode
|
|
2547
|
+
typeToSimplifiedTypeNode,
|
|
2548
|
+
isGlobalErrorType,
|
|
2549
|
+
getTypeAtLocation
|
|
2523
2550
|
};
|
|
2524
2551
|
}
|
|
2525
2552
|
|
|
@@ -2641,7 +2668,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2641
2668
|
return isSymbolExportOfPackageModule(symbol3, packageName, memberName, isCorrectSourceFile);
|
|
2642
2669
|
};
|
|
2643
2670
|
const findSymbolsMatchingPackageAndExportedName = (packageName, exportedSymbolName) => cachedBy(
|
|
2644
|
-
fn("TypeParser.findSymbolsMatchingPackageAndExportedName")(function* (
|
|
2671
|
+
fn("TypeParser.findSymbolsMatchingPackageAndExportedName")(function* () {
|
|
2645
2672
|
const result = [];
|
|
2646
2673
|
for (const sourceFile of program.getSourceFiles()) {
|
|
2647
2674
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -2655,7 +2682,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2655
2682
|
return result;
|
|
2656
2683
|
}),
|
|
2657
2684
|
`TypeParser.findSymbolsMatchingPackageAndExportedName(${packageName}, ${exportedSymbolName})`,
|
|
2658
|
-
(
|
|
2685
|
+
() => program
|
|
2659
2686
|
);
|
|
2660
2687
|
const isCauseTypeSourceFile = cachedBy(
|
|
2661
2688
|
fn("TypeParser.isCauseTypeSourceFile")(function* (sourceFile) {
|
|
@@ -2670,20 +2697,22 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2670
2697
|
"TypeParser.isCauseTypeSourceFile",
|
|
2671
2698
|
(sourceFile) => sourceFile
|
|
2672
2699
|
);
|
|
2673
|
-
const
|
|
2674
|
-
fn("TypeParser.
|
|
2675
|
-
const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")(
|
|
2676
|
-
const result = [];
|
|
2700
|
+
const extendsCauseYieldableError = cachedBy(
|
|
2701
|
+
fn("TypeParser.extendsCauseYieldableError")(function* (givenType) {
|
|
2702
|
+
const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")();
|
|
2677
2703
|
for (const [symbol3, sourceFile] of symbols) {
|
|
2678
|
-
const causeFile = yield* isCauseTypeSourceFile(sourceFile);
|
|
2704
|
+
const causeFile = yield* pipe(isCauseTypeSourceFile(sourceFile), orElse2(() => void_));
|
|
2679
2705
|
if (!causeFile) continue;
|
|
2680
2706
|
const type = typeChecker.getDeclaredTypeOfSymbol(symbol3);
|
|
2681
|
-
|
|
2707
|
+
if (!type) continue;
|
|
2708
|
+
if (typeChecker.isTypeAssignableTo(givenType, type)) {
|
|
2709
|
+
return type;
|
|
2710
|
+
}
|
|
2682
2711
|
}
|
|
2683
|
-
return
|
|
2712
|
+
return yield* typeParserIssue("Type does not extend Cause.YieldableError", givenType);
|
|
2684
2713
|
}),
|
|
2685
|
-
"TypeParser.
|
|
2686
|
-
(
|
|
2714
|
+
"TypeParser.extendsCauseYieldableError",
|
|
2715
|
+
(type) => type
|
|
2687
2716
|
);
|
|
2688
2717
|
function covariantTypeArgument(type) {
|
|
2689
2718
|
const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
|
|
@@ -3073,7 +3102,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3073
3102
|
}
|
|
3074
3103
|
if (ts.isYieldExpression(nodeToCheck) && nodeToCheck.asteriskToken && nodeToCheck.expression) {
|
|
3075
3104
|
const yieldedExpression = nodeToCheck.expression;
|
|
3076
|
-
const type =
|
|
3105
|
+
const type = typeCheckerUtils.getTypeAtLocation(yieldedExpression);
|
|
3106
|
+
if (!type) continue;
|
|
3077
3107
|
const { A: successType } = yield* effectType(type, yieldedExpression);
|
|
3078
3108
|
let replacementNode = succeed(yieldedExpression);
|
|
3079
3109
|
if (!explicitReturn && !(successType.flags & ts.TypeFlags.VoidLike)) {
|
|
@@ -3664,11 +3694,79 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3664
3694
|
"TypeParser.extendsEffectService",
|
|
3665
3695
|
(atLocation) => atLocation
|
|
3666
3696
|
);
|
|
3697
|
+
const isEffectSqlModelTypeSourceFile = cachedBy(
|
|
3698
|
+
fn("TypeParser.isEffectSqlModelTypeSourceFile")(function* (sourceFile) {
|
|
3699
|
+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
3700
|
+
if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
|
|
3701
|
+
const classSymbol = typeChecker.tryGetMemberInModuleExports("Class", moduleSymbol);
|
|
3702
|
+
if (!classSymbol) return yield* typeParserIssue("Model's Class type not found", void 0, sourceFile);
|
|
3703
|
+
const makeRepositorySymbol = typeChecker.tryGetMemberInModuleExports("makeRepository", moduleSymbol);
|
|
3704
|
+
if (!makeRepositorySymbol) {
|
|
3705
|
+
return yield* typeParserIssue("Model's makeRepository type not found", void 0, sourceFile);
|
|
3706
|
+
}
|
|
3707
|
+
const makeDataLoadersSymbol = typeChecker.tryGetMemberInModuleExports("makeDataLoaders", moduleSymbol);
|
|
3708
|
+
if (!makeDataLoadersSymbol) {
|
|
3709
|
+
return yield* typeParserIssue("Model's makeDataLoaders type not found", void 0, sourceFile);
|
|
3710
|
+
}
|
|
3711
|
+
return sourceFile;
|
|
3712
|
+
}),
|
|
3713
|
+
"TypeParser.isEffectSqlModelTypeSourceFile",
|
|
3714
|
+
(sourceFile) => sourceFile
|
|
3715
|
+
);
|
|
3716
|
+
const isNodeReferenceToEffectSqlModelModuleApi = (memberName) => cachedBy(
|
|
3717
|
+
fn("TypeParser.isNodeReferenceToEffectSqlModelModuleApi")(function* (node) {
|
|
3718
|
+
return yield* isNodeReferenceToExportOfPackageModule(
|
|
3719
|
+
node,
|
|
3720
|
+
"@effect/sql",
|
|
3721
|
+
isEffectSqlModelTypeSourceFile,
|
|
3722
|
+
memberName
|
|
3723
|
+
);
|
|
3724
|
+
}),
|
|
3725
|
+
`TypeParser.isNodeReferenceToEffectSqlModelModuleApi(${memberName})`,
|
|
3726
|
+
(node) => node
|
|
3727
|
+
);
|
|
3728
|
+
const extendsEffectSqlModelClass = cachedBy(
|
|
3729
|
+
fn("TypeParser.extendsEffectSqlModelClass")(function* (atLocation) {
|
|
3730
|
+
if (!atLocation.name) {
|
|
3731
|
+
return yield* typeParserIssue("Class has no name", void 0, atLocation);
|
|
3732
|
+
}
|
|
3733
|
+
const heritageClauses = atLocation.heritageClauses;
|
|
3734
|
+
if (!heritageClauses) {
|
|
3735
|
+
return yield* typeParserIssue("Class has no heritage clauses", void 0, atLocation);
|
|
3736
|
+
}
|
|
3737
|
+
for (const heritageClause of heritageClauses) {
|
|
3738
|
+
for (const typeX of heritageClause.types) {
|
|
3739
|
+
if (ts.isExpressionWithTypeArguments(typeX)) {
|
|
3740
|
+
const expression = typeX.expression;
|
|
3741
|
+
if (ts.isCallExpression(expression)) {
|
|
3742
|
+
const schemaCall = expression.expression;
|
|
3743
|
+
if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
|
|
3744
|
+
const isEffectSchemaModuleApi = yield* pipe(
|
|
3745
|
+
isNodeReferenceToEffectSqlModelModuleApi("Class")(schemaCall.expression),
|
|
3746
|
+
option
|
|
3747
|
+
);
|
|
3748
|
+
if (isSome2(isEffectSchemaModuleApi)) {
|
|
3749
|
+
return {
|
|
3750
|
+
className: atLocation.name,
|
|
3751
|
+
selfTypeNode: schemaCall.typeArguments[0]
|
|
3752
|
+
};
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
return yield* typeParserIssue("Class does not extend @effect/sql's Model.Class", void 0, atLocation);
|
|
3760
|
+
}),
|
|
3761
|
+
"TypeParser.extendsEffectSqlModelClass",
|
|
3762
|
+
(atLocation) => atLocation
|
|
3763
|
+
);
|
|
3667
3764
|
return {
|
|
3668
3765
|
isNodeReferenceToEffectModuleApi,
|
|
3669
3766
|
isNodeReferenceToEffectSchemaModuleApi,
|
|
3670
3767
|
isNodeReferenceToEffectDataModuleApi,
|
|
3671
3768
|
isNodeReferenceToEffectContextModuleApi,
|
|
3769
|
+
isNodeReferenceToEffectSqlModelModuleApi,
|
|
3672
3770
|
effectType,
|
|
3673
3771
|
strictEffectType,
|
|
3674
3772
|
layerType,
|
|
@@ -3678,7 +3776,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3678
3776
|
effectGen,
|
|
3679
3777
|
effectFnUntracedGen,
|
|
3680
3778
|
effectFnGen,
|
|
3681
|
-
|
|
3779
|
+
extendsCauseYieldableError,
|
|
3682
3780
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
3683
3781
|
effectSchemaType,
|
|
3684
3782
|
contextTag,
|
|
@@ -3694,7 +3792,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3694
3792
|
extendsSchemaTaggedError,
|
|
3695
3793
|
extendsDataTaggedError,
|
|
3696
3794
|
extendsDataTaggedClass,
|
|
3697
|
-
extendsSchemaTaggedRequest
|
|
3795
|
+
extendsSchemaTaggedRequest,
|
|
3796
|
+
extendsEffectSqlModelClass
|
|
3698
3797
|
};
|
|
3699
3798
|
}
|
|
3700
3799
|
|
|
@@ -3702,10 +3801,12 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3702
3801
|
var anyUnknownInErrorContext = createDiagnostic({
|
|
3703
3802
|
name: "anyUnknownInErrorContext",
|
|
3704
3803
|
code: 28,
|
|
3804
|
+
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
3705
3805
|
severity: "off",
|
|
3706
3806
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
3707
3807
|
const ts = yield* service(TypeScriptApi);
|
|
3708
3808
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3809
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
3709
3810
|
const typeParser = yield* service(TypeParser);
|
|
3710
3811
|
const isAnyOrUnknown = (type) => (type.flags & ts.TypeFlags.Any) > 0 || (type.flags & ts.TypeFlags.Unknown) > 0;
|
|
3711
3812
|
const matchingNodes = [];
|
|
@@ -3725,7 +3826,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
3725
3826
|
if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
|
|
3726
3827
|
if (node.type) {
|
|
3727
3828
|
const typeNode = node.type;
|
|
3728
|
-
const type2 =
|
|
3829
|
+
const type2 = typeCheckerUtils.getTypeAtLocation(node.type);
|
|
3830
|
+
if (!type2) continue;
|
|
3729
3831
|
const expectedEffect = yield* pipe(
|
|
3730
3832
|
typeParser.strictEffectType(type2, node.type),
|
|
3731
3833
|
orElse2(() => typeParser.layerType(type2, typeNode)),
|
|
@@ -3736,11 +3838,7 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
3736
3838
|
}
|
|
3737
3839
|
ts.forEachChild(node, appendNodeToVisit);
|
|
3738
3840
|
if (!ts.isExpression(node)) continue;
|
|
3739
|
-
|
|
3740
|
-
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) continue;
|
|
3741
|
-
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) continue;
|
|
3742
|
-
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) continue;
|
|
3743
|
-
let type = typeChecker.getTypeAtLocation(node);
|
|
3841
|
+
let type = typeCheckerUtils.getTypeAtLocation(node);
|
|
3744
3842
|
if (ts.isCallExpression(node)) {
|
|
3745
3843
|
const resolvedSignature = typeChecker.getResolvedSignature(node);
|
|
3746
3844
|
if (resolvedSignature) {
|
|
@@ -3806,11 +3904,13 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
3806
3904
|
var catchUnfailableEffect = createDiagnostic({
|
|
3807
3905
|
name: "catchUnfailableEffect",
|
|
3808
3906
|
code: 2,
|
|
3907
|
+
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
3809
3908
|
severity: "suggestion",
|
|
3810
3909
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
3811
3910
|
const ts = yield* service(TypeScriptApi);
|
|
3812
3911
|
const typeParser = yield* service(TypeParser);
|
|
3813
3912
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3913
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
3814
3914
|
const nodeToVisit = [];
|
|
3815
3915
|
const appendNodeToVisit = (node) => {
|
|
3816
3916
|
nodeToVisit.push(node);
|
|
@@ -3841,7 +3941,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
3841
3941
|
if (argIndex !== -1) {
|
|
3842
3942
|
let effectTypeToCheck;
|
|
3843
3943
|
if (argIndex === 0) {
|
|
3844
|
-
effectTypeToCheck =
|
|
3944
|
+
effectTypeToCheck = typeCheckerUtils.getTypeAtLocation(subject);
|
|
3845
3945
|
} else {
|
|
3846
3946
|
const signature = typeChecker.getResolvedSignature(pipeCallNode);
|
|
3847
3947
|
if (signature) {
|
|
@@ -3880,6 +3980,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
3880
3980
|
var classSelfMismatch = createDiagnostic({
|
|
3881
3981
|
name: "classSelfMismatch",
|
|
3882
3982
|
code: 20,
|
|
3983
|
+
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
3883
3984
|
severity: "error",
|
|
3884
3985
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
3885
3986
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -3901,6 +4002,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
3901
4002
|
orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
|
|
3902
4003
|
orElse2(() => typeParser.extendsSchemaTaggedError(node)),
|
|
3903
4004
|
orElse2(() => typeParser.extendsSchemaTaggedRequest(node)),
|
|
4005
|
+
orElse2(() => typeParser.extendsEffectSqlModelClass(node)),
|
|
3904
4006
|
orElse2(() => void_)
|
|
3905
4007
|
);
|
|
3906
4008
|
if (result) {
|
|
@@ -4010,6 +4112,7 @@ function createString(sourceFile, identifier, kind) {
|
|
|
4010
4112
|
var deterministicKeys = createDiagnostic({
|
|
4011
4113
|
name: "deterministicKeys",
|
|
4012
4114
|
code: 25,
|
|
4115
|
+
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
4013
4116
|
severity: "off",
|
|
4014
4117
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
4015
4118
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4130,6 +4233,7 @@ var programResolvedCacheSize = /* @__PURE__ */ new Map();
|
|
|
4130
4233
|
var duplicatePackage = createDiagnostic({
|
|
4131
4234
|
name: "duplicatePackage",
|
|
4132
4235
|
code: 6,
|
|
4236
|
+
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
4133
4237
|
severity: "warning",
|
|
4134
4238
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
4135
4239
|
const program = yield* service(TypeScriptProgram);
|
|
@@ -4177,6 +4281,7 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
4177
4281
|
var effectGenUsesAdapter = createDiagnostic({
|
|
4178
4282
|
name: "effectGenUsesAdapter",
|
|
4179
4283
|
code: 23,
|
|
4284
|
+
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
4180
4285
|
severity: "warning",
|
|
4181
4286
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
4182
4287
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4214,6 +4319,7 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
4214
4319
|
var effectInVoidSuccess = createDiagnostic({
|
|
4215
4320
|
name: "effectInVoidSuccess",
|
|
4216
4321
|
code: 14,
|
|
4322
|
+
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
4217
4323
|
severity: "warning",
|
|
4218
4324
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
4219
4325
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4262,10 +4368,12 @@ var effectInVoidSuccess = createDiagnostic({
|
|
|
4262
4368
|
var floatingEffect = createDiagnostic({
|
|
4263
4369
|
name: "floatingEffect",
|
|
4264
4370
|
code: 3,
|
|
4371
|
+
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
4265
4372
|
severity: "error",
|
|
4266
4373
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
4267
4374
|
const ts = yield* service(TypeScriptApi);
|
|
4268
4375
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
4376
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4269
4377
|
const typeParser = yield* service(TypeParser);
|
|
4270
4378
|
function isFloatingExpression(node) {
|
|
4271
4379
|
if (!ts.isExpressionStatement(node)) return false;
|
|
@@ -4284,7 +4392,8 @@ var floatingEffect = createDiagnostic({
|
|
|
4284
4392
|
const node = nodeToVisit.shift();
|
|
4285
4393
|
ts.forEachChild(node, appendNodeToVisit);
|
|
4286
4394
|
if (!isFloatingExpression(node)) continue;
|
|
4287
|
-
const type =
|
|
4395
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
4396
|
+
if (!type) continue;
|
|
4288
4397
|
const effect = yield* option(typeParser.effectType(type, node.expression));
|
|
4289
4398
|
if (isSome2(effect)) {
|
|
4290
4399
|
const allowedFloatingEffects = yield* pipe(
|
|
@@ -4310,6 +4419,7 @@ var floatingEffect = createDiagnostic({
|
|
|
4310
4419
|
var genericEffectServices = createDiagnostic({
|
|
4311
4420
|
name: "genericEffectServices",
|
|
4312
4421
|
code: 10,
|
|
4422
|
+
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
4313
4423
|
severity: "warning",
|
|
4314
4424
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
4315
4425
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4352,10 +4462,56 @@ var genericEffectServices = createDiagnostic({
|
|
|
4352
4462
|
})
|
|
4353
4463
|
});
|
|
4354
4464
|
|
|
4465
|
+
// src/diagnostics/globalErrorInEffectFailure.ts
|
|
4466
|
+
var globalErrorInEffectFailure = createDiagnostic({
|
|
4467
|
+
name: "globalErrorInEffectFailure",
|
|
4468
|
+
code: 35,
|
|
4469
|
+
description: "Warns when Effect.fail is called with the global Error type",
|
|
4470
|
+
severity: "warning",
|
|
4471
|
+
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
4472
|
+
const ts = yield* service(TypeScriptApi);
|
|
4473
|
+
const typeParser = yield* service(TypeParser);
|
|
4474
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4475
|
+
const nodeToVisit = [];
|
|
4476
|
+
const appendNodeToVisit = (node) => {
|
|
4477
|
+
nodeToVisit.push(node);
|
|
4478
|
+
return void 0;
|
|
4479
|
+
};
|
|
4480
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
4481
|
+
while (nodeToVisit.length > 0) {
|
|
4482
|
+
const node = nodeToVisit.shift();
|
|
4483
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
4484
|
+
if (ts.isCallExpression(node)) {
|
|
4485
|
+
yield* pipe(
|
|
4486
|
+
typeParser.isNodeReferenceToEffectModuleApi("fail")(node.expression),
|
|
4487
|
+
flatMap2(() => {
|
|
4488
|
+
if (node.arguments.length > 0) {
|
|
4489
|
+
const failArgument = node.arguments[0];
|
|
4490
|
+
const argumentType = typeCheckerUtils.getTypeAtLocation(failArgument);
|
|
4491
|
+
if (argumentType && typeCheckerUtils.isGlobalErrorType(argumentType)) {
|
|
4492
|
+
return sync(
|
|
4493
|
+
() => report({
|
|
4494
|
+
location: node,
|
|
4495
|
+
messageText: `Effect.fail is called with the global Error type. It's not recommended to use the global Error type in Effect failures as they can get merged together. Instead, use tagged errors (Data.TaggedError) or custom errors with a discriminator property to get properly type-checked errors.`,
|
|
4496
|
+
fixes: []
|
|
4497
|
+
})
|
|
4498
|
+
);
|
|
4499
|
+
}
|
|
4500
|
+
}
|
|
4501
|
+
return void_;
|
|
4502
|
+
}),
|
|
4503
|
+
ignore
|
|
4504
|
+
);
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
})
|
|
4508
|
+
});
|
|
4509
|
+
|
|
4355
4510
|
// src/diagnostics/importFromBarrel.ts
|
|
4356
4511
|
var importFromBarrel = createDiagnostic({
|
|
4357
4512
|
name: "importFromBarrel",
|
|
4358
4513
|
code: 12,
|
|
4514
|
+
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
4359
4515
|
severity: "off",
|
|
4360
4516
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
4361
4517
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
@@ -4495,6 +4651,7 @@ var importFromBarrel = createDiagnostic({
|
|
|
4495
4651
|
var leakingRequirements = createDiagnostic({
|
|
4496
4652
|
name: "leakingRequirements",
|
|
4497
4653
|
code: 8,
|
|
4654
|
+
description: "Detects implementation services leaked in service methods",
|
|
4498
4655
|
severity: "suggestion",
|
|
4499
4656
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
4500
4657
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4602,7 +4759,8 @@ More info at https://effect.website/docs/requirements-management/layers/#avoidin
|
|
|
4602
4759
|
const node = nodeToVisit.shift();
|
|
4603
4760
|
const typesToCheck = [];
|
|
4604
4761
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && ts.idText(node.expression.name) === "GenericTag") {
|
|
4605
|
-
|
|
4762
|
+
const nodeType = typeCheckerUtils.getTypeAtLocation(node);
|
|
4763
|
+
if (nodeType) typesToCheck.push([nodeType, node]);
|
|
4606
4764
|
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
4607
4765
|
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
4608
4766
|
if (classSym) {
|
|
@@ -4636,10 +4794,12 @@ More info at https://effect.website/docs/requirements-management/layers/#avoidin
|
|
|
4636
4794
|
var missedPipeableOpportunity = createDiagnostic({
|
|
4637
4795
|
name: "missedPipeableOpportunity",
|
|
4638
4796
|
code: 26,
|
|
4797
|
+
description: "Enforces the use of pipeable style for nested function calls",
|
|
4639
4798
|
severity: "off",
|
|
4640
4799
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
4641
4800
|
const ts = yield* service(TypeScriptApi);
|
|
4642
4801
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
4802
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4643
4803
|
const typeParser = yield* service(TypeParser);
|
|
4644
4804
|
const options = yield* service(LanguageServicePluginOptions);
|
|
4645
4805
|
const nodeToVisit = [sourceFile];
|
|
@@ -4670,7 +4830,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
4670
4830
|
const originalParentChain = parentChain.slice();
|
|
4671
4831
|
while (parentChain.length > options.pipeableMinArgCount) {
|
|
4672
4832
|
const subject = parentChain.pop();
|
|
4673
|
-
const resultType =
|
|
4833
|
+
const resultType = typeCheckerUtils.getTypeAtLocation(subject);
|
|
4834
|
+
if (!resultType) continue;
|
|
4674
4835
|
const pipeableType = yield* pipe(typeParser.pipeableType(resultType, subject), orElse2(() => void_));
|
|
4675
4836
|
if (pipeableType) {
|
|
4676
4837
|
report({
|
|
@@ -4715,6 +4876,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
4715
4876
|
var missingEffectContext = createDiagnostic({
|
|
4716
4877
|
name: "missingEffectContext",
|
|
4717
4878
|
code: 1,
|
|
4879
|
+
description: "Reports missing service requirements in Effect context channel",
|
|
4718
4880
|
severity: "error",
|
|
4719
4881
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
4720
4882
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -4763,6 +4925,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
4763
4925
|
var missingEffectError = createDiagnostic({
|
|
4764
4926
|
name: "missingEffectError",
|
|
4765
4927
|
code: 1,
|
|
4928
|
+
description: "Reports missing error types in Effect error channel",
|
|
4766
4929
|
severity: "error",
|
|
4767
4930
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
4768
4931
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4902,6 +5065,7 @@ var missingEffectError = createDiagnostic({
|
|
|
4902
5065
|
var missingEffectServiceDependency = createDiagnostic({
|
|
4903
5066
|
name: "missingEffectServiceDependency",
|
|
4904
5067
|
code: 22,
|
|
5068
|
+
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
4905
5069
|
severity: "off",
|
|
4906
5070
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
4907
5071
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4943,13 +5107,15 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
4943
5107
|
excludeNever
|
|
4944
5108
|
);
|
|
4945
5109
|
const providedIndexes = /* @__PURE__ */ new Set();
|
|
4946
|
-
const optionsType = typeChecker.getTypeAtLocation(options);
|
|
4947
|
-
const dependenciesProperty = typeChecker.getPropertyOfType(optionsType, "dependencies");
|
|
4948
5110
|
let types = [];
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
const
|
|
4952
|
-
|
|
5111
|
+
const optionsType = typeCheckerUtils.getTypeAtLocation(options);
|
|
5112
|
+
if (optionsType) {
|
|
5113
|
+
const dependenciesProperty = typeChecker.getPropertyOfType(optionsType, "dependencies");
|
|
5114
|
+
if (dependenciesProperty) {
|
|
5115
|
+
const dependenciesTypes = typeChecker.getTypeOfSymbolAtLocation(dependenciesProperty, options);
|
|
5116
|
+
const numberIndexType = typeChecker.getIndexTypeOfType(dependenciesTypes, ts.IndexKind.Number);
|
|
5117
|
+
types = numberIndexType ? typeCheckerUtils.unrollUnionMembers(numberIndexType) : [];
|
|
5118
|
+
}
|
|
4953
5119
|
}
|
|
4954
5120
|
for (const depType of types) {
|
|
4955
5121
|
const depLayerResult = yield* pipe(
|
|
@@ -4992,10 +5158,11 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
4992
5158
|
var missingReturnYieldStar = createDiagnostic({
|
|
4993
5159
|
name: "missingReturnYieldStar",
|
|
4994
5160
|
code: 7,
|
|
5161
|
+
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
4995
5162
|
severity: "error",
|
|
4996
5163
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
4997
5164
|
const ts = yield* service(TypeScriptApi);
|
|
4998
|
-
const
|
|
5165
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4999
5166
|
const typeParser = yield* service(TypeParser);
|
|
5000
5167
|
const nodeToVisit = [];
|
|
5001
5168
|
const appendNodeToVisit = (node) => {
|
|
@@ -5007,42 +5174,44 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
5007
5174
|
const node = nodeToVisit.shift();
|
|
5008
5175
|
ts.forEachChild(node, appendNodeToVisit);
|
|
5009
5176
|
if (ts.isYieldExpression(node) && node.expression && node.asteriskToken) {
|
|
5010
|
-
const type =
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5177
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
5178
|
+
if (type) {
|
|
5179
|
+
const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
|
|
5180
|
+
if (isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never) {
|
|
5181
|
+
const generatorFunctionOrReturnStatement = ts.findAncestor(
|
|
5182
|
+
node,
|
|
5183
|
+
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isReturnStatement(_) || ts.isThrowStatement(_)
|
|
5184
|
+
);
|
|
5185
|
+
if (generatorFunctionOrReturnStatement && !ts.isReturnStatement(generatorFunctionOrReturnStatement) && !ts.isThrowStatement(generatorFunctionOrReturnStatement)) {
|
|
5186
|
+
if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.parent) {
|
|
5187
|
+
const effectGenNode = generatorFunctionOrReturnStatement.parent;
|
|
5188
|
+
const effectGenLike = yield* pipe(
|
|
5189
|
+
typeParser.effectGen(effectGenNode),
|
|
5190
|
+
orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
|
|
5191
|
+
orElse2(() => typeParser.effectFnGen(effectGenNode)),
|
|
5192
|
+
option
|
|
5193
|
+
);
|
|
5194
|
+
if (isSome2(effectGenLike)) {
|
|
5195
|
+
const fix = node.expression ? [{
|
|
5196
|
+
fixName: "missingReturnYieldStar_fix",
|
|
5197
|
+
description: "Add return statement",
|
|
5198
|
+
apply: gen(function* () {
|
|
5199
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5200
|
+
changeTracker.replaceNode(
|
|
5201
|
+
sourceFile,
|
|
5202
|
+
node,
|
|
5203
|
+
ts.factory.createReturnStatement(
|
|
5204
|
+
node
|
|
5205
|
+
)
|
|
5206
|
+
);
|
|
5207
|
+
})
|
|
5208
|
+
}] : [];
|
|
5209
|
+
report({
|
|
5210
|
+
location: node,
|
|
5211
|
+
messageText: `It is recommended to use return yield* for Effects that never succeed to signal a definitive exit point for type narrowing and tooling support.`,
|
|
5212
|
+
fixes: fix
|
|
5213
|
+
});
|
|
5214
|
+
}
|
|
5046
5215
|
}
|
|
5047
5216
|
}
|
|
5048
5217
|
}
|
|
@@ -5056,6 +5225,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
5056
5225
|
var missingStarInYieldEffectGen = createDiagnostic({
|
|
5057
5226
|
name: "missingStarInYieldEffectGen",
|
|
5058
5227
|
code: 4,
|
|
5228
|
+
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
5059
5229
|
severity: "error",
|
|
5060
5230
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
5061
5231
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -5130,11 +5300,12 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
5130
5300
|
var multipleEffectProvide = createDiagnostic({
|
|
5131
5301
|
name: "multipleEffectProvide",
|
|
5132
5302
|
code: 18,
|
|
5303
|
+
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
5133
5304
|
severity: "warning",
|
|
5134
5305
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
5135
5306
|
const ts = yield* service(TypeScriptApi);
|
|
5136
5307
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
5137
|
-
const
|
|
5308
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
5138
5309
|
const typeParser = yield* service(TypeParser);
|
|
5139
5310
|
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
5140
5311
|
sourceFile,
|
|
@@ -5149,7 +5320,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
5149
5320
|
const parseEffectProvideLayer = (node) => {
|
|
5150
5321
|
if (ts.isCallExpression(node) && node.arguments.length > 0) {
|
|
5151
5322
|
const layer = node.arguments[0];
|
|
5152
|
-
const type =
|
|
5323
|
+
const type = typeCheckerUtils.getTypeAtLocation(layer);
|
|
5324
|
+
if (!type) return void_;
|
|
5153
5325
|
return pipe(
|
|
5154
5326
|
typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression),
|
|
5155
5327
|
flatMap2(() => typeParser.layerType(type, layer)),
|
|
@@ -5227,6 +5399,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
5227
5399
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
5228
5400
|
name: "nonObjectEffectServiceType",
|
|
5229
5401
|
code: 24,
|
|
5402
|
+
description: "Ensures Effect.Service types are objects, not primitives",
|
|
5230
5403
|
severity: "error",
|
|
5231
5404
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
5232
5405
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -5265,12 +5438,13 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
5265
5438
|
fixes: []
|
|
5266
5439
|
};
|
|
5267
5440
|
if (propertyName === "succeed") {
|
|
5268
|
-
const valueType =
|
|
5269
|
-
if (isPrimitiveType(valueType)) {
|
|
5441
|
+
const valueType = typeCheckerUtils.getTypeAtLocation(propertyValue);
|
|
5442
|
+
if (valueType && isPrimitiveType(valueType)) {
|
|
5270
5443
|
report(errorToReport);
|
|
5271
5444
|
}
|
|
5272
5445
|
} else if (propertyName === "sync") {
|
|
5273
|
-
const valueType =
|
|
5446
|
+
const valueType = typeCheckerUtils.getTypeAtLocation(propertyValue);
|
|
5447
|
+
if (!valueType) continue;
|
|
5274
5448
|
const signatures = typeChecker.getSignaturesOfType(valueType, ts.SignatureKind.Call);
|
|
5275
5449
|
for (const signature of signatures) {
|
|
5276
5450
|
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
@@ -5280,7 +5454,8 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
5280
5454
|
}
|
|
5281
5455
|
}
|
|
5282
5456
|
} else if (propertyName === "effect" || propertyName === "scoped") {
|
|
5283
|
-
const valueType =
|
|
5457
|
+
const valueType = typeCheckerUtils.getTypeAtLocation(propertyValue);
|
|
5458
|
+
if (!valueType) continue;
|
|
5284
5459
|
const effectResult = yield* pipe(
|
|
5285
5460
|
typeParser.effectType(valueType, propertyValue),
|
|
5286
5461
|
orElse2(() => void_)
|
|
@@ -5627,7 +5802,8 @@ var annotate = createCodegen({
|
|
|
5627
5802
|
}
|
|
5628
5803
|
for (const variableDeclaration of variableDeclarations) {
|
|
5629
5804
|
if (!variableDeclaration.initializer) continue;
|
|
5630
|
-
const initializerType =
|
|
5805
|
+
const initializerType = typeCheckerUtils.getTypeAtLocation(variableDeclaration.initializer);
|
|
5806
|
+
if (!initializerType) continue;
|
|
5631
5807
|
const enclosingNode = ts.findAncestor(variableDeclaration, (_) => tsUtils.isDeclarationKind(_.kind)) || sourceFile;
|
|
5632
5808
|
const initializerTypeNode = fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
|
|
5633
5809
|
initializerType,
|
|
@@ -6079,7 +6255,7 @@ var findNodeToProcess = fn("StructuralSchemaGen.findNodeToProcess")(
|
|
|
6079
6255
|
function* (sourceFile, textRange) {
|
|
6080
6256
|
const ts = yield* service(TypeScriptApi);
|
|
6081
6257
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
6082
|
-
const
|
|
6258
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6083
6259
|
return pipe(
|
|
6084
6260
|
tsUtils.getAncestorNodesInRange(sourceFile, textRange),
|
|
6085
6261
|
filter((node) => ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)),
|
|
@@ -6088,7 +6264,7 @@ var findNodeToProcess = fn("StructuralSchemaGen.findNodeToProcess")(
|
|
|
6088
6264
|
map3((node) => ({
|
|
6089
6265
|
node,
|
|
6090
6266
|
identifier: node.name,
|
|
6091
|
-
type:
|
|
6267
|
+
type: typeCheckerUtils.getTypeAtLocation(node.name),
|
|
6092
6268
|
isExported: node.modifiers ? (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 : false
|
|
6093
6269
|
})),
|
|
6094
6270
|
filter(({ type }) => !!type),
|
|
@@ -6266,7 +6442,7 @@ var typeToSchema = createCodegen({
|
|
|
6266
6442
|
)
|
|
6267
6443
|
);
|
|
6268
6444
|
}
|
|
6269
|
-
const type =
|
|
6445
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.name);
|
|
6270
6446
|
if (!type) {
|
|
6271
6447
|
return yield* fail(
|
|
6272
6448
|
new CodegenNotApplicableError(
|
|
@@ -6347,6 +6523,7 @@ var codegens = [accessors, annotate, typeToSchema];
|
|
|
6347
6523
|
var outdatedEffectCodegen = createDiagnostic({
|
|
6348
6524
|
name: "outdatedEffectCodegen",
|
|
6349
6525
|
code: 19,
|
|
6526
|
+
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
6350
6527
|
severity: "warning",
|
|
6351
6528
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
6352
6529
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
@@ -6392,11 +6569,12 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
6392
6569
|
var overriddenSchemaConstructor = createDiagnostic({
|
|
6393
6570
|
name: "overriddenSchemaConstructor",
|
|
6394
6571
|
code: 30,
|
|
6572
|
+
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
6395
6573
|
severity: "error",
|
|
6396
6574
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
6397
6575
|
const ts = yield* service(TypeScriptApi);
|
|
6398
6576
|
const typeParser = yield* service(TypeParser);
|
|
6399
|
-
const
|
|
6577
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6400
6578
|
function isAllowedConstructor(node) {
|
|
6401
6579
|
if (node.body && node.body.statements.length === 1) {
|
|
6402
6580
|
const expressionStatement = node.body.statements[0];
|
|
@@ -6430,7 +6608,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
6430
6608
|
for (const heritageClause of node.heritageClauses) {
|
|
6431
6609
|
if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
6432
6610
|
for (const type of heritageClause.types) {
|
|
6433
|
-
const typeAtLocation =
|
|
6611
|
+
const typeAtLocation = typeCheckerUtils.getTypeAtLocation(type.expression);
|
|
6612
|
+
if (!typeAtLocation) continue;
|
|
6434
6613
|
const isSchema = yield* pipe(
|
|
6435
6614
|
typeParser.effectSchemaType(typeAtLocation, type.expression),
|
|
6436
6615
|
map4(() => true),
|
|
@@ -6527,10 +6706,11 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
6527
6706
|
var returnEffectInGen = createDiagnostic({
|
|
6528
6707
|
name: "returnEffectInGen",
|
|
6529
6708
|
code: 11,
|
|
6709
|
+
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
6530
6710
|
severity: "suggestion",
|
|
6531
6711
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
6532
6712
|
const ts = yield* service(TypeScriptApi);
|
|
6533
|
-
const
|
|
6713
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6534
6714
|
const typeParser = yield* service(TypeParser);
|
|
6535
6715
|
const nodeToVisit = [];
|
|
6536
6716
|
const appendNodeToVisit = (node) => {
|
|
@@ -6548,7 +6728,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
6548
6728
|
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
|
|
6549
6729
|
);
|
|
6550
6730
|
if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
|
|
6551
|
-
const type =
|
|
6731
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
6732
|
+
if (!type) continue;
|
|
6552
6733
|
const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
6553
6734
|
if (isSome2(maybeEffect)) {
|
|
6554
6735
|
if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
|
|
@@ -6594,6 +6775,7 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
6594
6775
|
var runEffectInsideEffect = createDiagnostic({
|
|
6595
6776
|
name: "runEffectInsideEffect",
|
|
6596
6777
|
code: 32,
|
|
6778
|
+
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
6597
6779
|
severity: "suggestion",
|
|
6598
6780
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
6599
6781
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6733,6 +6915,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
6733
6915
|
var schemaStructWithTag = createDiagnostic({
|
|
6734
6916
|
name: "schemaStructWithTag",
|
|
6735
6917
|
code: 34,
|
|
6918
|
+
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
6736
6919
|
severity: "suggestion",
|
|
6737
6920
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
6738
6921
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6812,6 +6995,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
6812
6995
|
var schemaUnionOfLiterals = createDiagnostic({
|
|
6813
6996
|
name: "schemaUnionOfLiterals",
|
|
6814
6997
|
code: 33,
|
|
6998
|
+
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
6815
6999
|
severity: "off",
|
|
6816
7000
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
6817
7001
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6885,6 +7069,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
6885
7069
|
var scopeInLayerEffect = createDiagnostic({
|
|
6886
7070
|
name: "scopeInLayerEffect",
|
|
6887
7071
|
code: 13,
|
|
7072
|
+
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
6888
7073
|
severity: "warning",
|
|
6889
7074
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
6890
7075
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6943,12 +7128,14 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
6943
7128
|
const node = nodeToVisit.shift();
|
|
6944
7129
|
const layerEffectApiCall = parseLayerEffectApiCall(node);
|
|
6945
7130
|
if (layerEffectApiCall) {
|
|
6946
|
-
const type =
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
7131
|
+
const type = typeCheckerUtils.getTypeAtLocation(node);
|
|
7132
|
+
if (type) {
|
|
7133
|
+
yield* pipe(
|
|
7134
|
+
typeParser.layerType(type, node),
|
|
7135
|
+
flatMap2(({ RIn }) => reportIfLayerRequireScope(RIn, node, layerEffectApiCall.methodIdentifier)),
|
|
7136
|
+
ignore
|
|
7137
|
+
);
|
|
7138
|
+
}
|
|
6952
7139
|
continue;
|
|
6953
7140
|
}
|
|
6954
7141
|
if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
@@ -6976,6 +7163,7 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
6976
7163
|
var strictBooleanExpressions = createDiagnostic({
|
|
6977
7164
|
name: "strictBooleanExpressions",
|
|
6978
7165
|
code: 17,
|
|
7166
|
+
description: "Enforces boolean types in conditional expressions for type safety",
|
|
6979
7167
|
severity: "off",
|
|
6980
7168
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
6981
7169
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7017,7 +7205,8 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
7017
7205
|
if (!nodeToCheck) continue;
|
|
7018
7206
|
if (!conditionChecks.has(nodeToCheck.parent)) continue;
|
|
7019
7207
|
if (!ts.isExpression(nodeToCheck)) continue;
|
|
7020
|
-
const nodeType =
|
|
7208
|
+
const nodeType = typeCheckerUtils.getTypeAtLocation(nodeToCheck);
|
|
7209
|
+
if (!nodeType) continue;
|
|
7021
7210
|
const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
|
|
7022
7211
|
let typesToCheck = [constrainedType || nodeType];
|
|
7023
7212
|
while (typesToCheck.length > 0) {
|
|
@@ -7045,10 +7234,11 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
7045
7234
|
var strictEffectProvide = createDiagnostic({
|
|
7046
7235
|
name: "strictEffectProvide",
|
|
7047
7236
|
code: 27,
|
|
7237
|
+
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
7048
7238
|
severity: "off",
|
|
7049
7239
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
7050
7240
|
const ts = yield* service(TypeScriptApi);
|
|
7051
|
-
const
|
|
7241
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7052
7242
|
const typeParser = yield* service(TypeParser);
|
|
7053
7243
|
const parseEffectProvideWithLayer = (node) => gen(function* () {
|
|
7054
7244
|
if (!ts.isCallExpression(node) || node.arguments.length === 0) {
|
|
@@ -7057,7 +7247,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
7057
7247
|
yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
|
|
7058
7248
|
return yield* firstSuccessOf(
|
|
7059
7249
|
node.arguments.map((arg) => {
|
|
7060
|
-
const argType =
|
|
7250
|
+
const argType = typeCheckerUtils.getTypeAtLocation(arg);
|
|
7251
|
+
if (!argType) return typeParserIssue("Could not get argument type");
|
|
7061
7252
|
return typeParser.layerType(argType, arg);
|
|
7062
7253
|
})
|
|
7063
7254
|
);
|
|
@@ -7089,6 +7280,7 @@ var strictEffectProvide = createDiagnostic({
|
|
|
7089
7280
|
var tryCatchInEffectGen = createDiagnostic({
|
|
7090
7281
|
name: "tryCatchInEffectGen",
|
|
7091
7282
|
code: 15,
|
|
7283
|
+
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
7092
7284
|
severity: "suggestion",
|
|
7093
7285
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
7094
7286
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7134,6 +7326,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
7134
7326
|
var unknownInEffectCatch = createDiagnostic({
|
|
7135
7327
|
name: "unknownInEffectCatch",
|
|
7136
7328
|
code: 31,
|
|
7329
|
+
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
7137
7330
|
severity: "warning",
|
|
7138
7331
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
7139
7332
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7191,6 +7384,7 @@ Consider wrapping unknown errors into Effect's Data.TaggedError for example, or
|
|
|
7191
7384
|
var unnecessaryEffectGen = createDiagnostic({
|
|
7192
7385
|
name: "unnecessaryEffectGen",
|
|
7193
7386
|
code: 5,
|
|
7387
|
+
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
7194
7388
|
severity: "suggestion",
|
|
7195
7389
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
7196
7390
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7234,15 +7428,12 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
7234
7428
|
var unnecessaryFailYieldableError = createDiagnostic({
|
|
7235
7429
|
name: "unnecessaryFailYieldableError",
|
|
7236
7430
|
code: 29,
|
|
7431
|
+
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
7237
7432
|
severity: "suggestion",
|
|
7238
7433
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
7239
7434
|
const ts = yield* service(TypeScriptApi);
|
|
7240
7435
|
const typeParser = yield* service(TypeParser);
|
|
7241
|
-
const
|
|
7242
|
-
const yieldableErrorTypes = yield* pipe(
|
|
7243
|
-
typeParser.effectCauseYieldableErrorTypes(sourceFile),
|
|
7244
|
-
orElse2(() => succeed([]))
|
|
7245
|
-
);
|
|
7436
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7246
7437
|
const nodeToVisit = [];
|
|
7247
7438
|
const appendNodeToVisit = (node) => {
|
|
7248
7439
|
nodeToVisit.push(node);
|
|
@@ -7256,32 +7447,34 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
7256
7447
|
const callExpression = node.expression;
|
|
7257
7448
|
yield* pipe(
|
|
7258
7449
|
typeParser.isNodeReferenceToEffectModuleApi("fail")(callExpression.expression),
|
|
7259
|
-
|
|
7450
|
+
flatMap2(() => {
|
|
7260
7451
|
if (callExpression.arguments.length > 0) {
|
|
7261
7452
|
const failArgument = callExpression.arguments[0];
|
|
7262
|
-
const argumentType =
|
|
7263
|
-
|
|
7264
|
-
|
|
7453
|
+
const argumentType = typeCheckerUtils.getTypeAtLocation(failArgument);
|
|
7454
|
+
if (!argumentType) return void_;
|
|
7455
|
+
return pipe(
|
|
7456
|
+
typeParser.extendsCauseYieldableError(argumentType),
|
|
7457
|
+
map4(
|
|
7458
|
+
() => report({
|
|
7459
|
+
location: node,
|
|
7460
|
+
messageText: `This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead.`,
|
|
7461
|
+
fixes: [{
|
|
7462
|
+
fixName: "unnecessaryFailYieldableError_fix",
|
|
7463
|
+
description: "Replace yield* Effect.fail with yield*",
|
|
7464
|
+
apply: gen(function* () {
|
|
7465
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
7466
|
+
changeTracker.replaceNode(
|
|
7467
|
+
sourceFile,
|
|
7468
|
+
callExpression,
|
|
7469
|
+
failArgument
|
|
7470
|
+
);
|
|
7471
|
+
})
|
|
7472
|
+
}]
|
|
7473
|
+
})
|
|
7474
|
+
)
|
|
7265
7475
|
);
|
|
7266
|
-
if (isYieldableError) {
|
|
7267
|
-
report({
|
|
7268
|
-
location: node,
|
|
7269
|
-
messageText: `This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead.`,
|
|
7270
|
-
fixes: [{
|
|
7271
|
-
fixName: "unnecessaryFailYieldableError_fix",
|
|
7272
|
-
description: "Replace yield* Effect.fail with yield*",
|
|
7273
|
-
apply: gen(function* () {
|
|
7274
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
7275
|
-
changeTracker.replaceNode(
|
|
7276
|
-
sourceFile,
|
|
7277
|
-
callExpression,
|
|
7278
|
-
failArgument
|
|
7279
|
-
);
|
|
7280
|
-
})
|
|
7281
|
-
}]
|
|
7282
|
-
});
|
|
7283
|
-
}
|
|
7284
7476
|
}
|
|
7477
|
+
return void_;
|
|
7285
7478
|
}),
|
|
7286
7479
|
ignore
|
|
7287
7480
|
);
|
|
@@ -7294,6 +7487,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
7294
7487
|
var unnecessaryPipe = createDiagnostic({
|
|
7295
7488
|
name: "unnecessaryPipe",
|
|
7296
7489
|
code: 9,
|
|
7490
|
+
description: "Removes pipe calls with no arguments",
|
|
7297
7491
|
severity: "suggestion",
|
|
7298
7492
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
7299
7493
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7339,6 +7533,7 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
7339
7533
|
var unnecessaryPipeChain = createDiagnostic({
|
|
7340
7534
|
name: "unnecessaryPipeChain",
|
|
7341
7535
|
code: 16,
|
|
7536
|
+
description: "Simplifies chained pipe calls into a single pipe call",
|
|
7342
7537
|
severity: "suggestion",
|
|
7343
7538
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
7344
7539
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7413,6 +7608,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
7413
7608
|
var unsupportedServiceAccessors = createDiagnostic({
|
|
7414
7609
|
name: "unsupportedServiceAccessors",
|
|
7415
7610
|
code: 21,
|
|
7611
|
+
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
7416
7612
|
severity: "warning",
|
|
7417
7613
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
7418
7614
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7500,7 +7696,8 @@ var diagnostics = [
|
|
|
7500
7696
|
unknownInEffectCatch,
|
|
7501
7697
|
runEffectInsideEffect,
|
|
7502
7698
|
schemaUnionOfLiterals,
|
|
7503
|
-
schemaStructWithTag
|
|
7699
|
+
schemaStructWithTag,
|
|
7700
|
+
globalErrorInEffectFailure
|
|
7504
7701
|
];
|
|
7505
7702
|
|
|
7506
7703
|
// src/effect-lsp-patch-utils.ts
|