@effect/tsgo 0.0.14 → 0.0.16
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/bin/effect-tsgo.js +1117 -328
- package/package.json +8 -8
package/bin/effect-tsgo.js
CHANGED
|
@@ -34157,14 +34157,14 @@ const defaultFormatter = (options) => {
|
|
|
34157
34157
|
* Strips ANSI escape codes from a string to calculate visual width.
|
|
34158
34158
|
* @internal
|
|
34159
34159
|
*/
|
|
34160
|
-
const stripAnsi = (text) => {
|
|
34160
|
+
const stripAnsi$1 = (text) => {
|
|
34161
34161
|
return text.replace(/\u001B\[[0-9;]*m/g, "");
|
|
34162
34162
|
};
|
|
34163
34163
|
/**
|
|
34164
34164
|
* Gets the visual length of a string (excluding ANSI codes).
|
|
34165
34165
|
* @internal
|
|
34166
34166
|
*/
|
|
34167
|
-
const visualLength = (text) => stripAnsi(text).length;
|
|
34167
|
+
const visualLength = (text) => stripAnsi$1(text).length;
|
|
34168
34168
|
/**
|
|
34169
34169
|
* Helper function to pad strings to a specified width.
|
|
34170
34170
|
* @internal
|
|
@@ -45596,7 +45596,7 @@ const cursorMove = (column, row = 0) => {
|
|
|
45596
45596
|
return command;
|
|
45597
45597
|
};
|
|
45598
45598
|
/** @internal */
|
|
45599
|
-
const eraseLines
|
|
45599
|
+
const eraseLines = (rows) => {
|
|
45600
45600
|
let command = "";
|
|
45601
45601
|
for (let i = 0; i < rows; i++) command += `${ESC}2K` + (i < rows - 1 ? `${ESC}1A` : "");
|
|
45602
45602
|
if (rows > 0) command += `${ESC}G`;
|
|
@@ -45812,20 +45812,20 @@ const Action$1 = /* @__PURE__ */ taggedEnum();
|
|
|
45812
45812
|
/**
|
|
45813
45813
|
* Clears all lines taken up by the specified `text`.
|
|
45814
45814
|
*/
|
|
45815
|
-
const eraseText
|
|
45815
|
+
const eraseText = (text, columns) => {
|
|
45816
45816
|
if (columns === 0) return eraseLine + cursorTo(0);
|
|
45817
45817
|
let rows = 0;
|
|
45818
45818
|
const lines = text.split(NEWLINE_REGEXP);
|
|
45819
45819
|
for (const line of lines) rows += 1 + Math.floor(Math.max(line.length - 1, 0) / columns);
|
|
45820
|
-
return eraseLines
|
|
45820
|
+
return eraseLines(rows);
|
|
45821
45821
|
};
|
|
45822
45822
|
const lines = (prompt, columns) => {
|
|
45823
45823
|
const lines = prompt.split(NEWLINE_REGEXP);
|
|
45824
45824
|
return columns === 0 ? lines.length : pipe(map$7(lines, (line) => Math.ceil(line.length / columns)), reduce(0, (left, right) => left + right));
|
|
45825
45825
|
};
|
|
45826
45826
|
const clearOutputWithError = (outputText, columns, errorText) => {
|
|
45827
|
-
if (errorText !== void 0 && errorText.length > 0) return cursorDown(lines(errorText, columns)) + eraseText
|
|
45828
|
-
return eraseText
|
|
45827
|
+
if (errorText !== void 0 && errorText.length > 0) return cursorDown(lines(errorText, columns)) + eraseText(`\n${errorText}`, columns) + eraseText(outputText, columns);
|
|
45828
|
+
return eraseText(outputText, columns);
|
|
45829
45829
|
};
|
|
45830
45830
|
const renderBeep = beep;
|
|
45831
45831
|
const NEWLINE_REGEXP = /\r?\n/;
|
|
@@ -45833,7 +45833,7 @@ const handleConfirmClear = (options) => {
|
|
|
45833
45833
|
return fnUntraced(function* (state, _) {
|
|
45834
45834
|
const columns = yield* (yield* Terminal).columns;
|
|
45835
45835
|
const figures = yield* platformFigures;
|
|
45836
|
-
return eraseText
|
|
45836
|
+
return eraseText(renderConfirmOutput(state.value ? options.placeholder.defaultConfirm : options.placeholder.defaultDeny, "?", figures.pointerSmall, options, { plain: true }), columns) + (eraseLine + cursorLeft);
|
|
45837
45837
|
});
|
|
45838
45838
|
};
|
|
45839
45839
|
const renderConfirmOutput = (confirm, leadingSymbol, trailingSymbol, options, renderOptions) => renderPrompt(confirm, options.message, leadingSymbol, trailingSymbol, renderOptions);
|
|
@@ -45903,7 +45903,7 @@ const renderMultiSelectChoices = (state, options, figures, renderOptions) => {
|
|
|
45903
45903
|
const inverseSelectionText = options?.inverseSelection ?? "Inverse Selection";
|
|
45904
45904
|
const metaOptions = [{ title: selectAllText }, { title: inverseSelectionText }];
|
|
45905
45905
|
const allChoices = [...metaOptions, ...choices];
|
|
45906
|
-
const toDisplay = entriesToDisplay
|
|
45906
|
+
const toDisplay = entriesToDisplay(state.index, allChoices.length, options.maxPerPage);
|
|
45907
45907
|
const documents = [];
|
|
45908
45908
|
for (let index = toDisplay.startIndex; index < toDisplay.endIndex; index++) {
|
|
45909
45909
|
const choice = allChoices[index];
|
|
@@ -46039,7 +46039,7 @@ const renderChoiceTitle = (choice, isSelected, renderOptions) => {
|
|
|
46039
46039
|
};
|
|
46040
46040
|
const renderSelectChoices = (state, options, figures, renderOptions) => {
|
|
46041
46041
|
const choices = options.choices;
|
|
46042
|
-
const toDisplay = entriesToDisplay
|
|
46042
|
+
const toDisplay = entriesToDisplay(state, choices.length, options.maxPerPage);
|
|
46043
46043
|
const documents = [];
|
|
46044
46044
|
for (let index = toDisplay.startIndex; index < toDisplay.endIndex; index++) {
|
|
46045
46045
|
const choice = choices[index];
|
|
@@ -46086,7 +46086,7 @@ const handleSelectClear = (options) => fnUntraced(function* (state, _) {
|
|
|
46086
46086
|
const columns = yield* (yield* Terminal).columns;
|
|
46087
46087
|
const figures = yield* platformFigures;
|
|
46088
46088
|
const clearPrompt = eraseLine + cursorLeft;
|
|
46089
|
-
return eraseText
|
|
46089
|
+
return eraseText(`${renderSelectOutput("?", figures.pointerSmall, options, { plain: true })}\n${renderSelectChoices(state, options, figures, { plain: true })}`, columns) + clearPrompt;
|
|
46090
46090
|
});
|
|
46091
46091
|
const handleSelectProcess = (options) => {
|
|
46092
46092
|
return (input, state) => {
|
|
@@ -46262,7 +46262,7 @@ const basePrompt = (options, type) => {
|
|
|
46262
46262
|
clear: handleTextClear(opts)
|
|
46263
46263
|
});
|
|
46264
46264
|
};
|
|
46265
|
-
const entriesToDisplay
|
|
46265
|
+
const entriesToDisplay = (cursor, total, maxVisible) => {
|
|
46266
46266
|
const max = maxVisible === void 0 ? total : maxVisible;
|
|
46267
46267
|
let startIndex = Math.min(total - max, cursor - Math.floor(max / 2));
|
|
46268
46268
|
if (startIndex < 0) startIndex = 0;
|
|
@@ -195732,7 +195732,7 @@ var FileReadError = class extends TaggedError("FileReadError") {
|
|
|
195732
195732
|
//#endregion
|
|
195733
195733
|
//#region package.json
|
|
195734
195734
|
var name = "@effect/tsgo";
|
|
195735
|
-
var version = "0.0.
|
|
195735
|
+
var version = "0.0.16";
|
|
195736
195736
|
|
|
195737
195737
|
//#endregion
|
|
195738
195738
|
//#region src/setup/consts.ts
|
|
@@ -196029,8 +196029,7 @@ const computePackageJsonChanges = (current, target) => {
|
|
|
196029
196029
|
} else if (isSome(current.prepareScript) && !current.prepareScript.value.hasPatch) {
|
|
196030
196030
|
descriptions.push("Update prepare script to include patch command");
|
|
196031
196031
|
const newScript = `${current.prepareScript.value.script} && ${PATCH_COMMAND}`;
|
|
196032
|
-
|
|
196033
|
-
tracker.replaceNode(current.sourceFile, prepareProperty, newPrepareProp);
|
|
196032
|
+
tracker.replaceNode(current.sourceFile, prepareProperty.initializer, import_typescript.factory.createStringLiteral(newScript));
|
|
196034
196033
|
}
|
|
196035
196034
|
}
|
|
196036
196035
|
} else if (isNone(target.lspVersion) && isSome(current.prepareScript) && current.prepareScript.value.hasPatch) {
|
|
@@ -196078,7 +196077,43 @@ const computeTsConfigChanges = (current, target, lspVersion) => {
|
|
|
196078
196077
|
const rootObj = getRootObject(current.sourceFile);
|
|
196079
196078
|
if (!rootObj) return emptyFileChangesResult();
|
|
196080
196079
|
const compilerOptionsProperty = findPropertyInObject(rootObj, "compilerOptions");
|
|
196081
|
-
if (!compilerOptionsProperty || !import_typescript.isObjectLiteralExpression(compilerOptionsProperty.initializer))
|
|
196080
|
+
if (!compilerOptionsProperty || !import_typescript.isObjectLiteralExpression(compilerOptionsProperty.initializer)) {
|
|
196081
|
+
if (isNone(lspVersion)) return emptyFileChangesResult();
|
|
196082
|
+
const ctx = createTrackerContext();
|
|
196083
|
+
const fileChange = tsInternal.textChanges.ChangeTracker.with(ctx, (tracker) => {
|
|
196084
|
+
const schemaProperty = findPropertyInObject(rootObj, "$schema");
|
|
196085
|
+
const shouldAddSchema = !schemaProperty;
|
|
196086
|
+
const shouldUpdateSchema = !!schemaProperty && (!import_typescript.isStringLiteral(schemaProperty.initializer) || schemaProperty.initializer.text !== TSCONFIG_SCHEMA_URL);
|
|
196087
|
+
if (shouldAddSchema) descriptions.push("Add $schema to tsconfig");
|
|
196088
|
+
else if (shouldUpdateSchema) descriptions.push("Update $schema in tsconfig");
|
|
196089
|
+
descriptions.push(`Add compilerOptions with ${LSP_PLUGIN_NAME} plugin`);
|
|
196090
|
+
const schemaPropertyAssignment = import_typescript.factory.createPropertyAssignment(import_typescript.factory.createStringLiteral("$schema"), import_typescript.factory.createStringLiteral(TSCONFIG_SCHEMA_URL));
|
|
196091
|
+
const compilerOptionsAssignment = import_typescript.factory.createPropertyAssignment(import_typescript.factory.createStringLiteral("compilerOptions"), import_typescript.factory.createObjectLiteralExpression([import_typescript.factory.createPropertyAssignment(import_typescript.factory.createStringLiteral("plugins"), import_typescript.factory.createArrayLiteralExpression([createLspPluginObject(target)], true))], true));
|
|
196092
|
+
const nextProperties = rootObj.properties.map((property) => {
|
|
196093
|
+
if (schemaProperty && property === schemaProperty) return schemaPropertyAssignment;
|
|
196094
|
+
return property;
|
|
196095
|
+
});
|
|
196096
|
+
if (shouldAddSchema) nextProperties.push(schemaPropertyAssignment);
|
|
196097
|
+
nextProperties.push(compilerOptionsAssignment);
|
|
196098
|
+
tracker.replaceNode(current.sourceFile, rootObj, import_typescript.factory.createObjectLiteralExpression(nextProperties, true));
|
|
196099
|
+
}).find((fc) => fc.fileName === current.sourceFile.fileName);
|
|
196100
|
+
const changes = fileChange ? fileChange.textChanges : [];
|
|
196101
|
+
if (changes.length === 0) return {
|
|
196102
|
+
codeActions: [],
|
|
196103
|
+
messages
|
|
196104
|
+
};
|
|
196105
|
+
return {
|
|
196106
|
+
codeActions: [{
|
|
196107
|
+
description: descriptions.join("; "),
|
|
196108
|
+
changes: [{
|
|
196109
|
+
fileName: current.sourceFile.fileName,
|
|
196110
|
+
textChanges: changes,
|
|
196111
|
+
isNewFile: false
|
|
196112
|
+
}]
|
|
196113
|
+
}],
|
|
196114
|
+
messages
|
|
196115
|
+
};
|
|
196116
|
+
}
|
|
196082
196117
|
const compilerOptions = compilerOptionsProperty.initializer;
|
|
196083
196118
|
const ctx = createTrackerContext();
|
|
196084
196119
|
const fileChange = tsInternal.textChanges.ChangeTracker.with(ctx, (tracker) => {
|
|
@@ -196421,314 +196456,905 @@ const renderCodeActions = (result, assessmentState) => gen(function* () {
|
|
|
196421
196456
|
});
|
|
196422
196457
|
|
|
196423
196458
|
//#endregion
|
|
196424
|
-
//#region src/
|
|
196425
|
-
var
|
|
196459
|
+
//#region src/metadata.json
|
|
196460
|
+
var groups = [
|
|
196426
196461
|
{
|
|
196427
|
-
"
|
|
196428
|
-
"
|
|
196429
|
-
"
|
|
196430
|
-
"codes": [377030]
|
|
196462
|
+
"id": "correctness",
|
|
196463
|
+
"name": "Correctness",
|
|
196464
|
+
"description": "Wrong, unsafe, or structurally invalid code patterns."
|
|
196431
196465
|
},
|
|
196432
196466
|
{
|
|
196433
|
-
"
|
|
196434
|
-
"
|
|
196435
|
-
"
|
|
196436
|
-
"codes": [377010]
|
|
196467
|
+
"id": "antipattern",
|
|
196468
|
+
"name": "Anti-pattern",
|
|
196469
|
+
"description": "Discouraged patterns that often lead to bugs or confusing behavior."
|
|
196437
196470
|
},
|
|
196438
196471
|
{
|
|
196439
|
-
"
|
|
196440
|
-
"
|
|
196441
|
-
"
|
|
196442
|
-
|
|
196472
|
+
"id": "effectNative",
|
|
196473
|
+
"name": "Effect-native",
|
|
196474
|
+
"description": "Prefer Effect-native APIs and abstractions when available."
|
|
196475
|
+
},
|
|
196476
|
+
{
|
|
196477
|
+
"id": "style",
|
|
196478
|
+
"name": "Style",
|
|
196479
|
+
"description": "Cleanup, consistency, and idiomatic Effect code."
|
|
196480
|
+
}
|
|
196481
|
+
];
|
|
196482
|
+
var rules = [
|
|
196483
|
+
{
|
|
196484
|
+
"name": "anyUnknownInErrorContext",
|
|
196485
|
+
"group": "correctness",
|
|
196486
|
+
"description": "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
196487
|
+
"defaultSeverity": "off",
|
|
196488
|
+
"fixable": false,
|
|
196489
|
+
"supportedEffect": ["v3", "v4"],
|
|
196490
|
+
"codes": [377030],
|
|
196491
|
+
"preview": {
|
|
196492
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.gen(function*() {\n yield* Effect.services<unknown>()\n return yield* Effect.fail<any>(\"boom\")\n})\n",
|
|
196493
|
+
"diagnostics": [
|
|
196494
|
+
{
|
|
196495
|
+
"start": 46,
|
|
196496
|
+
"end": 53,
|
|
196497
|
+
"text": "This has unknown in the requirements channel and any in the error channel which is not recommended.\nOnly service identifiers should appear in the requirements channel.\nHaving an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example. effect(anyUnknownInErrorContext)"
|
|
196498
|
+
},
|
|
196499
|
+
{
|
|
196500
|
+
"start": 90,
|
|
196501
|
+
"end": 116,
|
|
196502
|
+
"text": "This has unknown in the requirements channel which is not recommended.\nOnly service identifiers should appear in the requirements channel. effect(anyUnknownInErrorContext)"
|
|
196503
|
+
},
|
|
196504
|
+
{
|
|
196505
|
+
"start": 133,
|
|
196506
|
+
"end": 157,
|
|
196507
|
+
"text": "This has any in the error channel which is not recommended.\nHaving an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example. effect(anyUnknownInErrorContext)"
|
|
196508
|
+
}
|
|
196509
|
+
]
|
|
196510
|
+
}
|
|
196443
196511
|
},
|
|
196444
196512
|
{
|
|
196445
196513
|
"name": "classSelfMismatch",
|
|
196514
|
+
"group": "correctness",
|
|
196446
196515
|
"description": "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
196447
196516
|
"defaultSeverity": "error",
|
|
196448
|
-
"
|
|
196449
|
-
|
|
196450
|
-
|
|
196451
|
-
"
|
|
196452
|
-
|
|
196453
|
-
|
|
196454
|
-
|
|
196517
|
+
"fixable": true,
|
|
196518
|
+
"supportedEffect": ["v3", "v4"],
|
|
196519
|
+
"codes": [377046],
|
|
196520
|
+
"preview": {
|
|
196521
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\ninterface ServiceShape { value: number }\n\nexport class InvalidContextTag\n extends Effect.Tag(\"ValidContextTag\")<ValidContextTag, ServiceShape>() {}\n\ndeclare class ValidContextTag {}\n",
|
|
196522
|
+
"diagnostics": [{
|
|
196523
|
+
"start": 154,
|
|
196524
|
+
"end": 169,
|
|
196525
|
+
"text": "Self type parameter should be 'InvalidContextTag'. effect(classSelfMismatch)"
|
|
196526
|
+
}]
|
|
196527
|
+
}
|
|
196455
196528
|
},
|
|
196456
196529
|
{
|
|
196457
196530
|
"name": "duplicatePackage",
|
|
196531
|
+
"group": "correctness",
|
|
196458
196532
|
"description": "Warns when multiple versions of an Effect-related package are detected in the program",
|
|
196459
196533
|
"defaultSeverity": "warning",
|
|
196460
|
-
"
|
|
196534
|
+
"fixable": false,
|
|
196535
|
+
"supportedEffect": ["v3", "v4"],
|
|
196536
|
+
"codes": [377051],
|
|
196537
|
+
"preview": {
|
|
196538
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\n// This preview only reports when the workspace resolves duplicated\n// Effect package versions.\nexport const preview = Effect.succeed(true)\n",
|
|
196539
|
+
"diagnostics": []
|
|
196540
|
+
}
|
|
196461
196541
|
},
|
|
196462
196542
|
{
|
|
196463
|
-
"name": "
|
|
196464
|
-
"
|
|
196543
|
+
"name": "floatingEffect",
|
|
196544
|
+
"group": "correctness",
|
|
196545
|
+
"description": "Detects Effect values that are neither yielded nor assigned",
|
|
196546
|
+
"defaultSeverity": "error",
|
|
196547
|
+
"fixable": false,
|
|
196548
|
+
"supportedEffect": ["v3", "v4"],
|
|
196549
|
+
"codes": [377001, 377058],
|
|
196550
|
+
"preview": {
|
|
196551
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nEffect.log(\"forgotten\")\n",
|
|
196552
|
+
"diagnostics": [{
|
|
196553
|
+
"start": 41,
|
|
196554
|
+
"end": 64,
|
|
196555
|
+
"text": "Effect must be yielded or assigned to a variable. effect(floatingEffect)"
|
|
196556
|
+
}]
|
|
196557
|
+
}
|
|
196558
|
+
},
|
|
196559
|
+
{
|
|
196560
|
+
"name": "genericEffectServices",
|
|
196561
|
+
"group": "correctness",
|
|
196562
|
+
"description": "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
196465
196563
|
"defaultSeverity": "warning",
|
|
196466
|
-
"
|
|
196564
|
+
"fixable": false,
|
|
196565
|
+
"supportedEffect": ["v3", "v4"],
|
|
196566
|
+
"codes": [377043],
|
|
196567
|
+
"preview": {
|
|
196568
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport class Preview<_A> extends Effect.Service<Preview<any>>()(\"Preview\", {\n succeed: {}\n}) {}\n",
|
|
196569
|
+
"diagnostics": [{
|
|
196570
|
+
"start": 46,
|
|
196571
|
+
"end": 53,
|
|
196572
|
+
"text": "Effect Services with type parameters are not supported because they cannot be properly discriminated at runtime, which may cause unexpected behavior. effect(genericEffectServices)"
|
|
196573
|
+
}]
|
|
196574
|
+
}
|
|
196467
196575
|
},
|
|
196468
196576
|
{
|
|
196469
|
-
"name": "
|
|
196470
|
-
"
|
|
196471
|
-
"
|
|
196472
|
-
"
|
|
196577
|
+
"name": "missingEffectContext",
|
|
196578
|
+
"group": "correctness",
|
|
196579
|
+
"description": "Detects Effect values with unhandled context requirements",
|
|
196580
|
+
"defaultSeverity": "error",
|
|
196581
|
+
"fixable": false,
|
|
196582
|
+
"supportedEffect": ["v3", "v4"],
|
|
196583
|
+
"codes": [377004],
|
|
196584
|
+
"preview": {
|
|
196585
|
+
"sourceText": "import { Effect, ServiceMap } from \"effect\"\n\nclass Db extends ServiceMap.Service<Db>()(\"Db\", { make: Effect.succeed({}) }) {}\n\n// @ts-expect-error\nexport const preview: Effect.Effect<void> = Db.asEffect().pipe(Effect.asVoid)\n",
|
|
196586
|
+
"diagnostics": [{
|
|
196587
|
+
"start": 160,
|
|
196588
|
+
"end": 167,
|
|
196589
|
+
"text": "Missing context Db in the expected Effect type. effect(missingEffectContext)"
|
|
196590
|
+
}]
|
|
196591
|
+
}
|
|
196473
196592
|
},
|
|
196474
196593
|
{
|
|
196475
|
-
"name": "
|
|
196476
|
-
"
|
|
196477
|
-
"
|
|
196478
|
-
"
|
|
196594
|
+
"name": "missingEffectError",
|
|
196595
|
+
"group": "correctness",
|
|
196596
|
+
"description": "Detects Effect values with unhandled error types",
|
|
196597
|
+
"defaultSeverity": "error",
|
|
196598
|
+
"fixable": true,
|
|
196599
|
+
"supportedEffect": ["v3", "v4"],
|
|
196600
|
+
"codes": [377003],
|
|
196601
|
+
"preview": {
|
|
196602
|
+
"sourceText": "import type * as Effect from \"effect/Effect\"\nimport { Data } from \"effect\"\n\nclass Boom extends Data.TaggedError(\"Boom\")<{}> {}\ndeclare const effect: Effect.Effect<number, Boom>\n\n// @ts-expect-error\nexport const preview: () => Effect.Effect<number> = () => effect\n",
|
|
196603
|
+
"diagnostics": [{
|
|
196604
|
+
"start": 256,
|
|
196605
|
+
"end": 262,
|
|
196606
|
+
"text": "Missing errors Boom in the expected Effect type. effect(missingEffectError)"
|
|
196607
|
+
}]
|
|
196608
|
+
}
|
|
196479
196609
|
},
|
|
196480
196610
|
{
|
|
196481
|
-
"name": "
|
|
196482
|
-
"
|
|
196483
|
-
"
|
|
196484
|
-
"
|
|
196611
|
+
"name": "missingLayerContext",
|
|
196612
|
+
"group": "correctness",
|
|
196613
|
+
"description": "Detects Layer values with unhandled context requirements",
|
|
196614
|
+
"defaultSeverity": "error",
|
|
196615
|
+
"fixable": false,
|
|
196616
|
+
"supportedEffect": ["v3", "v4"],
|
|
196617
|
+
"codes": [377034],
|
|
196618
|
+
"preview": {
|
|
196619
|
+
"sourceText": "import { Effect, Layer, ServiceMap } from \"effect\"\n\nclass A extends ServiceMap.Service<A>()(\"A\", { make: Effect.succeed({}) }) {\n static Default = Layer.effect(this, this.make)\n}\ndeclare const layer: Layer.Layer<A, never, A>\n// @ts-expect-error\nexport const preview: Layer.Layer<A> = layer\n",
|
|
196620
|
+
"diagnostics": [{
|
|
196621
|
+
"start": 259,
|
|
196622
|
+
"end": 266,
|
|
196623
|
+
"text": "Missing 'A' in the expected Layer context. effect(missingLayerContext)"
|
|
196624
|
+
}]
|
|
196625
|
+
}
|
|
196485
196626
|
},
|
|
196486
196627
|
{
|
|
196487
|
-
"name": "
|
|
196488
|
-
"
|
|
196628
|
+
"name": "missingReturnYieldStar",
|
|
196629
|
+
"group": "correctness",
|
|
196630
|
+
"description": "Suggests using return yield* for Effects that never succeed",
|
|
196631
|
+
"defaultSeverity": "error",
|
|
196632
|
+
"fixable": true,
|
|
196633
|
+
"supportedEffect": ["v3", "v4"],
|
|
196634
|
+
"codes": [377006],
|
|
196635
|
+
"preview": {
|
|
196636
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.gen(function*() {\n yield* Effect.log(\"before\")\n yield* Effect.fail(\"boom\")\n})\n",
|
|
196637
|
+
"diagnostics": [{
|
|
196638
|
+
"start": 121,
|
|
196639
|
+
"end": 126,
|
|
196640
|
+
"text": "It is recommended to use return yield* for Effects that never succeed to signal a definitive exit point for type narrowing and tooling support. effect(missingReturnYieldStar)"
|
|
196641
|
+
}]
|
|
196642
|
+
}
|
|
196643
|
+
},
|
|
196644
|
+
{
|
|
196645
|
+
"name": "missingStarInYieldEffectGen",
|
|
196646
|
+
"group": "correctness",
|
|
196647
|
+
"description": "Detects bare yield (without *) inside Effect generator scopes",
|
|
196648
|
+
"defaultSeverity": "error",
|
|
196649
|
+
"fixable": true,
|
|
196650
|
+
"supportedEffect": ["v3", "v4"],
|
|
196651
|
+
"codes": [377007, 377008],
|
|
196652
|
+
"preview": {
|
|
196653
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.gen(function*() {\n const value = yield Effect.succeed(1)\n return value\n})\n",
|
|
196654
|
+
"diagnostics": [{
|
|
196655
|
+
"start": 105,
|
|
196656
|
+
"end": 110,
|
|
196657
|
+
"text": "When yielding Effects inside Effect.gen, you should use yield* instead of yield. effect(missingStarInYieldEffectGen)"
|
|
196658
|
+
}]
|
|
196659
|
+
}
|
|
196660
|
+
},
|
|
196661
|
+
{
|
|
196662
|
+
"name": "nonObjectEffectServiceType",
|
|
196663
|
+
"group": "correctness",
|
|
196664
|
+
"description": "Ensures Effect.Service types are objects, not primitives",
|
|
196665
|
+
"defaultSeverity": "error",
|
|
196666
|
+
"fixable": false,
|
|
196667
|
+
"supportedEffect": ["v3"],
|
|
196668
|
+
"codes": [377048],
|
|
196669
|
+
"preview": {
|
|
196670
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport class BadService extends Effect.Service<BadService>()(\"BadService\", {\n // @ts-expect-error\n succeed: \"hello\" as const\n}) {}\n",
|
|
196671
|
+
"diagnostics": [{
|
|
196672
|
+
"start": 142,
|
|
196673
|
+
"end": 149,
|
|
196674
|
+
"text": "Effect.Service requires the service type to be an object {} and not a primitive type. Consider wrapping the value in an object, or manually using Context.Tag or Effect.Tag if you want to use a primitive instead. effect(nonObjectEffectServiceType)"
|
|
196675
|
+
}]
|
|
196676
|
+
}
|
|
196677
|
+
},
|
|
196678
|
+
{
|
|
196679
|
+
"name": "outdatedApi",
|
|
196680
|
+
"group": "correctness",
|
|
196681
|
+
"description": "Detects usage of APIs that have been removed or renamed in Effect v4",
|
|
196489
196682
|
"defaultSeverity": "warning",
|
|
196490
|
-
"
|
|
196683
|
+
"fixable": false,
|
|
196684
|
+
"supportedEffect": ["v4"],
|
|
196685
|
+
"codes": [377052, 377053],
|
|
196686
|
+
"preview": {
|
|
196687
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.gen(function*() {\n // @ts-expect-error\n return yield* Effect.runtime()\n})\n",
|
|
196688
|
+
"diagnostics": [{
|
|
196689
|
+
"start": 0,
|
|
196690
|
+
"end": 0,
|
|
196691
|
+
"text": "This project targets Effect v4, but is using Effect v3 APIs. To find the correct API to use, consult the Effect v4 documentation for the corresponding v4 replacement. effect(outdatedApi)"
|
|
196692
|
+
}, {
|
|
196693
|
+
"start": 126,
|
|
196694
|
+
"end": 133,
|
|
196695
|
+
"text": "runtime is an Effect v3 API, but the project is using Effect v4. Runtime has been removed in Effect v4. Use Effect.services to grab services and then run using Effect.runPromiseWith. effect(outdatedApi)"
|
|
196696
|
+
}]
|
|
196697
|
+
}
|
|
196491
196698
|
},
|
|
196492
196699
|
{
|
|
196493
|
-
"name": "
|
|
196494
|
-
"
|
|
196495
|
-
"
|
|
196496
|
-
"
|
|
196700
|
+
"name": "overriddenSchemaConstructor",
|
|
196701
|
+
"group": "correctness",
|
|
196702
|
+
"description": "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
196703
|
+
"defaultSeverity": "error",
|
|
196704
|
+
"fixable": true,
|
|
196705
|
+
"supportedEffect": ["v3", "v4"],
|
|
196706
|
+
"codes": [377044],
|
|
196707
|
+
"preview": {
|
|
196708
|
+
"sourceText": "import * as Schema from \"effect/Schema\"\n\nexport class User extends Schema.Class<User>(\"User\")({ name: Schema.String }) {\n constructor(readonly input: { name: string }) { super(input) }\n}\n",
|
|
196709
|
+
"diagnostics": [{
|
|
196710
|
+
"start": 123,
|
|
196711
|
+
"end": 134,
|
|
196712
|
+
"text": "Classes extending Schema must not override the constructor; this is because it silently breaks the schema decoding behaviour. If that's needed, we recommend instead to use a static 'new' method that constructs the instance. effect(overriddenSchemaConstructor)"
|
|
196713
|
+
}]
|
|
196714
|
+
}
|
|
196497
196715
|
},
|
|
196498
196716
|
{
|
|
196499
|
-
"name": "
|
|
196500
|
-
"
|
|
196717
|
+
"name": "catchUnfailableEffect",
|
|
196718
|
+
"group": "antipattern",
|
|
196719
|
+
"description": "Warns when using error handling on Effects that never fail",
|
|
196501
196720
|
"defaultSeverity": "suggestion",
|
|
196502
|
-
"
|
|
196721
|
+
"fixable": false,
|
|
196722
|
+
"supportedEffect": ["v3", "v4"],
|
|
196723
|
+
"codes": [377009],
|
|
196724
|
+
"preview": {
|
|
196725
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.succeed(1).pipe(\n Effect.catch(() => Effect.succeed(0))\n)\n",
|
|
196726
|
+
"diagnostics": [{
|
|
196727
|
+
"start": 82,
|
|
196728
|
+
"end": 94,
|
|
196729
|
+
"text": "Looks like the previous effect never fails, so probably this error handling will never be triggered. effect(catchUnfailableEffect)"
|
|
196730
|
+
}]
|
|
196731
|
+
}
|
|
196503
196732
|
},
|
|
196504
196733
|
{
|
|
196505
|
-
"name": "
|
|
196506
|
-
"
|
|
196507
|
-
"
|
|
196508
|
-
"
|
|
196734
|
+
"name": "effectFnIife",
|
|
196735
|
+
"group": "antipattern",
|
|
196736
|
+
"description": "Effect.fn or Effect.fnUntraced is called as an IIFE; use Effect.gen instead",
|
|
196737
|
+
"defaultSeverity": "warning",
|
|
196738
|
+
"fixable": true,
|
|
196739
|
+
"supportedEffect": ["v3", "v4"],
|
|
196740
|
+
"codes": [377011],
|
|
196741
|
+
"preview": {
|
|
196742
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.fn(\"preview\")(function*() {\n return yield* Effect.succeed(1)\n})()\n",
|
|
196743
|
+
"diagnostics": [{
|
|
196744
|
+
"start": 64,
|
|
196745
|
+
"end": 137,
|
|
196746
|
+
"text": "Effect.fn returns a reusable function that can take arguments, but here it's called immediately. Use Effect.gen instead with Effect.withSpan(\"preview\") piped in the end to maintain tracing spans. effect(effectFnIife)"
|
|
196747
|
+
}]
|
|
196748
|
+
}
|
|
196509
196749
|
},
|
|
196510
196750
|
{
|
|
196511
|
-
"name": "
|
|
196512
|
-
"
|
|
196513
|
-
"
|
|
196514
|
-
"
|
|
196751
|
+
"name": "effectGenUsesAdapter",
|
|
196752
|
+
"group": "antipattern",
|
|
196753
|
+
"description": "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
196754
|
+
"defaultSeverity": "warning",
|
|
196755
|
+
"fixable": false,
|
|
196756
|
+
"supportedEffect": ["v3", "v4"],
|
|
196757
|
+
"codes": [377027],
|
|
196758
|
+
"preview": {
|
|
196759
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.gen(function*(_) {\n return yield* Effect.succeed(1)\n})\n",
|
|
196760
|
+
"diagnostics": [{
|
|
196761
|
+
"start": 85,
|
|
196762
|
+
"end": 86,
|
|
196763
|
+
"text": "The adapter of Effect.gen is not required anymore, it is now just an alias of pipe. effect(effectGenUsesAdapter)"
|
|
196764
|
+
}]
|
|
196765
|
+
}
|
|
196515
196766
|
},
|
|
196516
196767
|
{
|
|
196517
|
-
"name": "
|
|
196518
|
-
"
|
|
196768
|
+
"name": "effectInFailure",
|
|
196769
|
+
"group": "antipattern",
|
|
196770
|
+
"description": "Warns when an Effect is used inside an Effect failure channel",
|
|
196519
196771
|
"defaultSeverity": "warning",
|
|
196520
|
-
"
|
|
196772
|
+
"fixable": false,
|
|
196773
|
+
"supportedEffect": ["v3", "v4"],
|
|
196774
|
+
"codes": [377054],
|
|
196775
|
+
"preview": {
|
|
196776
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.try({\n try: () => JSON.parse(\"{\"),\n catch: (error) => Effect.logError(error)\n})\n",
|
|
196777
|
+
"diagnostics": [{
|
|
196778
|
+
"start": 46,
|
|
196779
|
+
"end": 53,
|
|
196780
|
+
"text": "The error channel contains an Effect (Effect<void, never, never>). Putting Effect computations in the failure channel is not intended; keep only failure types there. effect(effectInFailure)"
|
|
196781
|
+
}, {
|
|
196782
|
+
"start": 56,
|
|
196783
|
+
"end": 144,
|
|
196784
|
+
"text": "The error channel contains an Effect (Effect<void, never, never>). Putting Effect computations in the failure channel is not intended; keep only failure types there. effect(effectInFailure)"
|
|
196785
|
+
}]
|
|
196786
|
+
}
|
|
196787
|
+
},
|
|
196788
|
+
{
|
|
196789
|
+
"name": "effectInVoidSuccess",
|
|
196790
|
+
"group": "antipattern",
|
|
196791
|
+
"description": "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
196792
|
+
"defaultSeverity": "warning",
|
|
196793
|
+
"fixable": false,
|
|
196794
|
+
"supportedEffect": ["v3", "v4"],
|
|
196795
|
+
"codes": [377020],
|
|
196796
|
+
"preview": {
|
|
196797
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview: Effect.Effect<void> = Effect.succeed(\n Effect.log(\"nested\")\n)\n",
|
|
196798
|
+
"diagnostics": [{
|
|
196799
|
+
"start": 54,
|
|
196800
|
+
"end": 61,
|
|
196801
|
+
"text": "There is a nested 'Effect<void, never, never>' in the 'void' success channel, beware that this could lead to nested Effect<Effect<...>> that won't be executed. effect(effectInVoidSuccess)"
|
|
196802
|
+
}]
|
|
196803
|
+
}
|
|
196521
196804
|
},
|
|
196522
196805
|
{
|
|
196523
196806
|
"name": "globalErrorInEffectCatch",
|
|
196807
|
+
"group": "antipattern",
|
|
196524
196808
|
"description": "Warns when catch callbacks return global Error type instead of typed errors",
|
|
196525
196809
|
"defaultSeverity": "warning",
|
|
196526
|
-
"
|
|
196810
|
+
"fixable": false,
|
|
196811
|
+
"supportedEffect": ["v3", "v4"],
|
|
196812
|
+
"codes": [377022],
|
|
196813
|
+
"preview": {
|
|
196814
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.tryPromise({\n try: async () => 1,\n catch: (error) => new Error(String(error))\n})\n",
|
|
196815
|
+
"diagnostics": [{
|
|
196816
|
+
"start": 56,
|
|
196817
|
+
"end": 73,
|
|
196818
|
+
"text": "The 'catch' callback in Effect.tryPromise returns global 'Error', which loses type safety as untagged errors merge together. Consider using a tagged error and optionally wrapping the original in a 'cause' property. effect(globalErrorInEffectCatch)"
|
|
196819
|
+
}]
|
|
196820
|
+
}
|
|
196527
196821
|
},
|
|
196528
196822
|
{
|
|
196529
196823
|
"name": "globalErrorInEffectFailure",
|
|
196824
|
+
"group": "antipattern",
|
|
196530
196825
|
"description": "Warns when the global Error type is used in an Effect failure channel",
|
|
196531
196826
|
"defaultSeverity": "warning",
|
|
196532
|
-
"
|
|
196533
|
-
|
|
196534
|
-
|
|
196535
|
-
"
|
|
196536
|
-
|
|
196537
|
-
|
|
196538
|
-
|
|
196827
|
+
"fixable": false,
|
|
196828
|
+
"supportedEffect": ["v3", "v4"],
|
|
196829
|
+
"codes": [377023],
|
|
196830
|
+
"preview": {
|
|
196831
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.fail(new Error(\"boom\"))\n",
|
|
196832
|
+
"diagnostics": [{
|
|
196833
|
+
"start": 68,
|
|
196834
|
+
"end": 85,
|
|
196835
|
+
"text": "Global 'Error' loses type safety as untagged errors merge together in the Effect failure channel. Consider using a tagged error and optionally wrapping the original in a 'cause' property. effect(globalErrorInEffectFailure)"
|
|
196836
|
+
}]
|
|
196837
|
+
}
|
|
196539
196838
|
},
|
|
196540
196839
|
{
|
|
196541
196840
|
"name": "layerMergeAllWithDependencies",
|
|
196841
|
+
"group": "antipattern",
|
|
196542
196842
|
"description": "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
|
|
196543
196843
|
"defaultSeverity": "warning",
|
|
196544
|
-
"
|
|
196844
|
+
"fixable": true,
|
|
196845
|
+
"supportedEffect": ["v3", "v4"],
|
|
196846
|
+
"codes": [377035],
|
|
196847
|
+
"preview": {
|
|
196848
|
+
"sourceText": "import { Effect, Layer, ServiceMap } from \"effect\"\n\nclass A extends ServiceMap.Service<A>()(\"A\", { make: Effect.succeed({}) }) {\n static Default = Layer.effect(this, this.make)\n}\nclass B extends ServiceMap.Service<B>()(\"B\", { make: Effect.as(A.asEffect(), {}) }) {\n static Default = Layer.effect(this, this.make)\n}\nexport const preview = Layer.mergeAll(A.Default, B.Default)\n",
|
|
196849
|
+
"diagnostics": [{
|
|
196850
|
+
"start": 355,
|
|
196851
|
+
"end": 364,
|
|
196852
|
+
"text": "This layer provides A which is required by another layer in the same Layer.mergeAll call. Layer.mergeAll creates layers in parallel, so dependencies between layers will not be satisfied. Consider moving this layer into a Layer.provideMerge after the Layer.mergeAll. effect(layerMergeAllWithDependencies)"
|
|
196853
|
+
}]
|
|
196854
|
+
}
|
|
196545
196855
|
},
|
|
196546
196856
|
{
|
|
196547
196857
|
"name": "leakingRequirements",
|
|
196858
|
+
"group": "antipattern",
|
|
196548
196859
|
"description": "Detects implementation services leaked in service methods",
|
|
196549
196860
|
"defaultSeverity": "suggestion",
|
|
196550
|
-
"
|
|
196861
|
+
"fixable": false,
|
|
196862
|
+
"supportedEffect": ["v3", "v4"],
|
|
196863
|
+
"codes": [377041],
|
|
196864
|
+
"preview": {
|
|
196865
|
+
"sourceText": "import type { Effect } from \"effect\"\nimport { ServiceMap } from \"effect\"\n\nclass FileSystem extends ServiceMap.Service<FileSystem, {\n write: (s: string) => Effect.Effect<void>\n}>()(\"FileSystem\") {}\n\nexport class Cache extends ServiceMap.Service<Cache, {\n read: Effect.Effect<string, never, FileSystem>\n save: () => Effect.Effect<void, never, FileSystem>\n}>()(\"Cache\") {}\n",
|
|
196866
|
+
"diagnostics": [{
|
|
196867
|
+
"start": 212,
|
|
196868
|
+
"end": 217,
|
|
196869
|
+
"text": "Methods of this Service require 'FileSystem' from every caller. This leaks implementation details — resolve these dependencies at Layer creation time. effect(leakingRequirements)"
|
|
196870
|
+
}]
|
|
196871
|
+
}
|
|
196551
196872
|
},
|
|
196552
196873
|
{
|
|
196553
|
-
"name": "
|
|
196554
|
-
"
|
|
196555
|
-
"
|
|
196556
|
-
"
|
|
196874
|
+
"name": "multipleEffectProvide",
|
|
196875
|
+
"group": "antipattern",
|
|
196876
|
+
"description": "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
196877
|
+
"defaultSeverity": "warning",
|
|
196878
|
+
"fixable": true,
|
|
196879
|
+
"supportedEffect": ["v3", "v4"],
|
|
196880
|
+
"codes": [377033],
|
|
196881
|
+
"preview": {
|
|
196882
|
+
"sourceText": "import { Effect, Layer, ServiceMap } from \"effect\"\n\nclass A extends ServiceMap.Service<A>()(\"A\", { make: Effect.succeed({}) }) {\n static Default = Layer.effect(this, this.make)\n}\nclass B extends ServiceMap.Service<B>()(\"B\", { make: Effect.succeed({}) }) {\n static Default = Layer.effect(this, this.make)\n}\nexport const preview = Effect.void.pipe(Effect.provide(A.Default), Effect.provide(B.Default))\n",
|
|
196883
|
+
"diagnostics": [{
|
|
196884
|
+
"start": 348,
|
|
196885
|
+
"end": 373,
|
|
196886
|
+
"text": "Avoid chaining Effect.provide calls, as this can lead to service lifecycle issues. Instead, merge layers and provide them in a single call. effect(multipleEffectProvide)"
|
|
196887
|
+
}]
|
|
196888
|
+
}
|
|
196557
196889
|
},
|
|
196558
196890
|
{
|
|
196559
|
-
"name": "
|
|
196560
|
-
"
|
|
196561
|
-
"
|
|
196562
|
-
"
|
|
196891
|
+
"name": "returnEffectInGen",
|
|
196892
|
+
"group": "antipattern",
|
|
196893
|
+
"description": "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
196894
|
+
"defaultSeverity": "suggestion",
|
|
196895
|
+
"fixable": true,
|
|
196896
|
+
"supportedEffect": ["v3", "v4"],
|
|
196897
|
+
"codes": [377014],
|
|
196898
|
+
"preview": {
|
|
196899
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.gen(function*() {\n return Effect.succeed(1)\n})\n",
|
|
196900
|
+
"diagnostics": [{
|
|
196901
|
+
"start": 91,
|
|
196902
|
+
"end": 97,
|
|
196903
|
+
"text": "You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>.\nMaybe you wanted to return yield* instead?\nNested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect, if so you can safely disable this diagnostic for this line through quickfixes. effect(returnEffectInGen)"
|
|
196904
|
+
}]
|
|
196905
|
+
}
|
|
196563
196906
|
},
|
|
196564
196907
|
{
|
|
196565
|
-
"name": "
|
|
196566
|
-
"
|
|
196567
|
-
"
|
|
196568
|
-
"
|
|
196908
|
+
"name": "runEffectInsideEffect",
|
|
196909
|
+
"group": "antipattern",
|
|
196910
|
+
"description": "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
196911
|
+
"defaultSeverity": "suggestion",
|
|
196912
|
+
"fixable": true,
|
|
196913
|
+
"supportedEffect": ["v3"],
|
|
196914
|
+
"codes": [377024, 377025],
|
|
196915
|
+
"preview": {
|
|
196916
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.gen(function*() {\n const run = () => Effect.runSync(Effect.succeed(1))\n return run()\n})\n",
|
|
196917
|
+
"diagnostics": [{
|
|
196918
|
+
"start": 101,
|
|
196919
|
+
"end": 115,
|
|
196920
|
+
"text": "Using Effect.runSync inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.\nConsider extracting the Runtime by using for example Effect.runtime and then use Runtime.runSync with the extracted runtime instead. effect(runEffectInsideEffect)"
|
|
196921
|
+
}]
|
|
196922
|
+
}
|
|
196569
196923
|
},
|
|
196570
196924
|
{
|
|
196571
|
-
"name": "
|
|
196572
|
-
"
|
|
196573
|
-
"
|
|
196574
|
-
"
|
|
196925
|
+
"name": "schemaSyncInEffect",
|
|
196926
|
+
"group": "antipattern",
|
|
196927
|
+
"description": "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
196928
|
+
"defaultSeverity": "suggestion",
|
|
196929
|
+
"fixable": false,
|
|
196930
|
+
"supportedEffect": ["v3"],
|
|
196931
|
+
"codes": [377037],
|
|
196932
|
+
"preview": {
|
|
196933
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\n\nconst Person = Schema.Struct({ name: Schema.String, age: Schema.Number })\n\nexport const preview = Effect.gen(function*() {\n const input = yield* Effect.succeed({ name: \"Ada\", age: 1 })\n return Schema.decodeSync(Person)(input)\n})\n",
|
|
196934
|
+
"diagnostics": [{
|
|
196935
|
+
"start": 276,
|
|
196936
|
+
"end": 293,
|
|
196937
|
+
"text": "Using Schema.decodeSync inside an Effect generator is not recommended. Use Schema.decode instead to get properly typed error channel. effect(schemaSyncInEffect)"
|
|
196938
|
+
}]
|
|
196939
|
+
}
|
|
196575
196940
|
},
|
|
196576
196941
|
{
|
|
196577
|
-
"name": "
|
|
196578
|
-
"
|
|
196579
|
-
"
|
|
196580
|
-
"
|
|
196942
|
+
"name": "scopeInLayerEffect",
|
|
196943
|
+
"group": "antipattern",
|
|
196944
|
+
"description": "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
196945
|
+
"defaultSeverity": "warning",
|
|
196946
|
+
"fixable": true,
|
|
196947
|
+
"supportedEffect": ["v3"],
|
|
196948
|
+
"codes": [377031],
|
|
196949
|
+
"preview": {
|
|
196950
|
+
"sourceText": "import * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\n\nclass Cache extends Context.Tag(\"Cache\")<Cache, { ok: true }>() {}\nexport const preview = Layer.effect(Cache, Effect.gen(function*() {\n yield* Effect.addFinalizer(() => Effect.void)\n return { ok: true as const }\n}))\n",
|
|
196951
|
+
"diagnostics": [{
|
|
196952
|
+
"start": 211,
|
|
196953
|
+
"end": 338,
|
|
196954
|
+
"text": "Seems like you are constructing a layer with a scope in the requirements.\nConsider using \"scoped\" instead to get rid of the scope in the requirements. effect(scopeInLayerEffect)"
|
|
196955
|
+
}]
|
|
196956
|
+
}
|
|
196581
196957
|
},
|
|
196582
196958
|
{
|
|
196583
|
-
"name": "
|
|
196584
|
-
"
|
|
196585
|
-
"
|
|
196586
|
-
"
|
|
196959
|
+
"name": "strictEffectProvide",
|
|
196960
|
+
"group": "antipattern",
|
|
196961
|
+
"description": "Warns when using Effect.provide with layers outside of application entry points",
|
|
196962
|
+
"defaultSeverity": "off",
|
|
196963
|
+
"fixable": false,
|
|
196964
|
+
"supportedEffect": ["v3", "v4"],
|
|
196965
|
+
"codes": [377032],
|
|
196966
|
+
"preview": {
|
|
196967
|
+
"sourceText": "import { Effect, Layer, ServiceMap } from \"effect\"\n\nclass Config extends ServiceMap.Service<Config>()(\"Config\", { make: Effect.succeed({}) }) {\n static Default = Layer.effect(this, this.make)\n}\nexport const preview = Effect.void.pipe(Effect.provide(Config.Default))\n",
|
|
196968
|
+
"diagnostics": [{
|
|
196969
|
+
"start": 235,
|
|
196970
|
+
"end": 265,
|
|
196971
|
+
"text": "Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide)"
|
|
196972
|
+
}]
|
|
196973
|
+
}
|
|
196587
196974
|
},
|
|
196588
196975
|
{
|
|
196589
|
-
"name": "
|
|
196590
|
-
"
|
|
196591
|
-
"
|
|
196592
|
-
"
|
|
196976
|
+
"name": "tryCatchInEffectGen",
|
|
196977
|
+
"group": "antipattern",
|
|
196978
|
+
"description": "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
196979
|
+
"defaultSeverity": "suggestion",
|
|
196980
|
+
"fixable": false,
|
|
196981
|
+
"supportedEffect": ["v3", "v4"],
|
|
196982
|
+
"codes": [377012],
|
|
196983
|
+
"preview": {
|
|
196984
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.gen(function*() {\n try { return yield* Effect.succeed(1) }\n catch { return 0 }\n})\n",
|
|
196985
|
+
"diagnostics": [{
|
|
196986
|
+
"start": 91,
|
|
196987
|
+
"end": 151,
|
|
196988
|
+
"text": "Avoid using try/catch inside Effect generators. Use Effect's error handling mechanisms instead (e.g. Effect.try, Effect.tryPromise, Effect.catch, Effect.catchTag). effect(tryCatchInEffectGen)"
|
|
196989
|
+
}]
|
|
196990
|
+
}
|
|
196593
196991
|
},
|
|
196594
196992
|
{
|
|
196595
|
-
"name": "
|
|
196596
|
-
"
|
|
196993
|
+
"name": "unknownInEffectCatch",
|
|
196994
|
+
"group": "antipattern",
|
|
196995
|
+
"description": "Warns when catch callbacks return unknown instead of typed errors",
|
|
196597
196996
|
"defaultSeverity": "warning",
|
|
196598
|
-
"
|
|
196997
|
+
"fixable": false,
|
|
196998
|
+
"supportedEffect": ["v3", "v4"],
|
|
196999
|
+
"codes": [377021],
|
|
197000
|
+
"preview": {
|
|
197001
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.tryPromise({\n try: async () => 1,\n catch: (error) => error\n})\n",
|
|
197002
|
+
"diagnostics": [{
|
|
197003
|
+
"start": 56,
|
|
197004
|
+
"end": 73,
|
|
197005
|
+
"text": "The 'catch' callback in Effect.tryPromise returns 'unknown'. The catch callback should be used to provide typed errors.\nConsider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised. effect(unknownInEffectCatch)"
|
|
197006
|
+
}]
|
|
197007
|
+
}
|
|
197008
|
+
},
|
|
197009
|
+
{
|
|
197010
|
+
"name": "extendsNativeError",
|
|
197011
|
+
"group": "effectNative",
|
|
197012
|
+
"description": "Warns when a class directly extends the native Error class",
|
|
197013
|
+
"defaultSeverity": "off",
|
|
197014
|
+
"fixable": false,
|
|
197015
|
+
"supportedEffect": ["v3", "v4"],
|
|
197016
|
+
"codes": [377055],
|
|
197017
|
+
"preview": {
|
|
197018
|
+
"sourceText": "\nexport class PreviewError extends Error {}\n",
|
|
197019
|
+
"diagnostics": [{
|
|
197020
|
+
"start": 14,
|
|
197021
|
+
"end": 26,
|
|
197022
|
+
"text": "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. effect(extendsNativeError)"
|
|
197023
|
+
}]
|
|
197024
|
+
}
|
|
197025
|
+
},
|
|
197026
|
+
{
|
|
197027
|
+
"name": "instanceOfSchema",
|
|
197028
|
+
"group": "effectNative",
|
|
197029
|
+
"description": "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
197030
|
+
"defaultSeverity": "off",
|
|
197031
|
+
"fixable": true,
|
|
197032
|
+
"supportedEffect": ["v3", "v4"],
|
|
197033
|
+
"codes": [377042],
|
|
197034
|
+
"preview": {
|
|
197035
|
+
"sourceText": "import { Schema } from \"effect\"\n\nclass User extends Schema.Class<User>(\"User\")({ name: Schema.String }) {}\ndeclare const value: unknown\nexport const preview = value instanceof User\n",
|
|
197036
|
+
"diagnostics": [{
|
|
197037
|
+
"start": 159,
|
|
197038
|
+
"end": 180,
|
|
197039
|
+
"text": "Consider using Schema.is instead of instanceof for Effect Schema types. effect(instanceOfSchema)"
|
|
197040
|
+
}]
|
|
197041
|
+
}
|
|
196599
197042
|
},
|
|
196600
197043
|
{
|
|
196601
197044
|
"name": "nodeBuiltinImport",
|
|
197045
|
+
"group": "effectNative",
|
|
196602
197046
|
"description": "Warns when importing Node.js built-in modules that have Effect-native counterparts",
|
|
196603
197047
|
"defaultSeverity": "off",
|
|
196604
|
-
"
|
|
197048
|
+
"fixable": false,
|
|
197049
|
+
"supportedEffect": ["v3", "v4"],
|
|
197050
|
+
"codes": [377057],
|
|
197051
|
+
"preview": {
|
|
197052
|
+
"sourceText": "import fs from \"node:fs\"\n\nexport const preview = fs.readFileSync\n",
|
|
197053
|
+
"diagnostics": [{
|
|
197054
|
+
"start": 15,
|
|
197055
|
+
"end": 24,
|
|
197056
|
+
"text": "Prefer using FileSystem from @effect/platform instead of the Node.js 'fs' module. effect(nodeBuiltinImport)"
|
|
197057
|
+
}]
|
|
197058
|
+
}
|
|
196605
197059
|
},
|
|
196606
197060
|
{
|
|
196607
|
-
"name": "
|
|
196608
|
-
"
|
|
196609
|
-
"
|
|
196610
|
-
"
|
|
197061
|
+
"name": "preferSchemaOverJson",
|
|
197062
|
+
"group": "effectNative",
|
|
197063
|
+
"description": "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify",
|
|
197064
|
+
"defaultSeverity": "suggestion",
|
|
197065
|
+
"fixable": false,
|
|
197066
|
+
"supportedEffect": ["v3", "v4"],
|
|
197067
|
+
"codes": [377026],
|
|
197068
|
+
"preview": {
|
|
197069
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.gen(function*() {\n const text = yield* Effect.succeed('{\"ok\":true}')\n return JSON.parse(text)\n})\n",
|
|
197070
|
+
"diagnostics": [{
|
|
197071
|
+
"start": 142,
|
|
197072
|
+
"end": 158,
|
|
197073
|
+
"text": "Consider using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify. effect(preferSchemaOverJson)"
|
|
197074
|
+
}]
|
|
197075
|
+
}
|
|
196611
197076
|
},
|
|
196612
197077
|
{
|
|
196613
|
-
"name": "
|
|
196614
|
-
"
|
|
196615
|
-
"
|
|
196616
|
-
"
|
|
197078
|
+
"name": "catchAllToMapError",
|
|
197079
|
+
"group": "style",
|
|
197080
|
+
"description": "Suggests using Effect.mapError instead of Effect.catch + Effect.fail",
|
|
197081
|
+
"defaultSeverity": "suggestion",
|
|
197082
|
+
"fixable": true,
|
|
197083
|
+
"supportedEffect": ["v3", "v4"],
|
|
197084
|
+
"codes": [377010],
|
|
197085
|
+
"preview": {
|
|
197086
|
+
"sourceText": "import { Effect } from \"effect\"\n\nclass WrappedError {\n constructor(readonly cause: unknown) {}\n}\n\nexport const preview = Effect.fail(\"boom\").pipe(\n Effect.catch((cause) => Effect.fail(new WrappedError(cause)))\n)\n",
|
|
197087
|
+
"diagnostics": [{
|
|
197088
|
+
"start": 150,
|
|
197089
|
+
"end": 162,
|
|
197090
|
+
"text": "You can use Effect.mapError instead of Effect.catch + Effect.fail to transform the error type. effect(catchAllToMapError)"
|
|
197091
|
+
}]
|
|
197092
|
+
}
|
|
196617
197093
|
},
|
|
196618
197094
|
{
|
|
196619
|
-
"name": "
|
|
196620
|
-
"
|
|
196621
|
-
"
|
|
196622
|
-
"
|
|
197095
|
+
"name": "deterministicKeys",
|
|
197096
|
+
"group": "style",
|
|
197097
|
+
"description": "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
197098
|
+
"defaultSeverity": "off",
|
|
197099
|
+
"fixable": true,
|
|
197100
|
+
"supportedEffect": ["v3", "v4"],
|
|
197101
|
+
"codes": [377049],
|
|
197102
|
+
"preview": {
|
|
197103
|
+
"sourceText": "import { ServiceMap } from \"effect\"\n\nexport class RenamedService\n extends ServiceMap.Service<RenamedService, {}>()(\"CustomIdentifier\") {}\n",
|
|
197104
|
+
"diagnostics": []
|
|
197105
|
+
}
|
|
196623
197106
|
},
|
|
196624
197107
|
{
|
|
196625
|
-
"name": "
|
|
196626
|
-
"
|
|
197108
|
+
"name": "effectFnOpportunity",
|
|
197109
|
+
"group": "style",
|
|
197110
|
+
"description": "Suggests using Effect.fn for functions that return an Effect",
|
|
196627
197111
|
"defaultSeverity": "suggestion",
|
|
196628
|
-
"
|
|
197112
|
+
"fixable": true,
|
|
197113
|
+
"supportedEffect": ["v3", "v4"],
|
|
197114
|
+
"codes": [377047],
|
|
197115
|
+
"preview": {
|
|
197116
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = () => Effect.gen(function*() {\n return yield* Effect.succeed(1)\n})\n",
|
|
197117
|
+
"diagnostics": [{
|
|
197118
|
+
"start": 54,
|
|
197119
|
+
"end": 61,
|
|
197120
|
+
"text": "Can be rewritten as a reusable function: Effect.fn(function*() { ... }). effect(effectFnOpportunity)"
|
|
197121
|
+
}]
|
|
197122
|
+
}
|
|
196629
197123
|
},
|
|
196630
197124
|
{
|
|
196631
|
-
"name": "
|
|
196632
|
-
"
|
|
197125
|
+
"name": "effectMapVoid",
|
|
197126
|
+
"group": "style",
|
|
197127
|
+
"description": "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
|
|
196633
197128
|
"defaultSeverity": "suggestion",
|
|
196634
|
-
"
|
|
197129
|
+
"fixable": true,
|
|
197130
|
+
"supportedEffect": ["v3", "v4"],
|
|
197131
|
+
"codes": [377018],
|
|
197132
|
+
"preview": {
|
|
197133
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.succeed(1).pipe(\n Effect.map(() => undefined)\n)\n",
|
|
197134
|
+
"diagnostics": [{
|
|
197135
|
+
"start": 82,
|
|
197136
|
+
"end": 92,
|
|
197137
|
+
"text": "Effect.asVoid can be used instead to discard the success value. effect(effectMapVoid)"
|
|
197138
|
+
}]
|
|
197139
|
+
}
|
|
196635
197140
|
},
|
|
196636
197141
|
{
|
|
196637
|
-
"name": "
|
|
196638
|
-
"
|
|
197142
|
+
"name": "effectSucceedWithVoid",
|
|
197143
|
+
"group": "style",
|
|
197144
|
+
"description": "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
196639
197145
|
"defaultSeverity": "suggestion",
|
|
196640
|
-
"
|
|
197146
|
+
"fixable": true,
|
|
197147
|
+
"supportedEffect": ["v3", "v4"],
|
|
197148
|
+
"codes": [377016],
|
|
197149
|
+
"preview": {
|
|
197150
|
+
"sourceText": "import { Effect } from \"effect\"\n\nexport const preview = Effect.succeed(undefined)\n",
|
|
197151
|
+
"diagnostics": [{
|
|
197152
|
+
"start": 56,
|
|
197153
|
+
"end": 81,
|
|
197154
|
+
"text": "Effect.void can be used instead of Effect.succeed(undefined) or Effect.succeed(void 0). effect(effectSucceedWithVoid)"
|
|
197155
|
+
}]
|
|
197156
|
+
}
|
|
196641
197157
|
},
|
|
196642
197158
|
{
|
|
196643
|
-
"name": "
|
|
196644
|
-
"
|
|
196645
|
-
"
|
|
196646
|
-
"
|
|
197159
|
+
"name": "missedPipeableOpportunity",
|
|
197160
|
+
"group": "style",
|
|
197161
|
+
"description": "Suggests using .pipe() for nested function calls",
|
|
197162
|
+
"defaultSeverity": "off",
|
|
197163
|
+
"fixable": true,
|
|
197164
|
+
"supportedEffect": ["v3", "v4"],
|
|
197165
|
+
"codes": [377050],
|
|
197166
|
+
"preview": {
|
|
197167
|
+
"sourceText": "import { identity, Schema } from \"effect\"\n\nconst User = Schema.Struct({ id: Schema.Number })\nexport const preview = identity(identity(Schema.decodeEffect(User)({ id: 1 })))\n",
|
|
197168
|
+
"diagnostics": [{
|
|
197169
|
+
"start": 116,
|
|
197170
|
+
"end": 172,
|
|
197171
|
+
"text": "Nested function calls can be converted to pipeable style for better readability; consider using Schema.decodeEffect(User)({ id: 1 }).pipe(...) instead. effect(missedPipeableOpportunity)"
|
|
197172
|
+
}]
|
|
197173
|
+
}
|
|
196647
197174
|
},
|
|
196648
197175
|
{
|
|
196649
|
-
"name": "
|
|
196650
|
-
"
|
|
197176
|
+
"name": "missingEffectServiceDependency",
|
|
197177
|
+
"group": "style",
|
|
197178
|
+
"description": "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
197179
|
+
"defaultSeverity": "off",
|
|
197180
|
+
"fixable": false,
|
|
197181
|
+
"supportedEffect": ["v3"],
|
|
197182
|
+
"codes": [377039, 377040],
|
|
197183
|
+
"preview": {
|
|
197184
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nclass Db extends Effect.Service<Db>()(\"Db\", { succeed: { ok: true } }) {}\nexport class Repo extends Effect.Service<Repo>()(\"Repo\", {\n effect: Effect.gen(function*() {\n yield* Db\n return { all: Effect.succeed([] as Array<number>) }\n })\n}) {}\n",
|
|
197185
|
+
"diagnostics": [{
|
|
197186
|
+
"start": 128,
|
|
197187
|
+
"end": 132,
|
|
197188
|
+
"text": "Service 'Db' is required but not provided by dependencies. effect(missingEffectServiceDependency)"
|
|
197189
|
+
}]
|
|
197190
|
+
}
|
|
197191
|
+
},
|
|
197192
|
+
{
|
|
197193
|
+
"name": "redundantSchemaTagIdentifier",
|
|
197194
|
+
"group": "style",
|
|
197195
|
+
"description": "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
|
|
196651
197196
|
"defaultSeverity": "suggestion",
|
|
196652
|
-
"
|
|
197197
|
+
"fixable": true,
|
|
197198
|
+
"supportedEffect": ["v3", "v4"],
|
|
197199
|
+
"codes": [377045],
|
|
197200
|
+
"preview": {
|
|
197201
|
+
"sourceText": "import * as Schema from \"effect/Schema\"\n\nexport class Preview\n extends Schema.TaggedClass<Preview>(\"Preview\")(\"Preview\", {\n value: Schema.String\n }) {}\n",
|
|
197202
|
+
"diagnostics": [{
|
|
197203
|
+
"start": 100,
|
|
197204
|
+
"end": 109,
|
|
197205
|
+
"text": "Identifier 'Preview' is redundant since it equals the _tag value. effect(redundantSchemaTagIdentifier)"
|
|
197206
|
+
}]
|
|
197207
|
+
}
|
|
196653
197208
|
},
|
|
196654
197209
|
{
|
|
196655
|
-
"name": "
|
|
196656
|
-
"
|
|
197210
|
+
"name": "schemaStructWithTag",
|
|
197211
|
+
"group": "style",
|
|
197212
|
+
"description": "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
196657
197213
|
"defaultSeverity": "suggestion",
|
|
196658
|
-
"
|
|
197214
|
+
"fixable": true,
|
|
197215
|
+
"supportedEffect": ["v3", "v4"],
|
|
197216
|
+
"codes": [377036],
|
|
197217
|
+
"preview": {
|
|
197218
|
+
"sourceText": "import * as Schema from \"effect/Schema\"\n\nexport const preview = Schema.Struct({\n _tag: Schema.Literal(\"User\"),\n name: Schema.String\n})\n",
|
|
197219
|
+
"diagnostics": [{
|
|
197220
|
+
"start": 64,
|
|
197221
|
+
"end": 136,
|
|
197222
|
+
"text": "Schema.Struct with a _tag field can be simplified to Schema.TaggedStruct to make the tag optional in the constructor. effect(schemaStructWithTag)"
|
|
197223
|
+
}]
|
|
197224
|
+
}
|
|
196659
197225
|
},
|
|
196660
197226
|
{
|
|
196661
197227
|
"name": "schemaUnionOfLiterals",
|
|
197228
|
+
"group": "style",
|
|
196662
197229
|
"description": "Suggests combining multiple Schema.Literal calls in Schema.Union into a single Schema.Literal",
|
|
196663
197230
|
"defaultSeverity": "off",
|
|
196664
|
-
"
|
|
196665
|
-
|
|
196666
|
-
|
|
196667
|
-
"
|
|
196668
|
-
|
|
196669
|
-
|
|
196670
|
-
|
|
197231
|
+
"fixable": true,
|
|
197232
|
+
"supportedEffect": ["v3"],
|
|
197233
|
+
"codes": [377038],
|
|
197234
|
+
"preview": {
|
|
197235
|
+
"sourceText": "import * as Schema from \"effect/Schema\"\n\nexport const preview = Schema.Union(Schema.Literal(\"a\"), Schema.Literal(\"b\"))\n",
|
|
197236
|
+
"diagnostics": [{
|
|
197237
|
+
"start": 64,
|
|
197238
|
+
"end": 118,
|
|
197239
|
+
"text": "A Schema.Union of multiple Schema.Literal calls can be simplified to a single Schema.Literal call. effect(schemaUnionOfLiterals)"
|
|
197240
|
+
}]
|
|
197241
|
+
}
|
|
196671
197242
|
},
|
|
196672
197243
|
{
|
|
196673
197244
|
"name": "serviceNotAsClass",
|
|
197245
|
+
"group": "style",
|
|
196674
197246
|
"description": "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
|
|
196675
197247
|
"defaultSeverity": "off",
|
|
196676
|
-
"
|
|
197248
|
+
"fixable": true,
|
|
197249
|
+
"supportedEffect": ["v4"],
|
|
197250
|
+
"codes": [377056],
|
|
197251
|
+
"preview": {
|
|
197252
|
+
"sourceText": "import { ServiceMap } from \"effect\"\n\nexport const Preview = ServiceMap.Service<{ port: number }>(\"Preview\")\n",
|
|
197253
|
+
"diagnostics": [{
|
|
197254
|
+
"start": 60,
|
|
197255
|
+
"end": 107,
|
|
197256
|
+
"text": "ServiceMap.Service should be used in a class declaration instead of as a variable. Use: class Preview extends ServiceMap.Service<Preview, { port: number }>()(\"Preview\") {} effect(serviceNotAsClass)"
|
|
197257
|
+
}]
|
|
197258
|
+
}
|
|
196677
197259
|
},
|
|
196678
197260
|
{
|
|
196679
197261
|
"name": "strictBooleanExpressions",
|
|
197262
|
+
"group": "style",
|
|
196680
197263
|
"description": "Enforces boolean types in conditional expressions for type safety",
|
|
196681
197264
|
"defaultSeverity": "off",
|
|
196682
|
-
"
|
|
196683
|
-
|
|
196684
|
-
|
|
196685
|
-
"
|
|
196686
|
-
|
|
196687
|
-
|
|
196688
|
-
|
|
196689
|
-
|
|
196690
|
-
|
|
196691
|
-
|
|
196692
|
-
|
|
196693
|
-
|
|
196694
|
-
|
|
196695
|
-
|
|
196696
|
-
|
|
196697
|
-
"name": "unknownInEffectCatch",
|
|
196698
|
-
"description": "Warns when catch callbacks return unknown instead of typed errors",
|
|
196699
|
-
"defaultSeverity": "warning",
|
|
196700
|
-
"codes": [377021]
|
|
197265
|
+
"fixable": false,
|
|
197266
|
+
"supportedEffect": ["v3", "v4"],
|
|
197267
|
+
"codes": [377029],
|
|
197268
|
+
"preview": {
|
|
197269
|
+
"sourceText": "\ndeclare const value: string | undefined\nexport const preview = value ? 1 : 0\n",
|
|
197270
|
+
"diagnostics": [{
|
|
197271
|
+
"start": 64,
|
|
197272
|
+
"end": 69,
|
|
197273
|
+
"text": "Unexpected `string` type in condition, expected strictly a boolean instead. effect(strictBooleanExpressions)"
|
|
197274
|
+
}, {
|
|
197275
|
+
"start": 64,
|
|
197276
|
+
"end": 69,
|
|
197277
|
+
"text": "Unexpected `undefined` type in condition, expected strictly a boolean instead. effect(strictBooleanExpressions)"
|
|
197278
|
+
}]
|
|
197279
|
+
}
|
|
196701
197280
|
},
|
|
196702
197281
|
{
|
|
196703
197282
|
"name": "unnecessaryEffectGen",
|
|
197283
|
+
"group": "style",
|
|
196704
197284
|
"description": "Suggests removing Effect.gen when it contains only a single return statement",
|
|
196705
197285
|
"defaultSeverity": "suggestion",
|
|
196706
|
-
"
|
|
197286
|
+
"fixable": true,
|
|
197287
|
+
"supportedEffect": ["v3", "v4"],
|
|
197288
|
+
"codes": [377017],
|
|
197289
|
+
"preview": {
|
|
197290
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.gen(function*() {\n return yield* Effect.succeed(1)\n})\n",
|
|
197291
|
+
"diagnostics": [{
|
|
197292
|
+
"start": 64,
|
|
197293
|
+
"end": 125,
|
|
197294
|
+
"text": "This Effect.gen contains a single return statement. effect(unnecessaryEffectGen)"
|
|
197295
|
+
}]
|
|
197296
|
+
}
|
|
196707
197297
|
},
|
|
196708
197298
|
{
|
|
196709
197299
|
"name": "unnecessaryFailYieldableError",
|
|
197300
|
+
"group": "style",
|
|
196710
197301
|
"description": "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
196711
197302
|
"defaultSeverity": "suggestion",
|
|
196712
|
-
"
|
|
197303
|
+
"fixable": true,
|
|
197304
|
+
"supportedEffect": ["v3", "v4"],
|
|
197305
|
+
"codes": [377019],
|
|
197306
|
+
"preview": {
|
|
197307
|
+
"sourceText": "import * as Data from \"effect/Data\"\nimport * as Effect from \"effect/Effect\"\n\nclass Boom extends Data.TaggedError(\"Boom\")<{}> {}\nexport const preview = Effect.gen(function*() {\n yield* Effect.fail(new Boom())\n})\n",
|
|
197308
|
+
"diagnostics": [{
|
|
197309
|
+
"start": 178,
|
|
197310
|
+
"end": 183,
|
|
197311
|
+
"text": "This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead. effect(unnecessaryFailYieldableError)"
|
|
197312
|
+
}]
|
|
197313
|
+
}
|
|
196713
197314
|
},
|
|
196714
197315
|
{
|
|
196715
197316
|
"name": "unnecessaryPipe",
|
|
197317
|
+
"group": "style",
|
|
196716
197318
|
"description": "Removes pipe calls with no arguments",
|
|
196717
197319
|
"defaultSeverity": "suggestion",
|
|
196718
|
-
"
|
|
197320
|
+
"fixable": true,
|
|
197321
|
+
"supportedEffect": ["v3", "v4"],
|
|
197322
|
+
"codes": [377013],
|
|
197323
|
+
"preview": {
|
|
197324
|
+
"sourceText": "import { pipe } from \"effect/Function\"\n\nexport const preview = pipe(1)\n",
|
|
197325
|
+
"diagnostics": [{
|
|
197326
|
+
"start": 63,
|
|
197327
|
+
"end": 70,
|
|
197328
|
+
"text": "This pipe call contains no arguments. effect(unnecessaryPipe)"
|
|
197329
|
+
}]
|
|
197330
|
+
}
|
|
196719
197331
|
},
|
|
196720
197332
|
{
|
|
196721
197333
|
"name": "unnecessaryPipeChain",
|
|
197334
|
+
"group": "style",
|
|
196722
197335
|
"description": "Simplifies chained pipe calls into a single pipe call",
|
|
196723
197336
|
"defaultSeverity": "suggestion",
|
|
196724
|
-
"
|
|
197337
|
+
"fixable": true,
|
|
197338
|
+
"supportedEffect": ["v3", "v4"],
|
|
197339
|
+
"codes": [377015],
|
|
197340
|
+
"preview": {
|
|
197341
|
+
"sourceText": "import * as Effect from \"effect/Effect\"\n\nexport const preview = Effect.succeed(1).pipe(Effect.asVoid).pipe(Effect.as(\"done\"))\n",
|
|
197342
|
+
"diagnostics": [{
|
|
197343
|
+
"start": 64,
|
|
197344
|
+
"end": 125,
|
|
197345
|
+
"text": "Chained pipe calls can be simplified to a single pipe call. effect(unnecessaryPipeChain)"
|
|
197346
|
+
}]
|
|
197347
|
+
}
|
|
196725
197348
|
}
|
|
196726
197349
|
];
|
|
196727
197350
|
|
|
196728
197351
|
//#endregion
|
|
196729
197352
|
//#region src/setup/rule-info.ts
|
|
196730
197353
|
function getAllRules() {
|
|
196731
|
-
return
|
|
197354
|
+
return rules;
|
|
197355
|
+
}
|
|
197356
|
+
function getAllGroups() {
|
|
197357
|
+
return groups;
|
|
196732
197358
|
}
|
|
196733
197359
|
function cycleSeverity(current, direction) {
|
|
196734
197360
|
const order = [
|
|
@@ -196759,187 +197385,349 @@ function getSeverityShortName(severity) {
|
|
|
196759
197385
|
const RESET = "\x1B[0m";
|
|
196760
197386
|
const BOLD = "\x1B[0;1m";
|
|
196761
197387
|
const DIM = "\x1B[0;90m";
|
|
196762
|
-
const
|
|
196763
|
-
const
|
|
196764
|
-
const
|
|
196765
|
-
const
|
|
196766
|
-
const
|
|
196767
|
-
const BG_YELLOW = "\x1B[43m";
|
|
196768
|
-
const BG_BLUE = "\x1B[0;44m";
|
|
196769
|
-
const BG_CYAN = "\x1B[0;46m";
|
|
197388
|
+
const RED = "\x1B[0;31m";
|
|
197389
|
+
const YELLOW = "\x1B[0;33m";
|
|
197390
|
+
const BLUE = "\x1B[0;34m";
|
|
197391
|
+
const ITALIC = "\x1B[0;3m";
|
|
197392
|
+
const UNDERLINE = "\x1B[0;4m";
|
|
196770
197393
|
const ansi = (text, code) => `${code}${text}${RESET}`;
|
|
196771
197394
|
const ERASE_LINE = "\x1B[2K";
|
|
196772
197395
|
const CURSOR_LEFT = "\r";
|
|
196773
197396
|
const CURSOR_HIDE = "\x1B[?25l";
|
|
196774
197397
|
const CURSOR_TO_0 = "\x1B[G";
|
|
196775
197398
|
const BEEP = "\x07";
|
|
197399
|
+
const ANSI_ESCAPE_REGEX = new RegExp(String.raw`\u001b\[[0-?]*[ -/]*[@-~]`, "g");
|
|
197400
|
+
const stripAnsi = (text) => text.replace(ANSI_ESCAPE_REGEX, "");
|
|
197401
|
+
const visibleLength = (text) => stripAnsi(text).length;
|
|
196776
197402
|
|
|
196777
197403
|
//#endregion
|
|
196778
197404
|
//#region src/setup/rule-prompt.ts
|
|
196779
|
-
|
|
196780
|
-
let result = "";
|
|
196781
|
-
for (let i = 0; i < count; i++) {
|
|
196782
|
-
if (i > 0) result += "\x1B[1A";
|
|
196783
|
-
result += ERASE_LINE;
|
|
196784
|
-
}
|
|
196785
|
-
if (count > 0) result += CURSOR_LEFT;
|
|
196786
|
-
return result;
|
|
196787
|
-
}
|
|
197405
|
+
const diagnosticGroups = getAllGroups();
|
|
196788
197406
|
const Action = taggedEnum();
|
|
196789
|
-
const
|
|
196790
|
-
|
|
196791
|
-
|
|
196792
|
-
|
|
196793
|
-
const lines = text.split(/\r?\n/);
|
|
196794
|
-
for (const line of lines) rows += 1 + Math.floor(Math.max(line.length - 1, 0) / columns);
|
|
196795
|
-
return eraseLines(rows);
|
|
197407
|
+
const SEARCH_ICON = "/";
|
|
197408
|
+
const MIN_PREVIEW_AND_MESSAGES_LINES = 18;
|
|
197409
|
+
function getControlsLegend(searchText) {
|
|
197410
|
+
return `\u2190/\u2192 change rule \u2191/\u2193 change severity ${searchText.length === 0 ? `${SEARCH_ICON} type to search` : `${SEARCH_ICON} searching: ${searchText}`}`;
|
|
196796
197411
|
}
|
|
196797
|
-
function
|
|
196798
|
-
const max = maxVisible === void 0 ? total : maxVisible;
|
|
196799
|
-
let startIndex = Math.min(total - max, cursor - Math.floor(max / 2));
|
|
196800
|
-
if (startIndex < 0) startIndex = 0;
|
|
196801
|
-
const endIndex = Math.min(startIndex + max, total);
|
|
197412
|
+
function getSeveritySymbol(severity) {
|
|
196802
197413
|
return {
|
|
196803
|
-
|
|
196804
|
-
|
|
196805
|
-
|
|
197414
|
+
off: ".",
|
|
197415
|
+
suggestion: "?",
|
|
197416
|
+
message: "i",
|
|
197417
|
+
warning: "!",
|
|
197418
|
+
error: "x"
|
|
197419
|
+
}[severity];
|
|
196806
197420
|
}
|
|
196807
|
-
const figuresValue = {
|
|
196808
|
-
arrowUp: "↑",
|
|
196809
|
-
arrowDown: "↓",
|
|
196810
|
-
tick: "✔",
|
|
196811
|
-
pointerSmall: "›"
|
|
196812
|
-
};
|
|
196813
197421
|
function getSeverityStyle(severity) {
|
|
196814
197422
|
return {
|
|
196815
|
-
off:
|
|
196816
|
-
suggestion:
|
|
196817
|
-
message:
|
|
196818
|
-
warning:
|
|
196819
|
-
error:
|
|
197423
|
+
off: DIM,
|
|
197424
|
+
suggestion: DIM,
|
|
197425
|
+
message: BLUE,
|
|
197426
|
+
warning: YELLOW,
|
|
197427
|
+
error: RED
|
|
196820
197428
|
}[severity];
|
|
196821
197429
|
}
|
|
196822
|
-
function
|
|
196823
|
-
|
|
196824
|
-
|
|
196825
|
-
|
|
196826
|
-
|
|
196827
|
-
|
|
196828
|
-
|
|
197430
|
+
function renderEntry(entry, severity, isSelected) {
|
|
197431
|
+
return `${ansi(getSeveritySymbol(severity), getSeverityStyle(severity))} ${isSelected ? ansi(entry.name, UNDERLINE) : entry.name}`;
|
|
197432
|
+
}
|
|
197433
|
+
function rowsForLength(length, columns) {
|
|
197434
|
+
if (columns <= 0) return 1;
|
|
197435
|
+
return Math.max(1, 1 + Math.floor(Math.max(length - 1, 0) / columns));
|
|
197436
|
+
}
|
|
197437
|
+
function eraseRenderedLines(lines, columns) {
|
|
197438
|
+
let result = "";
|
|
197439
|
+
for (let lineIndex = lines.length - 1; lineIndex >= 0; lineIndex--) {
|
|
197440
|
+
const rows = rowsForLength(visibleLength(lines[lineIndex] ?? ""), columns);
|
|
197441
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
|
197442
|
+
result += ERASE_LINE;
|
|
197443
|
+
if (!(lineIndex === 0 && rowIndex === rows - 1)) result += "\x1B[1A";
|
|
196829
197444
|
}
|
|
196830
|
-
}
|
|
197445
|
+
}
|
|
197446
|
+
if (lines.length > 0) result += CURSOR_LEFT;
|
|
197447
|
+
return result;
|
|
196831
197448
|
}
|
|
196832
|
-
function
|
|
196833
|
-
|
|
196834
|
-
const
|
|
196835
|
-
|
|
196836
|
-
|
|
196837
|
-
|
|
196838
|
-
const
|
|
196839
|
-
|
|
196840
|
-
|
|
196841
|
-
if (index === toDisplay.startIndex && toDisplay.startIndex > 0) prefix = figs.arrowUp;
|
|
196842
|
-
else if (index === toDisplay.endIndex - 1 && toDisplay.endIndex < options.rules.length) prefix = figs.arrowDown;
|
|
196843
|
-
const severityStr = ansi(` ${getSeverityShortName(currentSeverity).padEnd(MAX_SEVERITY_LENGTH, " ")} `, getSeverityStyle(currentSeverity));
|
|
196844
|
-
const nameText = hasChanged ? `${rule.name}*` : rule.name;
|
|
196845
|
-
const nameStr = isHighlighted ? ansi(nameText, CYAN_BRIGHT) : nameText;
|
|
196846
|
-
const mainLine = `${prefix} ${severityStr} ${nameStr}`;
|
|
196847
|
-
if (isHighlighted && rule.description) {
|
|
196848
|
-
const indentWidth = 2 + (MAX_SEVERITY_LENGTH + 2) + 1;
|
|
196849
|
-
const indent = " ".repeat(indentWidth);
|
|
196850
|
-
const availableWidth = columns - indentWidth;
|
|
196851
|
-
const truncatedDescription = availableWidth > 0 && rule.description.length > availableWidth ? rule.description.substring(0, availableWidth - 1) + "…" : rule.description;
|
|
196852
|
-
documents.push(mainLine + "\n" + ansi(indent + truncatedDescription, DIM));
|
|
196853
|
-
} else documents.push(mainLine);
|
|
197449
|
+
function wrapPaddedText(text, initialPadding, endPadding, columns) {
|
|
197450
|
+
if (text.length === 0) return [initialPadding + endPadding];
|
|
197451
|
+
const available = Math.max(columns - visibleLength(initialPadding) - visibleLength(endPadding), 1);
|
|
197452
|
+
const lines = [];
|
|
197453
|
+
let remaining = text;
|
|
197454
|
+
while (remaining.length > 0) {
|
|
197455
|
+
const chunk = remaining.slice(0, available);
|
|
197456
|
+
lines.push(initialPadding + chunk + endPadding);
|
|
197457
|
+
remaining = remaining.slice(chunk.length);
|
|
196854
197458
|
}
|
|
196855
|
-
return
|
|
197459
|
+
return lines;
|
|
196856
197460
|
}
|
|
196857
|
-
function
|
|
196858
|
-
|
|
196859
|
-
|
|
196860
|
-
|
|
196861
|
-
|
|
196862
|
-
|
|
197461
|
+
function wrapListItemText(text, firstLinePadding, continuationPadding, endPadding, columns) {
|
|
197462
|
+
if (text.length === 0) return [firstLinePadding + endPadding];
|
|
197463
|
+
const firstAvailable = Math.max(columns - visibleLength(firstLinePadding) - visibleLength(endPadding), 1);
|
|
197464
|
+
const continuationAvailable = Math.max(columns - visibleLength(continuationPadding) - visibleLength(endPadding), 1);
|
|
197465
|
+
const lines = [];
|
|
197466
|
+
let remaining = text;
|
|
197467
|
+
let isFirstLine = true;
|
|
197468
|
+
while (remaining.length > 0) {
|
|
197469
|
+
const padding = isFirstLine ? firstLinePadding : continuationPadding;
|
|
197470
|
+
const available = isFirstLine ? firstAvailable : continuationAvailable;
|
|
197471
|
+
const chunk = remaining.slice(0, available);
|
|
197472
|
+
lines.push(padding + chunk + endPadding);
|
|
197473
|
+
remaining = remaining.slice(chunk.length);
|
|
197474
|
+
isFirstLine = false;
|
|
197475
|
+
}
|
|
197476
|
+
return lines;
|
|
197477
|
+
}
|
|
197478
|
+
function renderPaddedLine(text, initialPadding, endPadding, columns) {
|
|
197479
|
+
const available = Math.max(columns - visibleLength(initialPadding) - visibleLength(endPadding), 0);
|
|
197480
|
+
const truncated = visibleLength(text) <= available ? text : text.slice(0, available);
|
|
197481
|
+
const padding = Math.max(available - visibleLength(truncated), 0);
|
|
197482
|
+
return initialPadding + truncated + " ".repeat(padding) + endPadding;
|
|
197483
|
+
}
|
|
197484
|
+
function mergeHighlightRanges(ranges) {
|
|
197485
|
+
const sorted = ranges.filter((range) => range.end > range.start).slice().sort((a, b) => a.start - b.start);
|
|
197486
|
+
const merged = [];
|
|
197487
|
+
for (const range of sorted) {
|
|
197488
|
+
const previous = merged[merged.length - 1];
|
|
197489
|
+
if (!previous || range.start > previous.end) {
|
|
197490
|
+
merged.push(range);
|
|
197491
|
+
continue;
|
|
197492
|
+
}
|
|
197493
|
+
merged[merged.length - 1] = {
|
|
197494
|
+
start: previous.start,
|
|
197495
|
+
end: Math.max(previous.end, range.end)
|
|
197496
|
+
};
|
|
197497
|
+
}
|
|
197498
|
+
return merged;
|
|
197499
|
+
}
|
|
197500
|
+
function stylePreviewLine(line, lineStart, ranges) {
|
|
197501
|
+
if (line.length === 0) return "";
|
|
197502
|
+
const lineEnd = lineStart + line.length;
|
|
197503
|
+
let cursor = 0;
|
|
197504
|
+
let rendered = "";
|
|
197505
|
+
for (const range of ranges) {
|
|
197506
|
+
const start = Math.max(range.start, lineStart);
|
|
197507
|
+
const end = Math.min(range.end, lineEnd);
|
|
197508
|
+
if (end <= start) continue;
|
|
197509
|
+
const startIndex = start - lineStart;
|
|
197510
|
+
const endIndex = end - lineStart;
|
|
197511
|
+
if (cursor < startIndex) rendered += ansi(line.slice(cursor, startIndex), DIM);
|
|
197512
|
+
rendered += ansi(line.slice(startIndex, endIndex), UNDERLINE);
|
|
197513
|
+
cursor = endIndex;
|
|
197514
|
+
}
|
|
197515
|
+
if (cursor < line.length) rendered += ansi(line.slice(cursor), DIM);
|
|
197516
|
+
return rendered;
|
|
197517
|
+
}
|
|
197518
|
+
function wrapSourceLine(line, lineStart, availableWidth) {
|
|
197519
|
+
if (line.length === 0) return [{
|
|
197520
|
+
text: "",
|
|
197521
|
+
start: lineStart,
|
|
197522
|
+
end: lineStart
|
|
197523
|
+
}];
|
|
197524
|
+
const width = Math.max(availableWidth, 1);
|
|
197525
|
+
const wrapped = [];
|
|
197526
|
+
let offset = 0;
|
|
197527
|
+
while (offset < line.length) {
|
|
197528
|
+
const text = line.slice(offset, offset + width);
|
|
197529
|
+
wrapped.push({
|
|
197530
|
+
text,
|
|
197531
|
+
start: lineStart + offset,
|
|
197532
|
+
end: lineStart + offset + text.length
|
|
197533
|
+
});
|
|
197534
|
+
offset += text.length;
|
|
197535
|
+
}
|
|
197536
|
+
return wrapped;
|
|
197537
|
+
}
|
|
197538
|
+
function wrapPreviewSourceText(sourceText, columns) {
|
|
197539
|
+
const availableWidth = Math.max(columns - 2, 1);
|
|
197540
|
+
const logicalLines = sourceText.split("\n");
|
|
197541
|
+
const wrapped = [];
|
|
197542
|
+
let offset = 0;
|
|
197543
|
+
for (const line of logicalLines) {
|
|
197544
|
+
for (const wrappedLine of wrapSourceLine(line, offset, availableWidth)) wrapped.push(wrappedLine);
|
|
197545
|
+
offset += line.length + 1;
|
|
197546
|
+
}
|
|
197547
|
+
return wrapped;
|
|
197548
|
+
}
|
|
197549
|
+
function renderPreviewSourceText(sourceText, diagnostics, columns) {
|
|
197550
|
+
const ranges = mergeHighlightRanges(diagnostics.map((diagnostic) => ({
|
|
197551
|
+
start: diagnostic.start,
|
|
197552
|
+
end: diagnostic.end
|
|
197553
|
+
})));
|
|
197554
|
+
return wrapPreviewSourceText(sourceText, columns).map((line) => {
|
|
197555
|
+
return CURSOR_TO_0 + renderPaddedLine(stylePreviewLine(line.text, line.start, ranges), " ", "", columns);
|
|
196863
197556
|
});
|
|
196864
197557
|
}
|
|
196865
|
-
function
|
|
196866
|
-
return
|
|
196867
|
-
|
|
196868
|
-
|
|
196869
|
-
|
|
196870
|
-
|
|
196871
|
-
|
|
196872
|
-
|
|
197558
|
+
function renderPreviewMessages(diagnostics, columns) {
|
|
197559
|
+
return Array.from(new Set(diagnostics.map((diagnostic) => diagnostic.text))).flatMap((message) => {
|
|
197560
|
+
let isFirstBlock = true;
|
|
197561
|
+
return message.split("\n").flatMap((line) => {
|
|
197562
|
+
const wrappedLines = wrapListItemText(line, isFirstBlock ? "- " : " ", " ", "", columns);
|
|
197563
|
+
isFirstBlock = false;
|
|
197564
|
+
return wrappedLines.map((wrappedLine) => CURSOR_TO_0 + ansi(wrappedLine, DIM + ITALIC));
|
|
197565
|
+
});
|
|
196873
197566
|
});
|
|
196874
197567
|
}
|
|
196875
|
-
function
|
|
196876
|
-
|
|
196877
|
-
|
|
196878
|
-
|
|
196879
|
-
|
|
196880
|
-
|
|
197568
|
+
function renderDivider(columns, legendText) {
|
|
197569
|
+
if (legendText === void 0) return ansi("─".repeat(Math.max(columns, 0)), DIM);
|
|
197570
|
+
const legend = ` ${legendText} `;
|
|
197571
|
+
const legendLength = visibleLength(legend);
|
|
197572
|
+
if (columns <= legendLength) return ansi(legend.slice(0, Math.max(columns, 0)), DIM);
|
|
197573
|
+
const remaining = columns - legendLength;
|
|
197574
|
+
const left = "─".repeat(Math.floor(remaining / 2));
|
|
197575
|
+
const right = "─".repeat(remaining - left.length);
|
|
197576
|
+
return ansi(left + legend + right, DIM);
|
|
196881
197577
|
}
|
|
196882
|
-
function
|
|
196883
|
-
|
|
196884
|
-
|
|
196885
|
-
|
|
196886
|
-
index: newIndex
|
|
196887
|
-
} }));
|
|
197578
|
+
function renderSelectedRuleDivider(selected, severities, columns) {
|
|
197579
|
+
if (!selected) return renderDivider(columns);
|
|
197580
|
+
const currentSeverity = severities[selected.name] ?? selected.defaultSeverity;
|
|
197581
|
+
return renderDivider(columns, `${selected.name} (currently set as ${getSeverityShortName(currentSeverity)})`);
|
|
196888
197582
|
}
|
|
196889
|
-
function
|
|
196890
|
-
|
|
196891
|
-
const
|
|
196892
|
-
return
|
|
196893
|
-
|
|
196894
|
-
|
|
196895
|
-
|
|
196896
|
-
|
|
196897
|
-
|
|
196898
|
-
|
|
197583
|
+
function matchesSearch(entry, searchText) {
|
|
197584
|
+
if (searchText.length === 0) return true;
|
|
197585
|
+
const normalized = searchText.toLowerCase();
|
|
197586
|
+
return entry.name.toLowerCase().includes(normalized) || entry.description.toLowerCase().includes(normalized) || entry.previewSourceText.toLowerCase().includes(normalized);
|
|
197587
|
+
}
|
|
197588
|
+
function getFilteredEntries(entries, searchText) {
|
|
197589
|
+
return entries.filter((entry) => matchesSearch(entry, searchText));
|
|
197590
|
+
}
|
|
197591
|
+
function normalizeStartIndex(length, startIndex) {
|
|
197592
|
+
if (length <= 0) return 0;
|
|
197593
|
+
return (startIndex % length + length) % length;
|
|
197594
|
+
}
|
|
197595
|
+
function isPrintableInput(input) {
|
|
197596
|
+
const printablePattern = new RegExp(String.raw`^[^\u0000-\u001F\u007F]+$`, "u");
|
|
197597
|
+
return !input.key.ctrl && !input.key.meta && input.input !== void 0 && input.input.length > 0 && printablePattern.test(input.input);
|
|
197598
|
+
}
|
|
197599
|
+
function buildVisibleEntries(entries, severities, startIndex, columns) {
|
|
197600
|
+
if (entries.length === 0) return {
|
|
197601
|
+
fullLine: renderPaddedLine(ansi("No matching rules", DIM), " ", " ", columns),
|
|
197602
|
+
visibleRules: []
|
|
197603
|
+
};
|
|
197604
|
+
const itemColumns = Math.max(columns - 4, 0);
|
|
197605
|
+
const separator = " ";
|
|
197606
|
+
const visibleEntries = [];
|
|
197607
|
+
const visibleRules = [];
|
|
197608
|
+
let currentLength = 0;
|
|
197609
|
+
let seenCount = 0;
|
|
197610
|
+
while (seenCount < entries.length) {
|
|
197611
|
+
const rule = entries[(startIndex + seenCount) % entries.length];
|
|
197612
|
+
const entry = renderEntry(rule, severities[rule.name] ?? rule.defaultSeverity, seenCount === 0);
|
|
197613
|
+
const nextLength = visibleEntries.length === 0 ? visibleLength(entry) : currentLength + 2 + visibleLength(entry);
|
|
197614
|
+
if (nextLength > itemColumns) break;
|
|
197615
|
+
visibleEntries.push(entry);
|
|
197616
|
+
visibleRules.push(rule);
|
|
197617
|
+
currentLength = nextLength;
|
|
197618
|
+
seenCount++;
|
|
197619
|
+
}
|
|
197620
|
+
const leftMarker = entries.length > 1 ? ansi("←", DIM) : " ";
|
|
197621
|
+
const rightMarker = entries.length > 1 ? ansi("→", DIM) : " ";
|
|
197622
|
+
return {
|
|
197623
|
+
fullLine: renderPaddedLine(visibleEntries.join(separator), `${leftMarker} `, ` ${rightMarker}`, columns),
|
|
197624
|
+
visibleRules
|
|
197625
|
+
};
|
|
196899
197626
|
}
|
|
196900
|
-
function
|
|
197627
|
+
function buildGroupLine(selected, groups, columns) {
|
|
197628
|
+
if (!selected) return renderPaddedLine("", " ", " ", columns);
|
|
197629
|
+
const selectedIndex = groups.findIndex((group) => group.id === selected.group);
|
|
197630
|
+
return renderPaddedLine(groups.map((_, index) => groups[(selectedIndex + index) % groups.length]).map((group, index) => {
|
|
197631
|
+
const label = group.name.toUpperCase();
|
|
197632
|
+
return index === 0 ? ansi(label, BOLD) : ansi(label, DIM);
|
|
197633
|
+
}).join(" "), " ", " ", columns);
|
|
197634
|
+
}
|
|
197635
|
+
function buildFrame(entries, groups, searchText, severities, startIndex, columns) {
|
|
197636
|
+
const visible = buildVisibleEntries(entries, severities, startIndex, columns);
|
|
197637
|
+
const selected = visible.visibleRules[0];
|
|
197638
|
+
const wrappedDescription = wrapPaddedText(selected?.description ?? "", " ", "", columns);
|
|
197639
|
+
const previewLines = renderPreviewSourceText(selected?.previewSourceText ?? "", selected?.previewDiagnostics ?? [], columns);
|
|
197640
|
+
const previewMessages = renderPreviewMessages(selected?.previewDiagnostics ?? [], columns);
|
|
197641
|
+
const previewSectionLines = [...previewLines, ...previewMessages];
|
|
197642
|
+
const paddingLines = Array.from({ length: Math.max(MIN_PREVIEW_AND_MESSAGES_LINES - previewSectionLines.length, 0) }, () => "");
|
|
197643
|
+
return [
|
|
197644
|
+
CURSOR_HIDE + renderSelectedRuleDivider(selected, severities, columns),
|
|
197645
|
+
...previewSectionLines,
|
|
197646
|
+
...paddingLines,
|
|
197647
|
+
CURSOR_TO_0 + renderDivider(columns),
|
|
197648
|
+
CURSOR_TO_0 + buildGroupLine(selected, groups, columns),
|
|
197649
|
+
CURSOR_TO_0 + visible.fullLine,
|
|
197650
|
+
...wrappedDescription.map((line) => CURSOR_TO_0 + ansi(line, DIM)),
|
|
197651
|
+
CURSOR_TO_0 + renderDivider(columns, getControlsLegend(searchText)),
|
|
197652
|
+
""
|
|
197653
|
+
];
|
|
197654
|
+
}
|
|
197655
|
+
function buildState(entries, groups, startIndex, searchText, severities) {
|
|
197656
|
+
return gen(function* () {
|
|
197657
|
+
const terminal = yield* Terminal;
|
|
197658
|
+
const columns = Math.max(yield* terminal.columns, 1);
|
|
197659
|
+
const filteredEntries = getFilteredEntries(entries, searchText);
|
|
197660
|
+
const normalizedStartIndex = normalizeStartIndex(filteredEntries.length, startIndex);
|
|
197661
|
+
return {
|
|
197662
|
+
startIndex: normalizedStartIndex,
|
|
197663
|
+
searchText,
|
|
197664
|
+
severities,
|
|
197665
|
+
renderedColumns: columns,
|
|
197666
|
+
renderedLines: buildFrame(filteredEntries, groups, searchText, severities, normalizedStartIndex, columns)
|
|
197667
|
+
};
|
|
197668
|
+
});
|
|
197669
|
+
}
|
|
197670
|
+
function renderSubmission(state, entries) {
|
|
197671
|
+
return succeed(CURSOR_TO_0 + JSON.stringify(Object.fromEntries(entries.flatMap((entry) => {
|
|
197672
|
+
const severity = state.severities[entry.name];
|
|
197673
|
+
return severity !== void 0 && severity !== entry.defaultSeverity ? [[entry.name, severity]] : [];
|
|
197674
|
+
}))) + "\n");
|
|
197675
|
+
}
|
|
197676
|
+
function handleProcess(entries, groups) {
|
|
196901
197677
|
return (input, state) => {
|
|
196902
|
-
const
|
|
197678
|
+
const filteredEntries = getFilteredEntries(entries, state.searchText);
|
|
196903
197679
|
switch (input.key.name) {
|
|
196904
|
-
case "
|
|
196905
|
-
case "
|
|
196906
|
-
|
|
196907
|
-
|
|
196908
|
-
case "
|
|
196909
|
-
|
|
197680
|
+
case "backspace": return buildState(entries, groups, 0, state.searchText.slice(0, -1), state.severities).pipe(map$2((nextState) => Action.NextFrame({ state: nextState })));
|
|
197681
|
+
case "left":
|
|
197682
|
+
if (filteredEntries.length === 0) return succeed(Action.Beep());
|
|
197683
|
+
return buildState(entries, groups, state.startIndex - 1, state.searchText, state.severities).pipe(map$2((nextState) => Action.NextFrame({ state: nextState })));
|
|
197684
|
+
case "right":
|
|
197685
|
+
if (filteredEntries.length === 0) return succeed(Action.Beep());
|
|
197686
|
+
return buildState(entries, groups, state.startIndex + 1, state.searchText, state.severities).pipe(map$2((nextState) => Action.NextFrame({ state: nextState })));
|
|
197687
|
+
case "up":
|
|
197688
|
+
case "down":
|
|
197689
|
+
if (filteredEntries.length === 0) return succeed(Action.Beep());
|
|
197690
|
+
return buildState(entries, groups, state.startIndex, state.searchText, {
|
|
197691
|
+
...state.severities,
|
|
197692
|
+
[filteredEntries[state.startIndex].name]: cycleSeverity(state.severities[filteredEntries[state.startIndex].name] ?? filteredEntries[state.startIndex].defaultSeverity, input.key.name === "up" ? "left" : "right")
|
|
197693
|
+
}).pipe(map$2((nextState) => Action.NextFrame({ state: nextState })));
|
|
196910
197694
|
case "enter":
|
|
196911
|
-
case "return": return succeed(Action.Submit({ value:
|
|
196912
|
-
|
|
197695
|
+
case "return": return succeed(Action.Submit({ value: Object.fromEntries(entries.flatMap((entry) => {
|
|
197696
|
+
const severity = state.severities[entry.name];
|
|
197697
|
+
return severity !== void 0 && severity !== entry.defaultSeverity ? [[entry.name, severity]] : [];
|
|
197698
|
+
})) }));
|
|
197699
|
+
default:
|
|
197700
|
+
if (!isPrintableInput(input)) return succeed(Action.Beep());
|
|
197701
|
+
return buildState(entries, groups, 0, state.searchText + input.input, state.severities).pipe(map$2((nextState) => Action.NextFrame({ state: nextState })));
|
|
196913
197702
|
}
|
|
196914
197703
|
};
|
|
196915
197704
|
}
|
|
196916
|
-
function
|
|
196917
|
-
return
|
|
196918
|
-
|
|
196919
|
-
|
|
196920
|
-
|
|
196921
|
-
|
|
196922
|
-
|
|
196923
|
-
|
|
196924
|
-
|
|
196925
|
-
Beep: () => succeed(BEEP),
|
|
196926
|
-
NextFrame: ({ state }) => renderNextFrame(state, options),
|
|
196927
|
-
Submit: () => renderSubmission(state, options)
|
|
196928
|
-
});
|
|
197705
|
+
function getPromptEntries(rules) {
|
|
197706
|
+
return rules.map((rule) => ({
|
|
197707
|
+
name: rule.name,
|
|
197708
|
+
group: rule.group,
|
|
197709
|
+
description: rule.description,
|
|
197710
|
+
previewSourceText: rule.preview.sourceText,
|
|
197711
|
+
previewDiagnostics: rule.preview.diagnostics,
|
|
197712
|
+
defaultSeverity: rule.defaultSeverity
|
|
197713
|
+
}));
|
|
196929
197714
|
}
|
|
196930
197715
|
function createRulePrompt(rules, initialSeverities) {
|
|
196931
|
-
const
|
|
196932
|
-
|
|
196933
|
-
|
|
196934
|
-
|
|
196935
|
-
|
|
196936
|
-
|
|
196937
|
-
|
|
196938
|
-
|
|
196939
|
-
|
|
196940
|
-
|
|
196941
|
-
process: handleProcess(
|
|
196942
|
-
clear: () =>
|
|
197716
|
+
const entries = getPromptEntries(rules);
|
|
197717
|
+
const groups = diagnosticGroups;
|
|
197718
|
+
return custom(buildState(entries, groups, 0, "", initialSeverities), {
|
|
197719
|
+
render: (state, action) => {
|
|
197720
|
+
switch (action._tag) {
|
|
197721
|
+
case "Beep": return succeed(BEEP);
|
|
197722
|
+
case "NextFrame": return succeed(action.state.renderedLines.join("\n"));
|
|
197723
|
+
case "Submit": return renderSubmission(state, entries);
|
|
197724
|
+
}
|
|
197725
|
+
},
|
|
197726
|
+
process: handleProcess(entries, groups),
|
|
197727
|
+
clear: (state) => gen(function* () {
|
|
197728
|
+
const columns = yield* (yield* Terminal).columns;
|
|
197729
|
+
return eraseRenderedLines(state.renderedLines, columns);
|
|
197730
|
+
})
|
|
196943
197731
|
});
|
|
196944
197732
|
}
|
|
196945
197733
|
|
|
@@ -196988,16 +197776,17 @@ const gatherTargetState = (assessment, context) => gen(function* () {
|
|
|
196988
197776
|
editors: []
|
|
196989
197777
|
};
|
|
196990
197778
|
const diagnosticSeverities = (yield* select({
|
|
196991
|
-
message: "Would you like to customize the
|
|
197779
|
+
message: "Would you like to customize the diagnostics that the language service will provide?",
|
|
196992
197780
|
choices: [{
|
|
196993
197781
|
title: "Yes",
|
|
196994
|
-
description: "
|
|
197782
|
+
description: "Manually review and select which diagnostics to enable",
|
|
196995
197783
|
value: true,
|
|
196996
197784
|
selected: true
|
|
196997
197785
|
}, {
|
|
196998
197786
|
title: "No",
|
|
196999
|
-
description: "Keep the
|
|
197000
|
-
value: false
|
|
197787
|
+
description: "Keep the defaults provided by the language service",
|
|
197788
|
+
value: false,
|
|
197789
|
+
selected: false
|
|
197001
197790
|
}]
|
|
197002
197791
|
})) ? some(yield* createRulePrompt(getAllRules(), getOrElse$1(assessment.tsconfig.currentDiagnosticSeverities, () => ({})))) : none$3();
|
|
197003
197792
|
const hasVscodeSettings = isSome(assessment.vscodeSettings);
|