@effect/language-service 0.78.0 → 0.80.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 +67 -44
- package/cli.js +497 -10
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +456 -4
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +473 -12
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +450 -4
- package/transform.js.map +1 -1
|
@@ -1637,10 +1637,151 @@ var defaults = {
|
|
|
1637
1637
|
extendedKeyDetection: false,
|
|
1638
1638
|
ignoreEffectWarningsInTscExitCode: false,
|
|
1639
1639
|
ignoreEffectSuggestionsInTscExitCode: true,
|
|
1640
|
+
ignoreEffectErrorsInTscExitCode: false,
|
|
1640
1641
|
pipeableMinArgCount: 2,
|
|
1641
1642
|
effectFn: ["span"],
|
|
1642
1643
|
layerGraphFollowDepth: 0,
|
|
1643
|
-
mermaidProvider: "mermaid.live"
|
|
1644
|
+
mermaidProvider: "mermaid.live",
|
|
1645
|
+
skipDisabledOptimization: false
|
|
1646
|
+
};
|
|
1647
|
+
var booleanSchema = (description, defaultValue) => ({
|
|
1648
|
+
type: "boolean",
|
|
1649
|
+
description,
|
|
1650
|
+
default: defaultValue
|
|
1651
|
+
});
|
|
1652
|
+
var stringArraySchema = (description, defaultValue) => ({
|
|
1653
|
+
type: "array",
|
|
1654
|
+
description,
|
|
1655
|
+
default: defaultValue,
|
|
1656
|
+
items: { type: "string" }
|
|
1657
|
+
});
|
|
1658
|
+
var stringEnumSchema = (description, values, defaultValue) => ({
|
|
1659
|
+
type: "string",
|
|
1660
|
+
description,
|
|
1661
|
+
enum: values,
|
|
1662
|
+
default: defaultValue
|
|
1663
|
+
});
|
|
1664
|
+
var languageServicePluginAdditionalPropertiesJsonSchema = {
|
|
1665
|
+
refactors: booleanSchema("Controls Effect refactors.", defaults.refactors),
|
|
1666
|
+
diagnostics: booleanSchema("Controls Effect diagnostics.", defaults.diagnostics),
|
|
1667
|
+
diagnosticsName: booleanSchema(
|
|
1668
|
+
"Controls whether to include the rule name in diagnostic messages.",
|
|
1669
|
+
defaults.diagnosticsName
|
|
1670
|
+
),
|
|
1671
|
+
missingDiagnosticNextLine: stringEnumSchema(
|
|
1672
|
+
"Controls the severity of warnings for unused @effect-diagnostics-next-line comments.",
|
|
1673
|
+
["off", "error", "warning", "message", "suggestion"],
|
|
1674
|
+
defaults.missingDiagnosticNextLine
|
|
1675
|
+
),
|
|
1676
|
+
includeSuggestionsInTsc: booleanSchema(
|
|
1677
|
+
"When patch mode is enabled, reports suggestion diagnostics as messages in TSC with a [suggestion] prefix.",
|
|
1678
|
+
defaults.includeSuggestionsInTsc
|
|
1679
|
+
),
|
|
1680
|
+
ignoreEffectWarningsInTscExitCode: booleanSchema(
|
|
1681
|
+
"When enabled, Effect warnings do not affect the patched tsc exit code.",
|
|
1682
|
+
defaults.ignoreEffectWarningsInTscExitCode
|
|
1683
|
+
),
|
|
1684
|
+
ignoreEffectErrorsInTscExitCode: booleanSchema(
|
|
1685
|
+
"When enabled, Effect errors do not affect the patched tsc exit code.",
|
|
1686
|
+
defaults.ignoreEffectErrorsInTscExitCode
|
|
1687
|
+
),
|
|
1688
|
+
ignoreEffectSuggestionsInTscExitCode: booleanSchema(
|
|
1689
|
+
"When enabled, Effect suggestions do not affect the patched tsc exit code.",
|
|
1690
|
+
defaults.ignoreEffectSuggestionsInTscExitCode
|
|
1691
|
+
),
|
|
1692
|
+
quickinfoEffectParameters: stringEnumSchema(
|
|
1693
|
+
"Controls when Effect quickinfo should include full type parameters.",
|
|
1694
|
+
["always", "never", "whentruncated"],
|
|
1695
|
+
defaults.quickinfoEffectParameters
|
|
1696
|
+
),
|
|
1697
|
+
quickinfo: booleanSchema("Controls Effect quickinfo.", defaults.quickinfo),
|
|
1698
|
+
quickinfoMaximumLength: {
|
|
1699
|
+
type: "number",
|
|
1700
|
+
description: "Controls the maximum quickinfo length. Use -1 to disable truncation.",
|
|
1701
|
+
default: defaults.quickinfoMaximumLength
|
|
1702
|
+
},
|
|
1703
|
+
keyPatterns: {
|
|
1704
|
+
type: "array",
|
|
1705
|
+
description: "Configures key patterns used for generated Effect service and error keys.",
|
|
1706
|
+
default: defaults.keyPatterns,
|
|
1707
|
+
items: {
|
|
1708
|
+
type: "object",
|
|
1709
|
+
properties: {
|
|
1710
|
+
target: stringEnumSchema("The key builder target.", ["service", "error", "custom"], "service"),
|
|
1711
|
+
pattern: stringEnumSchema(
|
|
1712
|
+
"The key generation pattern.",
|
|
1713
|
+
["package-identifier", "default", "default-hashed"],
|
|
1714
|
+
"default"
|
|
1715
|
+
),
|
|
1716
|
+
skipLeadingPath: stringArraySchema("Path prefixes to strip before generating keys.", ["src/"])
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
},
|
|
1720
|
+
extendedKeyDetection: booleanSchema(
|
|
1721
|
+
"Enables extended heuristics when detecting key sources.",
|
|
1722
|
+
defaults.extendedKeyDetection
|
|
1723
|
+
),
|
|
1724
|
+
completions: booleanSchema("Controls Effect completions.", defaults.completions),
|
|
1725
|
+
goto: booleanSchema("Controls Effect goto references support.", defaults.goto),
|
|
1726
|
+
inlays: booleanSchema("Controls Effect inlay hints.", defaults.inlays),
|
|
1727
|
+
allowedDuplicatedPackages: stringArraySchema(
|
|
1728
|
+
"Package names that are allowed to duplicate Effect as a peer dependency.",
|
|
1729
|
+
defaults.allowedDuplicatedPackages
|
|
1730
|
+
),
|
|
1731
|
+
namespaceImportPackages: stringArraySchema(
|
|
1732
|
+
"Package names that should prefer namespace imports.",
|
|
1733
|
+
defaults.namespaceImportPackages
|
|
1734
|
+
),
|
|
1735
|
+
topLevelNamedReexports: stringEnumSchema(
|
|
1736
|
+
"For namespaceImportPackages, controls how top-level named re-exports are handled.",
|
|
1737
|
+
["ignore", "follow"],
|
|
1738
|
+
defaults.topLevelNamedReexports
|
|
1739
|
+
),
|
|
1740
|
+
barrelImportPackages: stringArraySchema(
|
|
1741
|
+
"Package names that should prefer imports from their top-level barrel file.",
|
|
1742
|
+
defaults.barrelImportPackages
|
|
1743
|
+
),
|
|
1744
|
+
importAliases: {
|
|
1745
|
+
type: "object",
|
|
1746
|
+
description: "Custom aliases to use for imported identifiers.",
|
|
1747
|
+
default: defaults.importAliases,
|
|
1748
|
+
additionalProperties: {
|
|
1749
|
+
type: "string"
|
|
1750
|
+
}
|
|
1751
|
+
},
|
|
1752
|
+
renames: booleanSchema("Controls Effect rename helpers.", defaults.renames),
|
|
1753
|
+
noExternal: booleanSchema(
|
|
1754
|
+
"Disables features that link to external websites.",
|
|
1755
|
+
defaults.noExternal
|
|
1756
|
+
),
|
|
1757
|
+
pipeableMinArgCount: {
|
|
1758
|
+
type: "number",
|
|
1759
|
+
description: "Minimum argument count required before pipeable suggestions are emitted.",
|
|
1760
|
+
default: defaults.pipeableMinArgCount
|
|
1761
|
+
},
|
|
1762
|
+
effectFn: {
|
|
1763
|
+
type: "array",
|
|
1764
|
+
description: "Configures which Effect.fn variants should be suggested.",
|
|
1765
|
+
default: defaults.effectFn,
|
|
1766
|
+
items: {
|
|
1767
|
+
type: "string",
|
|
1768
|
+
enum: ["untraced", "span", "suggested-span", "inferred-span", "no-span"]
|
|
1769
|
+
}
|
|
1770
|
+
},
|
|
1771
|
+
layerGraphFollowDepth: {
|
|
1772
|
+
type: "number",
|
|
1773
|
+
description: "Controls how deeply layer graph analysis follows dependencies.",
|
|
1774
|
+
default: defaults.layerGraphFollowDepth
|
|
1775
|
+
},
|
|
1776
|
+
mermaidProvider: {
|
|
1777
|
+
type: "string",
|
|
1778
|
+
description: "Controls which Mermaid renderer is used for layer graphs.",
|
|
1779
|
+
default: defaults.mermaidProvider
|
|
1780
|
+
},
|
|
1781
|
+
skipDisabledOptimization: booleanSchema(
|
|
1782
|
+
"When enabled, disabled diagnostics are still processed so comment-based overrides can be honored.",
|
|
1783
|
+
defaults.skipDisabledOptimization
|
|
1784
|
+
)
|
|
1644
1785
|
};
|
|
1645
1786
|
function parseKeyPatterns(patterns) {
|
|
1646
1787
|
const result = [];
|
|
@@ -1664,6 +1805,7 @@ function parse(config) {
|
|
|
1664
1805
|
includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
|
|
1665
1806
|
ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
|
|
1666
1807
|
ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
|
|
1808
|
+
ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
|
|
1667
1809
|
quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
|
|
1668
1810
|
quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
|
|
1669
1811
|
quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
|
|
@@ -1684,7 +1826,8 @@ function parse(config) {
|
|
|
1684
1826
|
(_) => _.toLowerCase()
|
|
1685
1827
|
) : defaults.effectFn,
|
|
1686
1828
|
layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
|
|
1687
|
-
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
|
|
1829
|
+
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
|
|
1830
|
+
skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
|
|
1688
1831
|
};
|
|
1689
1832
|
}
|
|
1690
1833
|
|
|
@@ -2454,7 +2597,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
2454
2597
|
if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
|
|
2455
2598
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2456
2599
|
}
|
|
2457
|
-
if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2600
|
+
if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2458
2601
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2459
2602
|
}
|
|
2460
2603
|
const fixByDisableNextLine = (node) => ({
|
|
@@ -5131,6 +5274,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
5131
5274
|
code: 28,
|
|
5132
5275
|
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
5133
5276
|
severity: "off",
|
|
5277
|
+
fixable: false,
|
|
5278
|
+
supportedEffect: ["v3", "v4"],
|
|
5134
5279
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
5135
5280
|
const ts = yield* service(TypeScriptApi);
|
|
5136
5281
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -5234,6 +5379,8 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5234
5379
|
code: 39,
|
|
5235
5380
|
description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
|
|
5236
5381
|
severity: "suggestion",
|
|
5382
|
+
fixable: true,
|
|
5383
|
+
supportedEffect: ["v3", "v4"],
|
|
5237
5384
|
apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
|
|
5238
5385
|
const ts = yield* service(TypeScriptApi);
|
|
5239
5386
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5331,6 +5478,8 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5331
5478
|
code: 2,
|
|
5332
5479
|
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
5333
5480
|
severity: "suggestion",
|
|
5481
|
+
fixable: false,
|
|
5482
|
+
supportedEffect: ["v3", "v4"],
|
|
5334
5483
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
5335
5484
|
const ts = yield* service(TypeScriptApi);
|
|
5336
5485
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5380,6 +5529,8 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5380
5529
|
code: 20,
|
|
5381
5530
|
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
5382
5531
|
severity: "error",
|
|
5532
|
+
fixable: true,
|
|
5533
|
+
supportedEffect: ["v3", "v4"],
|
|
5383
5534
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
5384
5535
|
const ts = yield* service(TypeScriptApi);
|
|
5385
5536
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5518,6 +5669,8 @@ var deterministicKeys = createDiagnostic({
|
|
|
5518
5669
|
code: 25,
|
|
5519
5670
|
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
5520
5671
|
severity: "off",
|
|
5672
|
+
fixable: true,
|
|
5673
|
+
supportedEffect: ["v3", "v4"],
|
|
5521
5674
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
5522
5675
|
const ts = yield* service(TypeScriptApi);
|
|
5523
5676
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5635,6 +5788,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5635
5788
|
code: 6,
|
|
5636
5789
|
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
5637
5790
|
severity: "warning",
|
|
5791
|
+
fixable: false,
|
|
5792
|
+
supportedEffect: ["v3", "v4"],
|
|
5638
5793
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
5639
5794
|
const typeParser = yield* service(TypeParser);
|
|
5640
5795
|
const options = yield* service(LanguageServicePluginOptions);
|
|
@@ -5664,6 +5819,8 @@ var effectFnIife = createDiagnostic({
|
|
|
5664
5819
|
code: 46,
|
|
5665
5820
|
description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
|
|
5666
5821
|
severity: "warning",
|
|
5822
|
+
fixable: true,
|
|
5823
|
+
supportedEffect: ["v3", "v4"],
|
|
5667
5824
|
apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
|
|
5668
5825
|
const ts = yield* service(TypeScriptApi);
|
|
5669
5826
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5766,6 +5923,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5766
5923
|
code: 41,
|
|
5767
5924
|
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
5768
5925
|
severity: "suggestion",
|
|
5926
|
+
fixable: true,
|
|
5927
|
+
supportedEffect: ["v3", "v4"],
|
|
5769
5928
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
5770
5929
|
const ts = yield* service(TypeScriptApi);
|
|
5771
5930
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6358,6 +6517,8 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
6358
6517
|
code: 23,
|
|
6359
6518
|
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
6360
6519
|
severity: "warning",
|
|
6520
|
+
fixable: false,
|
|
6521
|
+
supportedEffect: ["v3", "v4"],
|
|
6361
6522
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
6362
6523
|
const ts = yield* service(TypeScriptApi);
|
|
6363
6524
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6396,6 +6557,8 @@ var effectInFailure = createDiagnostic({
|
|
|
6396
6557
|
code: 49,
|
|
6397
6558
|
description: "Warns when an Effect is used inside an Effect failure channel",
|
|
6398
6559
|
severity: "warning",
|
|
6560
|
+
fixable: false,
|
|
6561
|
+
supportedEffect: ["v3", "v4"],
|
|
6399
6562
|
apply: fn("effectInFailure.apply")(function* (sourceFile, report) {
|
|
6400
6563
|
const ts = yield* service(TypeScriptApi);
|
|
6401
6564
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6460,6 +6623,8 @@ var effectInVoidSuccess = createDiagnostic({
|
|
|
6460
6623
|
code: 14,
|
|
6461
6624
|
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
6462
6625
|
severity: "warning",
|
|
6626
|
+
fixable: false,
|
|
6627
|
+
supportedEffect: ["v3", "v4"],
|
|
6463
6628
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
6464
6629
|
const ts = yield* service(TypeScriptApi);
|
|
6465
6630
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6509,6 +6674,8 @@ var effectMapVoid = createDiagnostic({
|
|
|
6509
6674
|
code: 40,
|
|
6510
6675
|
description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
|
|
6511
6676
|
severity: "suggestion",
|
|
6677
|
+
fixable: true,
|
|
6678
|
+
supportedEffect: ["v3", "v4"],
|
|
6512
6679
|
apply: fn("effectMapVoid.apply")(function* (sourceFile, report) {
|
|
6513
6680
|
const ts = yield* service(TypeScriptApi);
|
|
6514
6681
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6573,6 +6740,8 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6573
6740
|
code: 47,
|
|
6574
6741
|
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
6575
6742
|
severity: "suggestion",
|
|
6743
|
+
fixable: true,
|
|
6744
|
+
supportedEffect: ["v3", "v4"],
|
|
6576
6745
|
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
6577
6746
|
const ts = yield* service(TypeScriptApi);
|
|
6578
6747
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6618,12 +6787,66 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6618
6787
|
})
|
|
6619
6788
|
});
|
|
6620
6789
|
|
|
6790
|
+
// src/diagnostics/extendsNativeError.ts
|
|
6791
|
+
var extendsNativeError = createDiagnostic({
|
|
6792
|
+
name: "extendsNativeError",
|
|
6793
|
+
code: 50,
|
|
6794
|
+
description: "Warns when a class directly extends the native Error class",
|
|
6795
|
+
severity: "off",
|
|
6796
|
+
fixable: false,
|
|
6797
|
+
supportedEffect: ["v3", "v4"],
|
|
6798
|
+
apply: fn("extendsNativeError.apply")(function* (sourceFile, report) {
|
|
6799
|
+
const ts = yield* service(TypeScriptApi);
|
|
6800
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6801
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
6802
|
+
if (!errorSymbol) return;
|
|
6803
|
+
const nodeToVisit = [];
|
|
6804
|
+
const appendNodeToVisit = (node) => {
|
|
6805
|
+
nodeToVisit.push(node);
|
|
6806
|
+
return void 0;
|
|
6807
|
+
};
|
|
6808
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
6809
|
+
while (nodeToVisit.length > 0) {
|
|
6810
|
+
const node = nodeToVisit.shift();
|
|
6811
|
+
if (ts.isClassDeclaration(node) && node.heritageClauses) {
|
|
6812
|
+
for (const clause of node.heritageClauses) {
|
|
6813
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
6814
|
+
const typeExpression = clause.types[0].expression;
|
|
6815
|
+
const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
|
|
6816
|
+
const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
|
|
6817
|
+
const isNativeError = resolvedSymbol === errorSymbol || (() => {
|
|
6818
|
+
if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
|
|
6819
|
+
const exprType = typeChecker.getTypeAtLocation(typeExpression);
|
|
6820
|
+
const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
|
|
6821
|
+
if (constructSignatures.length > 0) {
|
|
6822
|
+
const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
|
|
6823
|
+
return instanceType.symbol === errorSymbol;
|
|
6824
|
+
}
|
|
6825
|
+
return false;
|
|
6826
|
+
})();
|
|
6827
|
+
if (isNativeError) {
|
|
6828
|
+
report({
|
|
6829
|
+
location: node.name ?? typeExpression,
|
|
6830
|
+
messageText: "Avoid extending the native 'Error' class directly. Consider using a tagged error (e.g. Data.TaggedError) to maintain type safety in the Effect failure channel.",
|
|
6831
|
+
fixes: []
|
|
6832
|
+
});
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
6838
|
+
}
|
|
6839
|
+
})
|
|
6840
|
+
});
|
|
6841
|
+
|
|
6621
6842
|
// src/diagnostics/floatingEffect.ts
|
|
6622
6843
|
var floatingEffect = createDiagnostic({
|
|
6623
6844
|
name: "floatingEffect",
|
|
6624
6845
|
code: 3,
|
|
6625
6846
|
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
6626
6847
|
severity: "error",
|
|
6848
|
+
fixable: false,
|
|
6849
|
+
supportedEffect: ["v3", "v4"],
|
|
6627
6850
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
6628
6851
|
const ts = yield* service(TypeScriptApi);
|
|
6629
6852
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6675,6 +6898,8 @@ var genericEffectServices = createDiagnostic({
|
|
|
6675
6898
|
code: 10,
|
|
6676
6899
|
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
6677
6900
|
severity: "warning",
|
|
6901
|
+
fixable: false,
|
|
6902
|
+
supportedEffect: ["v3", "v4"],
|
|
6678
6903
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
6679
6904
|
const ts = yield* service(TypeScriptApi);
|
|
6680
6905
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6722,6 +6947,8 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
6722
6947
|
code: 36,
|
|
6723
6948
|
description: "Warns when catch callbacks return global Error type instead of typed errors",
|
|
6724
6949
|
severity: "warning",
|
|
6950
|
+
fixable: false,
|
|
6951
|
+
supportedEffect: ["v3", "v4"],
|
|
6725
6952
|
apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
|
|
6726
6953
|
const ts = yield* service(TypeScriptApi);
|
|
6727
6954
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6782,6 +7009,8 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
6782
7009
|
code: 35,
|
|
6783
7010
|
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
6784
7011
|
severity: "warning",
|
|
7012
|
+
fixable: false,
|
|
7013
|
+
supportedEffect: ["v3", "v4"],
|
|
6785
7014
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
6786
7015
|
const ts = yield* service(TypeScriptApi);
|
|
6787
7016
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6835,6 +7064,8 @@ var importFromBarrel = createDiagnostic({
|
|
|
6835
7064
|
code: 12,
|
|
6836
7065
|
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
6837
7066
|
severity: "off",
|
|
7067
|
+
fixable: true,
|
|
7068
|
+
supportedEffect: ["v3", "v4"],
|
|
6838
7069
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
6839
7070
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
6840
7071
|
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
|
|
@@ -6975,6 +7206,8 @@ var instanceOfSchema = createDiagnostic({
|
|
|
6975
7206
|
code: 45,
|
|
6976
7207
|
description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
6977
7208
|
severity: "off",
|
|
7209
|
+
fixable: true,
|
|
7210
|
+
supportedEffect: ["v3", "v4"],
|
|
6978
7211
|
apply: fn("instanceOfSchema.apply")(function* (sourceFile, report) {
|
|
6979
7212
|
const ts = yield* service(TypeScriptApi);
|
|
6980
7213
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7038,6 +7271,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
|
|
|
7038
7271
|
code: 37,
|
|
7039
7272
|
description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
|
|
7040
7273
|
severity: "warning",
|
|
7274
|
+
fixable: true,
|
|
7275
|
+
supportedEffect: ["v3", "v4"],
|
|
7041
7276
|
apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
|
|
7042
7277
|
const ts = yield* service(TypeScriptApi);
|
|
7043
7278
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7151,6 +7386,8 @@ var leakingRequirements = createDiagnostic({
|
|
|
7151
7386
|
code: 8,
|
|
7152
7387
|
description: "Detects implementation services leaked in service methods",
|
|
7153
7388
|
severity: "suggestion",
|
|
7389
|
+
fixable: false,
|
|
7390
|
+
supportedEffect: ["v3", "v4"],
|
|
7154
7391
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
7155
7392
|
const ts = yield* service(TypeScriptApi);
|
|
7156
7393
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7305,6 +7542,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
7305
7542
|
code: 26,
|
|
7306
7543
|
description: "Enforces the use of pipeable style for nested function calls",
|
|
7307
7544
|
severity: "off",
|
|
7545
|
+
fixable: true,
|
|
7546
|
+
supportedEffect: ["v3", "v4"],
|
|
7308
7547
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
7309
7548
|
const ts = yield* service(TypeScriptApi);
|
|
7310
7549
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7485,6 +7724,8 @@ var missingEffectContext = createDiagnostic({
|
|
|
7485
7724
|
code: 1,
|
|
7486
7725
|
description: "Reports missing service requirements in Effect context channel",
|
|
7487
7726
|
severity: "error",
|
|
7727
|
+
fixable: false,
|
|
7728
|
+
supportedEffect: ["v3", "v4"],
|
|
7488
7729
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
7489
7730
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7490
7731
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7534,6 +7775,8 @@ var missingEffectError = createDiagnostic({
|
|
|
7534
7775
|
code: 1,
|
|
7535
7776
|
description: "Reports missing error types in Effect error channel",
|
|
7536
7777
|
severity: "error",
|
|
7778
|
+
fixable: true,
|
|
7779
|
+
supportedEffect: ["v3", "v4"],
|
|
7537
7780
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
7538
7781
|
const ts = yield* service(TypeScriptApi);
|
|
7539
7782
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -7675,6 +7918,8 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
7675
7918
|
code: 22,
|
|
7676
7919
|
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
7677
7920
|
severity: "off",
|
|
7921
|
+
fixable: false,
|
|
7922
|
+
supportedEffect: ["v3"],
|
|
7678
7923
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
7679
7924
|
const ts = yield* service(TypeScriptApi);
|
|
7680
7925
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7769,6 +8014,8 @@ var missingLayerContext = createDiagnostic({
|
|
|
7769
8014
|
code: 38,
|
|
7770
8015
|
description: "Reports missing service requirements in Layer context channel",
|
|
7771
8016
|
severity: "error",
|
|
8017
|
+
fixable: false,
|
|
8018
|
+
supportedEffect: ["v3", "v4"],
|
|
7772
8019
|
apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
|
|
7773
8020
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7774
8021
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7818,6 +8065,8 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
7818
8065
|
code: 7,
|
|
7819
8066
|
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
7820
8067
|
severity: "error",
|
|
8068
|
+
fixable: true,
|
|
8069
|
+
supportedEffect: ["v3", "v4"],
|
|
7821
8070
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
7822
8071
|
const ts = yield* service(TypeScriptApi);
|
|
7823
8072
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -7868,6 +8117,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
7868
8117
|
code: 4,
|
|
7869
8118
|
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
7870
8119
|
severity: "error",
|
|
8120
|
+
fixable: true,
|
|
8121
|
+
supportedEffect: ["v3", "v4"],
|
|
7871
8122
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
7872
8123
|
const ts = yield* service(TypeScriptApi);
|
|
7873
8124
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7943,6 +8194,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
7943
8194
|
code: 18,
|
|
7944
8195
|
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
7945
8196
|
severity: "warning",
|
|
8197
|
+
fixable: true,
|
|
8198
|
+
supportedEffect: ["v3", "v4"],
|
|
7946
8199
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
7947
8200
|
const ts = yield* service(TypeScriptApi);
|
|
7948
8201
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -8029,12 +8282,85 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
8029
8282
|
})
|
|
8030
8283
|
});
|
|
8031
8284
|
|
|
8285
|
+
// src/diagnostics/nodeBuiltinImport.ts
|
|
8286
|
+
var moduleAlternativesV3 = /* @__PURE__ */ new Map([
|
|
8287
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8288
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8289
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8290
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8291
|
+
["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8292
|
+
["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8293
|
+
["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8294
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8295
|
+
["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8296
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8297
|
+
["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
|
|
8298
|
+
["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
|
|
8299
|
+
]);
|
|
8300
|
+
var moduleAlternativesV4 = /* @__PURE__ */ new Map([
|
|
8301
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8302
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8303
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8304
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8305
|
+
["path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8306
|
+
["node:path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8307
|
+
["path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8308
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8309
|
+
["path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8310
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8311
|
+
["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
|
|
8312
|
+
["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
|
|
8313
|
+
]);
|
|
8314
|
+
var nodeBuiltinImport = createDiagnostic({
|
|
8315
|
+
name: "nodeBuiltinImport",
|
|
8316
|
+
code: 52,
|
|
8317
|
+
description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
|
|
8318
|
+
severity: "off",
|
|
8319
|
+
fixable: false,
|
|
8320
|
+
supportedEffect: ["v3", "v4"],
|
|
8321
|
+
apply: fn("nodeBuiltinImport.apply")(function* (sourceFile, report) {
|
|
8322
|
+
const ts = yield* service(TypeScriptApi);
|
|
8323
|
+
const typeParser = yield* service(TypeParser);
|
|
8324
|
+
const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
|
|
8325
|
+
for (const statement of sourceFile.statements) {
|
|
8326
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
8327
|
+
const specifier = statement.moduleSpecifier.text;
|
|
8328
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8329
|
+
if (match2) {
|
|
8330
|
+
report({
|
|
8331
|
+
location: statement.moduleSpecifier,
|
|
8332
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8333
|
+
fixes: []
|
|
8334
|
+
});
|
|
8335
|
+
}
|
|
8336
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
8337
|
+
for (const decl of statement.declarationList.declarations) {
|
|
8338
|
+
if (decl.initializer && ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression) && ts.idText(decl.initializer.expression) === "require" && decl.initializer.arguments.length === 1 && ts.isStringLiteral(decl.initializer.arguments[0])) {
|
|
8339
|
+
const arg = decl.initializer.arguments[0];
|
|
8340
|
+
const specifier = arg.text;
|
|
8341
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8342
|
+
if (match2) {
|
|
8343
|
+
report({
|
|
8344
|
+
location: arg,
|
|
8345
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8346
|
+
fixes: []
|
|
8347
|
+
});
|
|
8348
|
+
}
|
|
8349
|
+
}
|
|
8350
|
+
}
|
|
8351
|
+
}
|
|
8352
|
+
}
|
|
8353
|
+
})
|
|
8354
|
+
});
|
|
8355
|
+
|
|
8032
8356
|
// src/diagnostics/nonObjectEffectServiceType.ts
|
|
8033
8357
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
8034
8358
|
name: "nonObjectEffectServiceType",
|
|
8035
8359
|
code: 24,
|
|
8036
8360
|
description: "Ensures Effect.Service types are objects, not primitives",
|
|
8037
8361
|
severity: "error",
|
|
8362
|
+
fixable: false,
|
|
8363
|
+
supportedEffect: ["v3"],
|
|
8038
8364
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
8039
8365
|
const ts = yield* service(TypeScriptApi);
|
|
8040
8366
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8817,6 +9143,8 @@ var outdatedApi = createDiagnostic({
|
|
|
8817
9143
|
code: 48,
|
|
8818
9144
|
description: "Detects usage of APIs that have been removed or renamed in Effect v4",
|
|
8819
9145
|
severity: "warning",
|
|
9146
|
+
fixable: false,
|
|
9147
|
+
supportedEffect: ["v4"],
|
|
8820
9148
|
apply: fn("outdatedApi.apply")(function* (sourceFile, report) {
|
|
8821
9149
|
const typeParser = yield* service(TypeParser);
|
|
8822
9150
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -9953,6 +10281,8 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
9953
10281
|
code: 19,
|
|
9954
10282
|
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
9955
10283
|
severity: "warning",
|
|
10284
|
+
fixable: true,
|
|
10285
|
+
supportedEffect: ["v3", "v4"],
|
|
9956
10286
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
9957
10287
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
9958
10288
|
for (const { codegen, hash: hash2, range } of codegensWithRanges) {
|
|
@@ -9999,6 +10329,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
9999
10329
|
code: 30,
|
|
10000
10330
|
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
10001
10331
|
severity: "error",
|
|
10332
|
+
fixable: true,
|
|
10333
|
+
supportedEffect: ["v3", "v4"],
|
|
10002
10334
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
10003
10335
|
const ts = yield* service(TypeScriptApi);
|
|
10004
10336
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10136,6 +10468,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
10136
10468
|
code: 44,
|
|
10137
10469
|
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
10138
10470
|
severity: "suggestion",
|
|
10471
|
+
fixable: false,
|
|
10472
|
+
supportedEffect: ["v3", "v4"],
|
|
10139
10473
|
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
10140
10474
|
const ts = yield* service(TypeScriptApi);
|
|
10141
10475
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10246,6 +10580,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
|
|
|
10246
10580
|
code: 42,
|
|
10247
10581
|
description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
|
|
10248
10582
|
severity: "suggestion",
|
|
10583
|
+
fixable: true,
|
|
10584
|
+
supportedEffect: ["v3", "v4"],
|
|
10249
10585
|
apply: fn("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
|
|
10250
10586
|
const ts = yield* service(TypeScriptApi);
|
|
10251
10587
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10296,6 +10632,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
10296
10632
|
code: 11,
|
|
10297
10633
|
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
10298
10634
|
severity: "suggestion",
|
|
10635
|
+
fixable: true,
|
|
10636
|
+
supportedEffect: ["v3", "v4"],
|
|
10299
10637
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
10300
10638
|
const ts = yield* service(TypeScriptApi);
|
|
10301
10639
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10365,6 +10703,8 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10365
10703
|
code: 32,
|
|
10366
10704
|
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
10367
10705
|
severity: "suggestion",
|
|
10706
|
+
fixable: true,
|
|
10707
|
+
supportedEffect: ["v3"],
|
|
10368
10708
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
10369
10709
|
const ts = yield* service(TypeScriptApi);
|
|
10370
10710
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10489,6 +10829,8 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
10489
10829
|
code: 34,
|
|
10490
10830
|
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
10491
10831
|
severity: "suggestion",
|
|
10832
|
+
fixable: true,
|
|
10833
|
+
supportedEffect: ["v3", "v4"],
|
|
10492
10834
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
10493
10835
|
const ts = yield* service(TypeScriptApi);
|
|
10494
10836
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10581,6 +10923,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
10581
10923
|
code: 43,
|
|
10582
10924
|
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
10583
10925
|
severity: "suggestion",
|
|
10926
|
+
fixable: false,
|
|
10927
|
+
supportedEffect: ["v3", "v4"],
|
|
10584
10928
|
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
10585
10929
|
const ts = yield* service(TypeScriptApi);
|
|
10586
10930
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10630,6 +10974,8 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
10630
10974
|
code: 33,
|
|
10631
10975
|
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
10632
10976
|
severity: "off",
|
|
10977
|
+
fixable: true,
|
|
10978
|
+
supportedEffect: ["v3"],
|
|
10633
10979
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
10634
10980
|
const ts = yield* service(TypeScriptApi);
|
|
10635
10981
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10705,6 +11051,8 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
10705
11051
|
code: 13,
|
|
10706
11052
|
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
10707
11053
|
severity: "warning",
|
|
11054
|
+
fixable: true,
|
|
11055
|
+
supportedEffect: ["v3"],
|
|
10708
11056
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
10709
11057
|
const ts = yield* service(TypeScriptApi);
|
|
10710
11058
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -10794,12 +11142,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
10794
11142
|
})
|
|
10795
11143
|
});
|
|
10796
11144
|
|
|
11145
|
+
// src/diagnostics/serviceNotAsClass.ts
|
|
11146
|
+
var serviceNotAsClass = createDiagnostic({
|
|
11147
|
+
name: "serviceNotAsClass",
|
|
11148
|
+
code: 51,
|
|
11149
|
+
description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
|
|
11150
|
+
severity: "off",
|
|
11151
|
+
fixable: true,
|
|
11152
|
+
supportedEffect: ["v4"],
|
|
11153
|
+
apply: fn("serviceNotAsClass.apply")(function* (sourceFile, report) {
|
|
11154
|
+
const ts = yield* service(TypeScriptApi);
|
|
11155
|
+
const typeParser = yield* service(TypeParser);
|
|
11156
|
+
if (typeParser.supportedEffect() === "v3") return;
|
|
11157
|
+
const nodeToVisit = [];
|
|
11158
|
+
const appendNodeToVisit = (node) => {
|
|
11159
|
+
nodeToVisit.push(node);
|
|
11160
|
+
return void 0;
|
|
11161
|
+
};
|
|
11162
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
11163
|
+
while (nodeToVisit.length > 0) {
|
|
11164
|
+
const node = nodeToVisit.shift();
|
|
11165
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
11166
|
+
if (!ts.isVariableDeclaration(node)) continue;
|
|
11167
|
+
if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
|
|
11168
|
+
const callExpr = node.initializer;
|
|
11169
|
+
if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
|
|
11170
|
+
const typeArgs = callExpr.typeArguments;
|
|
11171
|
+
const declList = node.parent;
|
|
11172
|
+
if (!ts.isVariableDeclarationList(declList)) continue;
|
|
11173
|
+
if (!(declList.flags & ts.NodeFlags.Const)) continue;
|
|
11174
|
+
const isServiceMapService = yield* pipe(
|
|
11175
|
+
typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
|
|
11176
|
+
orUndefined
|
|
11177
|
+
);
|
|
11178
|
+
if (!isServiceMapService) continue;
|
|
11179
|
+
const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
|
|
11180
|
+
const variableStatement = declList.parent;
|
|
11181
|
+
const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
|
|
11182
|
+
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11183
|
+
report({
|
|
11184
|
+
location: callExpr,
|
|
11185
|
+
messageText: `ServiceMap.Service should be used in a class declaration instead of as a variable. Use: class ${variableName} extends ServiceMap.Service<${variableName}, ${shapeText}>()("${argsText.replace(/['"]/g, "")}") {}`,
|
|
11186
|
+
fixes: [{
|
|
11187
|
+
fixName: "serviceNotAsClass",
|
|
11188
|
+
description: `Convert to class declaration`,
|
|
11189
|
+
apply: gen(function* () {
|
|
11190
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
11191
|
+
const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
|
|
11192
|
+
const innerCall = ts.factory.createCallExpression(
|
|
11193
|
+
callExpr.expression,
|
|
11194
|
+
[ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
|
|
11195
|
+
[]
|
|
11196
|
+
);
|
|
11197
|
+
const outerCall = ts.factory.createCallExpression(
|
|
11198
|
+
innerCall,
|
|
11199
|
+
void 0,
|
|
11200
|
+
[...callExpr.arguments]
|
|
11201
|
+
);
|
|
11202
|
+
const heritageClause = ts.factory.createHeritageClause(
|
|
11203
|
+
ts.SyntaxKind.ExtendsKeyword,
|
|
11204
|
+
[ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
|
|
11205
|
+
);
|
|
11206
|
+
const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
|
|
11207
|
+
const classDeclaration = ts.factory.createClassDeclaration(
|
|
11208
|
+
modifiers,
|
|
11209
|
+
ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
|
|
11210
|
+
void 0,
|
|
11211
|
+
[heritageClause],
|
|
11212
|
+
[]
|
|
11213
|
+
);
|
|
11214
|
+
changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
|
|
11215
|
+
})
|
|
11216
|
+
}]
|
|
11217
|
+
});
|
|
11218
|
+
}
|
|
11219
|
+
})
|
|
11220
|
+
});
|
|
11221
|
+
|
|
10797
11222
|
// src/diagnostics/strictBooleanExpressions.ts
|
|
10798
11223
|
var strictBooleanExpressions = createDiagnostic({
|
|
10799
11224
|
name: "strictBooleanExpressions",
|
|
10800
11225
|
code: 17,
|
|
10801
11226
|
description: "Enforces boolean types in conditional expressions for type safety",
|
|
10802
11227
|
severity: "off",
|
|
11228
|
+
fixable: false,
|
|
11229
|
+
supportedEffect: ["v3", "v4"],
|
|
10803
11230
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
10804
11231
|
const ts = yield* service(TypeScriptApi);
|
|
10805
11232
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -10871,6 +11298,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
10871
11298
|
code: 27,
|
|
10872
11299
|
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
10873
11300
|
severity: "off",
|
|
11301
|
+
fixable: false,
|
|
11302
|
+
supportedEffect: ["v3", "v4"],
|
|
10874
11303
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
10875
11304
|
const ts = yield* service(TypeScriptApi);
|
|
10876
11305
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10922,6 +11351,8 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
10922
11351
|
code: 15,
|
|
10923
11352
|
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
10924
11353
|
severity: "suggestion",
|
|
11354
|
+
fixable: false,
|
|
11355
|
+
supportedEffect: ["v3", "v4"],
|
|
10925
11356
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
10926
11357
|
const ts = yield* service(TypeScriptApi);
|
|
10927
11358
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10979,6 +11410,8 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
10979
11410
|
code: 31,
|
|
10980
11411
|
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
10981
11412
|
severity: "warning",
|
|
11413
|
+
fixable: false,
|
|
11414
|
+
supportedEffect: ["v3", "v4"],
|
|
10982
11415
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
10983
11416
|
const ts = yield* service(TypeScriptApi);
|
|
10984
11417
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11040,6 +11473,8 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
11040
11473
|
code: 5,
|
|
11041
11474
|
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
11042
11475
|
severity: "suggestion",
|
|
11476
|
+
fixable: true,
|
|
11477
|
+
supportedEffect: ["v3", "v4"],
|
|
11043
11478
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
11044
11479
|
const ts = yield* service(TypeScriptApi);
|
|
11045
11480
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11084,6 +11519,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
11084
11519
|
code: 29,
|
|
11085
11520
|
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
11086
11521
|
severity: "suggestion",
|
|
11522
|
+
fixable: true,
|
|
11523
|
+
supportedEffect: ["v3", "v4"],
|
|
11087
11524
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
11088
11525
|
const ts = yield* service(TypeScriptApi);
|
|
11089
11526
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11143,6 +11580,8 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
11143
11580
|
code: 9,
|
|
11144
11581
|
description: "Removes pipe calls with no arguments",
|
|
11145
11582
|
severity: "suggestion",
|
|
11583
|
+
fixable: true,
|
|
11584
|
+
supportedEffect: ["v3", "v4"],
|
|
11146
11585
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
11147
11586
|
const ts = yield* service(TypeScriptApi);
|
|
11148
11587
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11189,6 +11628,8 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
11189
11628
|
code: 16,
|
|
11190
11629
|
description: "Simplifies chained pipe calls into a single pipe call",
|
|
11191
11630
|
severity: "suggestion",
|
|
11631
|
+
fixable: true,
|
|
11632
|
+
supportedEffect: ["v3", "v4"],
|
|
11192
11633
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
11193
11634
|
const ts = yield* service(TypeScriptApi);
|
|
11194
11635
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11264,6 +11705,8 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
11264
11705
|
code: 21,
|
|
11265
11706
|
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
11266
11707
|
severity: "warning",
|
|
11708
|
+
fixable: true,
|
|
11709
|
+
supportedEffect: ["v3", "v4"],
|
|
11267
11710
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
11268
11711
|
const ts = yield* service(TypeScriptApi);
|
|
11269
11712
|
const nodeToVisit = [];
|
|
@@ -11366,7 +11809,10 @@ var diagnostics = [
|
|
|
11366
11809
|
effectFnOpportunity,
|
|
11367
11810
|
redundantSchemaTagIdentifier,
|
|
11368
11811
|
schemaSyncInEffect,
|
|
11369
|
-
preferSchemaOverJson
|
|
11812
|
+
preferSchemaOverJson,
|
|
11813
|
+
extendsNativeError,
|
|
11814
|
+
serviceNotAsClass,
|
|
11815
|
+
nodeBuiltinImport
|
|
11370
11816
|
];
|
|
11371
11817
|
|
|
11372
11818
|
// src/effect-lsp-patch-utils.ts
|
|
@@ -11447,6 +11893,12 @@ function extractDiagnosticsForExitStatus(tsInstance, program, diagnostics2, _mod
|
|
|
11447
11893
|
(_) => !(_.source === "effect" && _.category === tsInstance.DiagnosticCategory.Warning)
|
|
11448
11894
|
);
|
|
11449
11895
|
}
|
|
11896
|
+
if (parsedOptions.ignoreEffectErrorsInTscExitCode) {
|
|
11897
|
+
newDiagnostics = filter(
|
|
11898
|
+
newDiagnostics,
|
|
11899
|
+
(_) => !(_.source === "effect" && _.category === tsInstance.DiagnosticCategory.Error)
|
|
11900
|
+
);
|
|
11901
|
+
}
|
|
11450
11902
|
return newDiagnostics;
|
|
11451
11903
|
}
|
|
11452
11904
|
// Annotate the CommonJS export names for ESM import in node:
|