mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00

We have been stalled on ESLint 3.8.0 for some time. Current ESLint is 3.13.0. We have been unable to upgrade because of more aggressive reporting on some rules, including indentation. ESLint configuration options and bugfixes are now such that we can reasonably upgrade. PR-URL: https://github.com/nodejs/node/pull/10561 Reviewed-By: Teddy Katz <teddy.katz@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
242 lines
7 KiB
JavaScript
242 lines
7 KiB
JavaScript
/**
|
|
* @fileoverview A class of the code path segment.
|
|
* @author Toru Nagashima
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
const debug = require("./debug-helpers");
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Replaces unused segments with the previous segments of each unused segment.
|
|
*
|
|
* @param {CodePathSegment[]} segments - An array of segments to replace.
|
|
* @returns {CodePathSegment[]} The replaced array.
|
|
*/
|
|
function flattenUnusedSegments(segments) {
|
|
const done = Object.create(null);
|
|
const retv = [];
|
|
|
|
for (let i = 0; i < segments.length; ++i) {
|
|
const segment = segments[i];
|
|
|
|
// Ignores duplicated.
|
|
if (done[segment.id]) {
|
|
continue;
|
|
}
|
|
|
|
// Use previous segments if unused.
|
|
if (!segment.internal.used) {
|
|
for (let j = 0; j < segment.allPrevSegments.length; ++j) {
|
|
const prevSegment = segment.allPrevSegments[j];
|
|
|
|
if (!done[prevSegment.id]) {
|
|
done[prevSegment.id] = true;
|
|
retv.push(prevSegment);
|
|
}
|
|
}
|
|
} else {
|
|
done[segment.id] = true;
|
|
retv.push(segment);
|
|
}
|
|
}
|
|
|
|
return retv;
|
|
}
|
|
|
|
/**
|
|
* Checks whether or not a given segment is reachable.
|
|
*
|
|
* @param {CodePathSegment} segment - A segment to check.
|
|
* @returns {boolean} `true` if the segment is reachable.
|
|
*/
|
|
function isReachable(segment) {
|
|
return segment.reachable;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Public Interface
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* A code path segment.
|
|
*/
|
|
class CodePathSegment {
|
|
|
|
/**
|
|
* @param {string} id - An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
|
|
* This array includes unreachable segments.
|
|
* @param {boolean} reachable - A flag which shows this is reachable.
|
|
*/
|
|
constructor(id, allPrevSegments, reachable) {
|
|
|
|
/**
|
|
* The identifier of this code path.
|
|
* Rules use it to store additional information of each rule.
|
|
* @type {string}
|
|
*/
|
|
this.id = id;
|
|
|
|
/**
|
|
* An array of the next segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.nextSegments = [];
|
|
|
|
/**
|
|
* An array of the previous segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.prevSegments = allPrevSegments.filter(isReachable);
|
|
|
|
/**
|
|
* An array of the next segments.
|
|
* This array includes unreachable segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.allNextSegments = [];
|
|
|
|
/**
|
|
* An array of the previous segments.
|
|
* This array includes unreachable segments.
|
|
* @type {CodePathSegment[]}
|
|
*/
|
|
this.allPrevSegments = allPrevSegments;
|
|
|
|
/**
|
|
* A flag which shows this is reachable.
|
|
* @type {boolean}
|
|
*/
|
|
this.reachable = reachable;
|
|
|
|
// Internal data.
|
|
Object.defineProperty(this, "internal", {
|
|
value: {
|
|
used: false,
|
|
loopedPrevSegments: []
|
|
}
|
|
});
|
|
|
|
/* istanbul ignore if */
|
|
if (debug.enabled) {
|
|
this.internal.nodes = [];
|
|
this.internal.exitNodes = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks a given previous segment is coming from the end of a loop.
|
|
*
|
|
* @param {CodePathSegment} segment - A previous segment to check.
|
|
* @returns {boolean} `true` if the segment is coming from the end of a loop.
|
|
*/
|
|
isLoopedPrevSegment(segment) {
|
|
return this.internal.loopedPrevSegments.indexOf(segment) !== -1;
|
|
}
|
|
|
|
/**
|
|
* Creates the root segment.
|
|
*
|
|
* @param {string} id - An identifier.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newRoot(id) {
|
|
return new CodePathSegment(id, [], true);
|
|
}
|
|
|
|
/**
|
|
* Creates a segment that follows given segments.
|
|
*
|
|
* @param {string} id - An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newNext(id, allPrevSegments) {
|
|
return new CodePathSegment(
|
|
id,
|
|
flattenUnusedSegments(allPrevSegments),
|
|
allPrevSegments.some(isReachable));
|
|
}
|
|
|
|
/**
|
|
* Creates an unreachable segment that follows given segments.
|
|
*
|
|
* @param {string} id - An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newUnreachable(id, allPrevSegments) {
|
|
const segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false);
|
|
|
|
// In `if (a) return a; foo();` case, the unreachable segment preceded by
|
|
// the return statement is not used but must not be remove.
|
|
CodePathSegment.markUsed(segment);
|
|
|
|
return segment;
|
|
}
|
|
|
|
/**
|
|
* Creates a segment that follows given segments.
|
|
* This factory method does not connect with `allPrevSegments`.
|
|
* But this inherits `reachable` flag.
|
|
*
|
|
* @param {string} id - An identifier.
|
|
* @param {CodePathSegment[]} allPrevSegments - An array of the previous segments.
|
|
* @returns {CodePathSegment} The created segment.
|
|
*/
|
|
static newDisconnected(id, allPrevSegments) {
|
|
return new CodePathSegment(id, [], allPrevSegments.some(isReachable));
|
|
}
|
|
|
|
/**
|
|
* Makes a given segment being used.
|
|
*
|
|
* And this function registers the segment into the previous segments as a next.
|
|
*
|
|
* @param {CodePathSegment} segment - A segment to mark.
|
|
* @returns {void}
|
|
*/
|
|
static markUsed(segment) {
|
|
if (segment.internal.used) {
|
|
return;
|
|
}
|
|
segment.internal.used = true;
|
|
|
|
let i;
|
|
|
|
if (segment.reachable) {
|
|
for (i = 0; i < segment.allPrevSegments.length; ++i) {
|
|
const prevSegment = segment.allPrevSegments[i];
|
|
|
|
prevSegment.allNextSegments.push(segment);
|
|
prevSegment.nextSegments.push(segment);
|
|
}
|
|
} else {
|
|
for (i = 0; i < segment.allPrevSegments.length; ++i) {
|
|
segment.allPrevSegments[i].allNextSegments.push(segment);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Marks a previous segment as looped.
|
|
*
|
|
* @param {CodePathSegment} segment - A segment.
|
|
* @param {CodePathSegment} prevSegment - A previous segment to mark.
|
|
* @returns {void}
|
|
*/
|
|
static markPrevSegmentAsLooped(segment, prevSegment) {
|
|
segment.internal.loopedPrevSegments.push(prevSegment);
|
|
}
|
|
}
|
|
|
|
module.exports = CodePathSegment;
|