/
githubmr
/
facebook-react
Обзор
Документация
Войти
/
githubmr
/
facebook-react
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
packages/eslint-plugin-react-hooks/src/code-path-analysis/code-path-segment.js
225 строк
6 KB
Jan Kassens
[eslint-plugin-react-hooks] updates for component syntax (#33089)
02 май 2025, 22:04
Не верифицирован
02 май 2025, 22:04
4c4a57c
Код
Авторство
О чём код?
'use strict'; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ /** * 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: [], }, }); } /** * 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.includes(segment); } /** * 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, CodePathSegment.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, CodePathSegment.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); } /** * 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. */ static 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; } } module.exports = CodePathSegment;