@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/index.js
CHANGED
|
@@ -2198,10 +2198,151 @@ var defaults = {
|
|
|
2198
2198
|
extendedKeyDetection: false,
|
|
2199
2199
|
ignoreEffectWarningsInTscExitCode: false,
|
|
2200
2200
|
ignoreEffectSuggestionsInTscExitCode: true,
|
|
2201
|
+
ignoreEffectErrorsInTscExitCode: false,
|
|
2201
2202
|
pipeableMinArgCount: 2,
|
|
2202
2203
|
effectFn: ["span"],
|
|
2203
2204
|
layerGraphFollowDepth: 0,
|
|
2204
|
-
mermaidProvider: "mermaid.live"
|
|
2205
|
+
mermaidProvider: "mermaid.live",
|
|
2206
|
+
skipDisabledOptimization: false
|
|
2207
|
+
};
|
|
2208
|
+
var booleanSchema = (description, defaultValue) => ({
|
|
2209
|
+
type: "boolean",
|
|
2210
|
+
description,
|
|
2211
|
+
default: defaultValue
|
|
2212
|
+
});
|
|
2213
|
+
var stringArraySchema = (description, defaultValue) => ({
|
|
2214
|
+
type: "array",
|
|
2215
|
+
description,
|
|
2216
|
+
default: defaultValue,
|
|
2217
|
+
items: { type: "string" }
|
|
2218
|
+
});
|
|
2219
|
+
var stringEnumSchema = (description, values2, defaultValue) => ({
|
|
2220
|
+
type: "string",
|
|
2221
|
+
description,
|
|
2222
|
+
enum: values2,
|
|
2223
|
+
default: defaultValue
|
|
2224
|
+
});
|
|
2225
|
+
var languageServicePluginAdditionalPropertiesJsonSchema = {
|
|
2226
|
+
refactors: booleanSchema("Controls Effect refactors.", defaults.refactors),
|
|
2227
|
+
diagnostics: booleanSchema("Controls Effect diagnostics.", defaults.diagnostics),
|
|
2228
|
+
diagnosticsName: booleanSchema(
|
|
2229
|
+
"Controls whether to include the rule name in diagnostic messages.",
|
|
2230
|
+
defaults.diagnosticsName
|
|
2231
|
+
),
|
|
2232
|
+
missingDiagnosticNextLine: stringEnumSchema(
|
|
2233
|
+
"Controls the severity of warnings for unused @effect-diagnostics-next-line comments.",
|
|
2234
|
+
["off", "error", "warning", "message", "suggestion"],
|
|
2235
|
+
defaults.missingDiagnosticNextLine
|
|
2236
|
+
),
|
|
2237
|
+
includeSuggestionsInTsc: booleanSchema(
|
|
2238
|
+
"When patch mode is enabled, reports suggestion diagnostics as messages in TSC with a [suggestion] prefix.",
|
|
2239
|
+
defaults.includeSuggestionsInTsc
|
|
2240
|
+
),
|
|
2241
|
+
ignoreEffectWarningsInTscExitCode: booleanSchema(
|
|
2242
|
+
"When enabled, Effect warnings do not affect the patched tsc exit code.",
|
|
2243
|
+
defaults.ignoreEffectWarningsInTscExitCode
|
|
2244
|
+
),
|
|
2245
|
+
ignoreEffectErrorsInTscExitCode: booleanSchema(
|
|
2246
|
+
"When enabled, Effect errors do not affect the patched tsc exit code.",
|
|
2247
|
+
defaults.ignoreEffectErrorsInTscExitCode
|
|
2248
|
+
),
|
|
2249
|
+
ignoreEffectSuggestionsInTscExitCode: booleanSchema(
|
|
2250
|
+
"When enabled, Effect suggestions do not affect the patched tsc exit code.",
|
|
2251
|
+
defaults.ignoreEffectSuggestionsInTscExitCode
|
|
2252
|
+
),
|
|
2253
|
+
quickinfoEffectParameters: stringEnumSchema(
|
|
2254
|
+
"Controls when Effect quickinfo should include full type parameters.",
|
|
2255
|
+
["always", "never", "whentruncated"],
|
|
2256
|
+
defaults.quickinfoEffectParameters
|
|
2257
|
+
),
|
|
2258
|
+
quickinfo: booleanSchema("Controls Effect quickinfo.", defaults.quickinfo),
|
|
2259
|
+
quickinfoMaximumLength: {
|
|
2260
|
+
type: "number",
|
|
2261
|
+
description: "Controls the maximum quickinfo length. Use -1 to disable truncation.",
|
|
2262
|
+
default: defaults.quickinfoMaximumLength
|
|
2263
|
+
},
|
|
2264
|
+
keyPatterns: {
|
|
2265
|
+
type: "array",
|
|
2266
|
+
description: "Configures key patterns used for generated Effect service and error keys.",
|
|
2267
|
+
default: defaults.keyPatterns,
|
|
2268
|
+
items: {
|
|
2269
|
+
type: "object",
|
|
2270
|
+
properties: {
|
|
2271
|
+
target: stringEnumSchema("The key builder target.", ["service", "error", "custom"], "service"),
|
|
2272
|
+
pattern: stringEnumSchema(
|
|
2273
|
+
"The key generation pattern.",
|
|
2274
|
+
["package-identifier", "default", "default-hashed"],
|
|
2275
|
+
"default"
|
|
2276
|
+
),
|
|
2277
|
+
skipLeadingPath: stringArraySchema("Path prefixes to strip before generating keys.", ["src/"])
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
},
|
|
2281
|
+
extendedKeyDetection: booleanSchema(
|
|
2282
|
+
"Enables extended heuristics when detecting key sources.",
|
|
2283
|
+
defaults.extendedKeyDetection
|
|
2284
|
+
),
|
|
2285
|
+
completions: booleanSchema("Controls Effect completions.", defaults.completions),
|
|
2286
|
+
goto: booleanSchema("Controls Effect goto references support.", defaults.goto),
|
|
2287
|
+
inlays: booleanSchema("Controls Effect inlay hints.", defaults.inlays),
|
|
2288
|
+
allowedDuplicatedPackages: stringArraySchema(
|
|
2289
|
+
"Package names that are allowed to duplicate Effect as a peer dependency.",
|
|
2290
|
+
defaults.allowedDuplicatedPackages
|
|
2291
|
+
),
|
|
2292
|
+
namespaceImportPackages: stringArraySchema(
|
|
2293
|
+
"Package names that should prefer namespace imports.",
|
|
2294
|
+
defaults.namespaceImportPackages
|
|
2295
|
+
),
|
|
2296
|
+
topLevelNamedReexports: stringEnumSchema(
|
|
2297
|
+
"For namespaceImportPackages, controls how top-level named re-exports are handled.",
|
|
2298
|
+
["ignore", "follow"],
|
|
2299
|
+
defaults.topLevelNamedReexports
|
|
2300
|
+
),
|
|
2301
|
+
barrelImportPackages: stringArraySchema(
|
|
2302
|
+
"Package names that should prefer imports from their top-level barrel file.",
|
|
2303
|
+
defaults.barrelImportPackages
|
|
2304
|
+
),
|
|
2305
|
+
importAliases: {
|
|
2306
|
+
type: "object",
|
|
2307
|
+
description: "Custom aliases to use for imported identifiers.",
|
|
2308
|
+
default: defaults.importAliases,
|
|
2309
|
+
additionalProperties: {
|
|
2310
|
+
type: "string"
|
|
2311
|
+
}
|
|
2312
|
+
},
|
|
2313
|
+
renames: booleanSchema("Controls Effect rename helpers.", defaults.renames),
|
|
2314
|
+
noExternal: booleanSchema(
|
|
2315
|
+
"Disables features that link to external websites.",
|
|
2316
|
+
defaults.noExternal
|
|
2317
|
+
),
|
|
2318
|
+
pipeableMinArgCount: {
|
|
2319
|
+
type: "number",
|
|
2320
|
+
description: "Minimum argument count required before pipeable suggestions are emitted.",
|
|
2321
|
+
default: defaults.pipeableMinArgCount
|
|
2322
|
+
},
|
|
2323
|
+
effectFn: {
|
|
2324
|
+
type: "array",
|
|
2325
|
+
description: "Configures which Effect.fn variants should be suggested.",
|
|
2326
|
+
default: defaults.effectFn,
|
|
2327
|
+
items: {
|
|
2328
|
+
type: "string",
|
|
2329
|
+
enum: ["untraced", "span", "suggested-span", "inferred-span", "no-span"]
|
|
2330
|
+
}
|
|
2331
|
+
},
|
|
2332
|
+
layerGraphFollowDepth: {
|
|
2333
|
+
type: "number",
|
|
2334
|
+
description: "Controls how deeply layer graph analysis follows dependencies.",
|
|
2335
|
+
default: defaults.layerGraphFollowDepth
|
|
2336
|
+
},
|
|
2337
|
+
mermaidProvider: {
|
|
2338
|
+
type: "string",
|
|
2339
|
+
description: "Controls which Mermaid renderer is used for layer graphs.",
|
|
2340
|
+
default: defaults.mermaidProvider
|
|
2341
|
+
},
|
|
2342
|
+
skipDisabledOptimization: booleanSchema(
|
|
2343
|
+
"When enabled, disabled diagnostics are still processed so comment-based overrides can be honored.",
|
|
2344
|
+
defaults.skipDisabledOptimization
|
|
2345
|
+
)
|
|
2205
2346
|
};
|
|
2206
2347
|
function parseKeyPatterns(patterns) {
|
|
2207
2348
|
const result = [];
|
|
@@ -2225,6 +2366,7 @@ function parse(config) {
|
|
|
2225
2366
|
includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
|
|
2226
2367
|
ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
|
|
2227
2368
|
ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
|
|
2369
|
+
ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
|
|
2228
2370
|
quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
|
|
2229
2371
|
quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
|
|
2230
2372
|
quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
|
|
@@ -2245,7 +2387,8 @@ function parse(config) {
|
|
|
2245
2387
|
(_) => _.toLowerCase()
|
|
2246
2388
|
) : defaults.effectFn,
|
|
2247
2389
|
layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
|
|
2248
|
-
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
|
|
2390
|
+
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
|
|
2391
|
+
skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
|
|
2249
2392
|
};
|
|
2250
2393
|
}
|
|
2251
2394
|
|
|
@@ -3042,7 +3185,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
3042
3185
|
if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
|
|
3043
3186
|
return { diagnostics: diagnostics2, codeFixes };
|
|
3044
3187
|
}
|
|
3045
|
-
if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
3188
|
+
if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
3046
3189
|
return { diagnostics: diagnostics2, codeFixes };
|
|
3047
3190
|
}
|
|
3048
3191
|
const fixByDisableNextLine = (node) => ({
|
|
@@ -7011,6 +7154,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
7011
7154
|
code: 28,
|
|
7012
7155
|
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
7013
7156
|
severity: "off",
|
|
7157
|
+
fixable: false,
|
|
7158
|
+
supportedEffect: ["v3", "v4"],
|
|
7014
7159
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
7015
7160
|
const ts = yield* service(TypeScriptApi);
|
|
7016
7161
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7114,6 +7259,8 @@ var catchAllToMapError = createDiagnostic({
|
|
|
7114
7259
|
code: 39,
|
|
7115
7260
|
description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
|
|
7116
7261
|
severity: "suggestion",
|
|
7262
|
+
fixable: true,
|
|
7263
|
+
supportedEffect: ["v3", "v4"],
|
|
7117
7264
|
apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
|
|
7118
7265
|
const ts = yield* service(TypeScriptApi);
|
|
7119
7266
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7211,6 +7358,8 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
7211
7358
|
code: 2,
|
|
7212
7359
|
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
7213
7360
|
severity: "suggestion",
|
|
7361
|
+
fixable: false,
|
|
7362
|
+
supportedEffect: ["v3", "v4"],
|
|
7214
7363
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
7215
7364
|
const ts = yield* service(TypeScriptApi);
|
|
7216
7365
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7260,6 +7409,8 @@ var classSelfMismatch = createDiagnostic({
|
|
|
7260
7409
|
code: 20,
|
|
7261
7410
|
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
7262
7411
|
severity: "error",
|
|
7412
|
+
fixable: true,
|
|
7413
|
+
supportedEffect: ["v3", "v4"],
|
|
7263
7414
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
7264
7415
|
const ts = yield* service(TypeScriptApi);
|
|
7265
7416
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7332,6 +7483,8 @@ var deterministicKeys = createDiagnostic({
|
|
|
7332
7483
|
code: 25,
|
|
7333
7484
|
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
7334
7485
|
severity: "off",
|
|
7486
|
+
fixable: true,
|
|
7487
|
+
supportedEffect: ["v3", "v4"],
|
|
7335
7488
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
7336
7489
|
const ts = yield* service(TypeScriptApi);
|
|
7337
7490
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7449,6 +7602,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
7449
7602
|
code: 6,
|
|
7450
7603
|
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
7451
7604
|
severity: "warning",
|
|
7605
|
+
fixable: false,
|
|
7606
|
+
supportedEffect: ["v3", "v4"],
|
|
7452
7607
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
7453
7608
|
const typeParser = yield* service(TypeParser);
|
|
7454
7609
|
const options = yield* service(LanguageServicePluginOptions);
|
|
@@ -7478,6 +7633,8 @@ var effectFnIife = createDiagnostic({
|
|
|
7478
7633
|
code: 46,
|
|
7479
7634
|
description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
|
|
7480
7635
|
severity: "warning",
|
|
7636
|
+
fixable: true,
|
|
7637
|
+
supportedEffect: ["v3", "v4"],
|
|
7481
7638
|
apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
|
|
7482
7639
|
const ts = yield* service(TypeScriptApi);
|
|
7483
7640
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7580,6 +7737,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
7580
7737
|
code: 41,
|
|
7581
7738
|
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
7582
7739
|
severity: "suggestion",
|
|
7740
|
+
fixable: true,
|
|
7741
|
+
supportedEffect: ["v3", "v4"],
|
|
7583
7742
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
7584
7743
|
const ts = yield* service(TypeScriptApi);
|
|
7585
7744
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8172,6 +8331,8 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
8172
8331
|
code: 23,
|
|
8173
8332
|
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
8174
8333
|
severity: "warning",
|
|
8334
|
+
fixable: false,
|
|
8335
|
+
supportedEffect: ["v3", "v4"],
|
|
8175
8336
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
8176
8337
|
const ts = yield* service(TypeScriptApi);
|
|
8177
8338
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8210,6 +8371,8 @@ var effectInFailure = createDiagnostic({
|
|
|
8210
8371
|
code: 49,
|
|
8211
8372
|
description: "Warns when an Effect is used inside an Effect failure channel",
|
|
8212
8373
|
severity: "warning",
|
|
8374
|
+
fixable: false,
|
|
8375
|
+
supportedEffect: ["v3", "v4"],
|
|
8213
8376
|
apply: fn("effectInFailure.apply")(function* (sourceFile, report) {
|
|
8214
8377
|
const ts = yield* service(TypeScriptApi);
|
|
8215
8378
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8274,6 +8437,8 @@ var effectInVoidSuccess = createDiagnostic({
|
|
|
8274
8437
|
code: 14,
|
|
8275
8438
|
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
8276
8439
|
severity: "warning",
|
|
8440
|
+
fixable: false,
|
|
8441
|
+
supportedEffect: ["v3", "v4"],
|
|
8277
8442
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
8278
8443
|
const ts = yield* service(TypeScriptApi);
|
|
8279
8444
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8323,6 +8488,8 @@ var effectMapVoid = createDiagnostic({
|
|
|
8323
8488
|
code: 40,
|
|
8324
8489
|
description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
|
|
8325
8490
|
severity: "suggestion",
|
|
8491
|
+
fixable: true,
|
|
8492
|
+
supportedEffect: ["v3", "v4"],
|
|
8326
8493
|
apply: fn("effectMapVoid.apply")(function* (sourceFile, report) {
|
|
8327
8494
|
const ts = yield* service(TypeScriptApi);
|
|
8328
8495
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8387,6 +8554,8 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
8387
8554
|
code: 47,
|
|
8388
8555
|
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
8389
8556
|
severity: "suggestion",
|
|
8557
|
+
fixable: true,
|
|
8558
|
+
supportedEffect: ["v3", "v4"],
|
|
8390
8559
|
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
8391
8560
|
const ts = yield* service(TypeScriptApi);
|
|
8392
8561
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8432,12 +8601,66 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
8432
8601
|
})
|
|
8433
8602
|
});
|
|
8434
8603
|
|
|
8604
|
+
// src/diagnostics/extendsNativeError.ts
|
|
8605
|
+
var extendsNativeError = createDiagnostic({
|
|
8606
|
+
name: "extendsNativeError",
|
|
8607
|
+
code: 50,
|
|
8608
|
+
description: "Warns when a class directly extends the native Error class",
|
|
8609
|
+
severity: "off",
|
|
8610
|
+
fixable: false,
|
|
8611
|
+
supportedEffect: ["v3", "v4"],
|
|
8612
|
+
apply: fn("extendsNativeError.apply")(function* (sourceFile, report) {
|
|
8613
|
+
const ts = yield* service(TypeScriptApi);
|
|
8614
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
8615
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
8616
|
+
if (!errorSymbol) return;
|
|
8617
|
+
const nodeToVisit = [];
|
|
8618
|
+
const appendNodeToVisit = (node) => {
|
|
8619
|
+
nodeToVisit.push(node);
|
|
8620
|
+
return void 0;
|
|
8621
|
+
};
|
|
8622
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
8623
|
+
while (nodeToVisit.length > 0) {
|
|
8624
|
+
const node = nodeToVisit.shift();
|
|
8625
|
+
if (ts.isClassDeclaration(node) && node.heritageClauses) {
|
|
8626
|
+
for (const clause of node.heritageClauses) {
|
|
8627
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
8628
|
+
const typeExpression = clause.types[0].expression;
|
|
8629
|
+
const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
|
|
8630
|
+
const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
|
|
8631
|
+
const isNativeError = resolvedSymbol === errorSymbol || (() => {
|
|
8632
|
+
if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
|
|
8633
|
+
const exprType = typeChecker.getTypeAtLocation(typeExpression);
|
|
8634
|
+
const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
|
|
8635
|
+
if (constructSignatures.length > 0) {
|
|
8636
|
+
const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
|
|
8637
|
+
return instanceType.symbol === errorSymbol;
|
|
8638
|
+
}
|
|
8639
|
+
return false;
|
|
8640
|
+
})();
|
|
8641
|
+
if (isNativeError) {
|
|
8642
|
+
report({
|
|
8643
|
+
location: node.name ?? typeExpression,
|
|
8644
|
+
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.",
|
|
8645
|
+
fixes: []
|
|
8646
|
+
});
|
|
8647
|
+
}
|
|
8648
|
+
}
|
|
8649
|
+
}
|
|
8650
|
+
}
|
|
8651
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
8652
|
+
}
|
|
8653
|
+
})
|
|
8654
|
+
});
|
|
8655
|
+
|
|
8435
8656
|
// src/diagnostics/floatingEffect.ts
|
|
8436
8657
|
var floatingEffect = createDiagnostic({
|
|
8437
8658
|
name: "floatingEffect",
|
|
8438
8659
|
code: 3,
|
|
8439
8660
|
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
8440
8661
|
severity: "error",
|
|
8662
|
+
fixable: false,
|
|
8663
|
+
supportedEffect: ["v3", "v4"],
|
|
8441
8664
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
8442
8665
|
const ts = yield* service(TypeScriptApi);
|
|
8443
8666
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8489,6 +8712,8 @@ var genericEffectServices = createDiagnostic({
|
|
|
8489
8712
|
code: 10,
|
|
8490
8713
|
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
8491
8714
|
severity: "warning",
|
|
8715
|
+
fixable: false,
|
|
8716
|
+
supportedEffect: ["v3", "v4"],
|
|
8492
8717
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
8493
8718
|
const ts = yield* service(TypeScriptApi);
|
|
8494
8719
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8536,6 +8761,8 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
8536
8761
|
code: 36,
|
|
8537
8762
|
description: "Warns when catch callbacks return global Error type instead of typed errors",
|
|
8538
8763
|
severity: "warning",
|
|
8764
|
+
fixable: false,
|
|
8765
|
+
supportedEffect: ["v3", "v4"],
|
|
8539
8766
|
apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
|
|
8540
8767
|
const ts = yield* service(TypeScriptApi);
|
|
8541
8768
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8596,6 +8823,8 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
8596
8823
|
code: 35,
|
|
8597
8824
|
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
8598
8825
|
severity: "warning",
|
|
8826
|
+
fixable: false,
|
|
8827
|
+
supportedEffect: ["v3", "v4"],
|
|
8599
8828
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
8600
8829
|
const ts = yield* service(TypeScriptApi);
|
|
8601
8830
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8649,6 +8878,8 @@ var importFromBarrel = createDiagnostic({
|
|
|
8649
8878
|
code: 12,
|
|
8650
8879
|
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
8651
8880
|
severity: "off",
|
|
8881
|
+
fixable: true,
|
|
8882
|
+
supportedEffect: ["v3", "v4"],
|
|
8652
8883
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
8653
8884
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
8654
8885
|
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
|
|
@@ -8789,6 +9020,8 @@ var instanceOfSchema = createDiagnostic({
|
|
|
8789
9020
|
code: 45,
|
|
8790
9021
|
description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
8791
9022
|
severity: "off",
|
|
9023
|
+
fixable: true,
|
|
9024
|
+
supportedEffect: ["v3", "v4"],
|
|
8792
9025
|
apply: fn("instanceOfSchema.apply")(function* (sourceFile, report) {
|
|
8793
9026
|
const ts = yield* service(TypeScriptApi);
|
|
8794
9027
|
const typeParser = yield* service(TypeParser);
|
|
@@ -8852,6 +9085,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
|
|
|
8852
9085
|
code: 37,
|
|
8853
9086
|
description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
|
|
8854
9087
|
severity: "warning",
|
|
9088
|
+
fixable: true,
|
|
9089
|
+
supportedEffect: ["v3", "v4"],
|
|
8855
9090
|
apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
|
|
8856
9091
|
const ts = yield* service(TypeScriptApi);
|
|
8857
9092
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -8965,6 +9200,8 @@ var leakingRequirements = createDiagnostic({
|
|
|
8965
9200
|
code: 8,
|
|
8966
9201
|
description: "Detects implementation services leaked in service methods",
|
|
8967
9202
|
severity: "suggestion",
|
|
9203
|
+
fixable: false,
|
|
9204
|
+
supportedEffect: ["v3", "v4"],
|
|
8968
9205
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
8969
9206
|
const ts = yield* service(TypeScriptApi);
|
|
8970
9207
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -9119,6 +9356,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
9119
9356
|
code: 26,
|
|
9120
9357
|
description: "Enforces the use of pipeable style for nested function calls",
|
|
9121
9358
|
severity: "off",
|
|
9359
|
+
fixable: true,
|
|
9360
|
+
supportedEffect: ["v3", "v4"],
|
|
9122
9361
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
9123
9362
|
const ts = yield* service(TypeScriptApi);
|
|
9124
9363
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -9299,6 +9538,8 @@ var missingEffectContext = createDiagnostic({
|
|
|
9299
9538
|
code: 1,
|
|
9300
9539
|
description: "Reports missing service requirements in Effect context channel",
|
|
9301
9540
|
severity: "error",
|
|
9541
|
+
fixable: false,
|
|
9542
|
+
supportedEffect: ["v3", "v4"],
|
|
9302
9543
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
9303
9544
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
9304
9545
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9348,6 +9589,8 @@ var missingEffectError = createDiagnostic({
|
|
|
9348
9589
|
code: 1,
|
|
9349
9590
|
description: "Reports missing error types in Effect error channel",
|
|
9350
9591
|
severity: "error",
|
|
9592
|
+
fixable: true,
|
|
9593
|
+
supportedEffect: ["v3", "v4"],
|
|
9351
9594
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
9352
9595
|
const ts = yield* service(TypeScriptApi);
|
|
9353
9596
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -9489,6 +9732,8 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
9489
9732
|
code: 22,
|
|
9490
9733
|
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
9491
9734
|
severity: "off",
|
|
9735
|
+
fixable: false,
|
|
9736
|
+
supportedEffect: ["v3"],
|
|
9492
9737
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
9493
9738
|
const ts = yield* service(TypeScriptApi);
|
|
9494
9739
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -9583,6 +9828,8 @@ var missingLayerContext = createDiagnostic({
|
|
|
9583
9828
|
code: 38,
|
|
9584
9829
|
description: "Reports missing service requirements in Layer context channel",
|
|
9585
9830
|
severity: "error",
|
|
9831
|
+
fixable: false,
|
|
9832
|
+
supportedEffect: ["v3", "v4"],
|
|
9586
9833
|
apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
|
|
9587
9834
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
9588
9835
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9632,6 +9879,8 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
9632
9879
|
code: 7,
|
|
9633
9880
|
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
9634
9881
|
severity: "error",
|
|
9882
|
+
fixable: true,
|
|
9883
|
+
supportedEffect: ["v3", "v4"],
|
|
9635
9884
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
9636
9885
|
const ts = yield* service(TypeScriptApi);
|
|
9637
9886
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -9682,6 +9931,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
9682
9931
|
code: 4,
|
|
9683
9932
|
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
9684
9933
|
severity: "error",
|
|
9934
|
+
fixable: true,
|
|
9935
|
+
supportedEffect: ["v3", "v4"],
|
|
9685
9936
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
9686
9937
|
const ts = yield* service(TypeScriptApi);
|
|
9687
9938
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9757,6 +10008,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
9757
10008
|
code: 18,
|
|
9758
10009
|
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
9759
10010
|
severity: "warning",
|
|
10011
|
+
fixable: true,
|
|
10012
|
+
supportedEffect: ["v3", "v4"],
|
|
9760
10013
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
9761
10014
|
const ts = yield* service(TypeScriptApi);
|
|
9762
10015
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -9843,12 +10096,85 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
9843
10096
|
})
|
|
9844
10097
|
});
|
|
9845
10098
|
|
|
10099
|
+
// src/diagnostics/nodeBuiltinImport.ts
|
|
10100
|
+
var moduleAlternativesV3 = /* @__PURE__ */ new Map([
|
|
10101
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
10102
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
10103
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
10104
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
10105
|
+
["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
10106
|
+
["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
10107
|
+
["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
10108
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
10109
|
+
["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
10110
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
10111
|
+
["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
|
|
10112
|
+
["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
|
|
10113
|
+
]);
|
|
10114
|
+
var moduleAlternativesV4 = /* @__PURE__ */ new Map([
|
|
10115
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
10116
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
10117
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
10118
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
10119
|
+
["path", { alternative: "Path", module: "path", package: "effect" }],
|
|
10120
|
+
["node:path", { alternative: "Path", module: "path", package: "effect" }],
|
|
10121
|
+
["path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
10122
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
10123
|
+
["path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
10124
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
10125
|
+
["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
|
|
10126
|
+
["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
|
|
10127
|
+
]);
|
|
10128
|
+
var nodeBuiltinImport = createDiagnostic({
|
|
10129
|
+
name: "nodeBuiltinImport",
|
|
10130
|
+
code: 52,
|
|
10131
|
+
description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
|
|
10132
|
+
severity: "off",
|
|
10133
|
+
fixable: false,
|
|
10134
|
+
supportedEffect: ["v3", "v4"],
|
|
10135
|
+
apply: fn("nodeBuiltinImport.apply")(function* (sourceFile, report) {
|
|
10136
|
+
const ts = yield* service(TypeScriptApi);
|
|
10137
|
+
const typeParser = yield* service(TypeParser);
|
|
10138
|
+
const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
|
|
10139
|
+
for (const statement of sourceFile.statements) {
|
|
10140
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
10141
|
+
const specifier = statement.moduleSpecifier.text;
|
|
10142
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
10143
|
+
if (match2) {
|
|
10144
|
+
report({
|
|
10145
|
+
location: statement.moduleSpecifier,
|
|
10146
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
10147
|
+
fixes: []
|
|
10148
|
+
});
|
|
10149
|
+
}
|
|
10150
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
10151
|
+
for (const decl of statement.declarationList.declarations) {
|
|
10152
|
+
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])) {
|
|
10153
|
+
const arg = decl.initializer.arguments[0];
|
|
10154
|
+
const specifier = arg.text;
|
|
10155
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
10156
|
+
if (match2) {
|
|
10157
|
+
report({
|
|
10158
|
+
location: arg,
|
|
10159
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
10160
|
+
fixes: []
|
|
10161
|
+
});
|
|
10162
|
+
}
|
|
10163
|
+
}
|
|
10164
|
+
}
|
|
10165
|
+
}
|
|
10166
|
+
}
|
|
10167
|
+
})
|
|
10168
|
+
});
|
|
10169
|
+
|
|
9846
10170
|
// src/diagnostics/nonObjectEffectServiceType.ts
|
|
9847
10171
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
9848
10172
|
name: "nonObjectEffectServiceType",
|
|
9849
10173
|
code: 24,
|
|
9850
10174
|
description: "Ensures Effect.Service types are objects, not primitives",
|
|
9851
10175
|
severity: "error",
|
|
10176
|
+
fixable: false,
|
|
10177
|
+
supportedEffect: ["v3"],
|
|
9852
10178
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
9853
10179
|
const ts = yield* service(TypeScriptApi);
|
|
9854
10180
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -10631,6 +10957,8 @@ var outdatedApi = createDiagnostic({
|
|
|
10631
10957
|
code: 48,
|
|
10632
10958
|
description: "Detects usage of APIs that have been removed or renamed in Effect v4",
|
|
10633
10959
|
severity: "warning",
|
|
10960
|
+
fixable: false,
|
|
10961
|
+
supportedEffect: ["v4"],
|
|
10634
10962
|
apply: fn("outdatedApi.apply")(function* (sourceFile, report) {
|
|
10635
10963
|
const typeParser = yield* service(TypeParser);
|
|
10636
10964
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -10698,6 +11026,8 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
10698
11026
|
code: 19,
|
|
10699
11027
|
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
10700
11028
|
severity: "warning",
|
|
11029
|
+
fixable: true,
|
|
11030
|
+
supportedEffect: ["v3", "v4"],
|
|
10701
11031
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
10702
11032
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
10703
11033
|
for (const { codegen, hash: hash2, range } of codegensWithRanges) {
|
|
@@ -10744,6 +11074,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
10744
11074
|
code: 30,
|
|
10745
11075
|
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
10746
11076
|
severity: "error",
|
|
11077
|
+
fixable: true,
|
|
11078
|
+
supportedEffect: ["v3", "v4"],
|
|
10747
11079
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
10748
11080
|
const ts = yield* service(TypeScriptApi);
|
|
10749
11081
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10881,6 +11213,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
10881
11213
|
code: 44,
|
|
10882
11214
|
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
10883
11215
|
severity: "suggestion",
|
|
11216
|
+
fixable: false,
|
|
11217
|
+
supportedEffect: ["v3", "v4"],
|
|
10884
11218
|
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
10885
11219
|
const ts = yield* service(TypeScriptApi);
|
|
10886
11220
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10991,6 +11325,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
|
|
|
10991
11325
|
code: 42,
|
|
10992
11326
|
description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
|
|
10993
11327
|
severity: "suggestion",
|
|
11328
|
+
fixable: true,
|
|
11329
|
+
supportedEffect: ["v3", "v4"],
|
|
10994
11330
|
apply: fn("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
|
|
10995
11331
|
const ts = yield* service(TypeScriptApi);
|
|
10996
11332
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11041,6 +11377,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
11041
11377
|
code: 11,
|
|
11042
11378
|
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
11043
11379
|
severity: "suggestion",
|
|
11380
|
+
fixable: true,
|
|
11381
|
+
supportedEffect: ["v3", "v4"],
|
|
11044
11382
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
11045
11383
|
const ts = yield* service(TypeScriptApi);
|
|
11046
11384
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -11110,6 +11448,8 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11110
11448
|
code: 32,
|
|
11111
11449
|
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
11112
11450
|
severity: "suggestion",
|
|
11451
|
+
fixable: true,
|
|
11452
|
+
supportedEffect: ["v3"],
|
|
11113
11453
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
11114
11454
|
const ts = yield* service(TypeScriptApi);
|
|
11115
11455
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11234,6 +11574,8 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
11234
11574
|
code: 34,
|
|
11235
11575
|
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
11236
11576
|
severity: "suggestion",
|
|
11577
|
+
fixable: true,
|
|
11578
|
+
supportedEffect: ["v3", "v4"],
|
|
11237
11579
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
11238
11580
|
const ts = yield* service(TypeScriptApi);
|
|
11239
11581
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11326,6 +11668,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
11326
11668
|
code: 43,
|
|
11327
11669
|
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
11328
11670
|
severity: "suggestion",
|
|
11671
|
+
fixable: false,
|
|
11672
|
+
supportedEffect: ["v3", "v4"],
|
|
11329
11673
|
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
11330
11674
|
const ts = yield* service(TypeScriptApi);
|
|
11331
11675
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11375,6 +11719,8 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
11375
11719
|
code: 33,
|
|
11376
11720
|
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
11377
11721
|
severity: "off",
|
|
11722
|
+
fixable: true,
|
|
11723
|
+
supportedEffect: ["v3"],
|
|
11378
11724
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
11379
11725
|
const ts = yield* service(TypeScriptApi);
|
|
11380
11726
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11450,6 +11796,8 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
11450
11796
|
code: 13,
|
|
11451
11797
|
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
11452
11798
|
severity: "warning",
|
|
11799
|
+
fixable: true,
|
|
11800
|
+
supportedEffect: ["v3"],
|
|
11453
11801
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
11454
11802
|
const ts = yield* service(TypeScriptApi);
|
|
11455
11803
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -11539,12 +11887,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
11539
11887
|
})
|
|
11540
11888
|
});
|
|
11541
11889
|
|
|
11890
|
+
// src/diagnostics/serviceNotAsClass.ts
|
|
11891
|
+
var serviceNotAsClass = createDiagnostic({
|
|
11892
|
+
name: "serviceNotAsClass",
|
|
11893
|
+
code: 51,
|
|
11894
|
+
description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
|
|
11895
|
+
severity: "off",
|
|
11896
|
+
fixable: true,
|
|
11897
|
+
supportedEffect: ["v4"],
|
|
11898
|
+
apply: fn("serviceNotAsClass.apply")(function* (sourceFile, report) {
|
|
11899
|
+
const ts = yield* service(TypeScriptApi);
|
|
11900
|
+
const typeParser = yield* service(TypeParser);
|
|
11901
|
+
if (typeParser.supportedEffect() === "v3") return;
|
|
11902
|
+
const nodeToVisit = [];
|
|
11903
|
+
const appendNodeToVisit = (node) => {
|
|
11904
|
+
nodeToVisit.push(node);
|
|
11905
|
+
return void 0;
|
|
11906
|
+
};
|
|
11907
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
11908
|
+
while (nodeToVisit.length > 0) {
|
|
11909
|
+
const node = nodeToVisit.shift();
|
|
11910
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
11911
|
+
if (!ts.isVariableDeclaration(node)) continue;
|
|
11912
|
+
if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
|
|
11913
|
+
const callExpr = node.initializer;
|
|
11914
|
+
if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
|
|
11915
|
+
const typeArgs = callExpr.typeArguments;
|
|
11916
|
+
const declList = node.parent;
|
|
11917
|
+
if (!ts.isVariableDeclarationList(declList)) continue;
|
|
11918
|
+
if (!(declList.flags & ts.NodeFlags.Const)) continue;
|
|
11919
|
+
const isServiceMapService = yield* pipe(
|
|
11920
|
+
typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
|
|
11921
|
+
orUndefined
|
|
11922
|
+
);
|
|
11923
|
+
if (!isServiceMapService) continue;
|
|
11924
|
+
const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
|
|
11925
|
+
const variableStatement = declList.parent;
|
|
11926
|
+
const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
|
|
11927
|
+
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11928
|
+
report({
|
|
11929
|
+
location: callExpr,
|
|
11930
|
+
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, "")}") {}`,
|
|
11931
|
+
fixes: [{
|
|
11932
|
+
fixName: "serviceNotAsClass",
|
|
11933
|
+
description: `Convert to class declaration`,
|
|
11934
|
+
apply: gen(function* () {
|
|
11935
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
11936
|
+
const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
|
|
11937
|
+
const innerCall = ts.factory.createCallExpression(
|
|
11938
|
+
callExpr.expression,
|
|
11939
|
+
[ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
|
|
11940
|
+
[]
|
|
11941
|
+
);
|
|
11942
|
+
const outerCall = ts.factory.createCallExpression(
|
|
11943
|
+
innerCall,
|
|
11944
|
+
void 0,
|
|
11945
|
+
[...callExpr.arguments]
|
|
11946
|
+
);
|
|
11947
|
+
const heritageClause = ts.factory.createHeritageClause(
|
|
11948
|
+
ts.SyntaxKind.ExtendsKeyword,
|
|
11949
|
+
[ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
|
|
11950
|
+
);
|
|
11951
|
+
const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
|
|
11952
|
+
const classDeclaration = ts.factory.createClassDeclaration(
|
|
11953
|
+
modifiers,
|
|
11954
|
+
ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
|
|
11955
|
+
void 0,
|
|
11956
|
+
[heritageClause],
|
|
11957
|
+
[]
|
|
11958
|
+
);
|
|
11959
|
+
changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
|
|
11960
|
+
})
|
|
11961
|
+
}]
|
|
11962
|
+
});
|
|
11963
|
+
}
|
|
11964
|
+
})
|
|
11965
|
+
});
|
|
11966
|
+
|
|
11542
11967
|
// src/diagnostics/strictBooleanExpressions.ts
|
|
11543
11968
|
var strictBooleanExpressions = createDiagnostic({
|
|
11544
11969
|
name: "strictBooleanExpressions",
|
|
11545
11970
|
code: 17,
|
|
11546
11971
|
description: "Enforces boolean types in conditional expressions for type safety",
|
|
11547
11972
|
severity: "off",
|
|
11973
|
+
fixable: false,
|
|
11974
|
+
supportedEffect: ["v3", "v4"],
|
|
11548
11975
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
11549
11976
|
const ts = yield* service(TypeScriptApi);
|
|
11550
11977
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -11616,6 +12043,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
11616
12043
|
code: 27,
|
|
11617
12044
|
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
11618
12045
|
severity: "off",
|
|
12046
|
+
fixable: false,
|
|
12047
|
+
supportedEffect: ["v3", "v4"],
|
|
11619
12048
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
11620
12049
|
const ts = yield* service(TypeScriptApi);
|
|
11621
12050
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -11667,6 +12096,8 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
11667
12096
|
code: 15,
|
|
11668
12097
|
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
11669
12098
|
severity: "suggestion",
|
|
12099
|
+
fixable: false,
|
|
12100
|
+
supportedEffect: ["v3", "v4"],
|
|
11670
12101
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
11671
12102
|
const ts = yield* service(TypeScriptApi);
|
|
11672
12103
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11724,6 +12155,8 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
11724
12155
|
code: 31,
|
|
11725
12156
|
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
11726
12157
|
severity: "warning",
|
|
12158
|
+
fixable: false,
|
|
12159
|
+
supportedEffect: ["v3", "v4"],
|
|
11727
12160
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
11728
12161
|
const ts = yield* service(TypeScriptApi);
|
|
11729
12162
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11785,6 +12218,8 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
11785
12218
|
code: 5,
|
|
11786
12219
|
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
11787
12220
|
severity: "suggestion",
|
|
12221
|
+
fixable: true,
|
|
12222
|
+
supportedEffect: ["v3", "v4"],
|
|
11788
12223
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
11789
12224
|
const ts = yield* service(TypeScriptApi);
|
|
11790
12225
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11829,6 +12264,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
11829
12264
|
code: 29,
|
|
11830
12265
|
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
11831
12266
|
severity: "suggestion",
|
|
12267
|
+
fixable: true,
|
|
12268
|
+
supportedEffect: ["v3", "v4"],
|
|
11832
12269
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
11833
12270
|
const ts = yield* service(TypeScriptApi);
|
|
11834
12271
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11888,6 +12325,8 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
11888
12325
|
code: 9,
|
|
11889
12326
|
description: "Removes pipe calls with no arguments",
|
|
11890
12327
|
severity: "suggestion",
|
|
12328
|
+
fixable: true,
|
|
12329
|
+
supportedEffect: ["v3", "v4"],
|
|
11891
12330
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
11892
12331
|
const ts = yield* service(TypeScriptApi);
|
|
11893
12332
|
const typeParser = yield* service(TypeParser);
|
|
@@ -11934,6 +12373,8 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
11934
12373
|
code: 16,
|
|
11935
12374
|
description: "Simplifies chained pipe calls into a single pipe call",
|
|
11936
12375
|
severity: "suggestion",
|
|
12376
|
+
fixable: true,
|
|
12377
|
+
supportedEffect: ["v3", "v4"],
|
|
11937
12378
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
11938
12379
|
const ts = yield* service(TypeScriptApi);
|
|
11939
12380
|
const typeParser = yield* service(TypeParser);
|
|
@@ -12009,6 +12450,8 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
12009
12450
|
code: 21,
|
|
12010
12451
|
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
12011
12452
|
severity: "warning",
|
|
12453
|
+
fixable: true,
|
|
12454
|
+
supportedEffect: ["v3", "v4"],
|
|
12012
12455
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
12013
12456
|
const ts = yield* service(TypeScriptApi);
|
|
12014
12457
|
const nodeToVisit = [];
|
|
@@ -12111,7 +12554,10 @@ var diagnostics = [
|
|
|
12111
12554
|
effectFnOpportunity,
|
|
12112
12555
|
redundantSchemaTagIdentifier,
|
|
12113
12556
|
schemaSyncInEffect,
|
|
12114
|
-
preferSchemaOverJson
|
|
12557
|
+
preferSchemaOverJson,
|
|
12558
|
+
extendsNativeError,
|
|
12559
|
+
serviceNotAsClass,
|
|
12560
|
+
nodeBuiltinImport
|
|
12115
12561
|
];
|
|
12116
12562
|
|
|
12117
12563
|
// src/completions/effectDiagnosticsComment.ts
|
|
@@ -13335,7 +13781,10 @@ function effectRpcDefinition(applicableGotoDefinition, sourceFile, position) {
|
|
|
13335
13781
|
if (result.length === 0) return applicableGotoDefinition;
|
|
13336
13782
|
const effectRpcResult = result.map(([node]) => ({
|
|
13337
13783
|
fileName: node.getSourceFile().fileName,
|
|
13338
|
-
textSpan: ts.createTextSpan(
|
|
13784
|
+
textSpan: ts.createTextSpan(
|
|
13785
|
+
ts.getTokenPosOfNode(node, node.getSourceFile()),
|
|
13786
|
+
node.end - ts.getTokenPosOfNode(node, node.getSourceFile())
|
|
13787
|
+
),
|
|
13339
13788
|
kind: ts.ScriptElementKind.constElement,
|
|
13340
13789
|
name: rpcName,
|
|
13341
13790
|
containerKind: ts.ScriptElementKind.constElement,
|
|
@@ -13348,7 +13797,10 @@ function effectRpcDefinition(applicableGotoDefinition, sourceFile, position) {
|
|
|
13348
13797
|
};
|
|
13349
13798
|
}
|
|
13350
13799
|
return {
|
|
13351
|
-
textSpan: ts.createTextSpan(
|
|
13800
|
+
textSpan: ts.createTextSpan(
|
|
13801
|
+
ts.getTokenPosOfNode(callNode, callNode.getSourceFile()),
|
|
13802
|
+
callNode.end - ts.getTokenPosOfNode(callNode, callNode.getSourceFile())
|
|
13803
|
+
),
|
|
13352
13804
|
definitions: effectRpcResult
|
|
13353
13805
|
};
|
|
13354
13806
|
});
|
|
@@ -13384,7 +13836,7 @@ var middlewareGenLike = fn("middlewareGenLike")(function* (sourceFile, _span, pr
|
|
|
13384
13836
|
parseType(possiblyGen),
|
|
13385
13837
|
map5((_) => {
|
|
13386
13838
|
const argsCloseParen = ts.findChildOfKind(_.generatorFunction, ts.SyntaxKind.CloseParenToken, sourceFile);
|
|
13387
|
-
if (argsCloseParen && _.body && inlayHint.position >= argsCloseParen.end && inlayHint.position <= _.body
|
|
13839
|
+
if (argsCloseParen && _.body && inlayHint.position >= argsCloseParen.end && inlayHint.position <= ts.getTokenPosOfNode(_.body, sourceFile)) {
|
|
13388
13840
|
shouldOmit = true;
|
|
13389
13841
|
}
|
|
13390
13842
|
}),
|
|
@@ -20164,7 +20616,8 @@ var OnlyLiteralPropertiesSupportedError = class {
|
|
|
20164
20616
|
}
|
|
20165
20617
|
_tag = "@effect/language-service/OnlyLiteralPropertiesSupportedError";
|
|
20166
20618
|
toString() {
|
|
20167
|
-
|
|
20619
|
+
const sourceFile = this.node.getSourceFile();
|
|
20620
|
+
return `Could not process ${sourceFile.text.substring(this.node.pos, this.node.end)} as only literal properties are supported.`;
|
|
20168
20621
|
}
|
|
20169
20622
|
};
|
|
20170
20623
|
var RequiredExplicitTypesError = class {
|
|
@@ -20173,7 +20626,8 @@ var RequiredExplicitTypesError = class {
|
|
|
20173
20626
|
}
|
|
20174
20627
|
_tag = "@effect/language-service/RequiredExplicitTypesError";
|
|
20175
20628
|
toString() {
|
|
20176
|
-
|
|
20629
|
+
const sourceFile = this.node.getSourceFile();
|
|
20630
|
+
return `Could not process ${sourceFile.text.substring(this.node.pos, this.node.end)} as only explicit types are supported.`;
|
|
20177
20631
|
}
|
|
20178
20632
|
};
|
|
20179
20633
|
var IndexSignatureWithMoreThanOneParameterError = class {
|
|
@@ -20182,7 +20636,8 @@ var IndexSignatureWithMoreThanOneParameterError = class {
|
|
|
20182
20636
|
}
|
|
20183
20637
|
_tag = "@effect/language-service/IndexSignatureWithMoreThanOneParameterError";
|
|
20184
20638
|
toString() {
|
|
20185
|
-
|
|
20639
|
+
const sourceFile = this.node.getSourceFile();
|
|
20640
|
+
return `Could not process ${sourceFile.text.substring(this.node.pos, this.node.end)} as only index signatures with one parameter are supported.`;
|
|
20186
20641
|
}
|
|
20187
20642
|
};
|
|
20188
20643
|
var SchemaGenContext = Tag("SchemaGenContext");
|
|
@@ -20282,7 +20737,7 @@ var parseAllLiterals = fn(
|
|
|
20282
20737
|
var createUnsupportedNodeComment = (ts, sourceFile, node) => ts.addSyntheticTrailingComment(
|
|
20283
20738
|
ts.factory.createIdentifier(""),
|
|
20284
20739
|
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
20285
|
-
" Not supported conversion: " +
|
|
20740
|
+
" Not supported conversion: " + sourceFile.text.substring(ts.getTokenPosOfNode(node, sourceFile), node.end) + " "
|
|
20286
20741
|
);
|
|
20287
20742
|
var processNode = fn("SchemaGen.processNode")(function* (node, isVirtualTypeNode) {
|
|
20288
20743
|
const { createApiCall, createApiPropertyAccess, entityNameToDataTypeName, sourceFile, supportedEffect, ts } = yield* service(
|
|
@@ -20368,7 +20823,13 @@ var processNode = fn("SchemaGen.processNode")(function* (node, isVirtualTypeNode
|
|
|
20368
20823
|
if (typeNode) return yield* processNode(typeNode, true);
|
|
20369
20824
|
}
|
|
20370
20825
|
}
|
|
20371
|
-
if (!isVirtualTypeNode && ts.isIndexedAccessTypeNode(node) && ts.isParenthesizedTypeNode(node.objectType) && ts.isTypeQueryNode(node.objectType.type) && ts.isTypeOperatorNode(node.indexType) && node.indexType.operator === ts.SyntaxKind.KeyOfKeyword && ts.isTypeQueryNode(node.indexType.type) &&
|
|
20826
|
+
if (!isVirtualTypeNode && ts.isIndexedAccessTypeNode(node) && ts.isParenthesizedTypeNode(node.objectType) && ts.isTypeQueryNode(node.objectType.type) && ts.isTypeOperatorNode(node.indexType) && node.indexType.operator === ts.SyntaxKind.KeyOfKeyword && ts.isTypeQueryNode(node.indexType.type) && sourceFile.text.substring(
|
|
20827
|
+
ts.getTokenPosOfNode(node.indexType.type.exprName, sourceFile),
|
|
20828
|
+
node.indexType.type.exprName.end
|
|
20829
|
+
).trim() === sourceFile.text.substring(
|
|
20830
|
+
ts.getTokenPosOfNode(node.objectType.type.exprName, sourceFile),
|
|
20831
|
+
node.objectType.type.exprName.end
|
|
20832
|
+
).trim()) {
|
|
20372
20833
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
20373
20834
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
20374
20835
|
const type = typeCheckerUtils.getTypeAtLocation(node);
|