@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
package/transform.js
CHANGED
|
@@ -24,7 +24,7 @@ __export(transform_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(transform_exports);
|
|
26
26
|
|
|
27
|
-
// node_modules/.pnpm/effect@3.19.
|
|
27
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Function.js
|
|
28
28
|
var isFunction = (input) => typeof input === "function";
|
|
29
29
|
var dual = function(arity, body) {
|
|
30
30
|
if (typeof arity === "function") {
|
|
@@ -120,7 +120,7 @@ function pipe(a, ab, bc, cd, de, ef, fg, gh, hi) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// node_modules/.pnpm/effect@3.19.
|
|
123
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/GlobalValue.js
|
|
124
124
|
var globalStoreId = `effect/GlobalValue`;
|
|
125
125
|
var globalStore;
|
|
126
126
|
var globalValue = (id, compute) => {
|
|
@@ -134,7 +134,7 @@ var globalValue = (id, compute) => {
|
|
|
134
134
|
return globalStore.get(id);
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
-
// node_modules/.pnpm/effect@3.19.
|
|
137
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Predicate.js
|
|
138
138
|
var isString = (input) => typeof input === "string";
|
|
139
139
|
var isNumber = (input) => typeof input === "number";
|
|
140
140
|
var isBoolean = (input) => typeof input === "boolean";
|
|
@@ -144,7 +144,7 @@ var isObject = (input) => isRecordOrArray(input) || isFunction2(input);
|
|
|
144
144
|
var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObject(self) && property in self);
|
|
145
145
|
var isRecord = (input) => isRecordOrArray(input) && !Array.isArray(input);
|
|
146
146
|
|
|
147
|
-
// node_modules/.pnpm/effect@3.19.
|
|
147
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Utils.js
|
|
148
148
|
var GenKindTypeId = /* @__PURE__ */ Symbol.for("effect/Gen/GenKind");
|
|
149
149
|
var GenKindImpl = class {
|
|
150
150
|
value;
|
|
@@ -266,7 +266,7 @@ var internalCall = isNotOptimizedAway ? standard.effect_internal_function : forc
|
|
|
266
266
|
var genConstructor = function* () {
|
|
267
267
|
}.constructor;
|
|
268
268
|
|
|
269
|
-
// node_modules/.pnpm/effect@3.19.
|
|
269
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Hash.js
|
|
270
270
|
var randomHashCache = /* @__PURE__ */ globalValue(/* @__PURE__ */ Symbol.for("effect/Hash/randomHashCache"), () => /* @__PURE__ */ new WeakMap());
|
|
271
271
|
var symbol = /* @__PURE__ */ Symbol.for("effect/Hash");
|
|
272
272
|
var hash = (self) => {
|
|
@@ -291,6 +291,9 @@ var hash = (self) => {
|
|
|
291
291
|
if (self === null) {
|
|
292
292
|
return string("null");
|
|
293
293
|
} else if (self instanceof Date) {
|
|
294
|
+
if (Number.isNaN(self.getTime())) {
|
|
295
|
+
return string("Invalid Date");
|
|
296
|
+
}
|
|
294
297
|
return hash(self.toISOString());
|
|
295
298
|
} else if (self instanceof URL) {
|
|
296
299
|
return hash(self.href);
|
|
@@ -365,7 +368,7 @@ var cached = function() {
|
|
|
365
368
|
return hash2;
|
|
366
369
|
};
|
|
367
370
|
|
|
368
|
-
// node_modules/.pnpm/effect@3.19.
|
|
371
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Equal.js
|
|
369
372
|
var symbol2 = /* @__PURE__ */ Symbol.for("effect/Equal");
|
|
370
373
|
function equals() {
|
|
371
374
|
if (arguments.length === 1) {
|
|
@@ -390,7 +393,9 @@ function compareBoth(self, that) {
|
|
|
390
393
|
return structuralRegionState.enabled && structuralRegionState.tester ? structuralRegionState.tester(self, that) : false;
|
|
391
394
|
}
|
|
392
395
|
} else if (self instanceof Date && that instanceof Date) {
|
|
393
|
-
|
|
396
|
+
const t1 = self.getTime();
|
|
397
|
+
const t2 = that.getTime();
|
|
398
|
+
return t1 === t2 || Number.isNaN(t1) && Number.isNaN(t2);
|
|
394
399
|
} else if (self instanceof URL && that instanceof URL) {
|
|
395
400
|
return self.href === that.href;
|
|
396
401
|
}
|
|
@@ -419,7 +424,7 @@ function compareBoth(self, that) {
|
|
|
419
424
|
var isEqual = (u) => hasProperty(u, symbol2);
|
|
420
425
|
var equivalence = () => equals;
|
|
421
426
|
|
|
422
|
-
// node_modules/.pnpm/effect@3.19.
|
|
427
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Inspectable.js
|
|
423
428
|
var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
424
429
|
var toJSON = (x) => {
|
|
425
430
|
try {
|
|
@@ -471,7 +476,7 @@ var redact = (u) => {
|
|
|
471
476
|
return u;
|
|
472
477
|
};
|
|
473
478
|
|
|
474
|
-
// node_modules/.pnpm/effect@3.19.
|
|
479
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Pipeable.js
|
|
475
480
|
var pipeArguments = (self, args2) => {
|
|
476
481
|
switch (args2.length) {
|
|
477
482
|
case 0:
|
|
@@ -504,14 +509,14 @@ var pipeArguments = (self, args2) => {
|
|
|
504
509
|
}
|
|
505
510
|
};
|
|
506
511
|
|
|
507
|
-
// node_modules/.pnpm/effect@3.19.
|
|
512
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/opCodes/effect.js
|
|
508
513
|
var OP_COMMIT = "Commit";
|
|
509
514
|
|
|
510
|
-
// node_modules/.pnpm/effect@3.19.
|
|
511
|
-
var moduleVersion = "3.19.
|
|
515
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/version.js
|
|
516
|
+
var moduleVersion = "3.19.13";
|
|
512
517
|
var getCurrentVersion = () => moduleVersion;
|
|
513
518
|
|
|
514
|
-
// node_modules/.pnpm/effect@3.19.
|
|
519
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/effectable.js
|
|
515
520
|
var EffectTypeId = /* @__PURE__ */ Symbol.for("effect/Effect");
|
|
516
521
|
var StreamTypeId = /* @__PURE__ */ Symbol.for("effect/Stream");
|
|
517
522
|
var SinkTypeId = /* @__PURE__ */ Symbol.for("effect/Sink");
|
|
@@ -598,7 +603,7 @@ var StructuralCommitPrototype = {
|
|
|
598
603
|
...StructuralPrototype
|
|
599
604
|
};
|
|
600
605
|
|
|
601
|
-
// node_modules/.pnpm/effect@3.19.
|
|
606
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/option.js
|
|
602
607
|
var TypeId = /* @__PURE__ */ Symbol.for("effect/Option");
|
|
603
608
|
var CommonProto = {
|
|
604
609
|
...EffectPrototype,
|
|
@@ -656,7 +661,7 @@ var some = (value) => {
|
|
|
656
661
|
return a;
|
|
657
662
|
};
|
|
658
663
|
|
|
659
|
-
// node_modules/.pnpm/effect@3.19.
|
|
664
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/either.js
|
|
660
665
|
var TypeId2 = /* @__PURE__ */ Symbol.for("effect/Either");
|
|
661
666
|
var CommonProto2 = {
|
|
662
667
|
...EffectPrototype,
|
|
@@ -718,7 +723,7 @@ var right = (right3) => {
|
|
|
718
723
|
return a;
|
|
719
724
|
};
|
|
720
725
|
|
|
721
|
-
// node_modules/.pnpm/effect@3.19.
|
|
726
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Either.js
|
|
722
727
|
var right2 = right;
|
|
723
728
|
var left2 = left;
|
|
724
729
|
var isLeft2 = isLeft;
|
|
@@ -726,14 +731,14 @@ var isRight2 = isRight;
|
|
|
726
731
|
var map = /* @__PURE__ */ dual(2, (self, f) => isRight2(self) ? right2(f(self.right)) : left2(self.left));
|
|
727
732
|
var getOrElse = /* @__PURE__ */ dual(2, (self, onLeft) => isLeft2(self) ? onLeft(self.left) : self.right);
|
|
728
733
|
|
|
729
|
-
// node_modules/.pnpm/effect@3.19.
|
|
734
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/internal/array.js
|
|
730
735
|
var isNonEmptyArray = (self) => self.length > 0;
|
|
731
736
|
|
|
732
|
-
// node_modules/.pnpm/effect@3.19.
|
|
737
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Order.js
|
|
733
738
|
var make = (compare) => (self, that) => self === that ? 0 : compare(self, that);
|
|
734
739
|
var string2 = /* @__PURE__ */ make((self, that) => self < that ? -1 : 1);
|
|
735
740
|
|
|
736
|
-
// node_modules/.pnpm/effect@3.19.
|
|
741
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Option.js
|
|
737
742
|
var none2 = () => none;
|
|
738
743
|
var some2 = some;
|
|
739
744
|
var isNone2 = isNone;
|
|
@@ -743,7 +748,7 @@ var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : se
|
|
|
743
748
|
var fromNullable = (nullableValue) => nullableValue == null ? none2() : some2(nullableValue);
|
|
744
749
|
var getOrUndefined = /* @__PURE__ */ getOrElse2(constUndefined);
|
|
745
750
|
|
|
746
|
-
// node_modules/.pnpm/effect@3.19.
|
|
751
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Record.js
|
|
747
752
|
var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
748
753
|
const out = {
|
|
749
754
|
...self
|
|
@@ -755,7 +760,7 @@ var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
755
760
|
});
|
|
756
761
|
var keys = (self) => Object.keys(self);
|
|
757
762
|
|
|
758
|
-
// node_modules/.pnpm/effect@3.19.
|
|
763
|
+
// node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Array.js
|
|
759
764
|
var fromIterable = (collection) => Array.isArray(collection) ? collection : Array.from(collection);
|
|
760
765
|
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
761
766
|
var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable(self).concat(fromIterable(that)));
|
|
@@ -795,7 +800,10 @@ var containsWith = (isEquivalent) => dual(2, (self, a) => {
|
|
|
795
800
|
var _equivalence = /* @__PURE__ */ equivalence();
|
|
796
801
|
var intersectionWith = (isEquivalent) => {
|
|
797
802
|
const has = containsWith(isEquivalent);
|
|
798
|
-
return dual(2, (self, that) =>
|
|
803
|
+
return dual(2, (self, that) => {
|
|
804
|
+
const bs = fromIterable(that);
|
|
805
|
+
return fromIterable(self).filter((a) => has(bs, a));
|
|
806
|
+
});
|
|
799
807
|
};
|
|
800
808
|
var intersection = /* @__PURE__ */ intersectionWith(_equivalence);
|
|
801
809
|
var empty = () => [];
|
|
@@ -873,12 +881,12 @@ var SingleShotGen2 = class _SingleShotGen {
|
|
|
873
881
|
return new _SingleShotGen(this.self);
|
|
874
882
|
}
|
|
875
883
|
};
|
|
876
|
-
var evaluate = Symbol.for("Nano.evaluate");
|
|
877
|
-
var contA = Symbol.for("Nano.contA");
|
|
878
|
-
var contE = Symbol.for("Nano.contE");
|
|
879
|
-
var contAll = Symbol.for("Nano.contAll");
|
|
880
|
-
var NanoYield = Symbol.for("Nano.yield");
|
|
881
|
-
var args = Symbol.for("Nano.args");
|
|
884
|
+
var evaluate = /* @__PURE__ */ Symbol.for("Nano.evaluate");
|
|
885
|
+
var contA = /* @__PURE__ */ Symbol.for("Nano.contA");
|
|
886
|
+
var contE = /* @__PURE__ */ Symbol.for("Nano.contE");
|
|
887
|
+
var contAll = /* @__PURE__ */ Symbol.for("Nano.contAll");
|
|
888
|
+
var NanoYield = /* @__PURE__ */ Symbol.for("Nano.yield");
|
|
889
|
+
var args = /* @__PURE__ */ Symbol.for("Nano.args");
|
|
882
890
|
var NanoDefectException = class {
|
|
883
891
|
constructor(message, lastSpan) {
|
|
884
892
|
this.message = message;
|
|
@@ -1688,7 +1696,9 @@ function makeTypeScriptUtils(ts) {
|
|
|
1688
1696
|
} else {
|
|
1689
1697
|
return;
|
|
1690
1698
|
}
|
|
1691
|
-
|
|
1699
|
+
const importDeclaration = ts.findAncestor(accessedObject, ts.isImportDeclaration);
|
|
1700
|
+
if (importDeclaration) return;
|
|
1701
|
+
return { accessedObject, outerNode, replacementSpan, insideImportDeclaration: !!importDeclaration };
|
|
1692
1702
|
}
|
|
1693
1703
|
function parseDataForExtendsClassCompletion(sourceFile, position) {
|
|
1694
1704
|
const maybeInfos = parseAccessedExpressionForCompletion(sourceFile, position);
|
|
@@ -2187,6 +2197,8 @@ var nanoLayer2 = (fa) => pipe(
|
|
|
2187
2197
|
function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
2188
2198
|
const readonlyArraySymbol = typeChecker.resolveName("ReadonlyArray", void 0, ts.SymbolFlags.Type, false);
|
|
2189
2199
|
const globalReadonlyArrayType = readonlyArraySymbol ? typeChecker.getDeclaredTypeOfSymbol(readonlyArraySymbol) : void 0;
|
|
2200
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
2201
|
+
const globalErrorType = errorSymbol ? typeChecker.getDeclaredTypeOfSymbol(errorSymbol) : void 0;
|
|
2190
2202
|
function isUnion(type) {
|
|
2191
2203
|
return !!(type.flags & ts.TypeFlags.Union);
|
|
2192
2204
|
}
|
|
@@ -2435,6 +2447,10 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2435
2447
|
function typeToSimplifiedTypeNode(type, enclosingNode, flags) {
|
|
2436
2448
|
return typeToSimplifiedTypeNodeWorker(type, enclosingNode, flags, 0);
|
|
2437
2449
|
}
|
|
2450
|
+
function isGlobalErrorType(type) {
|
|
2451
|
+
if (!globalErrorType) return false;
|
|
2452
|
+
return typeChecker.isTypeAssignableTo(type, globalErrorType) && typeChecker.isTypeAssignableTo(globalErrorType, type);
|
|
2453
|
+
}
|
|
2438
2454
|
function typeToSimplifiedTypeNodeWorker(type, enclosingNode, flags, depth) {
|
|
2439
2455
|
const fallbackStandard = () => {
|
|
2440
2456
|
const typeNode = typeChecker.typeToTypeNode(type, enclosingNode, flags);
|
|
@@ -2504,6 +2520,15 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2504
2520
|
}
|
|
2505
2521
|
return fallbackStandard();
|
|
2506
2522
|
}
|
|
2523
|
+
function getTypeAtLocation(node) {
|
|
2524
|
+
if (node.parent && ts.isJsxSelfClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
2525
|
+
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
2526
|
+
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
2527
|
+
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
2528
|
+
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
2529
|
+
return typeChecker.getTypeAtLocation(node);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2507
2532
|
return {
|
|
2508
2533
|
isUnion,
|
|
2509
2534
|
isReadonlyArrayType,
|
|
@@ -2515,7 +2540,9 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2515
2540
|
deterministicTypeOrder,
|
|
2516
2541
|
getInferredReturnType,
|
|
2517
2542
|
expectedAndRealType,
|
|
2518
|
-
typeToSimplifiedTypeNode
|
|
2543
|
+
typeToSimplifiedTypeNode,
|
|
2544
|
+
isGlobalErrorType,
|
|
2545
|
+
getTypeAtLocation
|
|
2519
2546
|
};
|
|
2520
2547
|
}
|
|
2521
2548
|
|
|
@@ -2637,7 +2664,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2637
2664
|
return isSymbolExportOfPackageModule(symbol3, packageName, memberName, isCorrectSourceFile);
|
|
2638
2665
|
};
|
|
2639
2666
|
const findSymbolsMatchingPackageAndExportedName = (packageName, exportedSymbolName) => cachedBy(
|
|
2640
|
-
fn("TypeParser.findSymbolsMatchingPackageAndExportedName")(function* (
|
|
2667
|
+
fn("TypeParser.findSymbolsMatchingPackageAndExportedName")(function* () {
|
|
2641
2668
|
const result = [];
|
|
2642
2669
|
for (const sourceFile of program.getSourceFiles()) {
|
|
2643
2670
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -2651,7 +2678,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2651
2678
|
return result;
|
|
2652
2679
|
}),
|
|
2653
2680
|
`TypeParser.findSymbolsMatchingPackageAndExportedName(${packageName}, ${exportedSymbolName})`,
|
|
2654
|
-
(
|
|
2681
|
+
() => program
|
|
2655
2682
|
);
|
|
2656
2683
|
const isCauseTypeSourceFile = cachedBy(
|
|
2657
2684
|
fn("TypeParser.isCauseTypeSourceFile")(function* (sourceFile) {
|
|
@@ -2666,20 +2693,22 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2666
2693
|
"TypeParser.isCauseTypeSourceFile",
|
|
2667
2694
|
(sourceFile) => sourceFile
|
|
2668
2695
|
);
|
|
2669
|
-
const
|
|
2670
|
-
fn("TypeParser.
|
|
2671
|
-
const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")(
|
|
2672
|
-
const result = [];
|
|
2696
|
+
const extendsCauseYieldableError = cachedBy(
|
|
2697
|
+
fn("TypeParser.extendsCauseYieldableError")(function* (givenType) {
|
|
2698
|
+
const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")();
|
|
2673
2699
|
for (const [symbol3, sourceFile] of symbols) {
|
|
2674
|
-
const causeFile = yield* isCauseTypeSourceFile(sourceFile);
|
|
2700
|
+
const causeFile = yield* pipe(isCauseTypeSourceFile(sourceFile), orElse2(() => void_));
|
|
2675
2701
|
if (!causeFile) continue;
|
|
2676
2702
|
const type = typeChecker.getDeclaredTypeOfSymbol(symbol3);
|
|
2677
|
-
|
|
2703
|
+
if (!type) continue;
|
|
2704
|
+
if (typeChecker.isTypeAssignableTo(givenType, type)) {
|
|
2705
|
+
return type;
|
|
2706
|
+
}
|
|
2678
2707
|
}
|
|
2679
|
-
return
|
|
2708
|
+
return yield* typeParserIssue("Type does not extend Cause.YieldableError", givenType);
|
|
2680
2709
|
}),
|
|
2681
|
-
"TypeParser.
|
|
2682
|
-
(
|
|
2710
|
+
"TypeParser.extendsCauseYieldableError",
|
|
2711
|
+
(type) => type
|
|
2683
2712
|
);
|
|
2684
2713
|
function covariantTypeArgument(type) {
|
|
2685
2714
|
const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
|
|
@@ -3069,7 +3098,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3069
3098
|
}
|
|
3070
3099
|
if (ts.isYieldExpression(nodeToCheck) && nodeToCheck.asteriskToken && nodeToCheck.expression) {
|
|
3071
3100
|
const yieldedExpression = nodeToCheck.expression;
|
|
3072
|
-
const type =
|
|
3101
|
+
const type = typeCheckerUtils.getTypeAtLocation(yieldedExpression);
|
|
3102
|
+
if (!type) continue;
|
|
3073
3103
|
const { A: successType } = yield* effectType(type, yieldedExpression);
|
|
3074
3104
|
let replacementNode = succeed(yieldedExpression);
|
|
3075
3105
|
if (!explicitReturn && !(successType.flags & ts.TypeFlags.VoidLike)) {
|
|
@@ -3660,11 +3690,79 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3660
3690
|
"TypeParser.extendsEffectService",
|
|
3661
3691
|
(atLocation) => atLocation
|
|
3662
3692
|
);
|
|
3693
|
+
const isEffectSqlModelTypeSourceFile = cachedBy(
|
|
3694
|
+
fn("TypeParser.isEffectSqlModelTypeSourceFile")(function* (sourceFile) {
|
|
3695
|
+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
3696
|
+
if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
|
|
3697
|
+
const classSymbol = typeChecker.tryGetMemberInModuleExports("Class", moduleSymbol);
|
|
3698
|
+
if (!classSymbol) return yield* typeParserIssue("Model's Class type not found", void 0, sourceFile);
|
|
3699
|
+
const makeRepositorySymbol = typeChecker.tryGetMemberInModuleExports("makeRepository", moduleSymbol);
|
|
3700
|
+
if (!makeRepositorySymbol) {
|
|
3701
|
+
return yield* typeParserIssue("Model's makeRepository type not found", void 0, sourceFile);
|
|
3702
|
+
}
|
|
3703
|
+
const makeDataLoadersSymbol = typeChecker.tryGetMemberInModuleExports("makeDataLoaders", moduleSymbol);
|
|
3704
|
+
if (!makeDataLoadersSymbol) {
|
|
3705
|
+
return yield* typeParserIssue("Model's makeDataLoaders type not found", void 0, sourceFile);
|
|
3706
|
+
}
|
|
3707
|
+
return sourceFile;
|
|
3708
|
+
}),
|
|
3709
|
+
"TypeParser.isEffectSqlModelTypeSourceFile",
|
|
3710
|
+
(sourceFile) => sourceFile
|
|
3711
|
+
);
|
|
3712
|
+
const isNodeReferenceToEffectSqlModelModuleApi = (memberName) => cachedBy(
|
|
3713
|
+
fn("TypeParser.isNodeReferenceToEffectSqlModelModuleApi")(function* (node) {
|
|
3714
|
+
return yield* isNodeReferenceToExportOfPackageModule(
|
|
3715
|
+
node,
|
|
3716
|
+
"@effect/sql",
|
|
3717
|
+
isEffectSqlModelTypeSourceFile,
|
|
3718
|
+
memberName
|
|
3719
|
+
);
|
|
3720
|
+
}),
|
|
3721
|
+
`TypeParser.isNodeReferenceToEffectSqlModelModuleApi(${memberName})`,
|
|
3722
|
+
(node) => node
|
|
3723
|
+
);
|
|
3724
|
+
const extendsEffectSqlModelClass = cachedBy(
|
|
3725
|
+
fn("TypeParser.extendsEffectSqlModelClass")(function* (atLocation) {
|
|
3726
|
+
if (!atLocation.name) {
|
|
3727
|
+
return yield* typeParserIssue("Class has no name", void 0, atLocation);
|
|
3728
|
+
}
|
|
3729
|
+
const heritageClauses = atLocation.heritageClauses;
|
|
3730
|
+
if (!heritageClauses) {
|
|
3731
|
+
return yield* typeParserIssue("Class has no heritage clauses", void 0, atLocation);
|
|
3732
|
+
}
|
|
3733
|
+
for (const heritageClause of heritageClauses) {
|
|
3734
|
+
for (const typeX of heritageClause.types) {
|
|
3735
|
+
if (ts.isExpressionWithTypeArguments(typeX)) {
|
|
3736
|
+
const expression = typeX.expression;
|
|
3737
|
+
if (ts.isCallExpression(expression)) {
|
|
3738
|
+
const schemaCall = expression.expression;
|
|
3739
|
+
if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
|
|
3740
|
+
const isEffectSchemaModuleApi = yield* pipe(
|
|
3741
|
+
isNodeReferenceToEffectSqlModelModuleApi("Class")(schemaCall.expression),
|
|
3742
|
+
option
|
|
3743
|
+
);
|
|
3744
|
+
if (isSome2(isEffectSchemaModuleApi)) {
|
|
3745
|
+
return {
|
|
3746
|
+
className: atLocation.name,
|
|
3747
|
+
selfTypeNode: schemaCall.typeArguments[0]
|
|
3748
|
+
};
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
return yield* typeParserIssue("Class does not extend @effect/sql's Model.Class", void 0, atLocation);
|
|
3756
|
+
}),
|
|
3757
|
+
"TypeParser.extendsEffectSqlModelClass",
|
|
3758
|
+
(atLocation) => atLocation
|
|
3759
|
+
);
|
|
3663
3760
|
return {
|
|
3664
3761
|
isNodeReferenceToEffectModuleApi,
|
|
3665
3762
|
isNodeReferenceToEffectSchemaModuleApi,
|
|
3666
3763
|
isNodeReferenceToEffectDataModuleApi,
|
|
3667
3764
|
isNodeReferenceToEffectContextModuleApi,
|
|
3765
|
+
isNodeReferenceToEffectSqlModelModuleApi,
|
|
3668
3766
|
effectType,
|
|
3669
3767
|
strictEffectType,
|
|
3670
3768
|
layerType,
|
|
@@ -3674,7 +3772,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3674
3772
|
effectGen,
|
|
3675
3773
|
effectFnUntracedGen,
|
|
3676
3774
|
effectFnGen,
|
|
3677
|
-
|
|
3775
|
+
extendsCauseYieldableError,
|
|
3678
3776
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
3679
3777
|
effectSchemaType,
|
|
3680
3778
|
contextTag,
|
|
@@ -3690,7 +3788,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3690
3788
|
extendsSchemaTaggedError,
|
|
3691
3789
|
extendsDataTaggedError,
|
|
3692
3790
|
extendsDataTaggedClass,
|
|
3693
|
-
extendsSchemaTaggedRequest
|
|
3791
|
+
extendsSchemaTaggedRequest,
|
|
3792
|
+
extendsEffectSqlModelClass
|
|
3694
3793
|
};
|
|
3695
3794
|
}
|
|
3696
3795
|
|
|
@@ -3698,10 +3797,12 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3698
3797
|
var anyUnknownInErrorContext = createDiagnostic({
|
|
3699
3798
|
name: "anyUnknownInErrorContext",
|
|
3700
3799
|
code: 28,
|
|
3800
|
+
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
3701
3801
|
severity: "off",
|
|
3702
3802
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
3703
3803
|
const ts = yield* service(TypeScriptApi);
|
|
3704
3804
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3805
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
3705
3806
|
const typeParser = yield* service(TypeParser);
|
|
3706
3807
|
const isAnyOrUnknown = (type) => (type.flags & ts.TypeFlags.Any) > 0 || (type.flags & ts.TypeFlags.Unknown) > 0;
|
|
3707
3808
|
const matchingNodes = [];
|
|
@@ -3721,7 +3822,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
3721
3822
|
if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
|
|
3722
3823
|
if (node.type) {
|
|
3723
3824
|
const typeNode = node.type;
|
|
3724
|
-
const type2 =
|
|
3825
|
+
const type2 = typeCheckerUtils.getTypeAtLocation(node.type);
|
|
3826
|
+
if (!type2) continue;
|
|
3725
3827
|
const expectedEffect = yield* pipe(
|
|
3726
3828
|
typeParser.strictEffectType(type2, node.type),
|
|
3727
3829
|
orElse2(() => typeParser.layerType(type2, typeNode)),
|
|
@@ -3732,11 +3834,7 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
3732
3834
|
}
|
|
3733
3835
|
ts.forEachChild(node, appendNodeToVisit);
|
|
3734
3836
|
if (!ts.isExpression(node)) continue;
|
|
3735
|
-
|
|
3736
|
-
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) continue;
|
|
3737
|
-
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) continue;
|
|
3738
|
-
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) continue;
|
|
3739
|
-
let type = typeChecker.getTypeAtLocation(node);
|
|
3837
|
+
let type = typeCheckerUtils.getTypeAtLocation(node);
|
|
3740
3838
|
if (ts.isCallExpression(node)) {
|
|
3741
3839
|
const resolvedSignature = typeChecker.getResolvedSignature(node);
|
|
3742
3840
|
if (resolvedSignature) {
|
|
@@ -3802,11 +3900,13 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
3802
3900
|
var catchUnfailableEffect = createDiagnostic({
|
|
3803
3901
|
name: "catchUnfailableEffect",
|
|
3804
3902
|
code: 2,
|
|
3903
|
+
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
3805
3904
|
severity: "suggestion",
|
|
3806
3905
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
3807
3906
|
const ts = yield* service(TypeScriptApi);
|
|
3808
3907
|
const typeParser = yield* service(TypeParser);
|
|
3809
3908
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3909
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
3810
3910
|
const nodeToVisit = [];
|
|
3811
3911
|
const appendNodeToVisit = (node) => {
|
|
3812
3912
|
nodeToVisit.push(node);
|
|
@@ -3837,7 +3937,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
3837
3937
|
if (argIndex !== -1) {
|
|
3838
3938
|
let effectTypeToCheck;
|
|
3839
3939
|
if (argIndex === 0) {
|
|
3840
|
-
effectTypeToCheck =
|
|
3940
|
+
effectTypeToCheck = typeCheckerUtils.getTypeAtLocation(subject);
|
|
3841
3941
|
} else {
|
|
3842
3942
|
const signature = typeChecker.getResolvedSignature(pipeCallNode);
|
|
3843
3943
|
if (signature) {
|
|
@@ -3876,6 +3976,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
3876
3976
|
var classSelfMismatch = createDiagnostic({
|
|
3877
3977
|
name: "classSelfMismatch",
|
|
3878
3978
|
code: 20,
|
|
3979
|
+
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
3879
3980
|
severity: "error",
|
|
3880
3981
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
3881
3982
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -3897,6 +3998,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
3897
3998
|
orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
|
|
3898
3999
|
orElse2(() => typeParser.extendsSchemaTaggedError(node)),
|
|
3899
4000
|
orElse2(() => typeParser.extendsSchemaTaggedRequest(node)),
|
|
4001
|
+
orElse2(() => typeParser.extendsEffectSqlModelClass(node)),
|
|
3900
4002
|
orElse2(() => void_)
|
|
3901
4003
|
);
|
|
3902
4004
|
if (result) {
|
|
@@ -4006,6 +4108,7 @@ function createString(sourceFile, identifier, kind) {
|
|
|
4006
4108
|
var deterministicKeys = createDiagnostic({
|
|
4007
4109
|
name: "deterministicKeys",
|
|
4008
4110
|
code: 25,
|
|
4111
|
+
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
4009
4112
|
severity: "off",
|
|
4010
4113
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
4011
4114
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4126,6 +4229,7 @@ var programResolvedCacheSize = /* @__PURE__ */ new Map();
|
|
|
4126
4229
|
var duplicatePackage = createDiagnostic({
|
|
4127
4230
|
name: "duplicatePackage",
|
|
4128
4231
|
code: 6,
|
|
4232
|
+
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
4129
4233
|
severity: "warning",
|
|
4130
4234
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
4131
4235
|
const program = yield* service(TypeScriptProgram);
|
|
@@ -4173,6 +4277,7 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
4173
4277
|
var effectGenUsesAdapter = createDiagnostic({
|
|
4174
4278
|
name: "effectGenUsesAdapter",
|
|
4175
4279
|
code: 23,
|
|
4280
|
+
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
4176
4281
|
severity: "warning",
|
|
4177
4282
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
4178
4283
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4210,6 +4315,7 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
4210
4315
|
var effectInVoidSuccess = createDiagnostic({
|
|
4211
4316
|
name: "effectInVoidSuccess",
|
|
4212
4317
|
code: 14,
|
|
4318
|
+
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
4213
4319
|
severity: "warning",
|
|
4214
4320
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
4215
4321
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4258,10 +4364,12 @@ var effectInVoidSuccess = createDiagnostic({
|
|
|
4258
4364
|
var floatingEffect = createDiagnostic({
|
|
4259
4365
|
name: "floatingEffect",
|
|
4260
4366
|
code: 3,
|
|
4367
|
+
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
4261
4368
|
severity: "error",
|
|
4262
4369
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
4263
4370
|
const ts = yield* service(TypeScriptApi);
|
|
4264
4371
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
4372
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4265
4373
|
const typeParser = yield* service(TypeParser);
|
|
4266
4374
|
function isFloatingExpression(node) {
|
|
4267
4375
|
if (!ts.isExpressionStatement(node)) return false;
|
|
@@ -4280,7 +4388,8 @@ var floatingEffect = createDiagnostic({
|
|
|
4280
4388
|
const node = nodeToVisit.shift();
|
|
4281
4389
|
ts.forEachChild(node, appendNodeToVisit);
|
|
4282
4390
|
if (!isFloatingExpression(node)) continue;
|
|
4283
|
-
const type =
|
|
4391
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
4392
|
+
if (!type) continue;
|
|
4284
4393
|
const effect = yield* option(typeParser.effectType(type, node.expression));
|
|
4285
4394
|
if (isSome2(effect)) {
|
|
4286
4395
|
const allowedFloatingEffects = yield* pipe(
|
|
@@ -4306,6 +4415,7 @@ var floatingEffect = createDiagnostic({
|
|
|
4306
4415
|
var genericEffectServices = createDiagnostic({
|
|
4307
4416
|
name: "genericEffectServices",
|
|
4308
4417
|
code: 10,
|
|
4418
|
+
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
4309
4419
|
severity: "warning",
|
|
4310
4420
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
4311
4421
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4348,10 +4458,56 @@ var genericEffectServices = createDiagnostic({
|
|
|
4348
4458
|
})
|
|
4349
4459
|
});
|
|
4350
4460
|
|
|
4461
|
+
// src/diagnostics/globalErrorInEffectFailure.ts
|
|
4462
|
+
var globalErrorInEffectFailure = createDiagnostic({
|
|
4463
|
+
name: "globalErrorInEffectFailure",
|
|
4464
|
+
code: 35,
|
|
4465
|
+
description: "Warns when Effect.fail is called with the global Error type",
|
|
4466
|
+
severity: "warning",
|
|
4467
|
+
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
4468
|
+
const ts = yield* service(TypeScriptApi);
|
|
4469
|
+
const typeParser = yield* service(TypeParser);
|
|
4470
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4471
|
+
const nodeToVisit = [];
|
|
4472
|
+
const appendNodeToVisit = (node) => {
|
|
4473
|
+
nodeToVisit.push(node);
|
|
4474
|
+
return void 0;
|
|
4475
|
+
};
|
|
4476
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
4477
|
+
while (nodeToVisit.length > 0) {
|
|
4478
|
+
const node = nodeToVisit.shift();
|
|
4479
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
4480
|
+
if (ts.isCallExpression(node)) {
|
|
4481
|
+
yield* pipe(
|
|
4482
|
+
typeParser.isNodeReferenceToEffectModuleApi("fail")(node.expression),
|
|
4483
|
+
flatMap2(() => {
|
|
4484
|
+
if (node.arguments.length > 0) {
|
|
4485
|
+
const failArgument = node.arguments[0];
|
|
4486
|
+
const argumentType = typeCheckerUtils.getTypeAtLocation(failArgument);
|
|
4487
|
+
if (argumentType && typeCheckerUtils.isGlobalErrorType(argumentType)) {
|
|
4488
|
+
return sync(
|
|
4489
|
+
() => report({
|
|
4490
|
+
location: node,
|
|
4491
|
+
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.`,
|
|
4492
|
+
fixes: []
|
|
4493
|
+
})
|
|
4494
|
+
);
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
return void_;
|
|
4498
|
+
}),
|
|
4499
|
+
ignore
|
|
4500
|
+
);
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
})
|
|
4504
|
+
});
|
|
4505
|
+
|
|
4351
4506
|
// src/diagnostics/importFromBarrel.ts
|
|
4352
4507
|
var importFromBarrel = createDiagnostic({
|
|
4353
4508
|
name: "importFromBarrel",
|
|
4354
4509
|
code: 12,
|
|
4510
|
+
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
4355
4511
|
severity: "off",
|
|
4356
4512
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
4357
4513
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
@@ -4491,6 +4647,7 @@ var importFromBarrel = createDiagnostic({
|
|
|
4491
4647
|
var leakingRequirements = createDiagnostic({
|
|
4492
4648
|
name: "leakingRequirements",
|
|
4493
4649
|
code: 8,
|
|
4650
|
+
description: "Detects implementation services leaked in service methods",
|
|
4494
4651
|
severity: "suggestion",
|
|
4495
4652
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
4496
4653
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4598,7 +4755,8 @@ More info at https://effect.website/docs/requirements-management/layers/#avoidin
|
|
|
4598
4755
|
const node = nodeToVisit.shift();
|
|
4599
4756
|
const typesToCheck = [];
|
|
4600
4757
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && ts.idText(node.expression.name) === "GenericTag") {
|
|
4601
|
-
|
|
4758
|
+
const nodeType = typeCheckerUtils.getTypeAtLocation(node);
|
|
4759
|
+
if (nodeType) typesToCheck.push([nodeType, node]);
|
|
4602
4760
|
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
4603
4761
|
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
4604
4762
|
if (classSym) {
|
|
@@ -4632,10 +4790,12 @@ More info at https://effect.website/docs/requirements-management/layers/#avoidin
|
|
|
4632
4790
|
var missedPipeableOpportunity = createDiagnostic({
|
|
4633
4791
|
name: "missedPipeableOpportunity",
|
|
4634
4792
|
code: 26,
|
|
4793
|
+
description: "Enforces the use of pipeable style for nested function calls",
|
|
4635
4794
|
severity: "off",
|
|
4636
4795
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
4637
4796
|
const ts = yield* service(TypeScriptApi);
|
|
4638
4797
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
4798
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4639
4799
|
const typeParser = yield* service(TypeParser);
|
|
4640
4800
|
const options = yield* service(LanguageServicePluginOptions);
|
|
4641
4801
|
const nodeToVisit = [sourceFile];
|
|
@@ -4666,7 +4826,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
4666
4826
|
const originalParentChain = parentChain.slice();
|
|
4667
4827
|
while (parentChain.length > options.pipeableMinArgCount) {
|
|
4668
4828
|
const subject = parentChain.pop();
|
|
4669
|
-
const resultType =
|
|
4829
|
+
const resultType = typeCheckerUtils.getTypeAtLocation(subject);
|
|
4830
|
+
if (!resultType) continue;
|
|
4670
4831
|
const pipeableType = yield* pipe(typeParser.pipeableType(resultType, subject), orElse2(() => void_));
|
|
4671
4832
|
if (pipeableType) {
|
|
4672
4833
|
report({
|
|
@@ -4711,6 +4872,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
4711
4872
|
var missingEffectContext = createDiagnostic({
|
|
4712
4873
|
name: "missingEffectContext",
|
|
4713
4874
|
code: 1,
|
|
4875
|
+
description: "Reports missing service requirements in Effect context channel",
|
|
4714
4876
|
severity: "error",
|
|
4715
4877
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
4716
4878
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -4759,6 +4921,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
4759
4921
|
var missingEffectError = createDiagnostic({
|
|
4760
4922
|
name: "missingEffectError",
|
|
4761
4923
|
code: 1,
|
|
4924
|
+
description: "Reports missing error types in Effect error channel",
|
|
4762
4925
|
severity: "error",
|
|
4763
4926
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
4764
4927
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4898,6 +5061,7 @@ var missingEffectError = createDiagnostic({
|
|
|
4898
5061
|
var missingEffectServiceDependency = createDiagnostic({
|
|
4899
5062
|
name: "missingEffectServiceDependency",
|
|
4900
5063
|
code: 22,
|
|
5064
|
+
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
4901
5065
|
severity: "off",
|
|
4902
5066
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
4903
5067
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -4939,13 +5103,15 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
4939
5103
|
excludeNever
|
|
4940
5104
|
);
|
|
4941
5105
|
const providedIndexes = /* @__PURE__ */ new Set();
|
|
4942
|
-
const optionsType = typeChecker.getTypeAtLocation(options);
|
|
4943
|
-
const dependenciesProperty = typeChecker.getPropertyOfType(optionsType, "dependencies");
|
|
4944
5106
|
let types = [];
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
const
|
|
4948
|
-
|
|
5107
|
+
const optionsType = typeCheckerUtils.getTypeAtLocation(options);
|
|
5108
|
+
if (optionsType) {
|
|
5109
|
+
const dependenciesProperty = typeChecker.getPropertyOfType(optionsType, "dependencies");
|
|
5110
|
+
if (dependenciesProperty) {
|
|
5111
|
+
const dependenciesTypes = typeChecker.getTypeOfSymbolAtLocation(dependenciesProperty, options);
|
|
5112
|
+
const numberIndexType = typeChecker.getIndexTypeOfType(dependenciesTypes, ts.IndexKind.Number);
|
|
5113
|
+
types = numberIndexType ? typeCheckerUtils.unrollUnionMembers(numberIndexType) : [];
|
|
5114
|
+
}
|
|
4949
5115
|
}
|
|
4950
5116
|
for (const depType of types) {
|
|
4951
5117
|
const depLayerResult = yield* pipe(
|
|
@@ -4988,10 +5154,11 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
4988
5154
|
var missingReturnYieldStar = createDiagnostic({
|
|
4989
5155
|
name: "missingReturnYieldStar",
|
|
4990
5156
|
code: 7,
|
|
5157
|
+
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
4991
5158
|
severity: "error",
|
|
4992
5159
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
4993
5160
|
const ts = yield* service(TypeScriptApi);
|
|
4994
|
-
const
|
|
5161
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
4995
5162
|
const typeParser = yield* service(TypeParser);
|
|
4996
5163
|
const nodeToVisit = [];
|
|
4997
5164
|
const appendNodeToVisit = (node) => {
|
|
@@ -5003,42 +5170,44 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
5003
5170
|
const node = nodeToVisit.shift();
|
|
5004
5171
|
ts.forEachChild(node, appendNodeToVisit);
|
|
5005
5172
|
if (ts.isYieldExpression(node) && node.expression && node.asteriskToken) {
|
|
5006
|
-
const type =
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5173
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
5174
|
+
if (type) {
|
|
5175
|
+
const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
|
|
5176
|
+
if (isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never) {
|
|
5177
|
+
const generatorFunctionOrReturnStatement = ts.findAncestor(
|
|
5178
|
+
node,
|
|
5179
|
+
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isReturnStatement(_) || ts.isThrowStatement(_)
|
|
5180
|
+
);
|
|
5181
|
+
if (generatorFunctionOrReturnStatement && !ts.isReturnStatement(generatorFunctionOrReturnStatement) && !ts.isThrowStatement(generatorFunctionOrReturnStatement)) {
|
|
5182
|
+
if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.parent) {
|
|
5183
|
+
const effectGenNode = generatorFunctionOrReturnStatement.parent;
|
|
5184
|
+
const effectGenLike = yield* pipe(
|
|
5185
|
+
typeParser.effectGen(effectGenNode),
|
|
5186
|
+
orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
|
|
5187
|
+
orElse2(() => typeParser.effectFnGen(effectGenNode)),
|
|
5188
|
+
option
|
|
5189
|
+
);
|
|
5190
|
+
if (isSome2(effectGenLike)) {
|
|
5191
|
+
const fix = node.expression ? [{
|
|
5192
|
+
fixName: "missingReturnYieldStar_fix",
|
|
5193
|
+
description: "Add return statement",
|
|
5194
|
+
apply: gen(function* () {
|
|
5195
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5196
|
+
changeTracker.replaceNode(
|
|
5197
|
+
sourceFile,
|
|
5198
|
+
node,
|
|
5199
|
+
ts.factory.createReturnStatement(
|
|
5200
|
+
node
|
|
5201
|
+
)
|
|
5202
|
+
);
|
|
5203
|
+
})
|
|
5204
|
+
}] : [];
|
|
5205
|
+
report({
|
|
5206
|
+
location: node,
|
|
5207
|
+
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.`,
|
|
5208
|
+
fixes: fix
|
|
5209
|
+
});
|
|
5210
|
+
}
|
|
5042
5211
|
}
|
|
5043
5212
|
}
|
|
5044
5213
|
}
|
|
@@ -5052,6 +5221,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
5052
5221
|
var missingStarInYieldEffectGen = createDiagnostic({
|
|
5053
5222
|
name: "missingStarInYieldEffectGen",
|
|
5054
5223
|
code: 4,
|
|
5224
|
+
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
5055
5225
|
severity: "error",
|
|
5056
5226
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
5057
5227
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -5126,11 +5296,12 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
5126
5296
|
var multipleEffectProvide = createDiagnostic({
|
|
5127
5297
|
name: "multipleEffectProvide",
|
|
5128
5298
|
code: 18,
|
|
5299
|
+
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
5129
5300
|
severity: "warning",
|
|
5130
5301
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
5131
5302
|
const ts = yield* service(TypeScriptApi);
|
|
5132
5303
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
5133
|
-
const
|
|
5304
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
5134
5305
|
const typeParser = yield* service(TypeParser);
|
|
5135
5306
|
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
|
|
5136
5307
|
sourceFile,
|
|
@@ -5145,7 +5316,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
5145
5316
|
const parseEffectProvideLayer = (node) => {
|
|
5146
5317
|
if (ts.isCallExpression(node) && node.arguments.length > 0) {
|
|
5147
5318
|
const layer = node.arguments[0];
|
|
5148
|
-
const type =
|
|
5319
|
+
const type = typeCheckerUtils.getTypeAtLocation(layer);
|
|
5320
|
+
if (!type) return void_;
|
|
5149
5321
|
return pipe(
|
|
5150
5322
|
typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression),
|
|
5151
5323
|
flatMap2(() => typeParser.layerType(type, layer)),
|
|
@@ -5223,6 +5395,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
5223
5395
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
5224
5396
|
name: "nonObjectEffectServiceType",
|
|
5225
5397
|
code: 24,
|
|
5398
|
+
description: "Ensures Effect.Service types are objects, not primitives",
|
|
5226
5399
|
severity: "error",
|
|
5227
5400
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
5228
5401
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -5261,12 +5434,13 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
5261
5434
|
fixes: []
|
|
5262
5435
|
};
|
|
5263
5436
|
if (propertyName === "succeed") {
|
|
5264
|
-
const valueType =
|
|
5265
|
-
if (isPrimitiveType(valueType)) {
|
|
5437
|
+
const valueType = typeCheckerUtils.getTypeAtLocation(propertyValue);
|
|
5438
|
+
if (valueType && isPrimitiveType(valueType)) {
|
|
5266
5439
|
report(errorToReport);
|
|
5267
5440
|
}
|
|
5268
5441
|
} else if (propertyName === "sync") {
|
|
5269
|
-
const valueType =
|
|
5442
|
+
const valueType = typeCheckerUtils.getTypeAtLocation(propertyValue);
|
|
5443
|
+
if (!valueType) continue;
|
|
5270
5444
|
const signatures = typeChecker.getSignaturesOfType(valueType, ts.SignatureKind.Call);
|
|
5271
5445
|
for (const signature of signatures) {
|
|
5272
5446
|
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
@@ -5276,7 +5450,8 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
5276
5450
|
}
|
|
5277
5451
|
}
|
|
5278
5452
|
} else if (propertyName === "effect" || propertyName === "scoped") {
|
|
5279
|
-
const valueType =
|
|
5453
|
+
const valueType = typeCheckerUtils.getTypeAtLocation(propertyValue);
|
|
5454
|
+
if (!valueType) continue;
|
|
5280
5455
|
const effectResult = yield* pipe(
|
|
5281
5456
|
typeParser.effectType(valueType, propertyValue),
|
|
5282
5457
|
orElse2(() => void_)
|
|
@@ -5623,7 +5798,8 @@ var annotate = createCodegen({
|
|
|
5623
5798
|
}
|
|
5624
5799
|
for (const variableDeclaration of variableDeclarations) {
|
|
5625
5800
|
if (!variableDeclaration.initializer) continue;
|
|
5626
|
-
const initializerType =
|
|
5801
|
+
const initializerType = typeCheckerUtils.getTypeAtLocation(variableDeclaration.initializer);
|
|
5802
|
+
if (!initializerType) continue;
|
|
5627
5803
|
const enclosingNode = ts.findAncestor(variableDeclaration, (_) => tsUtils.isDeclarationKind(_.kind)) || sourceFile;
|
|
5628
5804
|
const initializerTypeNode = fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
|
|
5629
5805
|
initializerType,
|
|
@@ -6075,7 +6251,7 @@ var findNodeToProcess = fn("StructuralSchemaGen.findNodeToProcess")(
|
|
|
6075
6251
|
function* (sourceFile, textRange) {
|
|
6076
6252
|
const ts = yield* service(TypeScriptApi);
|
|
6077
6253
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
6078
|
-
const
|
|
6254
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6079
6255
|
return pipe(
|
|
6080
6256
|
tsUtils.getAncestorNodesInRange(sourceFile, textRange),
|
|
6081
6257
|
filter((node) => ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)),
|
|
@@ -6084,7 +6260,7 @@ var findNodeToProcess = fn("StructuralSchemaGen.findNodeToProcess")(
|
|
|
6084
6260
|
map3((node) => ({
|
|
6085
6261
|
node,
|
|
6086
6262
|
identifier: node.name,
|
|
6087
|
-
type:
|
|
6263
|
+
type: typeCheckerUtils.getTypeAtLocation(node.name),
|
|
6088
6264
|
isExported: node.modifiers ? (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 : false
|
|
6089
6265
|
})),
|
|
6090
6266
|
filter(({ type }) => !!type),
|
|
@@ -6262,7 +6438,7 @@ var typeToSchema = createCodegen({
|
|
|
6262
6438
|
)
|
|
6263
6439
|
);
|
|
6264
6440
|
}
|
|
6265
|
-
const type =
|
|
6441
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.name);
|
|
6266
6442
|
if (!type) {
|
|
6267
6443
|
return yield* fail(
|
|
6268
6444
|
new CodegenNotApplicableError(
|
|
@@ -6343,6 +6519,7 @@ var codegens = [accessors, annotate, typeToSchema];
|
|
|
6343
6519
|
var outdatedEffectCodegen = createDiagnostic({
|
|
6344
6520
|
name: "outdatedEffectCodegen",
|
|
6345
6521
|
code: 19,
|
|
6522
|
+
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
6346
6523
|
severity: "warning",
|
|
6347
6524
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
6348
6525
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
@@ -6388,11 +6565,12 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
6388
6565
|
var overriddenSchemaConstructor = createDiagnostic({
|
|
6389
6566
|
name: "overriddenSchemaConstructor",
|
|
6390
6567
|
code: 30,
|
|
6568
|
+
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
6391
6569
|
severity: "error",
|
|
6392
6570
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
6393
6571
|
const ts = yield* service(TypeScriptApi);
|
|
6394
6572
|
const typeParser = yield* service(TypeParser);
|
|
6395
|
-
const
|
|
6573
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6396
6574
|
function isAllowedConstructor(node) {
|
|
6397
6575
|
if (node.body && node.body.statements.length === 1) {
|
|
6398
6576
|
const expressionStatement = node.body.statements[0];
|
|
@@ -6426,7 +6604,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
6426
6604
|
for (const heritageClause of node.heritageClauses) {
|
|
6427
6605
|
if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
6428
6606
|
for (const type of heritageClause.types) {
|
|
6429
|
-
const typeAtLocation =
|
|
6607
|
+
const typeAtLocation = typeCheckerUtils.getTypeAtLocation(type.expression);
|
|
6608
|
+
if (!typeAtLocation) continue;
|
|
6430
6609
|
const isSchema = yield* pipe(
|
|
6431
6610
|
typeParser.effectSchemaType(typeAtLocation, type.expression),
|
|
6432
6611
|
map4(() => true),
|
|
@@ -6523,10 +6702,11 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
6523
6702
|
var returnEffectInGen = createDiagnostic({
|
|
6524
6703
|
name: "returnEffectInGen",
|
|
6525
6704
|
code: 11,
|
|
6705
|
+
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
6526
6706
|
severity: "suggestion",
|
|
6527
6707
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
6528
6708
|
const ts = yield* service(TypeScriptApi);
|
|
6529
|
-
const
|
|
6709
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6530
6710
|
const typeParser = yield* service(TypeParser);
|
|
6531
6711
|
const nodeToVisit = [];
|
|
6532
6712
|
const appendNodeToVisit = (node) => {
|
|
@@ -6544,7 +6724,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
6544
6724
|
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
|
|
6545
6725
|
);
|
|
6546
6726
|
if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
|
|
6547
|
-
const type =
|
|
6727
|
+
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
6728
|
+
if (!type) continue;
|
|
6548
6729
|
const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
6549
6730
|
if (isSome2(maybeEffect)) {
|
|
6550
6731
|
if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
|
|
@@ -6590,6 +6771,7 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
6590
6771
|
var runEffectInsideEffect = createDiagnostic({
|
|
6591
6772
|
name: "runEffectInsideEffect",
|
|
6592
6773
|
code: 32,
|
|
6774
|
+
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
6593
6775
|
severity: "suggestion",
|
|
6594
6776
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
6595
6777
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6729,6 +6911,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
6729
6911
|
var schemaStructWithTag = createDiagnostic({
|
|
6730
6912
|
name: "schemaStructWithTag",
|
|
6731
6913
|
code: 34,
|
|
6914
|
+
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
6732
6915
|
severity: "suggestion",
|
|
6733
6916
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
6734
6917
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6808,6 +6991,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
6808
6991
|
var schemaUnionOfLiterals = createDiagnostic({
|
|
6809
6992
|
name: "schemaUnionOfLiterals",
|
|
6810
6993
|
code: 33,
|
|
6994
|
+
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
6811
6995
|
severity: "off",
|
|
6812
6996
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
6813
6997
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6881,6 +7065,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
6881
7065
|
var scopeInLayerEffect = createDiagnostic({
|
|
6882
7066
|
name: "scopeInLayerEffect",
|
|
6883
7067
|
code: 13,
|
|
7068
|
+
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
6884
7069
|
severity: "warning",
|
|
6885
7070
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
6886
7071
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -6939,12 +7124,14 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
6939
7124
|
const node = nodeToVisit.shift();
|
|
6940
7125
|
const layerEffectApiCall = parseLayerEffectApiCall(node);
|
|
6941
7126
|
if (layerEffectApiCall) {
|
|
6942
|
-
const type =
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
7127
|
+
const type = typeCheckerUtils.getTypeAtLocation(node);
|
|
7128
|
+
if (type) {
|
|
7129
|
+
yield* pipe(
|
|
7130
|
+
typeParser.layerType(type, node),
|
|
7131
|
+
flatMap2(({ RIn }) => reportIfLayerRequireScope(RIn, node, layerEffectApiCall.methodIdentifier)),
|
|
7132
|
+
ignore
|
|
7133
|
+
);
|
|
7134
|
+
}
|
|
6948
7135
|
continue;
|
|
6949
7136
|
}
|
|
6950
7137
|
if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
@@ -6972,6 +7159,7 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
6972
7159
|
var strictBooleanExpressions = createDiagnostic({
|
|
6973
7160
|
name: "strictBooleanExpressions",
|
|
6974
7161
|
code: 17,
|
|
7162
|
+
description: "Enforces boolean types in conditional expressions for type safety",
|
|
6975
7163
|
severity: "off",
|
|
6976
7164
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
6977
7165
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7013,7 +7201,8 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
7013
7201
|
if (!nodeToCheck) continue;
|
|
7014
7202
|
if (!conditionChecks.has(nodeToCheck.parent)) continue;
|
|
7015
7203
|
if (!ts.isExpression(nodeToCheck)) continue;
|
|
7016
|
-
const nodeType =
|
|
7204
|
+
const nodeType = typeCheckerUtils.getTypeAtLocation(nodeToCheck);
|
|
7205
|
+
if (!nodeType) continue;
|
|
7017
7206
|
const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
|
|
7018
7207
|
let typesToCheck = [constrainedType || nodeType];
|
|
7019
7208
|
while (typesToCheck.length > 0) {
|
|
@@ -7041,10 +7230,11 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
7041
7230
|
var strictEffectProvide = createDiagnostic({
|
|
7042
7231
|
name: "strictEffectProvide",
|
|
7043
7232
|
code: 27,
|
|
7233
|
+
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
7044
7234
|
severity: "off",
|
|
7045
7235
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
7046
7236
|
const ts = yield* service(TypeScriptApi);
|
|
7047
|
-
const
|
|
7237
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7048
7238
|
const typeParser = yield* service(TypeParser);
|
|
7049
7239
|
const parseEffectProvideWithLayer = (node) => gen(function* () {
|
|
7050
7240
|
if (!ts.isCallExpression(node) || node.arguments.length === 0) {
|
|
@@ -7053,7 +7243,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
7053
7243
|
yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
|
|
7054
7244
|
return yield* firstSuccessOf(
|
|
7055
7245
|
node.arguments.map((arg) => {
|
|
7056
|
-
const argType =
|
|
7246
|
+
const argType = typeCheckerUtils.getTypeAtLocation(arg);
|
|
7247
|
+
if (!argType) return typeParserIssue("Could not get argument type");
|
|
7057
7248
|
return typeParser.layerType(argType, arg);
|
|
7058
7249
|
})
|
|
7059
7250
|
);
|
|
@@ -7085,6 +7276,7 @@ var strictEffectProvide = createDiagnostic({
|
|
|
7085
7276
|
var tryCatchInEffectGen = createDiagnostic({
|
|
7086
7277
|
name: "tryCatchInEffectGen",
|
|
7087
7278
|
code: 15,
|
|
7279
|
+
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
7088
7280
|
severity: "suggestion",
|
|
7089
7281
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
7090
7282
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7130,6 +7322,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
7130
7322
|
var unknownInEffectCatch = createDiagnostic({
|
|
7131
7323
|
name: "unknownInEffectCatch",
|
|
7132
7324
|
code: 31,
|
|
7325
|
+
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
7133
7326
|
severity: "warning",
|
|
7134
7327
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
7135
7328
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7187,6 +7380,7 @@ Consider wrapping unknown errors into Effect's Data.TaggedError for example, or
|
|
|
7187
7380
|
var unnecessaryEffectGen = createDiagnostic({
|
|
7188
7381
|
name: "unnecessaryEffectGen",
|
|
7189
7382
|
code: 5,
|
|
7383
|
+
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
7190
7384
|
severity: "suggestion",
|
|
7191
7385
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
7192
7386
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7230,15 +7424,12 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
7230
7424
|
var unnecessaryFailYieldableError = createDiagnostic({
|
|
7231
7425
|
name: "unnecessaryFailYieldableError",
|
|
7232
7426
|
code: 29,
|
|
7427
|
+
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
7233
7428
|
severity: "suggestion",
|
|
7234
7429
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
7235
7430
|
const ts = yield* service(TypeScriptApi);
|
|
7236
7431
|
const typeParser = yield* service(TypeParser);
|
|
7237
|
-
const
|
|
7238
|
-
const yieldableErrorTypes = yield* pipe(
|
|
7239
|
-
typeParser.effectCauseYieldableErrorTypes(sourceFile),
|
|
7240
|
-
orElse2(() => succeed([]))
|
|
7241
|
-
);
|
|
7432
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7242
7433
|
const nodeToVisit = [];
|
|
7243
7434
|
const appendNodeToVisit = (node) => {
|
|
7244
7435
|
nodeToVisit.push(node);
|
|
@@ -7252,32 +7443,34 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
7252
7443
|
const callExpression = node.expression;
|
|
7253
7444
|
yield* pipe(
|
|
7254
7445
|
typeParser.isNodeReferenceToEffectModuleApi("fail")(callExpression.expression),
|
|
7255
|
-
|
|
7446
|
+
flatMap2(() => {
|
|
7256
7447
|
if (callExpression.arguments.length > 0) {
|
|
7257
7448
|
const failArgument = callExpression.arguments[0];
|
|
7258
|
-
const argumentType =
|
|
7259
|
-
|
|
7260
|
-
|
|
7449
|
+
const argumentType = typeCheckerUtils.getTypeAtLocation(failArgument);
|
|
7450
|
+
if (!argumentType) return void_;
|
|
7451
|
+
return pipe(
|
|
7452
|
+
typeParser.extendsCauseYieldableError(argumentType),
|
|
7453
|
+
map4(
|
|
7454
|
+
() => report({
|
|
7455
|
+
location: node,
|
|
7456
|
+
messageText: `This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead.`,
|
|
7457
|
+
fixes: [{
|
|
7458
|
+
fixName: "unnecessaryFailYieldableError_fix",
|
|
7459
|
+
description: "Replace yield* Effect.fail with yield*",
|
|
7460
|
+
apply: gen(function* () {
|
|
7461
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
7462
|
+
changeTracker.replaceNode(
|
|
7463
|
+
sourceFile,
|
|
7464
|
+
callExpression,
|
|
7465
|
+
failArgument
|
|
7466
|
+
);
|
|
7467
|
+
})
|
|
7468
|
+
}]
|
|
7469
|
+
})
|
|
7470
|
+
)
|
|
7261
7471
|
);
|
|
7262
|
-
if (isYieldableError) {
|
|
7263
|
-
report({
|
|
7264
|
-
location: node,
|
|
7265
|
-
messageText: `This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead.`,
|
|
7266
|
-
fixes: [{
|
|
7267
|
-
fixName: "unnecessaryFailYieldableError_fix",
|
|
7268
|
-
description: "Replace yield* Effect.fail with yield*",
|
|
7269
|
-
apply: gen(function* () {
|
|
7270
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
7271
|
-
changeTracker.replaceNode(
|
|
7272
|
-
sourceFile,
|
|
7273
|
-
callExpression,
|
|
7274
|
-
failArgument
|
|
7275
|
-
);
|
|
7276
|
-
})
|
|
7277
|
-
}]
|
|
7278
|
-
});
|
|
7279
|
-
}
|
|
7280
7472
|
}
|
|
7473
|
+
return void_;
|
|
7281
7474
|
}),
|
|
7282
7475
|
ignore
|
|
7283
7476
|
);
|
|
@@ -7290,6 +7483,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
7290
7483
|
var unnecessaryPipe = createDiagnostic({
|
|
7291
7484
|
name: "unnecessaryPipe",
|
|
7292
7485
|
code: 9,
|
|
7486
|
+
description: "Removes pipe calls with no arguments",
|
|
7293
7487
|
severity: "suggestion",
|
|
7294
7488
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
7295
7489
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7335,6 +7529,7 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
7335
7529
|
var unnecessaryPipeChain = createDiagnostic({
|
|
7336
7530
|
name: "unnecessaryPipeChain",
|
|
7337
7531
|
code: 16,
|
|
7532
|
+
description: "Simplifies chained pipe calls into a single pipe call",
|
|
7338
7533
|
severity: "suggestion",
|
|
7339
7534
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
7340
7535
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7409,6 +7604,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
7409
7604
|
var unsupportedServiceAccessors = createDiagnostic({
|
|
7410
7605
|
name: "unsupportedServiceAccessors",
|
|
7411
7606
|
code: 21,
|
|
7607
|
+
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
7412
7608
|
severity: "warning",
|
|
7413
7609
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
7414
7610
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -7496,7 +7692,8 @@ var diagnostics = [
|
|
|
7496
7692
|
unknownInEffectCatch,
|
|
7497
7693
|
runEffectInsideEffect,
|
|
7498
7694
|
schemaUnionOfLiterals,
|
|
7499
|
-
schemaStructWithTag
|
|
7695
|
+
schemaStructWithTag,
|
|
7696
|
+
globalErrorInEffectFailure
|
|
7500
7697
|
];
|
|
7501
7698
|
|
|
7502
7699
|
// src/transform.ts
|