]>
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
{
37 * @param {string} id An identifier.
38 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
39 * This array includes unreachable segments.
40 * @param {boolean} reachable A flag which shows this is reachable.
42 constructor(id
, allPrevSegments
, reachable
) {
45 * The identifier of this code path.
46 * Rules use it to store additional information of each rule.
52 * An array of the next segments.
53 * @type {CodePathSegment[]}
55 this.nextSegments
= [];
58 * An array of the previous segments.
59 * @type {CodePathSegment[]}
61 this.prevSegments
= allPrevSegments
.filter(isReachable
);
64 * An array of the next segments.
65 * This array includes unreachable segments.
66 * @type {CodePathSegment[]}
68 this.allNextSegments
= [];
71 * An array of the previous segments.
72 * This array includes unreachable segments.
73 * @type {CodePathSegment[]}
75 this.allPrevSegments
= allPrevSegments
;
78 * A flag which shows this is reachable.
81 this.reachable
= reachable
;
84 Object
.defineProperty(this, "internal", {
87 loopedPrevSegments
: []
93 this.internal.nodes
= [];
98 * Checks a given previous segment is coming from the end of a loop.
99 * @param {CodePathSegment} segment A previous segment to check.
100 * @returns {boolean} `true` if the segment is coming from the end of a loop.
102 isLoopedPrevSegment(segment
) {
103 return this.internal.loopedPrevSegments
.includes(segment
);
107 * Creates the root segment.
108 * @param {string} id An identifier.
109 * @returns {CodePathSegment} The created segment.
112 return new CodePathSegment(id
, [], true);
116 * Creates a segment that follows given segments.
117 * @param {string} id An identifier.
118 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
119 * @returns {CodePathSegment} The created segment.
121 static newNext(id
, allPrevSegments
) {
122 return new CodePathSegment(
124 CodePathSegment
.flattenUnusedSegments(allPrevSegments
),
125 allPrevSegments
.some(isReachable
)
130 * Creates an unreachable segment that follows given segments.
131 * @param {string} id An identifier.
132 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
133 * @returns {CodePathSegment} The created segment.
135 static newUnreachable(id
, allPrevSegments
) {
136 const segment
= new CodePathSegment(id
, CodePathSegment
.flattenUnusedSegments(allPrevSegments
), false);
139 * In `if (a) return a; foo();` case, the unreachable segment preceded by
140 * the return statement is not used but must not be remove.
142 CodePathSegment
.markUsed(segment
);
148 * Creates a segment that follows given segments.
149 * This factory method does not connect with `allPrevSegments`.
150 * But this inherits `reachable` flag.
151 * @param {string} id An identifier.
152 * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
153 * @returns {CodePathSegment} The created segment.
155 static newDisconnected(id
, allPrevSegments
) {
156 return new CodePathSegment(id
, [], allPrevSegments
.some(isReachable
));
160 * Makes a given segment being used.
162 * And this function registers the segment into the previous segments as a next.
163 * @param {CodePathSegment} segment A segment to mark.
166 static markUsed(segment
) {
167 if (segment
.internal.used
) {
170 segment
.internal.used
= true;
174 if (segment
.reachable
) {
175 for (i
= 0; i
< segment
.allPrevSegments
.length
; ++i
) {
176 const prevSegment
= segment
.allPrevSegments
[i
];
178 prevSegment
.allNextSegments
.push(segment
);
179 prevSegment
.nextSegments
.push(segment
);
182 for (i
= 0; i
< segment
.allPrevSegments
.length
; ++i
) {
183 segment
.allPrevSegments
[i
].allNextSegments
.push(segment
);
189 * Marks a previous segment as looped.
190 * @param {CodePathSegment} segment A segment.
191 * @param {CodePathSegment} prevSegment A previous segment to mark.
194 static markPrevSegmentAsLooped(segment
, prevSegment
) {
195 segment
.internal.loopedPrevSegments
.push(prevSegment
);
199 * Replaces unused segments with the previous segments of each unused segment.
200 * @param {CodePathSegment[]} segments An array of segments to replace.
201 * @returns {CodePathSegment[]} The replaced array.
203 static flattenUnusedSegments(segments
) {
204 const done
= Object
.create(null);
207 for (let i
= 0; i
< segments
.length
; ++i
) {
208 const segment
= segments
[i
];
210 // Ignores duplicated.
211 if (done
[segment
.id
]) {
215 // Use previous segments if unused.
216 if (!segment
.internal.used
) {
217 for (let j
= 0; j
< segment
.allPrevSegments
.length
; ++j
) {
218 const prevSegment
= segment
.allPrevSegments
[j
];
220 if (!done
[prevSegment
.id
]) {
221 done
[prevSegment
.id
] = true;
222 retv
.push(prevSegment
);
226 done
[segment
.id
] = true;
235 module
.exports
= CodePathSegment
;