]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/linter/code-path-analysis/code-path-segment.js
2 * @fileoverview A class of the code path segment.
3 * @author Toru Nagashima
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const debug
= require("./debug-helpers");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
19 * Checks whether or not a given segment is reachable.
20 * @param {CodePathSegment} segment A segment to check.
21 * @returns {boolean} `true` if the segment is reachable.
23 function isReachable(segment
) {
24 return segment
.reachable
;
27 //------------------------------------------------------------------------------
29 //------------------------------------------------------------------------------
32 * A code path segment.
34 class CodePathSegment
{
36 // eslint-disable-next-line jsdoc/require-description
38 * @param {string} id An identifier.
39 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
40 * This array includes unreachable segments.
41 * @param {boolean} reachable A flag which shows this is reachable.
43 constructor(id
, allPrevSegments
, reachable
) {
46 * The identifier of this code path.
47 * Rules use it to store additional information of each rule.
53 * An array of the next segments.
54 * @type {CodePathSegment[]}
56 this.nextSegments
= [];
59 * An array of the previous segments.
60 * @type {CodePathSegment[]}
62 this.prevSegments
= allPrevSegments
.filter(isReachable
);
65 * An array of the next segments.
66 * This array includes unreachable segments.
67 * @type {CodePathSegment[]}
69 this.allNextSegments
= [];
72 * An array of the previous segments.
73 * This array includes unreachable segments.
74 * @type {CodePathSegment[]}
76 this.allPrevSegments
= allPrevSegments
;
79 * A flag which shows this is reachable.
82 this.reachable
= reachable
;
85 Object
.defineProperty(this, "internal", {
88 loopedPrevSegments
: []
92 /* istanbul ignore if */
94 this.internal.nodes
= [];
95 this.internal.exitNodes
= [];
100 * Checks a given previous segment is coming from the end of a loop.
101 * @param {CodePathSegment} segment A previous segment to check.
102 * @returns {boolean} `true` if the segment is coming from the end of a loop.
104 isLoopedPrevSegment(segment
) {
105 return this.internal.loopedPrevSegments
.indexOf(segment
) !== -1;
109 * Creates the root segment.
110 * @param {string} id An identifier.
111 * @returns {CodePathSegment} The created segment.
114 return new CodePathSegment(id
, [], true);
118 * Creates a segment that follows given segments.
119 * @param {string} id An identifier.
120 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
121 * @returns {CodePathSegment} The created segment.
123 static newNext(id
, allPrevSegments
) {
124 return new CodePathSegment(
126 CodePathSegment
.flattenUnusedSegments(allPrevSegments
),
127 allPrevSegments
.some(isReachable
)
132 * Creates an unreachable segment that follows given segments.
133 * @param {string} id An identifier.
134 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
135 * @returns {CodePathSegment} The created segment.
137 static newUnreachable(id
, allPrevSegments
) {
138 const segment
= new CodePathSegment(id
, CodePathSegment
.flattenUnusedSegments(allPrevSegments
), false);
141 * In `if (a) return a; foo();` case, the unreachable segment preceded by
142 * the return statement is not used but must not be remove.
144 CodePathSegment
.markUsed(segment
);
150 * Creates a segment that follows given segments.
151 * This factory method does not connect with `allPrevSegments`.
152 * But this inherits `reachable` flag.
153 * @param {string} id An identifier.
154 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
155 * @returns {CodePathSegment} The created segment.
157 static newDisconnected(id
, allPrevSegments
) {
158 return new CodePathSegment(id
, [], allPrevSegments
.some(isReachable
));
162 * Makes a given segment being used.
164 * And this function registers the segment into the previous segments as a next.
165 * @param {CodePathSegment} segment A segment to mark.
168 static markUsed(segment
) {
169 if (segment
.internal.used
) {
172 segment
.internal.used
= true;
176 if (segment
.reachable
) {
177 for (i
= 0; i
< segment
.allPrevSegments
.length
; ++i
) {
178 const prevSegment
= segment
.allPrevSegments
[i
];
180 prevSegment
.allNextSegments
.push(segment
);
181 prevSegment
.nextSegments
.push(segment
);
184 for (i
= 0; i
< segment
.allPrevSegments
.length
; ++i
) {
185 segment
.allPrevSegments
[i
].allNextSegments
.push(segment
);
191 * Marks a previous segment as looped.
192 * @param {CodePathSegment} segment A segment.
193 * @param {CodePathSegment} prevSegment A previous segment to mark.
196 static markPrevSegmentAsLooped(segment
, prevSegment
) {
197 segment
.internal.loopedPrevSegments
.push(prevSegment
);
201 * Replaces unused segments with the previous segments of each unused segment.
202 * @param {CodePathSegment[]} segments An array of segments to replace.
203 * @returns {CodePathSegment[]} The replaced array.
205 static flattenUnusedSegments(segments
) {
206 const done
= Object
.create(null);
209 for (let i
= 0; i
< segments
.length
; ++i
) {
210 const segment
= segments
[i
];
212 // Ignores duplicated.
213 if (done
[segment
.id
]) {
217 // Use previous segments if unused.
218 if (!segment
.internal.used
) {
219 for (let j
= 0; j
< segment
.allPrevSegments
.length
; ++j
) {
220 const prevSegment
= segment
.allPrevSegments
[j
];
222 if (!done
[prevSegment
.id
]) {
223 done
[prevSegment
.id
] = true;
224 retv
.push(prevSegment
);
228 done
[segment
.id
] = true;
237 module
.exports
= CodePathSegment
;