webpack/lib/util/mergeScope.js

89 lines
2.3 KiB
JavaScript

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
/** @typedef {import("eslint-scope").Reference} Reference */
/** @typedef {import("eslint-scope").Variable} Variable */
/** @typedef {import("estree").Node} Node */
/** @typedef {import("estree").Program} Program */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/**
* @param {Variable} variable variable
* @returns {Reference[]} references
*/
const getAllReferences = variable => {
let set = variable.references;
// Look for inner scope variables too (like in class Foo { t() { Foo } })
const identifiers = new Set(variable.identifiers);
for (const scope of variable.scope.childScopes) {
for (const innerVar of scope.variables) {
if (innerVar.identifiers.some(id => identifiers.has(id))) {
set = set.concat(innerVar.references);
break;
}
}
}
return set;
};
/**
* @param {Node | Node[]} ast ast
* @param {Node} node node
* @returns {undefined | Node[]} result
*/
const getPathInAst = (ast, node) => {
if (ast === node) {
return [];
}
const nr = /** @type {Range} */ (node.range);
/**
* @param {Node} n node
* @returns {Node[] | undefined} result
*/
const enterNode = n => {
if (!n) return;
const r = n.range;
if (r && r[0] <= nr[0] && r[1] >= nr[1]) {
const path = getPathInAst(n, node);
if (path) {
path.push(n);
return path;
}
}
};
if (Array.isArray(ast)) {
for (let i = 0; i < ast.length; i++) {
const enterResult = enterNode(ast[i]);
if (enterResult !== undefined) return enterResult;
}
} else if (ast && typeof ast === "object") {
const keys =
/** @type {Array<keyof Node>} */
(Object.keys(ast));
for (let i = 0; i < keys.length; i++) {
// We are making the faster check in `enterNode` using `n.range`
const value =
ast[
/** @type {Exclude<keyof Node, "range" | "loc" | "leadingComments" | "trailingComments">} */
(keys[i])
];
if (Array.isArray(value)) {
const pathResult = getPathInAst(value, node);
if (pathResult !== undefined) return pathResult;
} else if (value && typeof value === "object") {
const enterResult = enterNode(value);
if (enterResult !== undefined) return enterResult;
}
}
}
};
module.exports = { getAllReferences, getPathInAst };