UNPKG

@cspell/eslint-plugin

Version:
166 lines 5.13 kB
"use strict"; 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