@cspell/eslint-plugin
Version:
166 lines • 5.13 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AstPathScope = exports.AstScopeMatcher = void 0;
exports.scopeItem = scopeItem;
exports.parseScope = parseScope;
exports.keyToString = keyToString;
exports.mapNodeToScope = mapNodeToScope;
exports.mapNodeToScopeItem = mapNodeToScopeItem;
exports.mapScopeItemToString = mapScopeItemToString;
exports.astPathToScope = astPathToScope;
exports.astScopeToString = astScopeToString;
exports.astPathToScopeItems = astPathToScopeItems;
const node_assert_1 = __importDefault(require("node:assert"));
class AstScopeMatcher {
scope;
constructor(scope) {
this.scope = scope;
}
static fromScopeSelector(scopeSelector) {
return new AstScopeMatcher(parseScope(scopeSelector).reverse());
}
/**
* Score the astScope based on the given scope.
* @param astScope The scope to score.
* @returns The score of the scope. 0 = no match, higher the score the better the match.
*/
score(astScope) {
try {
const scopeItems = astScope.map(parseScopeItem).reverse();
return this.scoreItems(scopeItems);
}
catch {
console.error('Failed to parse scope: %o', astScope);
return 0;
}
}
/**
* Score the astScope based on the given scope.
* @param astScope The scope to score.
* @returns The score of the scope. 0 = no match, higher the score the better the match.
*/
scoreItems(scopeItems) {
const scope = this.scope;
let score = 0;
let scale = 1;
let matchKey = false;
for (let i = 0; i < scope.length; i++) {
const item = scopeItems[i];
if (!item)
return 0;
const curr = scope[i];
if (curr.type !== item.type)
return 0;
if (curr.childKey && item.childKey && curr.childKey !== item.childKey)
return 0;
if (curr.childKey && !item.childKey && matchKey)
return 0;
if (curr.childKey && (curr.childKey == item.childKey || !matchKey)) {
score += scale;
}
score += scale * 2;
matchKey = true;
scale *= 4;
}
return score;
}
matchPath(path) {
const s = this.scope[0];
// Early out
if (s?.type !== path.node.type)
return 0;
const items = astPathToScopeItems(path);
return this.scoreItems(items);
}
scopeField() {
return this.scope[0]?.childKey || 'value';
}
scopeType() {
return this.scope[0]?.type || '';
}
}
exports.AstScopeMatcher = AstScopeMatcher;
function scopeItem(type, childKey) {
return { type, childKey };
}
const regexValidScope = /^([\w.-]+)(?:\[([\w<>.-]*)\])?$/;
function parseScopeItem(item) {
const match = item.match(regexValidScope);
(0, node_assert_1.default)(match, `Invalid scope item: ${item}`);
const [_, type, key] = match;
return { type, childKey: key || undefined };
}
function parseScope(scope) {
return scope
.split(' ')
.filter((s) => s)
.map(parseScopeItem);
}
function keyToString(key) {
return key === undefined || key === null
? undefined
: typeof key === 'symbol'
? `<${Symbol.keyFor(key)}>`
: `${key}`;
}
function mapNodeToScope(p, key) {
return mapNodeToScopeItem(p, key);
}
function mapNodeToScopeItem(p, childKey) {
return scopeItem(p.node.type, keyToString(childKey));
}
function mapScopeItemToString(item) {
const { type, childKey: k } = item;
return k === undefined ? type : `${type}[${k}]`;
}
/**
* Convert an ASTPath to a scope.
* @param path - The path to convert to a scope.
* @returns
*/
function astPathToScope(path, mapFn = mapNodeToScope) {
return astPathToScopeItems(path, mapFn).map(mapScopeItemToString).reverse();
}
function astScopeToString(path, sep = ' ', mapFn) {
return astPathToScope(path, mapFn).join(sep);
}
function astPathToScopeItems(path, mapFn = mapNodeToScope) {
const parts = [];
let key = undefined;
while (path) {
parts.push(mapFn(path, key));
key = path?.key;
path = path.prev;
}
return parts;
}
class AstPathScope {
path;
items;
constructor(path) {
this.path = path;
this.items = astPathToScopeItems(path);
}
get scope() {
return this.items.map(mapScopeItemToString).reverse();
}
get scopeItems() {
return this.items;
}
get scopeString() {
return this.scope.join(' ');
}
score(matcher) {
const field = matcher.scopeField();
const node = this.path.node;
if (field in node && typeof node[field] === 'string') {
return matcher.scoreItems(this.items);
}
return 0;
}
}
exports.AstPathScope = AstPathScope;
//# sourceMappingURL=scope.cjs.map