@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
package/transform.js
CHANGED
|
@@ -1638,10 +1638,151 @@ var defaults = {
|
|
|
1638
1638
|
extendedKeyDetection: false,
|
|
1639
1639
|
ignoreEffectWarningsInTscExitCode: false,
|
|
1640
1640
|
ignoreEffectSuggestionsInTscExitCode: true,
|
|
1641
|
+
ignoreEffectErrorsInTscExitCode: false,
|
|
1641
1642
|
pipeableMinArgCount: 2,
|
|
1642
1643
|
effectFn: ["span"],
|
|
1643
1644
|
layerGraphFollowDepth: 0,
|
|
1644
|
-
mermaidProvider: "mermaid.live"
|
|
1645
|
+
mermaidProvider: "mermaid.live",
|
|
1646
|
+
skipDisabledOptimization: false
|
|
1647
|
+
};
|
|
1648
|
+
var booleanSchema = (description, defaultValue) => ({
|
|
1649
|
+
type: "boolean",
|
|
1650
|
+
description,
|
|
1651
|
+
default: defaultValue
|
|
1652
|
+
});
|
|
1653
|
+
var stringArraySchema = (description, defaultValue) => ({
|
|
1654
|
+
type: "array",
|
|
1655
|
+
description,
|
|
1656
|
+
default: defaultValue,
|
|
1657
|
+
items: { type: "string" }
|
|
1658
|
+
});
|
|
1659
|
+
var stringEnumSchema = (description, values, defaultValue) => ({
|
|
1660
|
+
type: "string",
|
|
1661
|
+
description,
|
|
1662
|
+
enum: values,
|
|
1663
|
+
default: defaultValue
|
|
1664
|
+
});
|
|
1665
|
+
var languageServicePluginAdditionalPropertiesJsonSchema = {
|
|
1666
|
+
refactors: booleanSchema("Controls Effect refactors.", defaults.refactors),
|
|
1667
|
+
diagnostics: booleanSchema("Controls Effect diagnostics.", defaults.diagnostics),
|
|
1668
|
+
diagnosticsName: booleanSchema(
|
|
1669
|
+
"Controls whether to include the rule name in diagnostic messages.",
|
|
1670
|
+
defaults.diagnosticsName
|
|
1671
|
+
),
|
|
1672
|
+
missingDiagnosticNextLine: stringEnumSchema(
|
|
1673
|
+
"Controls the severity of warnings for unused @effect-diagnostics-next-line comments.",
|
|
1674
|
+
["off", "error", "warning", "message", "suggestion"],
|
|
1675
|
+
defaults.missingDiagnosticNextLine
|
|
1676
|
+
),
|
|
1677
|
+
includeSuggestionsInTsc: booleanSchema(
|
|
1678
|
+
"When patch mode is enabled, reports suggestion diagnostics as messages in TSC with a [suggestion] prefix.",
|
|
1679
|
+
defaults.includeSuggestionsInTsc
|
|
1680
|
+
),
|
|
1681
|
+
ignoreEffectWarningsInTscExitCode: booleanSchema(
|
|
1682
|
+
"When enabled, Effect warnings do not affect the patched tsc exit code.",
|
|
1683
|
+
defaults.ignoreEffectWarningsInTscExitCode
|
|
1684
|
+
),
|
|
1685
|
+
ignoreEffectErrorsInTscExitCode: booleanSchema(
|
|
1686
|
+
"When enabled, Effect errors do not affect the patched tsc exit code.",
|
|
1687
|
+
defaults.ignoreEffectErrorsInTscExitCode
|
|
1688
|
+
),
|
|
1689
|
+
ignoreEffectSuggestionsInTscExitCode: booleanSchema(
|
|
1690
|
+
"When enabled, Effect suggestions do not affect the patched tsc exit code.",
|
|
1691
|
+
defaults.ignoreEffectSuggestionsInTscExitCode
|
|
1692
|
+
),
|
|
1693
|
+
quickinfoEffectParameters: stringEnumSchema(
|
|
1694
|
+
"Controls when Effect quickinfo should include full type parameters.",
|
|
1695
|
+
["always", "never", "whentruncated"],
|
|
1696
|
+
defaults.quickinfoEffectParameters
|
|
1697
|
+
),
|
|
1698
|
+
quickinfo: booleanSchema("Controls Effect quickinfo.", defaults.quickinfo),
|
|
1699
|
+
quickinfoMaximumLength: {
|
|
1700
|
+
type: "number",
|
|
1701
|
+
description: "Controls the maximum quickinfo length. Use -1 to disable truncation.",
|
|
1702
|
+
default: defaults.quickinfoMaximumLength
|
|
1703
|
+
},
|
|
1704
|
+
keyPatterns: {
|
|
1705
|
+
type: "array",
|
|
1706
|
+
description: "Configures key patterns used for generated Effect service and error keys.",
|
|
1707
|
+
default: defaults.keyPatterns,
|
|
1708
|
+
items: {
|
|
1709
|
+
type: "object",
|
|
1710
|
+
properties: {
|
|
1711
|
+
target: stringEnumSchema("The key builder target.", ["service", "error", "custom"], "service"),
|
|
1712
|
+
pattern: stringEnumSchema(
|
|
1713
|
+
"The key generation pattern.",
|
|
1714
|
+
["package-identifier", "default", "default-hashed"],
|
|
1715
|
+
"default"
|
|
1716
|
+
),
|
|
1717
|
+
skipLeadingPath: stringArraySchema("Path prefixes to strip before generating keys.", ["src/"])
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
},
|
|
1721
|
+
extendedKeyDetection: booleanSchema(
|
|
1722
|
+
"Enables extended heuristics when detecting key sources.",
|
|
1723
|
+
defaults.extendedKeyDetection
|
|
1724
|
+
),
|
|
1725
|
+
completions: booleanSchema("Controls Effect completions.", defaults.completions),
|
|
1726
|
+
goto: booleanSchema("Controls Effect goto references support.", defaults.goto),
|
|
1727
|
+
inlays: booleanSchema("Controls Effect inlay hints.", defaults.inlays),
|
|
1728
|
+
allowedDuplicatedPackages: stringArraySchema(
|
|
1729
|
+
"Package names that are allowed to duplicate Effect as a peer dependency.",
|
|
1730
|
+
defaults.allowedDuplicatedPackages
|
|
1731
|
+
),
|
|
1732
|
+
namespaceImportPackages: stringArraySchema(
|
|
1733
|
+
"Package names that should prefer namespace imports.",
|
|
1734
|
+
defaults.namespaceImportPackages
|
|
1735
|
+
),
|
|
1736
|
+
topLevelNamedReexports: stringEnumSchema(
|
|
1737
|
+
"For namespaceImportPackages, controls how top-level named re-exports are handled.",
|
|
1738
|
+
["ignore", "follow"],
|
|
1739
|
+
defaults.topLevelNamedReexports
|
|
1740
|
+
),
|
|
1741
|
+
barrelImportPackages: stringArraySchema(
|
|
1742
|
+
"Package names that should prefer imports from their top-level barrel file.",
|
|
1743
|
+
defaults.barrelImportPackages
|
|
1744
|
+
),
|
|
1745
|
+
importAliases: {
|
|
1746
|
+
type: "object",
|
|
1747
|
+
description: "Custom aliases to use for imported identifiers.",
|
|
1748
|
+
default: defaults.importAliases,
|
|
1749
|
+
additionalProperties: {
|
|
1750
|
+
type: "string"
|
|
1751
|
+
}
|
|
1752
|
+
},
|
|
1753
|
+
renames: booleanSchema("Controls Effect rename helpers.", defaults.renames),
|
|
1754
|
+
noExternal: booleanSchema(
|
|
1755
|
+
"Disables features that link to external websites.",
|
|
1756
|
+
defaults.noExternal
|
|
1757
|
+
),
|
|
1758
|
+
pipeableMinArgCount: {
|
|
1759
|
+
type: "number",
|
|
1760
|
+
description: "Minimum argument count required before pipeable suggestions are emitted.",
|
|
1761
|
+
default: defaults.pipeableMinArgCount
|
|
1762
|
+
},
|
|
1763
|
+
effectFn: {
|
|
1764
|
+
type: "array",
|
|
1765
|
+
description: "Configures which Effect.fn variants should be suggested.",
|
|
1766
|
+
default: defaults.effectFn,
|
|
1767
|
+
items: {
|
|
1768
|
+
type: "string",
|
|
1769
|
+
enum: ["untraced", "span", "suggested-span", "inferred-span", "no-span"]
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1772
|
+
layerGraphFollowDepth: {
|
|
1773
|
+
type: "number",
|
|
1774
|
+
description: "Controls how deeply layer graph analysis follows dependencies.",
|
|
1775
|
+
default: defaults.layerGraphFollowDepth
|
|
1776
|
+
},
|
|
1777
|
+
mermaidProvider: {
|
|
1778
|
+
type: "string",
|
|
1779
|
+
description: "Controls which Mermaid renderer is used for layer graphs.",
|
|
1780
|
+
default: defaults.mermaidProvider
|
|
1781
|
+
},
|
|
1782
|
+
skipDisabledOptimization: booleanSchema(
|
|
1783
|
+
"When enabled, disabled diagnostics are still processed so comment-based overrides can be honored.",
|
|
1784
|
+
defaults.skipDisabledOptimization
|
|
1785
|
+
)
|
|
1645
1786
|
};
|
|
1646
1787
|
function parseKeyPatterns(patterns) {
|
|
1647
1788
|
const result = [];
|
|
@@ -1665,6 +1806,7 @@ function parse(config) {
|
|
|
1665
1806
|
includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
|
|
1666
1807
|
ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
|
|
1667
1808
|
ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
|
|
1809
|
+
ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
|
|
1668
1810
|
quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
|
|
1669
1811
|
quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
|
|
1670
1812
|
quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
|
|
@@ -1685,7 +1827,8 @@ function parse(config) {
|
|
|
1685
1827
|
(_) => _.toLowerCase()
|
|
1686
1828
|
) : defaults.effectFn,
|
|
1687
1829
|
layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
|
|
1688
|
-
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
|
|
1830
|
+
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
|
|
1831
|
+
skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
|
|
1689
1832
|
};
|
|
1690
1833
|
}
|
|
1691
1834
|
|
|
@@ -2455,7 +2598,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
2455
2598
|
if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
|
|
2456
2599
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2457
2600
|
}
|
|
2458
|
-
if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2601
|
+
if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2459
2602
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2460
2603
|
}
|
|
2461
2604
|
const fixByDisableNextLine = (node) => ({
|
|
@@ -5127,6 +5270,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
5127
5270
|
code: 28,
|
|
5128
5271
|
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
5129
5272
|
severity: "off",
|
|
5273
|
+
fixable: false,
|
|
5274
|
+
supportedEffect: ["v3", "v4"],
|
|
5130
5275
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
5131
5276
|
const ts = yield* service(TypeScriptApi);
|
|
5132
5277
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -5230,6 +5375,8 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5230
5375
|
code: 39,
|
|
5231
5376
|
description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
|
|
5232
5377
|
severity: "suggestion",
|
|
5378
|
+
fixable: true,
|
|
5379
|
+
supportedEffect: ["v3", "v4"],
|
|
5233
5380
|
apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
|
|
5234
5381
|
const ts = yield* service(TypeScriptApi);
|
|
5235
5382
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5327,6 +5474,8 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5327
5474
|
code: 2,
|
|
5328
5475
|
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
5329
5476
|
severity: "suggestion",
|
|
5477
|
+
fixable: false,
|
|
5478
|
+
supportedEffect: ["v3", "v4"],
|
|
5330
5479
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
5331
5480
|
const ts = yield* service(TypeScriptApi);
|
|
5332
5481
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5376,6 +5525,8 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5376
5525
|
code: 20,
|
|
5377
5526
|
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
5378
5527
|
severity: "error",
|
|
5528
|
+
fixable: true,
|
|
5529
|
+
supportedEffect: ["v3", "v4"],
|
|
5379
5530
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
5380
5531
|
const ts = yield* service(TypeScriptApi);
|
|
5381
5532
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5514,6 +5665,8 @@ var deterministicKeys = createDiagnostic({
|
|
|
5514
5665
|
code: 25,
|
|
5515
5666
|
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
5516
5667
|
severity: "off",
|
|
5668
|
+
fixable: true,
|
|
5669
|
+
supportedEffect: ["v3", "v4"],
|
|
5517
5670
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
5518
5671
|
const ts = yield* service(TypeScriptApi);
|
|
5519
5672
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5631,6 +5784,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5631
5784
|
code: 6,
|
|
5632
5785
|
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
5633
5786
|
severity: "warning",
|
|
5787
|
+
fixable: false,
|
|
5788
|
+
supportedEffect: ["v3", "v4"],
|
|
5634
5789
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
5635
5790
|
const typeParser = yield* service(TypeParser);
|
|
5636
5791
|
const options = yield* service(LanguageServicePluginOptions);
|
|
@@ -5660,6 +5815,8 @@ var effectFnIife = createDiagnostic({
|
|
|
5660
5815
|
code: 46,
|
|
5661
5816
|
description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
|
|
5662
5817
|
severity: "warning",
|
|
5818
|
+
fixable: true,
|
|
5819
|
+
supportedEffect: ["v3", "v4"],
|
|
5663
5820
|
apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
|
|
5664
5821
|
const ts = yield* service(TypeScriptApi);
|
|
5665
5822
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5762,6 +5919,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5762
5919
|
code: 41,
|
|
5763
5920
|
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
5764
5921
|
severity: "suggestion",
|
|
5922
|
+
fixable: true,
|
|
5923
|
+
supportedEffect: ["v3", "v4"],
|
|
5765
5924
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
5766
5925
|
const ts = yield* service(TypeScriptApi);
|
|
5767
5926
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6354,6 +6513,8 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
6354
6513
|
code: 23,
|
|
6355
6514
|
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
6356
6515
|
severity: "warning",
|
|
6516
|
+
fixable: false,
|
|
6517
|
+
supportedEffect: ["v3", "v4"],
|
|
6357
6518
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
6358
6519
|
const ts = yield* service(TypeScriptApi);
|
|
6359
6520
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6392,6 +6553,8 @@ var effectInFailure = createDiagnostic({
|
|
|
6392
6553
|
code: 49,
|
|
6393
6554
|
description: "Warns when an Effect is used inside an Effect failure channel",
|
|
6394
6555
|
severity: "warning",
|
|
6556
|
+
fixable: false,
|
|
6557
|
+
supportedEffect: ["v3", "v4"],
|
|
6395
6558
|
apply: fn("effectInFailure.apply")(function* (sourceFile, report) {
|
|
6396
6559
|
const ts = yield* service(TypeScriptApi);
|
|
6397
6560
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6456,6 +6619,8 @@ var effectInVoidSuccess = createDiagnostic({
|
|
|
6456
6619
|
code: 14,
|
|
6457
6620
|
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
6458
6621
|
severity: "warning",
|
|
6622
|
+
fixable: false,
|
|
6623
|
+
supportedEffect: ["v3", "v4"],
|
|
6459
6624
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
6460
6625
|
const ts = yield* service(TypeScriptApi);
|
|
6461
6626
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6505,6 +6670,8 @@ var effectMapVoid = createDiagnostic({
|
|
|
6505
6670
|
code: 40,
|
|
6506
6671
|
description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
|
|
6507
6672
|
severity: "suggestion",
|
|
6673
|
+
fixable: true,
|
|
6674
|
+
supportedEffect: ["v3", "v4"],
|
|
6508
6675
|
apply: fn("effectMapVoid.apply")(function* (sourceFile, report) {
|
|
6509
6676
|
const ts = yield* service(TypeScriptApi);
|
|
6510
6677
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6569,6 +6736,8 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6569
6736
|
code: 47,
|
|
6570
6737
|
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
6571
6738
|
severity: "suggestion",
|
|
6739
|
+
fixable: true,
|
|
6740
|
+
supportedEffect: ["v3", "v4"],
|
|
6572
6741
|
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
6573
6742
|
const ts = yield* service(TypeScriptApi);
|
|
6574
6743
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6614,12 +6783,66 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6614
6783
|
})
|
|
6615
6784
|
});
|
|
6616
6785
|
|
|
6786
|
+
// src/diagnostics/extendsNativeError.ts
|
|
6787
|
+
var extendsNativeError = createDiagnostic({
|
|
6788
|
+
name: "extendsNativeError",
|
|
6789
|
+
code: 50,
|
|
6790
|
+
description: "Warns when a class directly extends the native Error class",
|
|
6791
|
+
severity: "off",
|
|
6792
|
+
fixable: false,
|
|
6793
|
+
supportedEffect: ["v3", "v4"],
|
|
6794
|
+
apply: fn("extendsNativeError.apply")(function* (sourceFile, report) {
|
|
6795
|
+
const ts = yield* service(TypeScriptApi);
|
|
6796
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6797
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
6798
|
+
if (!errorSymbol) return;
|
|
6799
|
+
const nodeToVisit = [];
|
|
6800
|
+
const appendNodeToVisit = (node) => {
|
|
6801
|
+
nodeToVisit.push(node);
|
|
6802
|
+
return void 0;
|
|
6803
|
+
};
|
|
6804
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
6805
|
+
while (nodeToVisit.length > 0) {
|
|
6806
|
+
const node = nodeToVisit.shift();
|
|
6807
|
+
if (ts.isClassDeclaration(node) && node.heritageClauses) {
|
|
6808
|
+
for (const clause of node.heritageClauses) {
|
|
6809
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
6810
|
+
const typeExpression = clause.types[0].expression;
|
|
6811
|
+
const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
|
|
6812
|
+
const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
|
|
6813
|
+
const isNativeError = resolvedSymbol === errorSymbol || (() => {
|
|
6814
|
+
if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
|
|
6815
|
+
const exprType = typeChecker.getTypeAtLocation(typeExpression);
|
|
6816
|
+
const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
|
|
6817
|
+
if (constructSignatures.length > 0) {
|
|
6818
|
+
const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
|
|
6819
|
+
return instanceType.symbol === errorSymbol;
|
|
6820
|
+
}
|
|
6821
|
+
return false;
|
|
6822
|
+
})();
|
|
6823
|
+
if (isNativeError) {
|
|
6824
|
+
report({
|
|
6825
|
+
location: node.name ?? typeExpression,
|
|
6826
|
+
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.",
|
|
6827
|
+
fixes: []
|
|
6828
|
+
});
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
6834
|
+
}
|
|
6835
|
+
})
|
|
6836
|
+
});
|
|
6837
|
+
|
|
6617
6838
|
// src/diagnostics/floatingEffect.ts
|
|
6618
6839
|
var floatingEffect = createDiagnostic({
|
|
6619
6840
|
name: "floatingEffect",
|
|
6620
6841
|
code: 3,
|
|
6621
6842
|
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
6622
6843
|
severity: "error",
|
|
6844
|
+
fixable: false,
|
|
6845
|
+
supportedEffect: ["v3", "v4"],
|
|
6623
6846
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
6624
6847
|
const ts = yield* service(TypeScriptApi);
|
|
6625
6848
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6671,6 +6894,8 @@ var genericEffectServices = createDiagnostic({
|
|
|
6671
6894
|
code: 10,
|
|
6672
6895
|
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
6673
6896
|
severity: "warning",
|
|
6897
|
+
fixable: false,
|
|
6898
|
+
supportedEffect: ["v3", "v4"],
|
|
6674
6899
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
6675
6900
|
const ts = yield* service(TypeScriptApi);
|
|
6676
6901
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6718,6 +6943,8 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
6718
6943
|
code: 36,
|
|
6719
6944
|
description: "Warns when catch callbacks return global Error type instead of typed errors",
|
|
6720
6945
|
severity: "warning",
|
|
6946
|
+
fixable: false,
|
|
6947
|
+
supportedEffect: ["v3", "v4"],
|
|
6721
6948
|
apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
|
|
6722
6949
|
const ts = yield* service(TypeScriptApi);
|
|
6723
6950
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6778,6 +7005,8 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
6778
7005
|
code: 35,
|
|
6779
7006
|
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
6780
7007
|
severity: "warning",
|
|
7008
|
+
fixable: false,
|
|
7009
|
+
supportedEffect: ["v3", "v4"],
|
|
6781
7010
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
6782
7011
|
const ts = yield* service(TypeScriptApi);
|
|
6783
7012
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6831,6 +7060,8 @@ var importFromBarrel = createDiagnostic({
|
|
|
6831
7060
|
code: 12,
|
|
6832
7061
|
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
6833
7062
|
severity: "off",
|
|
7063
|
+
fixable: true,
|
|
7064
|
+
supportedEffect: ["v3", "v4"],
|
|
6834
7065
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
6835
7066
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
6836
7067
|
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
|
|
@@ -6971,6 +7202,8 @@ var instanceOfSchema = createDiagnostic({
|
|
|
6971
7202
|
code: 45,
|
|
6972
7203
|
description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
6973
7204
|
severity: "off",
|
|
7205
|
+
fixable: true,
|
|
7206
|
+
supportedEffect: ["v3", "v4"],
|
|
6974
7207
|
apply: fn("instanceOfSchema.apply")(function* (sourceFile, report) {
|
|
6975
7208
|
const ts = yield* service(TypeScriptApi);
|
|
6976
7209
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7034,6 +7267,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
|
|
|
7034
7267
|
code: 37,
|
|
7035
7268
|
description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
|
|
7036
7269
|
severity: "warning",
|
|
7270
|
+
fixable: true,
|
|
7271
|
+
supportedEffect: ["v3", "v4"],
|
|
7037
7272
|
apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
|
|
7038
7273
|
const ts = yield* service(TypeScriptApi);
|
|
7039
7274
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7147,6 +7382,8 @@ var leakingRequirements = createDiagnostic({
|
|
|
7147
7382
|
code: 8,
|
|
7148
7383
|
description: "Detects implementation services leaked in service methods",
|
|
7149
7384
|
severity: "suggestion",
|
|
7385
|
+
fixable: false,
|
|
7386
|
+
supportedEffect: ["v3", "v4"],
|
|
7150
7387
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
7151
7388
|
const ts = yield* service(TypeScriptApi);
|
|
7152
7389
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7301,6 +7538,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
7301
7538
|
code: 26,
|
|
7302
7539
|
description: "Enforces the use of pipeable style for nested function calls",
|
|
7303
7540
|
severity: "off",
|
|
7541
|
+
fixable: true,
|
|
7542
|
+
supportedEffect: ["v3", "v4"],
|
|
7304
7543
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
7305
7544
|
const ts = yield* service(TypeScriptApi);
|
|
7306
7545
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7481,6 +7720,8 @@ var missingEffectContext = createDiagnostic({
|
|
|
7481
7720
|
code: 1,
|
|
7482
7721
|
description: "Reports missing service requirements in Effect context channel",
|
|
7483
7722
|
severity: "error",
|
|
7723
|
+
fixable: false,
|
|
7724
|
+
supportedEffect: ["v3", "v4"],
|
|
7484
7725
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
7485
7726
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7486
7727
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7530,6 +7771,8 @@ var missingEffectError = createDiagnostic({
|
|
|
7530
7771
|
code: 1,
|
|
7531
7772
|
description: "Reports missing error types in Effect error channel",
|
|
7532
7773
|
severity: "error",
|
|
7774
|
+
fixable: true,
|
|
7775
|
+
supportedEffect: ["v3", "v4"],
|
|
7533
7776
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
7534
7777
|
const ts = yield* service(TypeScriptApi);
|
|
7535
7778
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -7671,6 +7914,8 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
7671
7914
|
code: 22,
|
|
7672
7915
|
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
7673
7916
|
severity: "off",
|
|
7917
|
+
fixable: false,
|
|
7918
|
+
supportedEffect: ["v3"],
|
|
7674
7919
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
7675
7920
|
const ts = yield* service(TypeScriptApi);
|
|
7676
7921
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7765,6 +8010,8 @@ var missingLayerContext = createDiagnostic({
|
|
|
7765
8010
|
code: 38,
|
|
7766
8011
|
description: "Reports missing service requirements in Layer context channel",
|
|
7767
8012
|
severity: "error",
|
|
8013
|
+
fixable: false,
|
|
8014
|
+
supportedEffect: ["v3", "v4"],
|
|
7768
8015
|
apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
|
|
7769
8016
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7770
8017
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7814,6 +8061,8 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
7814
8061
|
code: 7,
|
|
7815
8062
|
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
7816
8063
|
severity: "error",
|
|
8064
|
+
fixable: true,
|
|
8065
|
+
supportedEffect: ["v3", "v4"],
|
|
7817
8066
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
7818
8067
|
const ts = yield* service(TypeScriptApi);
|
|
7819
8068
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -7864,6 +8113,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
7864
8113
|
code: 4,
|
|
7865
8114
|
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
7866
8115
|
severity: "error",
|
|
8116
|
+
fixable: true,
|
|
8117
|
+
supportedEffect: ["v3", "v4"],
|
|
7867
8118
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
7868
8119
|
const ts = yield* service(TypeScriptApi);
|
|
7869
8120
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7939,6 +8190,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
7939
8190
|
code: 18,
|
|
7940
8191
|
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
7941
8192
|
severity: "warning",
|
|
8193
|
+
fixable: true,
|
|
8194
|
+
supportedEffect: ["v3", "v4"],
|
|
7942
8195
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
7943
8196
|
const ts = yield* service(TypeScriptApi);
|
|
7944
8197
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -8025,12 +8278,85 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
8025
8278
|
})
|
|
8026
8279
|
});
|
|
8027
8280
|
|
|
8281
|
+
// src/diagnostics/nodeBuiltinImport.ts
|
|
8282
|
+
var moduleAlternativesV3 = /* @__PURE__ */ new Map([
|
|
8283
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8284
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8285
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8286
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8287
|
+
["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8288
|
+
["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8289
|
+
["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8290
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8291
|
+
["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8292
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8293
|
+
["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
|
|
8294
|
+
["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
|
|
8295
|
+
]);
|
|
8296
|
+
var moduleAlternativesV4 = /* @__PURE__ */ new Map([
|
|
8297
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8298
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8299
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8300
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8301
|
+
["path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8302
|
+
["node:path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8303
|
+
["path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8304
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8305
|
+
["path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8306
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8307
|
+
["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
|
|
8308
|
+
["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
|
|
8309
|
+
]);
|
|
8310
|
+
var nodeBuiltinImport = createDiagnostic({
|
|
8311
|
+
name: "nodeBuiltinImport",
|
|
8312
|
+
code: 52,
|
|
8313
|
+
description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
|
|
8314
|
+
severity: "off",
|
|
8315
|
+
fixable: false,
|
|
8316
|
+
supportedEffect: ["v3", "v4"],
|
|
8317
|
+
apply: fn("nodeBuiltinImport.apply")(function* (sourceFile, report) {
|
|
8318
|
+
const ts = yield* service(TypeScriptApi);
|
|
8319
|
+
const typeParser = yield* service(TypeParser);
|
|
8320
|
+
const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
|
|
8321
|
+
for (const statement of sourceFile.statements) {
|
|
8322
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
8323
|
+
const specifier = statement.moduleSpecifier.text;
|
|
8324
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8325
|
+
if (match2) {
|
|
8326
|
+
report({
|
|
8327
|
+
location: statement.moduleSpecifier,
|
|
8328
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8329
|
+
fixes: []
|
|
8330
|
+
});
|
|
8331
|
+
}
|
|
8332
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
8333
|
+
for (const decl of statement.declarationList.declarations) {
|
|
8334
|
+
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])) {
|
|
8335
|
+
const arg = decl.initializer.arguments[0];
|
|
8336
|
+
const specifier = arg.text;
|
|
8337
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8338
|
+
if (match2) {
|
|
8339
|
+
report({
|
|
8340
|
+
location: arg,
|
|
8341
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8342
|
+
fixes: []
|
|
8343
|
+
});
|
|
8344
|
+
}
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8347
|
+
}
|
|
8348
|
+
}
|
|
8349
|
+
})
|
|
8350
|
+
});
|
|
8351
|
+
|
|
8028
8352
|
// src/diagnostics/nonObjectEffectServiceType.ts
|
|
8029
8353
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
8030
8354
|
name: "nonObjectEffectServiceType",
|
|
8031
8355
|
code: 24,
|
|
8032
8356
|
description: "Ensures Effect.Service types are objects, not primitives",
|
|
8033
8357
|
severity: "error",
|
|
8358
|
+
fixable: false,
|
|
8359
|
+
supportedEffect: ["v3"],
|
|
8034
8360
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
8035
8361
|
const ts = yield* service(TypeScriptApi);
|
|
8036
8362
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8813,6 +9139,8 @@ var outdatedApi = createDiagnostic({
|
|
|
8813
9139
|
code: 48,
|
|
8814
9140
|
description: "Detects usage of APIs that have been removed or renamed in Effect v4",
|
|
8815
9141
|
severity: "warning",
|
|
9142
|
+
fixable: false,
|
|
9143
|
+
supportedEffect: ["v4"],
|
|
8816
9144
|
apply: fn("outdatedApi.apply")(function* (sourceFile, report) {
|
|
8817
9145
|
const typeParser = yield* service(TypeParser);
|
|
8818
9146
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -9949,6 +10277,8 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
9949
10277
|
code: 19,
|
|
9950
10278
|
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
9951
10279
|
severity: "warning",
|
|
10280
|
+
fixable: true,
|
|
10281
|
+
supportedEffect: ["v3", "v4"],
|
|
9952
10282
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
9953
10283
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
9954
10284
|
for (const { codegen, hash: hash2, range } of codegensWithRanges) {
|
|
@@ -9995,6 +10325,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
9995
10325
|
code: 30,
|
|
9996
10326
|
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
9997
10327
|
severity: "error",
|
|
10328
|
+
fixable: true,
|
|
10329
|
+
supportedEffect: ["v3", "v4"],
|
|
9998
10330
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
9999
10331
|
const ts = yield* service(TypeScriptApi);
|
|
10000
10332
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10132,6 +10464,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
10132
10464
|
code: 44,
|
|
10133
10465
|
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
10134
10466
|
severity: "suggestion",
|
|
10467
|
+
fixable: false,
|
|
10468
|
+
supportedEffect: ["v3", "v4"],
|
|
10135
10469
|
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
10136
10470
|
const ts = yield* service(TypeScriptApi);
|
|
10137
10471
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10242,6 +10576,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
|
|
|
10242
10576
|
code: 42,
|
|
10243
10577
|
description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
|
|
10244
10578
|
severity: "suggestion",
|
|
10579
|
+
fixable: true,
|
|
10580
|
+
supportedEffect: ["v3", "v4"],
|
|
10245
10581
|
apply: fn("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
|
|
10246
10582
|
const ts = yield* service(TypeScriptApi);
|
|
10247
10583
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10292,6 +10628,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
10292
10628
|
code: 11,
|
|
10293
10629
|
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
10294
10630
|
severity: "suggestion",
|
|
10631
|
+
fixable: true,
|
|
10632
|
+
supportedEffect: ["v3", "v4"],
|
|
10295
10633
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
10296
10634
|
const ts = yield* service(TypeScriptApi);
|
|
10297
10635
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10361,6 +10699,8 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10361
10699
|
code: 32,
|
|
10362
10700
|
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
10363
10701
|
severity: "suggestion",
|
|
10702
|
+
fixable: true,
|
|
10703
|
+
supportedEffect: ["v3"],
|
|
10364
10704
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
10365
10705
|
const ts = yield* service(TypeScriptApi);
|
|
10366
10706
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10485,6 +10825,8 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
10485
10825
|
code: 34,
|
|
10486
10826
|
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
10487
10827
|
severity: "suggestion",
|
|
10828
|
+
fixable: true,
|
|
10829
|
+
supportedEffect: ["v3", "v4"],
|
|
10488
10830
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
10489
10831
|
const ts = yield* service(TypeScriptApi);
|
|
10490
10832
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10577,6 +10919,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
10577
10919
|
code: 43,
|
|
10578
10920
|
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
10579
10921
|
severity: "suggestion",
|
|
10922
|
+
fixable: false,
|
|
10923
|
+
supportedEffect: ["v3", "v4"],
|
|
10580
10924
|
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
10581
10925
|
const ts = yield* service(TypeScriptApi);
|
|
10582
10926
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10626,6 +10970,8 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
10626
10970
|
code: 33,
|
|
10627
10971
|
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
10628
10972
|
severity: "off",
|
|
10973
|
+
fixable: true,
|
|
10974
|
+
supportedEffect: ["v3"],
|
|
10629
10975
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
10630
10976
|
const ts = yield* service(TypeScriptApi);
|
|
10631
10977
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10701,6 +11047,8 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
10701
11047
|
code: 13,
|
|
10702
11048
|
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
10703
11049
|
severity: "warning",
|
|
11050
|
+
fixable: true,
|
|
11051
|
+
supportedEffect: ["v3"],
|
|
10704
11052
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
10705
11053
|
const ts = yield* service(TypeScriptApi);
|
|
10706
11054
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -10790,12 +11138,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
10790
11138
|
})
|
|
10791
11139
|
});
|
|
10792
11140
|
|
|
11141
|
+
// src/diagnostics/serviceNotAsClass.ts
|
|
11142
|
+
var serviceNotAsClass = createDiagnostic({
|
|
11143
|
+
name: "serviceNotAsClass",
|
|
11144
|
+
code: 51,
|
|
11145
|
+
description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
|
|
11146
|
+
severity: "off",
|
|
11147
|
+
fixable: true,
|
|
11148
|
+
supportedEffect: ["v4"],
|
|
11149
|
+
apply: fn("serviceNotAsClass.apply")(function* (sourceFile, report) {
|
|
11150
|
+
const ts = yield* service(TypeScriptApi);
|
|
11151
|
+
const typeParser = yield* service(TypeParser);
|
|
11152
|
+
if (typeParser.supportedEffect() === "v3") return;
|
|
11153
|
+
const nodeToVisit = [];
|
|
11154
|
+
const appendNodeToVisit = (node) => {
|
|
11155
|
+
nodeToVisit.push(node);
|
|
11156
|
+
return void 0;
|
|
11157
|
+
};
|
|
11158
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
11159
|
+
while (nodeToVisit.length > 0) {
|
|
11160
|
+
const node = nodeToVisit.shift();
|
|
11161
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
11162
|
+
if (!ts.isVariableDeclaration(node)) continue;
|
|
11163
|
+
if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
|
|
11164
|
+
const callExpr = node.initializer;
|
|
11165
|
+
if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
|
|
11166
|
+
const typeArgs = callExpr.typeArguments;
|
|
11167
|
+
const declList = node.parent;
|
|
11168
|
+
if (!ts.isVariableDeclarationList(declList)) continue;
|
|
11169
|
+
if (!(declList.flags & ts.NodeFlags.Const)) continue;
|
|
11170
|
+
const isServiceMapService = yield* pipe(
|
|
11171
|
+
typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
|
|
11172
|
+
orUndefined
|
|
11173
|
+
);
|
|
11174
|
+
if (!isServiceMapService) continue;
|
|
11175
|
+
const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
|
|
11176
|
+
const variableStatement = declList.parent;
|
|
11177
|
+
const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
|
|
11178
|
+
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11179
|
+
report({
|
|
11180
|
+
location: callExpr,
|
|
11181
|
+
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, "")}") {}`,
|
|
11182
|
+
fixes: [{
|
|
11183
|
+
fixName: "serviceNotAsClass",
|
|
11184
|
+
description: `Convert to class declaration`,
|
|
11185
|
+
apply: gen(function* () {
|
|
11186
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
11187
|
+
const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
|
|
11188
|
+
const innerCall = ts.factory.createCallExpression(
|
|
11189
|
+
callExpr.expression,
|
|
11190
|
+
[ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
|
|
11191
|
+
[]
|
|
11192
|
+
);
|
|
11193
|
+
const outerCall = ts.factory.createCallExpression(
|
|
11194
|
+
innerCall,
|
|
11195
|
+
void 0,
|
|
11196
|
+
[...callExpr.arguments]
|
|
11197
|
+
);
|
|
11198
|
+
const heritageClause = ts.factory.createHeritageClause(
|
|
11199
|
+
ts.SyntaxKind.ExtendsKeyword,
|
|
11200
|
+
[ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
|
|
11201
|
+
);
|
|
11202
|
+
const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
|
|
11203
|
+
const classDeclaration = ts.factory.createClassDeclaration(
|
|
11204
|
+
modifiers,
|
|
11205
|
+
ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
|
|
11206
|
+
void 0,
|
|
11207
|
+
[heritageClause],
|
|
11208
|
+
[]
|
|
11209
|
+
);
|
|
11210
|
+
changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
|
|
11211
|
+
})
|
|
11212
|
+
}]
|
|
11213
|
+
});
|
|
11214
|
+
}
|
|
11215
|
+
})
|
|
11216
|
+
});
|
|
11217
|
+
|
|
10793
11218
|
// src/diagnostics/strictBooleanExpressions.ts
|
|
10794
11219
|
var strictBooleanExpressions = createDiagnostic({
|
|
10795
11220
|
name: "strictBooleanExpressions",
|
|
10796
11221
|
code: 17,
|
|
10797
11222
|
description: "Enforces boolean types in conditional expressions for type safety",
|
|
10798
11223
|
severity: "off",
|
|
11224
|
+
fixable: false,
|
|
11225
|
+
supportedEffect: ["v3", "v4"],
|
|
10799
11226
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
10800
11227
|
const ts = yield* service(TypeScriptApi);
|
|
10801
11228
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -10867,6 +11294,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
10867
11294
|
code: 27,
|
|
10868
11295
|
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
10869
11296
|
severity: "off",
|
|
11297
|
+
fixable: false,
|
|
11298
|
+
supportedEffect: ["v3", "v4"],
|
|
10870
11299
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
10871
11300
|
const ts = yield* service(TypeScriptApi);
|
|
10872
11301
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10918,6 +11347,8 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
10918
11347
|
code: 15,
|
|
10919
11348
|
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
10920
11349
|
severity: "suggestion",
|
|
11350
|
+
fixable: false,
|
|
11351
|
+
supportedEffect: ["v3", "v4"],
|
|
10921
11352
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
10922
11353
|
const ts = yield* service(TypeScriptApi);
|
|
10923
11354
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10975,6 +11406,8 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
10975
11406
|
code: 31,
|
|
10976
11407
|
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
10977
11408
|
severity: "warning",
|
|
11409
|
+
fixable: false,
|
|
11410
|
+
supportedEffect: ["v3", "v4"],
|
|
10978
11411
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
10979
11412
|
const ts = yield* service(TypeScriptApi);
|
|
10980
11413
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11036,6 +11469,8 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
11036
11469
|
code: 5,
|
|
11037
11470
|
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
11038
11471
|
severity: "suggestion",
|
|
11472
|
+
fixable: true,
|
|
11473
|
+
supportedEffect: ["v3", "v4"],
|
|
11039
11474
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
11040
11475
|
const ts = yield* service(TypeScriptApi);
|
|
11041
11476
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11080,6 +11515,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
11080
11515
|
code: 29,
|
|
11081
11516
|
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
11082
11517
|
severity: "suggestion",
|
|
11518
|
+
fixable: true,
|
|
11519
|
+
supportedEffect: ["v3", "v4"],
|
|
11083
11520
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
11084
11521
|
const ts = yield* service(TypeScriptApi);
|
|
11085
11522
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11139,6 +11576,8 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
11139
11576
|
code: 9,
|
|
11140
11577
|
description: "Removes pipe calls with no arguments",
|
|
11141
11578
|
severity: "suggestion",
|
|
11579
|
+
fixable: true,
|
|
11580
|
+
supportedEffect: ["v3", "v4"],
|
|
11142
11581
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
11143
11582
|
const ts = yield* service(TypeScriptApi);
|
|
11144
11583
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11185,6 +11624,8 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
11185
11624
|
code: 16,
|
|
11186
11625
|
description: "Simplifies chained pipe calls into a single pipe call",
|
|
11187
11626
|
severity: "suggestion",
|
|
11627
|
+
fixable: true,
|
|
11628
|
+
supportedEffect: ["v3", "v4"],
|
|
11188
11629
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
11189
11630
|
const ts = yield* service(TypeScriptApi);
|
|
11190
11631
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11260,6 +11701,8 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
11260
11701
|
code: 21,
|
|
11261
11702
|
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
11262
11703
|
severity: "warning",
|
|
11704
|
+
fixable: true,
|
|
11705
|
+
supportedEffect: ["v3", "v4"],
|
|
11263
11706
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
11264
11707
|
const ts = yield* service(TypeScriptApi);
|
|
11265
11708
|
const nodeToVisit = [];
|
|
@@ -11362,7 +11805,10 @@ var diagnostics = [
|
|
|
11362
11805
|
effectFnOpportunity,
|
|
11363
11806
|
redundantSchemaTagIdentifier,
|
|
11364
11807
|
schemaSyncInEffect,
|
|
11365
|
-
preferSchemaOverJson
|
|
11808
|
+
preferSchemaOverJson,
|
|
11809
|
+
extendsNativeError,
|
|
11810
|
+
serviceNotAsClass,
|
|
11811
|
+
nodeBuiltinImport
|
|
11366
11812
|
];
|
|
11367
11813
|
|
|
11368
11814
|
// src/transform.ts
|