Skip to content

Commit

Permalink
feat!: Remove CodePath#currentSegments (#17936)
Browse files Browse the repository at this point in the history
* feat!: Remove CodePath#currentSegments

fixes #17457

* update migration guide

* update related issue link

---------

Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
  • Loading branch information
mdjermanovic and nzakas committed Jan 1, 2024
1 parent 4a9cd1e commit d191bdd
Show file tree
Hide file tree
Showing 6 changed files with 11 additions and 112 deletions.
3 changes: 1 addition & 2 deletions docs/src/extend/code-path-analysis.md
Expand Up @@ -37,7 +37,6 @@ This has references of both the initial segment and the final segments of a code
* `finalSegments` (`CodePathSegment[]`) - The final segments which includes both returned and thrown.
* `returnedSegments` (`CodePathSegment[]`) - The final segments which includes only returned.
* `thrownSegments` (`CodePathSegment[]`) - The final segments which includes only thrown.
* `currentSegments` (`CodePathSegment[]`) - **Deprecated.** Segments of the current traversal position.
* `upper` (`CodePath|null`) - The code path of the upper function/global scope.
* `childCodePaths` (`CodePath[]`) - Code paths of functions this code path contains.

Expand Down Expand Up @@ -635,7 +634,7 @@ last();
```

If there is not `catch` block, `finally` block has two current segments.
At this time, `CodePath.currentSegments.length` is `2`.
At this time when running the previous example to find unreachable nodes, `currentSegments.length` is `2`.
One is the normal path, and another is the leaving path (`throw` or `return`).

:::img-container
Expand Down
9 changes: 9 additions & 0 deletions docs/src/use/migrate-to-9.0.0.md
Expand Up @@ -34,6 +34,7 @@ The lists below are ordered roughly by the number of users each change is expect
* [Node.js < v18.18, v19 are no longer supported](#drop-old-node)
* [Removed multiple `context` methods](#removed-context-methods)
* [Removed `sourceCode.getComments()`](#removed-sourcecode-getcomments)
* [Removed `CodePath#currentSegments`](#removed-codepath-currentsegments)
* [Function-style rules are no longer supported](#drop-function-style-rules)
* [`meta.schema` is required for rules with options](#meta-schema-required)
* [`FlatRuleTester` is now `RuleTester`](#flat-rule-tester)
Expand Down Expand Up @@ -277,6 +278,14 @@ ESLint v9.0.0 removes the deprecated `sourceCode.getComments()` method.

**Related Issues(s):** [#14744](https://github.com/eslint/eslint/issues/14744)

## <a name="removed-codepath-currentsegments"></a> Removed `CodePath#currentSegments`

ESLint v9.0.0 removes the deprecated `CodePath#currentSegments` property.

**To address:** Update your code following the recommendations in the [blog post](https://eslint.org/blog/2023/09/preparing-custom-rules-eslint-v9/#codepath%23currentsegments).

**Related Issues(s):** [#17457](https://github.com/eslint/eslint/issues/17457)

## <a name="drop-function-style-rules"></a> Function-style rules are no longer supported

ESLint v9.0.0 drops support for function-style rules. Function-style rules are rules created by exporting a function rather than an object with a `create()` method. This rule format was deprecated in 2016.
Expand Down
14 changes: 0 additions & 14 deletions lib/linter/code-path-analysis/code-path.js
Expand Up @@ -125,20 +125,6 @@ class CodePath {
return this.internal.thrownForkContext;
}

/**
* Tracks the traversal of the code path through each segment. This array
* starts empty and segments are added or removed as the code path is
* traversed. This array always ends up empty at the end of a code path
* traversal. The `CodePathState` uses this to track its progress through
* the code path.
* This is a passthrough to the underlying `CodePathState`.
* @type {CodePathSegment[]}
* @deprecated
*/
get currentSegments() {
return this.internal.currentSegments;
}

/**
* Traverses all segments in this code path.
*
Expand Down
27 changes: 1 addition & 26 deletions lib/rule-tester/rule-tester.js
Expand Up @@ -16,8 +16,7 @@ const
equal = require("fast-deep-equal"),
Traverser = require("../shared/traverser"),
{ getRuleOptionsSchema } = require("../config/flat-config-helpers"),
{ Linter, SourceCodeFixer, interpolate } = require("../linter"),
CodePath = require("../linter/code-path-analysis/code-path");
{ Linter, SourceCodeFixer, interpolate } = require("../linter");

const { FlatConfigArray } = require("../config/flat-config-array");
const { defaultConfig } = require("../config/default-config");
Expand Down Expand Up @@ -274,21 +273,6 @@ function wrapParser(parser) {
};
}

/**
* Emit a deprecation warning if rule uses CodePath#currentSegments.
* @param {string} ruleName Name of the rule.
* @returns {void}
*/
function emitCodePathCurrentSegmentsWarning(ruleName) {
if (!emitCodePathCurrentSegmentsWarning[`warned-${ruleName}`]) {
emitCodePathCurrentSegmentsWarning[`warned-${ruleName}`] = true;
process.emitWarning(
`"${ruleName}" rule uses CodePath#currentSegments and will stop working in ESLint v9. Please read the documentation for how to update your code: https://eslint.org/docs/latest/extend/code-path-analysis#usage-examples`,
"DeprecationWarning"
);
}
}

/**
* Function to replace forbidden `SourceCode` methods. Allows just one call per method.
* @param {string} methodName The name of the method to forbid.
Expand Down Expand Up @@ -753,24 +737,15 @@ class RuleTester {

// Verify the code.
const { applyLanguageOptions, applyInlineConfig, finalize } = SourceCode.prototype;
const originalCurrentSegments = Object.getOwnPropertyDescriptor(CodePath.prototype, "currentSegments");
let messages;

try {
Object.defineProperty(CodePath.prototype, "currentSegments", {
get() {
emitCodePathCurrentSegmentsWarning(ruleName);
return originalCurrentSegments.get.call(this);
}
});

forbiddenMethods.forEach(methodName => {
SourceCode.prototype[methodName] = throwForbiddenMethodError(methodName, SourceCode.prototype);
});

messages = linter.verify(code, configs, filename);
} finally {
Object.defineProperty(CodePath.prototype, "currentSegments", originalCurrentSegments);
SourceCode.prototype.applyInlineConfig = applyInlineConfig;
SourceCode.prototype.applyLanguageOptions = applyLanguageOptions;
SourceCode.prototype.finalize = finalize;
Expand Down
31 changes: 0 additions & 31 deletions tests/lib/linter/code-path-analysis/code-path-analyzer.js
Expand Up @@ -137,37 +137,6 @@ describe("CodePathAnalyzer", () => {
assert(actual[1].thrownSegments[0] instanceof CodePathSegment);
});

it("should have `currentSegments` as CodePathSegment[]", () => {
assert(Array.isArray(actual[0].currentSegments));
assert(Array.isArray(actual[1].currentSegments));
assert(actual[0].currentSegments.length === 0);
assert(actual[1].currentSegments.length === 0);

// there is the current segment in progress.
linter.defineRule("test", {
create() {
let codePath = null;

return {
onCodePathStart(cp) {
codePath = cp;
},
ReturnStatement() {
assert(codePath.currentSegments.length === 1);
assert(codePath.currentSegments[0] instanceof CodePathSegment);
},
ThrowStatement() {
assert(codePath.currentSegments.length === 1);
assert(codePath.currentSegments[0] instanceof CodePathSegment);
}
};
}
});
linter.verify(
"function foo(a) { if (a) return 0; else throw new Error(); }",
{ rules: { test: 2 } }
);
});
});

describe("interface of code path segments", () => {
Expand Down
39 changes: 0 additions & 39 deletions tests/lib/rule-tester/rule-tester.js
Expand Up @@ -2530,45 +2530,6 @@ describe("RuleTester", () => {
});
});

describe("deprecations", () => {
let processStub;

beforeEach(() => {
processStub = sinon.stub(process, "emitWarning");
});

afterEach(() => {
processStub.restore();
});

it("should emit a deprecation warning when CodePath#currentSegments is accessed", () => {

const useCurrentSegmentsRule = {
create: () => ({
onCodePathStart(codePath) {
codePath.currentSegments.forEach(() => { });
}
})
};

ruleTester.run("use-current-segments", useCurrentSegmentsRule, {
valid: ["foo"],
invalid: []
});

assert.strictEqual(processStub.callCount, 1, "calls `process.emitWarning()` once");
assert.deepStrictEqual(
processStub.getCall(0).args,
[
"\"use-current-segments\" rule uses CodePath#currentSegments and will stop working in ESLint v9. Please read the documentation for how to update your code: https://eslint.org/docs/latest/extend/code-path-analysis#usage-examples",
"DeprecationWarning"
]
);

});

});

/**
* Asserts that a particular value will be emitted from an EventEmitter.
* @param {EventEmitter} emitter The emitter that should emit a value
Expand Down

0 comments on commit d191bdd

Please sign in to comment.